ADFA-5244: Make CI able to catch the Spotless/source-tree failure - #1730
ADFA-5244: Make CI able to catch the Spotless/source-tree failure#1730davidschachterADFA wants to merge 7 commits into
Conversation
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 2 included reviews per hour; 0 remain after this review. 📝 Walkthrough
WalkthroughThe Spotless configuration excludes ChangesFormatting traversal
Estimated code review effort: 1 (Trivial) | ~2 minutes Merge Risk: ⚪ Minimal · up to This localized build configuration change excludes generated test-home content from formatting traversal while preserving the existing formatting checks; no actionable merge-blocking risk remains after normal checks and review. Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Full details: Docstring CoverageExplanation No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1 files. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
The task copied tooling-api-model.jar to <root>/tests/test-home/.cg/init/model.jar. Nothing reads that file, and nothing reads that directory. The only consumer of a "test home" is gradle-plugin's test helper, which resolves FileProvider.testHomeDir() -- testing/resources/test-home, a different directory -- and then *writes its own* init script there, with a classpath from Gradle's PluginUnderTestMetadataReading. It never asks for a model jar. A grep for model.jar across the repo returned only the task that produced it. The destination had drifted before: 2a84174 (Feb 2023) is "fix: invalid path specified in copyToTestDir", and #1161 renamed .androidide to .cg inside it. Removing it takes three problems with it: - into(rootProject.mkdir(...)) ran at configuration time, so merely realizing the task created directories in the source tree -- on --dry-run, and again after every clean. That is why tests/test-home kept reappearing. - outputs.upToDateWhen { false } on both the copy and jar meant any build touching this module re-jarred and re-copied unconditionally. - Its output being a directory inside the source tree is what tripped Gradle's implicit-dependency validation against Spotless (ADFA-5244). That was worked around at the consumer by excluding the directory from the Spotless walk. Verified: the jar still builds; tests/ is no longer created at configuration time; :app:assembleV8Debug succeeds with the task absent from the graph; and `:common:compileV8DebugKotlin spotlessCheck` -- the exact invocation ADFA-5244 was filed for -- now passes on this branch, which carries no Spotless exclude at all. The two .gitignore entries that existed only for this task's output go too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tooling-api-model:copyToTestDir writes a jar into tests/test-home, which lives in the source tree, so root spotlessJava's fileTree(rootDir) consumed another task's output. Gradle's validation then failed any invocation that both compiled and checked formatting -- the combination you run before pushing. spotlessCheck alone always passed, because copyToTestDir never entered the graph. That is what made this read as "my change broke Spotless". traversalExcludes already exists for exactly this, and its comment carries the rule this needs: a bare directory name so Gradle prunes the subtree instead of descending and filtering. Verified: the failing invocation (:common:compileV8DebugAndroidTestKotlin spotlessCheck) now succeeds; nothing is tracked under tests/ so no real source is hidden; and an injected 4-space indent still fails spotlessKotlinGradleCheck, so the check remains effective. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review found three things worth acting on here. The exclude was anchored to tests/test-home while .gitignore reserves tests/**/.cg/init/model.jar -- so a sibling generated directory would reintroduce the identical failure. Nothing under tests/ is tracked at all, so the whole subtree goes. The comment three lines above said "bare dir names required", which the new rooted entry appeared to violate. The real rule is that the pattern must match the directory node itself, rooted or bare; a bare name additionally matches that name at any depth, which is why "tests" is rooted here -- "test-home" would also prune testing/resources/test-home, the directory FileProvider.testHomeDir() actually points at. CI could not have caught a regression of this: it ran spotlessCheck standalone, the one invocation that always passed, because copyToTestDir never enters that graph. The step now runs a compile task in the same invocation, which is the combination that fails. What this PR still does not fix is the cause: copyToTestDir writes a jar nothing reads, into the source tree, from a configuration-time mkdir. That is ADFA-5263. Fixing it there would make this exclude unnecessary rather than permanent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The exclude existed because copyToTestDir wrote a jar into tests/test-home inside the source tree, which made Spotless consume another task's output. That task is deleted in ADFA-5263, so nothing creates the directory and there is nothing to prune -- keeping the exclude would leave a permanent workaround for a problem that no longer exists. What stays is the part that is worth keeping either way: the CI step that runs a compile task in the same invocation as spotlessCheck. CI ran spotlessCheck standalone, which is the one invocation that can never reproduce this class of failure, so any regression was invisible to it by construction. The comment above traversalExcludes also stays corrected: the rule is that a pattern must match the directory node itself, and a bare name matches that name at any depth -- "test-home" would have pruned testing/resources/test-home too. This branch is now based on ADFA-5263 rather than stage, because without that fix removing the exclude reintroduces the failure -- verified both ways. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
e82ffbf to
3d62974
Compare
The exclude is gone; this PR is now the CI guard plus a corrected commentReviewing this PR is what surfaced the actual cause: This PR is therefore rebased onto #1739 and its base retargeted there, because the two are genuinely coupled: I removed the exclude while still based on What remains, and why each part earns its place
Not related, despite the nameADFA-5265 ("Spotless is slow") was a separate ticket of mine and turned out to be a misdiagnosis — measured at 6.5s warm / 22s cold, against 20s for configuration alone. Closed. This ticket was about Spotless failing the build, which was entirely real. |
The comment this PR added claimed a bare exclude name "also matches that
name at any depth". It does not -- bare names are root-anchored, so
exclude("flox") prunes rootDir/flox and nothing else. Verified with a
probe project: with tests/ and testing/resources/test-home/ present,
exclude("tests") leaves a/tests/x untouched and exclude("test-home")
matches nothing at all.
That made the array's own **/ prefixes look redundant, so the comment
invited exactly the wrong simplification: reading "**/.gradle" as
equivalent to ".gradle" stops pruning every per-project cache dir and
brings back the ADFA-4816 12-minute spotlessCheck. The comment it
replaced ("Bare dir names required") had it right.
Also drops the reference to a "tests" entry, which commit 3d62974
removed, and the test-home example, which was inverted -- a bare
"test-home" is not dangerously broad, it is silently narrow.
Found in review of PR #1730.
Dropping both entries went one too far. The model.jar line is dead -- ADFA-5263 deleted the task that wrote it -- but the directory is not. writeInitScript() in gradle-plugin/src/test/.../utils.kt resolves FileProvider.testHomeDir() and creates .cg/init/androidide.init.gradle on every run of :gradle-plugin:test. That is a test writing a file at execution time, not a Gradle task declaring an output, so it never triggers the implicit-dependency validation this branch is about -- it just leaves "?? tests/" in git status after a test run, in a tree where nothing under tests/ is tracked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M4sTwYg47aK8VB9kRKZicU
|
Reviewed at xhigh. One fix pushed in 6c7a73f; two things about the PR as presented. Fixed: the The That is a test writing at execution time, not a task declaring an output, so it never trips the implicit-dependency validation this branch is about — it just leaves the tree dirty after a test run, in a directory where nothing is tracked. Restored the one line. The
The description no longer matches the diff The body's "The fix" section says Verified good The workflow's task choice does reproduce the failure. At the branch point |
|
Correction to my review above: I attributed the
The rest of the review is unaffected: the One more thing that a |
Brings in ADFA-5263 (#1739), which deleted copyToTestDir independently, and ADFA-5264 (#1740), which ignores the test project's .cg/ cache. With both in, this branch's diff is the three files it actually changes. Conflict was in .gitignore: stage removed both tests/ entries as part of #1739. Kept this branch's tests/test-home line -- the gradle-plugin tests still refill that directory -- and left the model.jar entry deleted, since the task that wrote it is gone. Moved the entry out from under the "Generated files for tooling API" header, which heads the composite-build output dirs and not this. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M4sTwYg47aK8VB9kRKZicU
|
Merged The diff is now the three files this PR is actually about — One conflict, in The description now describes what the diff does rather than the |
Three files. A CI step that can see the failure, a comment that says what the excludes actually do, and one
.gitignoreline.The bug
tooling-api-model:copyToTestDirwrote a jar into the source tree (tests/test-home/.cg/init/model.jar), and rootspotlessJavatargetsfileTree(rootDir). Gradle saw Spotless consuming another task's output and failed validation:The task itself is gone — ADFA-5263 (#1739) deleted it, having established that nothing reads the jar. What's left here is making sure the class of failure can't come back unseen.
Why CI couldn't see it
spotlessCheckalone always passed.copyToTestDirnever entered that graph, so the validation never ran. It failed only when a compile task shared the invocation — which is exactly what you run to verify a change before pushing. So it surfaced the moment you touched code and looked like your change had broken formatting. It cost me a detour confirming an unrelated branch was clean.The workflow now runs
:common:compileV8DebugKotlin spotlessChecktogether. Verified at the branch point9c8f21777, wherecopyToTestDirstill existed: that invocation fails with the error above, and passes at this branch's tip. The task pairing is the point of the step, so there's a comment on it saying why it must not be split back apart.The exclude comment
traversalExcludeshad a comment explaining that Gradle prunes a subtree only when an exclude matches the directory node itself —dir/**matches the contents instead and forces a descend-and-filter. True, but it omitted the half that bites: bare names are root-anchored."flox"prunesrootDir/floxand nothing else, which is why the three.-prefixed entries carry**/. Reading"**/.gradle"as equivalent to".gradle"and dropping the prefix would stop pruning every per-project cache dir and bring back the ADFA-4816 12-minutespotlessCheck. The comment now says both halves.No exclude is added. An earlier revision of this branch excluded
tests/; once #1739 removed the thing that wrote there, the exclude was hiding nothing and was dropped.The
.gitignoreline#1739 removed both
tests/entries.tests/**/.cg/init/model.jaris correctly gone — the task that wrote it is deleted.tests/test-homeshould have stayed:writeInitScript()ingradle-plugin/src/test/java/com/itsaky/androidide/gradle/utils.kt:86resolvesFileProvider.testHomeDir()and creates.cg/init/androidide.init.gradlethere on every run of:gradle-plugin:test. Without the line, a test run leaves?? tests/ingit status, in a directory where nothing is tracked.That is a test writing at execution time, not a task declaring an output, so it never trips the validation this branch is about — it just leaves the tree dirty. Restored, and moved out from under the "Generated files for tooling API" header, which heads the composite-build output dirs rather than this.
Verified
9c8f21777.tests/(git ls-files tests/is empty), so ignoring it hides no real source.build.gradle.ktsstill failsspotlessKotlinGradleCheck, and removing it passes. The check is still doing its job, not silently disabled.*.gradle, so the generated init script was never at risk of being format-checked.