Repository navigation
SpotlessApply: report changed files and only set didWork when files changed (#2715) - #3177
Merged
nedtwigg merged 4 commits intoNov 10, 2026
Merged
Conversation
…iffplug#2715) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MTr23z6ccMd2shvyTaTFVY
…hanged (diffplug#2715) - Each SpotlessApply writes the files its most recent run rewrote to build/spotless/<taskName>-changed-files.txt (configurable via changedFilesReport). The report is empty if nothing changed and is written even when the task then fails on lints. - didWork is now true only if a source file was actually rewritten. Clean files that are byte-identical to the source are no longer copied. - UpToDateTest: the run after a fix now shows the apply tasks UP-TO-DATE while the format task still runs. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MTr23z6ccMd2shvyTaTFVY
…diffplug#2715) The second apply after a fix re-runs the format task, but there is nothing left to apply, so the apply tasks are now UP-TO-DATE. Move the assertion for that step into GradleIntegrationHarness#applyOnlyRerunsFormatTask and use it from both UpToDateTest and BumpThisNumberIfACustomStepChangesTest. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MTr23z6ccMd2shvyTaTFVY
Addresses review feedback on diffplug#2715: the changed-files report should be a proper task output, so tasks that consume it work with Gradle's task graph and caching. - changedFilesReport is now @OutputFile instead of @internal, so a task that uses the provider as an input gets an implicit dependency on the apply task (no manual dependsOn). - Since apply declares outputs but no inputs, Gradle would otherwise mark it UP-TO-DATE whenever the report is unchanged and skip rewriting sources; outputs.upToDateWhen { false } keeps it always running (same approach as the IDE hook). Apply stays @DisableCachingByDefault. - Tests: consumer gets implicit dependency, consumer works with the configuration cache, and apply is never skipped because its report is unchanged (fails without upToDateWhen). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MTr23wUKk2wLNAcmdt8aq3
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.
Closes #2715
Why
Many builds run
spotlessApplylocally as part ofbuild, so developers never see what Spotless fixed. The issue asks for a way to tell whenspotlessApplyactually changed something, and which files. The obvious workaround (doLast { if (didWork) ... }) doesn't work today, becauseSpotlessApplyreportsdidWork = trueeven when it wrote nothing:didWork, so it showsSUCCESSevery timespotlessJavare-runs (e.g. on the build right after a fix)What
didWork:SpotlessApplyreports work only when it actually rewrote a source file; otherwise it showsUP-TO-DATE. Clean files identical to the source are no longer copied, so their mtimes aren't touched.SpotlessApplywrites the files its last run rewrote tobuild/spotless/<taskName>-changed-files.txt. That's one project-relative/-separated path per line, sorted, UTF-8. The report is empty if nothing changed, and it is still written when the task then fails on lints. The location is configurable via the newchangedFilesReportproperty:The report property is
@Internalon purpose. A task that declares outputs but no inputs can be considered up-to-date by Gradle, and apply must always run.Not changed (the "load-bearing" part from the issue discussion)
registerApplyAlreadyRanstill runs first, sospotlessCheckstill skips its work after apply ran. The lint failure path is unchanged.Visible behaviour change
On the build right after a fix, the format task still runs (its input was rewritten), but the apply tasks are now
UP-TO-DATEinstead ofSUCCESS.UpToDateTestasserted the old outcome in exactly that step, so those three steps now assert per-task outcomes.Tests
New
SpotlessApplyChangedFilesTest, written first and confirmed failing before the fix:UP-TO-DATE, empty reportdoLastRan locally, all passing (76/76):
UpToDateTest,ConfigurationCacheTest,GitRatchetGradleTest,IdeHookTest,MultiProjectTest,ErrorShouldRethrowTestIndependentTaskTest,PaddedCellTaskTest,DiffMessageFormatterTest,CompositeBuildRunToFixMessageTest,SpotlessTaskImplTestspotlessCheckand:plugin-gradle:check, including SpotBugsplugin-gradle/CHANGES.mdand the README are updated. Only plugin-gradle is affected, so the lib and Maven changelogs are untouched.🤖 Generated with Claude Code
https://claude.ai/code/session_01MTr23z6ccMd2shvyTaTFVY