ci: add on-demand "Publish images" workflow to force-publish tip of main - #69
Conversation
Images are tagged by git tree hash. When a PR is merged while its branch is behind main, GitHub writes a merge commit whose tree differs from the PR-head tree that ci.yml built, so the tip-of-main image has no matching tag. cd.yml's build-missing job normally backfills it on the push to main, but there is no supported way to force a publish on demand when that does not happen (e.g. the push's CD run was superseded in the cd-deploy concurrency group). Add .github/workflows/publish-images.yml: a workflow_dispatch job that force-(re)builds and pushes all three images (frontend, api, collab) for a chosen ref, defaulting to the tip of main. Publishing only — it does not deploy; cd.yml still owns rollout to production. The matrix, arm64 runner, tree -hash tag scheme and registry login are kept in sync with ci.yml and cd.yml. Document the escape hatch in the README's Container images section. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BcAqhmKSU8rnQHKcRyyhQ6
|
🤖 Starting work on this now. |
|
🤖 Watch live or take over the session here: https://claude.ai/code/session_01AaaPVXthKvyjAufVqtpePX |
There was a problem hiding this comment.
Solid, well-scoped escape hatch — matrix, runner, tag scheme, and login are faithfully in sync with ci.yml's build-and-push and cd.yml's build-missing, permissions stays least-privilege, and the empty-ref → dispatch-ref fallback in actions/checkout is correct. All CI checks pass. One narrow point on the build step re: actually honoring the "overwrite a bad/stale image" goal; see inline. Not a blocker.
|
The review is posted. #69 (review) SummaryI reviewed PR #69 ( Verdict: sound, well-scoped PR — approving in spirit with one narrow, non-blocking note. What I verified:
The one inline comment (with a one-cli… ✅ Opened pull request: imaustink/glyph#69 |
|
🤖 Starting work on this now. |
|
🤖 Watch live or take over the session here: https://claude.ai/code/session_01Bsb5Etje6GZdt1tCkF7xsS |
Address review: the "overwrites a bad or stale image" promise only held for a corrupt/mis-pushed tag. If the build itself produced the bad image (a base image that moved under a floating tag, or a poisoned local layer cache on a reused arc-runner-set runner), a plain docker build reuses those cached layers and reproduces the identical bad image, so the re-push fixes nothing. This is the deliberate force path, so bust the cache and re-pull the base for a genuinely fresh rebuild. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bsb5Etje6GZdt1tCkF7xsS
|
Picked this back up from the Addressed the one review comment (#discussion_r on
Branch sync: the branch was already up to date with Deliberately not changed:
All 9 CI checks passed on the prior commit; a fresh CI run is in progress on |
|
Everything is done. CI is re-running on the new commit (the workflow I touched is SummaryI picked up PR #69 ("ci: add on-demand 'Publish images' workflow") from the Feedback addressed — there was exactly one review comment (from the prior review), on
Branch sync: already up to date with Deliberately not done: didn't add ✅ Opened pull request: imaustink/glyph#69 |
Context
I merged 3 PRs (#62, #63, #64) back-to-back without their branches being up to date with
main. Because our images are tagged by git tree hash (git rev-parse HEAD^{tree}), that combination can leave the tip-of-main image unpublished, which is what this PR gives us a supported way to fix.Why merging behind
mainbreaks the tag matchci.yml'sbuild-and-pushpublishes an image tagged with the PR-head tree.cd.yml(on push tomain) resolves the tag as the merge-commit tree and deploys it.main, GitHub writes a real merge commit whose tree differs from the PR-head tree CI built → the tip-of-main tree has no matching image.That is exactly what happened here:
c51097195cb0c495cb0c4d9519759ab15f06691ceabuild-missinghad to rebuild4f090a4abcefd95bfe453cd.yml'sbuild-missingjob backfills the missing image on the push tomain, so the tip does self-heal in the normal case. The gap: there is no supported, on-demand way to force a publish when that backfill doesn't happen — e.g. a push's CD run is superseded in thecd-deployconcurrency group (which intentionally drops older queued runs so only the tip ships), or a bad/stale image needs to be overwritten.Change
Adds
.github/workflows/publish-images.yml— aworkflow_dispatchjob that force-(re)builds and pushes all three images (frontend,api,collab) for a chosenref, defaulting to the tip ofmain.cd.ymlstill owns rollout to production.build-missing, which skips when the tag exists), so it also overwrites a bad image under the same tag.arc-runner-setarm64 runner, tree-hash tag scheme, and Docker Hub login are kept in sync withci.yml'sbuild-and-pushandcd.yml'sbuild-missing.How to use it (the "in the meantime" force-publish)
After this merges, run Actions → Publish images → Run workflow on
main(leaverefblank) to force-publish the three tip-of-main images.Follow-up (not done here, per the ask)
The durable fix is the repo-settings change you mentioned — enabling "Require branches to be up to date before merging" on the
mainbranch protection rule so a merge can't produce a tree CI never built. Left out of this PR intentionally; this workflow is the interim tool.