Skip to content

fix: join the build lifecycle with dependsOn, not finalizedBy - #89

Merged
jimisola merged 1 commit into
mainfrom
fix/issue-88-build-lifecycle-cycle
Sep 6, 2026
Merged

fix: join the build lifecycle with dependsOn, not finalizedBy#89
jimisola merged 1 commit into
mainfrom
fix/issue-88-build-lifecycle-cycle

Conversation

@jimisola

@jimisola jimisola commented Sep 6, 2026

Copy link
Copy Markdown
Member

Closes #88.

What & Why

Since 0.1.2, a consumer that declares its own build.dependsOn(assembleRequirements) fails at configuration time — nothing compiles:

Circular dependency between the following tasks:
:assembleRequirements
\--- :build
     \--- :assembleRequirements (*)

0.1.2 added build.finalizedBy(assembleRequirements), which says the task runs after build. The consumer's line says before. Gradle rejects the contradiction.

Consumers had every reason to have written that line. 0.1.0 and 0.1.1 shipped no lifecycle wiring at all, while the 0.1.0 README documented assembleRequirements as "Depends on check task (ensures tests have run)" and "Runs automatically as part of build task". The plugin implemented neither, so consumers wired it by hand to get the documented behaviour — and 0.1.2 added the opposing edge with no migration note. Affected: 0.1.2, 1.0.0 and main; 0.1.1 is the last clean version.

The fix

Wire build dependsOn assembleRequirements dependsOn check instead of build finalizedBy assembleRequirements.

Same execution order — the task still runs after the tests whose XML it reads — but dependsOn composes where finalizedBy contradicts. dependsOn is idempotent, so an existing consumer's line becomes redundant rather than fatal, and no consumer has to edit its build file.

It also makes gradle assembleRequirements on its own meaningful: it now runs check first, so the zip contains test results instead of silently omitting them. Verified — running the task standalone produces both test_results/*.xml.

Verification

New BuildLifecycleWiringTest drives a real consumer project through TestKit. --dry-run is deliberate: a circular dependency is raised while Gradle builds the task graph, so the regression reproduces without compiling or resolving anything — the suite stays fast and offline.

I confirmed the test fails against the old wiring before making it pass:

BuildLifecycleWiringTest > consumerDeclaringBuildDependsOnAssembleRequirementsStillConfigures() FAILED
    org.gradle.testkit.runner.UnexpectedBuildFailure
3 tests completed, 1 failed

tests/fixtures/test_project structurally cannot catch this — it declares no wiring of its own, so it only ever exercises the case where the plugin is the sole author of these edges. That is why CI stayed green through the regression.

End-to-end, with the fixed plugin published to mavenLocal and the fixture given the wiring that used to break:

> Task :test
> Task :integrationTest
> Task :check
> Task :assembleRequirements
> Task :build
BUILD SUCCESSFUL

Zip contents unchanged and correct — requirements.yml, software_verification_cases.yml, annotations.yml carrying both SVC_001 and SVC_002, both test-result XMLs, reqstool_config.yml.

Docs

README.md, docs/ (usage, configuration, index) and CLAUDE.md all described build as finalized by the task. Updated, including a note that an existing build.dependsOn(assembleRequirements) is now redundant but harmless.

Author checklist

  • Conventional Commit title
  • DCO sign-off
  • ./gradlew build green, formatting applied via ./gradlew format
  • New test verified to fail before the fix
  • End-to-end validated against tests/fixtures/test_project
  • Docs updated to match behaviour

Test Plan

  1. ./gradlew build — all tests pass, including the three new lifecycle tests.
  2. Revert the one-line wiring change and re-run: consumerDeclaringBuildDependsOnAssembleRequirementsStillConfigures must fail with Circular dependency.
  3. From tests/fixtures/test_project, add tasks.named('build') { dependsOn(tasks.named('assembleRequirements')) } and run gradle build against a locally published plugin — configures and builds; check precedes assembleRequirements.

Note for release

This wants a patch release so affected consumers can move forward — 1.0.0 carries the regression, so the fix version is 1.0.1. Until then the workaround is to delete the manual wiring, which #88 records.

Since 0.1.2 a consumer that declares its own
`build.dependsOn(assembleRequirements)` fails at configuration time:

    Circular dependency between the following tasks:
    :assembleRequirements
    \--- :build
         \--- :assembleRequirements (*)

Nothing compiles -- the build dies before any task runs.

0.1.2 added `build.finalizedBy(assembleRequirements)`, which says the task
runs AFTER build. The consumer's line says before. Gradle rejects the
contradiction. Consumers had every reason to have written that line:
0.1.0 and 0.1.1 shipped no lifecycle wiring at all, while the 0.1.0
README documented the task as depending on `check` and running as part of
`build`. They wired by hand to get the documented behaviour, and 0.1.2
added the opposing edge with no migration note.

Wiring `build dependsOn assembleRequirements dependsOn check` instead
keeps the same execution order -- the task still runs after the tests
whose XML it reads -- while composing with those consumers rather than
contradicting them. dependsOn is idempotent, so their line is now
redundant and harmless, and no consumer has to edit its build file.

It also makes `gradle assembleRequirements` on its own meaningful: it now
runs `check` first, so the zip contains test results instead of silently
omitting them.

Covered by BuildLifecycleWiringTest, which drives a real consumer project
through TestKit with `--dry-run` -- a circular dependency is raised while
the task graph is built, so the regression is reproduced without
compiling or resolving anything. Verified to fail against the old wiring
before being made to pass. tests/fixtures/test_project cannot cover this:
it declares no wiring of its own, so it only ever exercises the case
where the plugin is the sole author of these edges.

Closes #88

Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
@jimisola
jimisola merged commit 3db2f91 into main Sep 6, 2026
11 checks passed
@jimisola
jimisola deleted the fix/issue-88-build-lifecycle-cycle branch September 6, 2026 00:18
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.

Circular dependency between build and assembleRequirements for consumers that wire build themselves (regression in 0.1.2, still in 1.0.0)

1 participant