Gate the Docker push on all builds; require validate-release (#414 Q4) - #417
Conversation
Full publish atomicity (#414 Q4): github-release already needs every build, but build-docker built and pushed the image gated only on validate-release, so a failure in a different build (e.g. the executable) still let the image push - a partial publish. Docker is the terminal registry push in the fleet (no repo pushes two registries at once), so make build-docker need every other build: the image publishes only when all enabled builds passed. A skipped (disabled) build does not block, a failed one does. No needs cycle (nothing needs docker back). Documented as WORKFLOW.md D4.5. Also require validate-release in the release-task interface contract. It is the symmetric branch<->version entry gate (D2.2); the older repos carry that check as a step inside github-release instead, so the contract flags them to adopt the entry-gate job on their next re-vendor. #414 Q1 (symmetric backstop + main/develop whitelist) and Q2 (expect_release_ assets) were already implemented (validate-release / D2.2, publish-plan / D2.3, and the expect_release_assets input); Q3 landed in #415. Q4 is the remainder. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates the release/publish contract and canonical workflow snippet to prevent partial publishes by ensuring Docker pushes only occur after all other enabled builds have completed successfully, and records the new guarantee in the workflow contract.
Changes:
- Document D4.5: require publish atomicity across all enabled build targets (including Docker as the terminal registry push).
- Tighten the
build-release-task.ymlinterface contract to require avalidate-releasejob. - Update the canonical
build-release-task.ymlsnippet sobuild-dockerdepends on the other build jobs (to prevent Docker from pushing when another build failed).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| WORKFLOW.md | Adds D4.5 to document the “no partial publish” guarantee across build targets. |
| spec/files.json | Updates the interface contract for .github/workflows/build-release-task.yml to require validate-release. |
| catalog/snippets/workflows/build-release-task.yml | Gates build-docker on the other builds to prevent Docker pushes on partial failures. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
A skipped GitHub Actions dependency skips the dependent, so build-docker needing every build would be skipped whenever a target is disabled - breaking smoke PRs that build only the changed target. Guard build-docker's if with !failure() && !cancelled(): a failed build still skips docker (atomicity holds), but a skipped (disabled or unvendored) build is tolerated so docker still builds on smoke. Corrected the comment and D4.5 to describe this, not plain-needs semantics. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
catalog/snippets/workflows/build-release-task.yml:153
build-dockeris intended to tolerate skipped build jobs (disabled targets) while still blocking on failures, butif: ${{ inputs.enable_docker && !failure() && !cancelled() }}does not force evaluation when aneedsjob is skipped/failed. In that case GitHub Actions can skip the job before the expression is evaluated, reintroducing the smoke-build breakage this change is trying to fix. Includealways()(or explicitneeds.<job>.resultchecks) so the job can still run when dependencies are skipped, while!failure() && !cancelled()continues to block real failures/cancellation.
if: ${{ inputs.enable_docker && !failure() && !cancelled() }}
WORKFLOW.md:171
- D4.5 documents the docker gate as
!failure() && !cancelled(), but that alone is not sufficient to allowbuild-dockerto run when one of itsneedsjobs is skipped (disabled target) - the workflow needs analways()/needs.<job>.result-style override to avoid downstream skip. If the implementation is updated to include that override, D4.5 should be updated to match so the contract description stays accurate.
- **D4.5 A build failure blocks every publish target.** Input: a real publish where one enabled build fails. Output: nothing publishes - `github-release` needs every build, so a failed build skips it (no tag, no release), and the terminal registry pusher (Docker) needs every other build and guards its `if` with `!failure() && !cancelled()`, so a failed build skips docker too (no image push) while a disabled or unchanged target - skipped, not failed - still lets docker build on smoke. *Prevents: a partial publish, e.g. a Docker image pushed while the executable build failed and no release was cut.* A repo pushing two registry targets at once would need a build/publish split behind an all-builds gate, which none does today.
Uh oh!
There was an error while loading. Please reload this page.
Resolves the last open item of #414 (Q4), plus a contract bump.
Q4 - full publish atomicity.
github-releasealreadyneedsevery build, so the tag/release is atomic. Butbuild-dockerbuilt + pushed the image gated only onvalidate-release, so a failure in a different build (e.g. the executable) still let the image push - a partial publish. Docker is the terminal registry push in the fleet (no repo pushes two registries at once), sobuild-dockernowneedsevery other build: the image publishes only when all enabled builds passed. A skipped (disabled) build does not block, a failed one does. Noneedscycle - nothing needs docker back (verified: the graph is a DAG). Documented as D4.5.Contract. Require
validate-releasein the release-task interface contract. It is the symmetric branch<->version entry gate (D2.2); the older repos (PhotoCleaner/PlexCleaner) carry that check as a step insidegithub-release, so the contract now flags them to adopt the entry-gate job on their next re-vendor.Already done (not in this PR):#414 Q1 (symmetric backstop + main/develop whitelist) was already implemented - the symmetric check in
validate-release(D2.2) and the branch whitelist inpublish-plan-task.yml(D2.3). Q2 (expect_release_assets) already exists. Q3 landed in #415. This PR is the Q4 remainder + the contract bump.