Skip to content

Commit 6271781

Browse files
committed
improvement(ci): promote superseded first-attempt runs forward
The stale-promotion guard skipped any run whose commit was no longer the branch head. If commit A passed its gate but was superseded mid-run by commit B, and B then failed tests, A's promotion was skipped and the deploy tags stayed on pre-A code with no automatic recovery (Cursor finding on #5712). A first-attempt run promoting an ancestor of the branch head is always a forward deploy — runs on a ref are serialized by the concurrency group, so nothing newer can have promoted first. Only re-runs of superseded commits (a rollback attempt) and force-pushed-away commits are skipped. Same semantics applied to the GHCR latest-tag guard.
1 parent 8adeaab commit 6271781

1 file changed

Lines changed: 20 additions & 17 deletions

File tree

.github/workflows/ci.yml

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -298,19 +298,21 @@ jobs:
298298
id: login-ecr
299299
uses: aws-actions/amazon-ecr-login@d539f0932e70871a027e9d5a9d8fc38589180a64 # v2
300300

301-
# Re-running this job from an old run would retag the deploy tags back
302-
# to that run's commit and immediately trigger a production deploy of
303-
# stale code. Only promote while this commit is still the branch head;
304-
# when superseded, skip cleanly — the newer run's promotion covers it.
301+
# Deploy-tag moves must be monotonic: a re-run of an old run must never
302+
# retag latest/staging back to stale code. A superseded first-attempt
303+
# run still promotes — the ci-<ref> concurrency group executes runs
304+
# serially in commit order, so an ancestor of head is a forward deploy.
305305
- name: Guard against stale promotion
306306
id: guard
307+
env:
308+
GH_TOKEN: ${{ github.token }}
307309
run: |
308-
HEAD_SHA="$(git ls-remote "https://github.com/${{ github.repository }}.git" "refs/heads/${GITHUB_REF_NAME}" | cut -f1)"
309-
if [ "$HEAD_SHA" != "${{ github.sha }}" ]; then
310-
echo "::warning::Skipping promotion of ${{ github.sha }}: ${GITHUB_REF_NAME} has moved to ${HEAD_SHA}. Moving the deploy tags to this commit would deploy stale code; push a revert commit to roll back instead."
311-
echo "fresh=false" >> $GITHUB_OUTPUT
312-
else
310+
STATUS="$(gh api "repos/${{ github.repository }}/compare/${{ github.sha }}...${GITHUB_REF_NAME}" --jq '.status' || echo "unknown")"
311+
if [ "$STATUS" = "identical" ] || { [ "$STATUS" = "ahead" ] && [ "${{ github.run_attempt }}" = "1" ]; }; then
313312
echo "fresh=true" >> $GITHUB_OUTPUT
313+
else
314+
echo "::warning::Skipping promotion of ${{ github.sha }} (branch compare: ${STATUS}, attempt ${{ github.run_attempt }}). Moving the deploy tags here could deploy stale code; push a revert commit to roll back instead."
315+
echo "fresh=false" >> $GITHUB_OUTPUT
314316
fi
315317
316318
- name: Promote images to deploy tags
@@ -419,18 +421,19 @@ jobs:
419421
username: ${{ github.repository_owner }}
420422
password: ${{ secrets.GITHUB_TOKEN }}
421423

422-
# Same protection as promote-images: a re-run of an old run must not
423-
# move the public latest tags back to a stale commit. Immutable tags
424-
# (sha and version) are still published — only latest moves are gated.
424+
# Same monotonic guard as promote-images, applied to the public latest
425+
# tags only — immutable sha and version tags are always published.
425426
- name: Guard against stale latest tags
426427
id: guard
428+
env:
429+
GH_TOKEN: ${{ github.token }}
427430
run: |
428-
HEAD_SHA="$(git ls-remote "https://github.com/${{ github.repository }}.git" "refs/heads/${GITHUB_REF_NAME}" | cut -f1)"
429-
if [ "$HEAD_SHA" != "${{ github.sha }}" ]; then
430-
echo "::warning::${GITHUB_REF_NAME} has moved to ${HEAD_SHA}; publishing immutable tags for ${{ github.sha }} but skipping the latest tags."
431-
echo "fresh=false" >> $GITHUB_OUTPUT
432-
else
431+
STATUS="$(gh api "repos/${{ github.repository }}/compare/${{ github.sha }}...${GITHUB_REF_NAME}" --jq '.status' || echo "unknown")"
432+
if [ "$STATUS" = "identical" ] || { [ "$STATUS" = "ahead" ] && [ "${{ github.run_attempt }}" = "1" ]; }; then
433433
echo "fresh=true" >> $GITHUB_OUTPUT
434+
else
435+
echo "::warning::Publishing immutable tags for ${{ github.sha }} but skipping the latest tags (branch compare: ${STATUS}, attempt ${{ github.run_attempt }})."
436+
echo "fresh=false" >> $GITHUB_OUTPUT
434437
fi
435438
436439
- name: Publish tags and manifests

0 commit comments

Comments
 (0)