Skip to content

Fix configuration cache compatibility in all tasks#3

Merged
ClankerGuru merged 3 commits into
mainfrom
fix/configuration-cache-compatibility
Apr 14, 2026
Merged

Fix configuration cache compatibility in all tasks#3
ClankerGuru merged 3 commits into
mainfrom
fix/configuration-cache-compatibility

Conversation

@ClankerGuru
Copy link
Copy Markdown
Owner

@ClankerGuru ClankerGuru commented Apr 14, 2026

Summary

  • Replace all project.rootDir, project.findProperty(), and project.gradle.includedBuilds access in @TaskAction methods with abstract Property<> fields wired at configuration time
  • Add OpsxConfig serializable data class for settings
  • Refactor SkillGenerator to accept data instead of Project
  • Remove dead inner task classes from Opsx.kt
  • All 14 tasks now work with Gradle configuration cache

Test plan

  • ./gradlew build passes (detekt, ktlint, 400 tests, kover)
  • ./gradlew opsx-status works with configuration cache
  • ./gradlew opsx-list works with configuration cache

Change proposed via opsx

This change was proposed with opsx-propose and applied with opsx-apply.

Summary by CodeRabbit

  • Refactor
    • Improved internal configuration architecture with enhanced dependency injection mechanisms across build system tasks and utilities.
    • Reorganized task setup workflow to support more flexible and testable configuration patterns.
    • Updated test infrastructure to align with refactored architecture.

Replace all project.rootDir, project.findProperty(), and
project.gradle.includedBuilds access in @TaskAction methods with
abstract Property<> fields wired at configuration time in Opsx.kt.

- Add OpsxConfig serializable data class for settings
- Convert all 14 tasks from lateinit extension to Property<> fields
- Refactor SkillGenerator to accept data instead of Project
- Remove dead inner task classes from Opsx.kt
- Split registerWorkflowTasks into smaller methods for detekt
- Update all tests for new Property-based API
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 14, 2026

Warning

Rate limit exceeded

@ClankerGuru has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 38 minutes and 25 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 38 minutes and 25 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4ed3bec8-bdcf-42ed-a6bc-134bd720e439

📥 Commits

Reviewing files that changed from the base of the PR and between 25ad613 and 14be04c.

📒 Files selected for processing (3)
  • README.md
  • src/main/kotlin/zone/clanker/opsx/Opsx.kt
  • src/test/kotlin/zone/clanker/opsx/skill/SkillGeneratorTest.kt
📝 Walkthrough

Walkthrough

This pull request refactors the Opsx Gradle plugin to decouple task execution from the plugin extension by introducing a new OpsxConfig model and replacing extension-based configuration with explicit Gradle Property-backed task inputs. The plugin now passes configuration, root directories, and other parameters directly to tasks rather than injecting the extension. SkillGenerator is similarly refactored to accept injected dependencies instead of relying on the Gradle Project API.

Changes

