ci(release): tag-last release pipeline — gate + build everything before the tag exists - #6890
Conversation
…re the tag exists release-packages.yml gains a preflight job that resolves one of four modes (release / cut-release / republish / stage) and the tag ONCE; every downstream job takes tag/version from its outputs. The per-leg 'latest release' fallback is gone — it used to upload pre-tag dispatches onto the PREVIOUS release. cut-release (workflow_dispatch, cut_release=true) is the new default flow: await-tests dispatches test.yml/simctl-tests.yml on the candidate SHA when needed and polls by head SHA; build + build-cross must go fully green; only then does create-release make the vX.Y.Z tag + GitHub Release (notes from changelog.d via cut_release_notes.sh --notes-only) and dispatch the tag-rider workflows (docs, benchmark, container-tests) that a GITHUB_TOKEN-created tag cannot fire itself. publish-assets is now the single upload path for all modes; homebrew/winget/update-workers hang off it, apt off tag-existence, npm still last and idempotent. A red gate or build leg now costs nothing: no burned tag, no half-published release. The legacy release-event path and an explicit existing_tag republish lever keep working; plain dispatch becomes a harmless stage-only smoke build. cut_release_notes.sh grows --notes-only (CI) and --fold vX.Y.Z (tag-scoped fragment removal after a tag-last release). /release skill rewritten for the new flow. Also fixes the homebrew tap commit message, which always said 'perry ' because $VERSION was never set in that step.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThe release process now validates tests and builds before CI creates the release tag and GitHub Release. Release assets are collected as workflow artifacts, published centrally, and downstream package jobs use resolved release metadata. Changelog fragments support separate notes generation and post-release folding. ChangesRelease pipeline
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ReleaseBranch
participant Preflight
participant AwaitTests
participant Build
participant CreateRelease
participant PublishAssets
ReleaseBranch->>Preflight: dispatch cut-release workflow
Preflight->>AwaitTests: resolve mode, tag, version, and SHA
AwaitTests->>Build: pass after exact-SHA test checks
Build->>CreateRelease: provide completed artifacts
CreateRelease->>PublishAssets: create tag and GitHub Release
PublishAssets->>ReleaseBranch: publish release assets
Possibly related PRs
Suggested reviewers: ✨ 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 |
What
Flips the release pipeline to tag-last: instead of pushing a
vX.Y.Ztag and hoping the pipeline goes green, you dispatchrelease-packages.ymlwithcut_release=true, it gates on tests + builds every leg, and only then creates the tag + GitHub Release and publishes. A red gate or a broken build leg now costs nothing — no burned tag, no half-published release.How
New
preflightjob resolves the run mode + tag once, up front; every downstream job readsneeds.preflight.outputs.{tag,version}:releaserelease: published(legacy)cut-releasecut_release=truerepublishexisting_tag=vX.Y.ZstageFootgun removed: every publish leg used to fall back to
gh release list --limit 1when there was no release event — a pre-tag dispatch would upload new binaries onto the previous release and point homebrew/apt/winget at the wrong version. That fallback is gone everywhere; republish takes an explicit tag.Key pieces:
await-tests(cut-release mode): dispatchestest.yml/simctl-tests.ymlon the pinned branch if no run exists on the SHA (fails fast if the ref moved), then polls by head SHA as before. Bypassed for republish/stage — the old manual lever.create-release(cut-release only, requiresbuild+build-crossfully green): re-checks the tag is still free, creates it atgithub.shawith notes fromchangelog.d/(cut_release_notes.sh --notes-only), then dispatches the tag-rider workflows (docs,benchmark,container-tests) — aGITHUB_TOKEN-created tag emits no push event, and the same token-suppression means therelease: publishedevent can't re-trigger this workflow (no double publish).benchmark.yml's hard-fail release gate still engages:startsWith(github.ref, 'refs/tags/v')holds when dispatched with--ref <tag>;container-testsLayer D likewise.publish-assets: single upload path for all modes (the build legs no longer touch the release at all). Host archives are a hard requirement; cross bundles stay best-effort on the legacy paths, matching the old per-leg semantics.homebrew/winget/update-workershang offpublish-assets(they consume release-download URLs);apthangs off tag-existence and runs in parallel;npm-publishstays last, idempotent, and now also waits forbuild-crossto complete (removes the old race wherestage-npm.shbackfilledlibperry_ui_android.afrom whatever cross artifacts happened to exist).Cargo.toml.permissions.actions: read → writefor the gate/tag-rider dispatches.scripts/cut_release_notes.shgrows two modes:--notes-only(print concatenated fragments; used by CI) and--fold vX.Y.Z(post-release fragment removal, scoped to the fragments recorded at the tag so entries merged after the release SHA survive for the next one). Legacy single-arg behavior unchanged./releaseskill rewritten for the new flow: pinrelease/vX.Y.Zbranch → dispatch withcut_release=true→ watch →--fold+ drop the pin branch. The pinned branch matters becauseworkflow_dispatchruns on ref tips andtest.yml'stest-<ref>concurrency group would cancel a running nightly if dispatched onmain.Drive-by: the homebrew tap commit message referenced a never-set shell
$VERSION— every tap commit was titled just "perry ". Now uses the step output.Failure semantics
Cargo.toml↔CLAUDE.mddrift / no fragments): fails in seconds, nothing runs.gh run rerun <id> --failedreruns the failed legs and everything downstream; npm skips already-published versions.Testing
actionlintclean (same 7 pre-existing shellcheck style/info findings asmain, line-shifted).shellcheck+bash -nclean oncut_release_notes.sh.!cancelled()guards onpublish-assets/apt/npm-publish; default needs-semantics elsewhere).stagedispatch first (build-only smoke), then the firstcut_release=truerelease.Summary by CodeRabbit