Fix the auto-tag push auth, and stop the two publishes racing - #12
Merged
Merged
Conversation
Two problems, both on the first real run of this workflow.
1. The tag push authenticated as github-actions[bot], not as the PAT:
remote: Permission to jamiewest/extensions.git denied to github-actions[bot]
fatal: ... The requested URL returned error: 403
actions/checkout persists GITHUB_TOKEN into an
`http.https://github.com/.extraheader` git config, and that header takes
precedence over credentials embedded in a push URL -- so
`git push https://x-access-token:${RELEASE_PAT}@github.com/...` never used
the PAT at all. Fixed with persist-credentials: false on the checkout,
which leaves the URL credentials as the only ones in play. The job keeps
contents: read deliberately: GITHUB_TOKEN should have no write access
here, since only a PAT-pushed tag triggers publish.yml.
2. Both tags were pushed back to back, so the two publish.yml runs raced.
extensions_flutter depends on extensions, so when the flutter publish won
the race it failed resolving a dependency that was not on pub.dev yet --
the workflow header acknowledged this and told the reader to re-run.
Now the dependent tag waits for the dependency to actually appear on
pub.dev (polling the versions API every 15s, default 20 minutes, override
with the PUBLISH_WAIT_SECONDS repo variable) before being pushed. The
wait also covers the case where the core tag already existed with its
publish still in flight, not just the case where this run pushed it.
A wait that times out fails the job and says which publish to check.
Note `needs:` between two jobs would not have fixed this: it waits for
the tag push to finish, not for the publish that the push triggers.
Also sets timeout-minutes: 45, since a run can now legitimately wait.
Verified by extracting the step's script and running it as CI does, with a
stubbed git for the push paths:
- no PAT, both unpublished -> exit 1, both reported (unchanged)
- both already on pub.dev -> exit 0, no wait, no summary
- core pending, dependency wait -> core tagged, wait engages, times out
at the deadline, exit 1 + summary
- core already published -> no wait, dependent tagged at once
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P889JtFvr4ypqnHYQZCPag
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two problems, both surfaced by the first real run of this workflow now that
RELEASE_PATexists.1. The push authenticated as the bot, not the PAT — this is what's blocking the release
The secret is set correctly — the
RELEASE_PAT-is-empty guard would have exited beforegit pushotherwise. The problem isactions/checkout: with the defaultpersist-credentials: trueit writesGITHUB_TOKENinto anhttp.https://github.com/.extraheadergit config, and that header takes precedence over credentials embedded in a push URL. Sonever used the PAT at all — it pushed as
github-actions[bot], which hascontents: read, hence the 403.Fixed by setting
persist-credentials: falseon the checkout, leaving the URL credentials as the only ones in play. The job keepscontents: readdeliberately:GITHUB_TOKENshould have no write access here, because only a PAT-pushed tag triggerspublish.yml. Both facts are now in the workflow header so this doesn't get "helpfully" reverted later.2. The two publishes raced
Both tags were pushed back to back, kicking off two concurrent
publish.ymlruns.extensions_flutterdepends onextensions: ^0.8.0, so whenever the flutter publish won the race it failed resolving a dependency that wasn't on pub.dev yet. The old header acknowledged this and told the reader to re-run by hand.The dependent tag now waits for the dependency to actually appear on pub.dev before being pushed — polling the versions API every 15s, 20 minutes by default, overridable with a
PUBLISH_WAIT_SECONDSrepo variable. The wait also covers the case where the core tag already existed with its publish still in flight, not just the case where this run pushed it. A wait that times out fails the job and names the publish run to go look at.Worth recording why not
needs:, since it was the obvious option: two jobs withneeds:would wait for the tag push to finish, not for the publish that push triggers. The race would survive it. The poll is the part that actually does the work.Also sets
timeout-minutes: 45, since a run can now legitimately sit and wait.Verification
Extracted the step's script and ran it the way CI does (
bash -e, same env), with a stubbedgitfor the push paths:YAML parses; the script passes
bash -n.After this merges
Re-run Auto-tag releases and the release should go end to end:
extensions-v0.8.1pushed → published →extensions_flutter-v0.6.0pushed once 0.8.1 is live → published. pub.dev is still serving 0.7.1 / 0.5.2 as of this PR.🤖 Generated with Claude Code
https://claude.ai/code/session_01P889JtFvr4ypqnHYQZCPag
Generated by Claude Code