Cohort / File(s) Summary
Configuration Model
src/main/kotlin/zone/clanker/opsx/model/OpsxConfig.kt
New serializable data class OpsxConfig with outputDir, specsDir, changesDir, and projectFile properties, replacing extension-based directory configuration.
Plugin Wiring
src/main/kotlin/zone/clanker/opsx/Opsx.kt
Refactored task registration to use Provider-backed configuration; added SettingsExtension.toOpsxConfig() conversion method; split workflow task registration; updated infrastructure tasks (opsx-status, opsx-list, opsx-sync, opsx-clean) to receive rootDir, config, and Gradle property inputs directly.
Skill Generation
src/main/kotlin/zone/clanker/opsx/skill/SkillGenerator.kt
Removed Gradle Project dependency; constructor now accepts injected rootDir: File, tasks: List<TaskInfo>, and buildNames: List<String>; updated method signatures to accept List<String> for builds instead of Collection<IncludedBuild>.
Workflow Helpers
src/main/kotlin/zone/clanker/opsx/workflow/ChangeReader.kt, ChangeWriter.kt, PromptBuilder.kt
Updated all three classes to accept OpsxConfig instead of Opsx.SettingsExtension; adjusted path construction to use config properties; renamed internal variables to avoid shadowing.
Task Implementations (Workflow)
src/main/kotlin/zone/clanker/opsx/task/ApplyTask.kt, ArchiveTask.kt, BulkArchiveTask.kt, ContinueTask.kt, ExploreTask.kt, FeedbackTask.kt, FfTask.kt, OnboardTask.kt, ProposeTask.kt, VerifyTask.kt
Replaced extension: Opsx.SettingsExtension field with explicit Gradle Property inputs (rootDir, config, and task-specific inputs like changeName, prompt, agent, model, spec); updated run() methods to resolve values from properties rather than extension/project lookups; adjusted helper method signatures to accept root: File parameter.
Task Implementations (Infrastructure)
src/main/kotlin/zone/clanker/opsx/task/CleanTask.kt, ListTask.kt, StatusTask.kt, SyncTask.kt
Added/updated Property-based inputs (rootDir, config, taskInfos, includedBuildNames, includedBuildDirs); removed extension dependency; updated directory/task iteration logic to use injected properties instead of Gradle API calls.
Tests (Plugin & Skill Generator)
src/test/kotlin/zone/clanker/opsx/OpsxPluginTest.kt, skill/SkillGeneratorTest.kt
Updated test setup to instantiate task classes directly; replaced extension assignments with property configuration; changed SkillGenerator construction to pass explicit task/build lists instead of Gradle Project.
Tests (Task Classes)
src/test/kotlin/zone/clanker/opsx/task/*.kt
Updated all task test files to set rootDir/config properties instead of extension; converted test helpers to produce OpsxConfig via toOpsxConfig(); adjusted method call signatures for refactored task helper methods (e.g., buildFfPrompt, buildVerifyPrompt now receive root: File as first parameter).
Tests (Workflow Helpers)
src/test/kotlin/zone/clanker/opsx/workflow/ChangeReaderTest.kt, ChangeWriterTest.kt, PromptBuilderTest.kt
Updated all helper class tests to pass OpsxConfig instances instead of Opsx.SettingsExtension to constructor/method calls; converted test-local extensions to configs using toOpsxConfig().

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 From extensions tangled deep in Gradle's core,
We freed the tasks with configs they adore—
Properties injected, dependencies lean,
The cleanest refactor I ever have seen!
No more Project chains, just values to pass,
A plugin reborn—now that's some first-class grass! 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix configuration cache compatibility in all tasks' directly and accurately summarizes the main purpose of this changeset, which is to refactor all tasks to use Property<>-based fields instead of direct project access to achieve Gradle configuration cache compatibility.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/configuration-cache-compatibility

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/test/kotlin/zone/clanker/opsx/task/CleanTaskTest.kt (1)

25-26: Add one non-empty includedBuildDirs case.

All of the updated setups initialize the new task input to emptyList(), so the included-build cleanup path never gets exercised. One fixture with a nested included build would give this refactor much better protection for very little extra test code.

Also applies to: 50-51, 87-88, 122-123, 153-154, 183-184, 204-205

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/kotlin/zone/clanker/opsx/task/CleanTaskTest.kt` around lines 25 -
26, The tests set task.includedBuildDirs to emptyList() everywhere so the
included-build cleanup path is never exercised; update the CleanTaskTest cases
that call task.includedBuildDirs.set(emptyList()) to include at least one
non-empty case by creating a nested included-build fixture (e.g., create a
directory under the test projectDir like "included" or "nested-build") and call
task.includedBuildDirs.set(listOf(includedDir)) for one test variant; ensure the
test asserts that the included build directory is processed/cleaned (same
assertions used for rootDir cleanup) and apply this change to each occurrence of
task.includedBuildDirs.set(emptyList()) in CleanTaskTest.kt so the
included-build branch is covered.
src/main/kotlin/zone/clanker/opsx/task/SyncTask.kt (1)

26-27: includedBuildDirs is unused in SyncTask.

The property is declared but never referenced within the SyncTask implementation—only includedBuildNames is passed to SkillGenerator. This appears to be a copy-paste artifact from CleanTask, where includedBuildDirs is actually used. Remove this property to improve code clarity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/kotlin/zone/clanker/opsx/task/SyncTask.kt` around lines 26 - 27,
Remove the unused includedBuildDirs property from SyncTask: delete the
`@get`:Internal abstract val includedBuildDirs: ListProperty<File> declaration and
any associated imports/annotations referencing it, leaving SyncTask to use
includedBuildNames (which is actually passed to SkillGenerator); ensure no
remaining references to includedBuildDirs exist (it was a copy-paste artifact
from CleanTask) so the class compiles cleanly.
src/main/kotlin/zone/clanker/opsx/task/OnboardTask.kt (1)

39-42: Bake the repo’s workflow guardrails into the onboarding prompt.

Now that buildOnboardPrompt(...) is the single place defining the guided tour, it should also teach the two repo-specific rules enforced elsewhere: start work via opsx-propose, and don’t manually edit files across included builds. Otherwise the onboarding path can teach a workflow the repo rejects.

Suggested prompt tweak
                 appendLine("- How to contribute changes using the opsx workflow")
+                appendLine("- That changes should start via `/opsx-propose` or `./gradlew -q opsx-propose`")
+                appendLine("- That included builds should not be edited manually; use OPSX Gradle tasks instead")
                 if (userPrompt.isNotBlank()) {

Based on learnings: Changes should be proposed via /opsx-propose or ./gradlew -q opsx-propose command, and do NOT manually edit files across included builds. Use the Gradle tasks provided by OPSX.

Also applies to: 51-57

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/kotlin/zone/clanker/opsx/task/OnboardTask.kt` around lines 39 - 42,
The onboarding prompt is missing repo-specific workflow guardrails; update the
buildOnboardPrompt(...) implementation (the single source for the guided tour)
to append explicit instructions that all changes must be proposed via the
opsx-propose entrypoints ("/opsx-propose" or "./gradlew -q opsx-propose") and
that contributors must NOT manually edit files across included builds (use the
provided Gradle OPSX tasks instead). Locate where PromptBuilder.srcxContext()
and PromptBuilder.projectDescription(cfg) are used to compose the prompt (calls
to buildOnboardPrompt in OnboardTask) and modify buildOnboardPrompt to include
these two rules so the prompt text presented by OnboardTask (and the other call
sites) enforces the repo workflow.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/kotlin/zone/clanker/opsx/Opsx.kt`:
- Around line 230-245: The provider lambdas for taskInfos, includedBuildNames,
and includedBuildDirs close over live Gradle model objects (rootProject.tasks
and rootProject.gradle.includedBuilds) and therefore must be evaluated during
configuration, not at task execution; change the Opsx.kt configuration so you
compute immutable snapshots (e.g., List<TaskInfo>, List<String>, List<File>) by
calling rootProject.tasks...map(...) and
rootProject.gradle.includedBuilds.map(...) immediately inside the configuration
block (instead of returning providers that reference the live model), then set
those snapshot values on the task properties so SyncTask.run() and
CleanTask.run() read only frozen data via .get() at execution time without
accessing the Gradle model. Ensure you update the code paths that set taskInfos,
includedBuildNames, and includedBuildDirs and keep
SyncTask.run()/CleanTask.run() signatures intact.

In `@src/test/kotlin/zone/clanker/opsx/skill/SkillGeneratorTest.kt`:
- Around line 30-38: The test "generates no files" for SkillGenerator
(constructed via SkillGenerator(project.projectDir, emptyList(), emptyList())
using ProjectBuilder) has a mismatched assertion: it asserts result.isNotEmpty()
shouldBe true while the name implies no files; verify the intended behavior of
SkillGenerator.generate(), then either change the assertion to result.isEmpty()
shouldBe true if no files are expected, or rename the test description (e.g.,
"still generates instruction files") to match the existing result.isNotEmpty()
shouldBe true assertion so the test name and assertion align.

---

Nitpick comments:
In `@src/main/kotlin/zone/clanker/opsx/task/OnboardTask.kt`:
- Around line 39-42: The onboarding prompt is missing repo-specific workflow
guardrails; update the buildOnboardPrompt(...) implementation (the single source
for the guided tour) to append explicit instructions that all changes must be
proposed via the opsx-propose entrypoints ("/opsx-propose" or "./gradlew -q
opsx-propose") and that contributors must NOT manually edit files across
included builds (use the provided Gradle OPSX tasks instead). Locate where
PromptBuilder.srcxContext() and PromptBuilder.projectDescription(cfg) are used
to compose the prompt (calls to buildOnboardPrompt in OnboardTask) and modify
buildOnboardPrompt to include these two rules so the prompt text presented by
OnboardTask (and the other call sites) enforces the repo workflow.

In `@src/main/kotlin/zone/clanker/opsx/task/SyncTask.kt`:
- Around line 26-27: Remove the unused includedBuildDirs property from SyncTask:
delete the `@get`:Internal abstract val includedBuildDirs: ListProperty<File>
declaration and any associated imports/annotations referencing it, leaving
SyncTask to use includedBuildNames (which is actually passed to SkillGenerator);
ensure no remaining references to includedBuildDirs exist (it was a copy-paste
artifact from CleanTask) so the class compiles cleanly.

In `@src/test/kotlin/zone/clanker/opsx/task/CleanTaskTest.kt`:
- Around line 25-26: The tests set task.includedBuildDirs to emptyList()
everywhere so the included-build cleanup path is never exercised; update the
CleanTaskTest cases that call task.includedBuildDirs.set(emptyList()) to include
at least one non-empty case by creating a nested included-build fixture (e.g.,
create a directory under the test projectDir like "included" or "nested-build")
and call task.includedBuildDirs.set(listOf(includedDir)) for one test variant;
ensure the test asserts that the included build directory is processed/cleaned
(same assertions used for rootDir cleanup) and apply this change to each
occurrence of task.includedBuildDirs.set(emptyList()) in CleanTaskTest.kt so the
included-build branch is covered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 89a523fd-793a-4b00-bb22-c5aa04de2a2e

📥 Commits

Reviewing files that changed from the base of the PR and between 19a6d3d and 25ad613.

📒 Files selected for processing (39)
  • src/main/kotlin/zone/clanker/opsx/Opsx.kt
  • src/main/kotlin/zone/clanker/opsx/model/OpsxConfig.kt
  • src/main/kotlin/zone/clanker/opsx/skill/SkillGenerator.kt
  • src/main/kotlin/zone/clanker/opsx/task/ApplyTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/ArchiveTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/BulkArchiveTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/CleanTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/ContinueTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/ExploreTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/FeedbackTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/FfTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/ListTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/OnboardTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/ProposeTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/StatusTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/SyncTask.kt
  • src/main/kotlin/zone/clanker/opsx/task/VerifyTask.kt
  • src/main/kotlin/zone/clanker/opsx/workflow/ChangeReader.kt
  • src/main/kotlin/zone/clanker/opsx/workflow/ChangeWriter.kt
  • src/main/kotlin/zone/clanker/opsx/workflow/PromptBuilder.kt
  • src/test/kotlin/zone/clanker/opsx/OpsxPluginTest.kt
  • src/test/kotlin/zone/clanker/opsx/skill/SkillGeneratorTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/ApplyTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/ArchiveTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/BulkArchiveTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/CleanTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/ContinueTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/ExploreTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/FeedbackTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/FfTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/ListTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/OnboardTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/ProposeTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/StatusTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/SyncTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/task/VerifyTaskTest.kt
  • src/test/kotlin/zone/clanker/opsx/workflow/ChangeReaderTest.kt
  • src/test/kotlin/zone/clanker/opsx/workflow/ChangeWriterTest.kt
  • src/test/kotlin/zone/clanker/opsx/workflow/PromptBuilderTest.kt

Comment thread src/main/kotlin/zone/clanker/opsx/Opsx.kt Outdated
Comment thread src/test/kotlin/zone/clanker/opsx/skill/SkillGeneratorTest.kt
Snapshot taskInfos, includedBuildNames, includedBuildDirs during
configuration instead of using providers that close over live Gradle
model. Fix misleading test name "generates no files" to "still
generates instruction files".
@ClankerGuru ClankerGuru merged commit df967db into main Apr 14, 2026
2 checks passed
@ClankerGuru ClankerGuru deleted the fix/configuration-cache-compatibility branch April 14, 2026 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant