fix(ci): keep the canary dist-tag from moving back to an older build - #3784
armando-navarro wants to merge 1 commit into
Conversation
Every canary publish moved the `canary` dist-tag, whatever commit it was built from. Two merges close together could publish out of order, and a re-run of an older run could publish its build last. The publish job now clones the repository's commit history and publishes a canary only when its commit comes after the commit of the canary on npm, or is the same commit under a new version. A build of an earlier commit is skipped with a warning. Commits are compared rather than versions, because a version can be higher for an older commit. Canary publishes also run one at a time, queued, so each check reads what the previous publish left on npm. Release publishes are unchanged. A scheduled run on an unchanged main now skips with a notice instead of failing on the duplicate version. Fixes angular#3783
tyler-reitz
left a comment
There was a problem hiding this comment.
Approving. queue: max checks out against GitHub's workflow-syntax docs: it is a real key, single is the default, and max holds up to 100 pending runs and releases them FIFO, so the serialization this check depends on does hold. The sha extraction also works on the live dist-tag, 21.0.0-canary.20260930011755.sha-59d44e7 to 59d44e7, and on the older a2662fe shape. And publish is a leaf job, so a skip breaks nothing downstream.
One thing the body understates. It says a failed check needs a person, but not the consequence: in the two cases you tested as failures, a missing canary dist-tag and a canary built from a commit that is not on main, the step exits 1, so every later push to main shows a red run until someone moves the tag. Worth a line in the body, or a comment in the step itself, since whoever hits it will be reading the red run rather than this PR.
Fixes #3783
The publish job now publishes a canary only when its commit comes after the commit of the canary already on npm, and canary publishes run one at a time.
Changes
All in the
publishjob of.github/workflows/test.yml.canaryfrom npm's dist-tags endpoint, which is not CDN-cached. The package data thatnpm viewreads is cached for 5 minutes.git clone --bare --filter=tree:0, which takes about half a second, and finds the commit named at the end of that canary's version.mainafter a release.concurrencyon the job. Canary publishes share the groupcanary-publishwithcancel-in-progress: falseandqueue: max, so they run one at a time and a waiting one is not replaced. Each release run gets a group of its own.Behavior to be aware of
mainits publish fails withE403today, as it did on 2026-09-30 and 2026-10-02. It now skips with a notice.canarydist-tag ever points at a build that is not frommain, every canary run fails until the tag is moved to a build frommain.queue: maxis recent. GitHub added it on 2026-05-07 (changelog).actionlint1.7.12 does not know the key yet (Actionlint does not know aboutqueue:key for concurrency rhysd/actionlint#657) and reports it as its only finding on this file.Verification
I ran the new step's script, taken from the YAML, with
bash -eagainst stand-in built packages. It cloned from GitHub and read npm for real, except where a case needed a differentcanaryon npm.mainis skipped with a warning, also when its version is higher.21.0.0-canary.a2662fename.main, a canary on npm from a commit that is not onmain, an unknown hash, and an npm reply withoutcanaryeach fail the job.21.0.0and21.0.0-rc.2publish without the check.curlorgit clonefails the job, and nothing publishes.npm publish --dry-runpacks the same files, with the same checksum, with and without the clone in the workspace.The concurrency queue can't be run locally. This PR's CI shows whether GitHub accepts the workflow file. The publish job itself only runs on
mainand on releases.