Clean the Compiler output directories only when the task executes (#21)#70
Merged
Merged
Conversation
`LaunchSpineCompiler` registered an unconditional `doFirst` action that wiped the target directories on every invocation. Combined with the historic lack of declared inputs and outputs, this forced users to run `./gradlew clean build`. The launch task is now `@CacheableTask` with declared inputs and outputs, so the eager wipe is unnecessary and hostile to incremental builds. Move the cleanup into an `exec()` override so it runs only when the task actually executes; up-to-date or cache-restored runs keep the generated code. Delete only this task's own output directories, preserving any that coincide with a source directory (the deprecated in-place overwrite mode). This drops the previous `sources`/`targets` zip with `Files.isSameFile`, and removes the early return on empty `sources` so descriptor-only mode no longer leaves stale files behind. Deletion uses an injected `FileSystemOperations` instead of `Task.project` at execution time. Add functional tests for the no-`clean` flows: a proto rename drops stale generated files, a deleted `generated/` directory is restored while `generateProto` stays up-to-date, an unrelated source change keeps the launch task up-to-date, and settings rewritten with identical content do not break up-to-dateness. Fixes #21 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`test-env` calls `disableDocumentationTasks()`, so its per-module Dokka tasks are skipped and it never produces the `module-descriptor.json` that the multi-module publication consolidates. Including it in the root `dokka(...)` aggregation made `:dokkaGeneratePublicationHtml` fail on the missing descriptor whenever `dokkaGenerate` ran. Filter it out so the aggregation matches the modules that actually generate documentation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves incremental build behavior for the Spine Compiler Gradle integration by ensuring LaunchSpineCompiler cleans its outputs only when the task actually executes (not on up-to-date / cache-restored runs), and adds functional test coverage for the no-clean workflows. It also includes a small fix for root Dokka aggregation and updates versions/reports.
Changes:
- Update
LaunchSpineCompilerto delete its target output directories insideexec()using injectedFileSystemOperations, preserving any target directory that matches a source directory. - Add functional tests covering incremental proto changes, deleted
generated/restoration, unrelated source changes, and stable settings rewrites. - Fix Dokka aggregation by excluding
test-env, and bump/update versions and generated dependency reports.
Reviewed changes
Copilot reviewed 19 out of 22 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| version.gradle.kts | Bump compiler version to 2.0.0-SNAPSHOT.052. |
| protoc-plugin/src/main/kotlin/io/spine/tools/compiler/protoc/Plugin.kt | Switch CodeGeneratorRequestWriter import to the io.spine.tools.code.proto package. |
| protoc-plugin/build.gradle.kts | Add tool-base dependency to supply CodeGeneratorRequestWriter. |
| gradle.properties | Enable Gradle build caching. (Config-managed in many Spine repos; not reviewed in depth here.) |
| gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/LaunchSpineCompiler.kt | Move cleanup to exec() and use injected FileSystemOperations so cleanup runs only on actual task execution. |
| gradle-plugin/src/functionalTest/kotlin/io/spine/tools/compiler/gradle/plugin/PluginSpec.kt | Add functional tests for incremental/no-clean scenarios and refactor test setup helper. |
| docs/dependencies/pom.xml | Update published-docs dependency versions to match the new snapshot set. |
| docs/dependencies/dependencies.md | Refresh generated dependency/license report content for the new version set. |
| buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt | Add tests for increment-guard branch/event logic. (Config-managed; skipped.) |
| buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/SiblingCoverage.kt | Add helper for cross-module Kover crediting. (Config-managed; skipped.) |
| buildSrc/src/main/kotlin/io/spine/gradle/report/coverage/KoverConfig.kt | Rename/refactor helper method for class name discovery. (Config-managed; skipped.) |
| buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt | Change guard logic to PR-base-branch based decision. (Config-managed; skipped.) |
| buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt | Bump tool-base version constants. (Config-managed; skipped.) |
| buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt | Bump core-jvm-plugins version constants. (Config-managed; skipped.) |
| buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt | Bump compiler fallback versions. (Config-managed; skipped.) |
| buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt | Bump spine-base version constants. (Config-managed; skipped.) |
| build.gradle.kts | Exclude test-env from Dokka aggregation to prevent missing module-descriptor.json failures. |
| .github/workflows/increment-guard.yml | Update version-guard workflow trigger/conditions. (Config-managed; skipped.) |
| .github/workflows/ensure-reports-updated.yml | Update license-reports workflow trigger/conditions. (Config-managed; skipped.) |
| .github/workflows/build-on-windows.yml | Simplify Windows workflow steps/Gradle invocation. (Config-managed; skipped.) |
| .agents/tasks/clean-output-only-when-needed.md | Task log/plan file. (Config-managed; skipped.) |
armiol
approved these changes
Jun 11, 2026
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #70 +/- ##
============================================
+ Coverage 75.09% 75.34% +0.25%
- Complexity 668 672 +4
============================================
Files 202 202
Lines 3915 3947 +32
Branches 395 393 -2
============================================
+ Hits 2940 2974 +34
+ Misses 857 855 -2
Partials 118 118 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Resolves #21 —
LaunchSpineCompilershould clean the output dir only when needed.LaunchSpineCompilerregistered an unconditionaldoFirstaction that wiped its target directories on every invocation. Together with the historic lack of declared inputs/outputs, this forced users to run./gradlew clean build. The task is now@CacheableTaskwith declared inputs and outputs, so the eager wipe is unnecessary and actively hostile to incremental builds.Changes
LaunchSpineCompiler— cleanup simplifiedexec()override, so it runs only when the task actually executes. Up-to-date and cache-restored runs leave the generated code intact — incremental builds no longer needclean.protocoverwrite mode). This removes the oldsources/targetszip +Files.isSameFile"gymnastics" noted in the issue.sources, so descriptor-only mode (protoc built-ins off) no longer leaves stale files behind.FileSystemOperationsinstead ofTask.projectat execution time (configuration-cache friendly).Functional tests — four new
PluginSpeccases for the no-cleanflows:generated/directory is restored whilegenerateProtostaysUP_TO_DATE;UP_TO_DATE;UP_TO_DATE.Dokka aggregation fix —
build.gradle.ktstest-envcallsdisableDocumentationTasks(), so it never produces themodule-descriptor.jsonthe multi-module Dokka publication consolidates. It was still in the rootdokka(...)aggregation, so:dokkaGeneratePublicationHtmlfailed on the missing descriptor wheneverdokkaGenerateran. Now excluded, so repo-widedokkaGeneratepasses. This was a pre-existing failure (unrelated toLaunchSpineCompilershould clean the output dir only when needed #21) surfaced while running the pre-PR checks.Verification
./gradlew build(CI parity): BUILD SUCCESSFUL, no failed tasks.:gradle-plugin:check: 15 functional tests, 0 failures (1 pre-existing@Disabledskip); detekt clean../gradlew dokkaGenerate(both changes present): BUILD SUCCESSFUL — root aggregation now green.spine-code-review,kotlin-engineer,review-docs— all APPROVE; actionable findings applied.Notes for the reviewer
sources, the task now cleans its declared output dirs instead of skipping cleanup. Targets are this task's own@OutputDirectories, so deleting them before regeneration is the intended contract (documented in the class KDoc).