Skip to content

SpotlessApply: report changed files and only set didWork when files changed (#2715) - #3177

Open
Pankraz76 wants to merge 3 commits into
diffplug:mainfrom
Pankraz76:feat/2715-apply-changed-files-report
Open

Pankraz76 wants to merge 3 commits into
diffplug:mainfrom
Pankraz76:feat/2715-apply-changed-files-report

Conversation

@Pankraz76

Copy link
Copy Markdown

Closes #2715

Why

Many builds run spotlessApply locally as part of build, so developers never see what Spotless fixed. The issue asks for a way to tell when spotlessApply actually changed something, and which files. The obvious workaround (doLast { if (didWork) ... }) doesn't work today, because SpotlessApply reports didWork = true even when it wrote nothing:

  • when there is nothing to apply, it copies the format task's didWork, so it shows SUCCESS every time spotlessJava re-runs (e.g. on the build right after a fix)
  • clean files that are byte-identical to the source were still copied and counted

What

  • Accurate didWork: SpotlessApply reports work only when it actually rewrote a source file; otherwise it shows UP-TO-DATE. Clean files identical to the source are no longer copied, so their mtimes aren't touched.
  • Changed-files report: every SpotlessApply writes the files its last run rewrote to build/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 new changedFilesReport property:
tasks.withType(com.diffplug.gradle.spotless.SpotlessApply).configureEach {
  def report = changedFilesReport
  doLast {
    if (didWork) {
      logger.lifecycle("Spotless fixed:\n" + report.get().asFile.text)
    }
  }
}

The report property is @Internal on 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)

registerApplyAlreadyRan still runs first, so spotlessCheck still 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-DATE instead of SUCCESS. UpToDateTest asserted 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:

  • unformatted files → report lists exactly the rewritten files
  • only clean files → apply UP-TO-DATE, empty report
  • second run with nothing to fix → report reset to empty
  • lint failure → report still lists the fixed file
  • custom report location read from a build script in doLast

Ran locally, all passing (76/76):

  • the new test
  • UpToDateTest, ConfigurationCacheTest, GitRatchetGradleTest, IdeHookTest, MultiProjectTest, ErrorShouldRethrowTest
  • IndependentTaskTest, PaddedCellTaskTest, DiffMessageFormatterTest, CompositeBuildRunToFixMessageTest, SpotlessTaskImplTest
  • spotlessCheck and :plugin-gradle:check, including SpotBugs

plugin-gradle/CHANGES.md and 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

…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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MTr23z6ccMd2shvyTaTFVY

This branch has not been deployed

No deployments
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.

feat(spotless/gradle-plugin): Allow SpotlessApply to notify when/what work was done

2 participants