ci(release): publish to Docker Hub + bump all actions to Node-24#469
Merged
Conversation
Every release now publishes the multi-arch manifest (version, short_version, latest) to both ghcr.io/basekick-labs/arc and docker.io/basekicklabs/arc. - docker-build: logs into Docker Hub + pushes the per-platform image by digest to both registries (second build-push is a buildkit cache hit). Asserts the manifest digest matches across registries. - docker-merge: creates the multi-arch manifest in both registries from the shared digests. Adds a `test_mode` workflow_dispatch input (default false). When true, the `latest` tag is suppressed end-to-end so a CI verification run can't clobber the real latest on either registry. Branch-push releases are never test mode. Requires repo secrets DOCKERHUB_USERNAME + DOCKERHUB_TOKEN (token is a Docker Hub access token with Read & Write, not the account password).
The first test run failed: my digest-equality assertion was wrong.
push-by-digest serialises the manifest per registry, so GHCR and
Docker Hub legitimately return DIFFERENT manifest digests for the
same image content — not a non-reproducible build.
Fix: drop the equality assertion. Write each registry's digest to its
own subdir (/tmp/digests/{ghcr,dockerhub}/) and have each merge step
reference that registry's digest set when building its manifest.
GitHub forces Node-24 for JS actions starting 2026-06-02 and removes
Node-20 from runners 2026-09-16. Bumping every JS action to its
lowest/current Node-24 major so the release pipeline doesn't break
mid-release.
Verified each action's Node runtime from its release notes / action.yml
rather than guessing:
actions/checkout v4 → v5 (v5 = first node24)
actions/setup-go v5 → v6 (v5 was node20; v6 = node24)
actions/upload-artifact v4 → v6 (v6 = first true node24 default)
actions/download-artifact v4 → v7 (v7 = first true node24; pairs w/ upload v6)
azure/setup-helm v4 → v5 (named in the deprecation warning)
azure/setup-kubectl v4 → v5 (node24)
docker/setup-qemu-action v3 → v4 (node24)
docker/setup-buildx-action v3 → v4 (node24)
docker/login-action v3 → v4 (node24)
docker/metadata-action v5 → v6 (node24)
docker/build-push-action v5,v6 → v7 (v7 = node24 default; unifies the
two new dual-registry pushes with
the existing helm-smoke build)
softprops/action-gh-release v1 → v3 (v3 = node24)
Left as-is (verified not affected):
helm/kind-action@v1 — action.yml already declares using: node24
anthropics/claude-code-action@v1 — composite action, no JS runtime
Chose the artifact pair upload@v6 + download@v7 (the first true node24
defaults) over v7/v8 to clear the deprecation without inheriting v7/v8's
ESM + direct-upload + digest-error behaviour changes mid-release-stabilisation.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ags page) The digest-and-merge pattern (imagetools create) pushes via the registry manifest API, which Docker Hub's Tags page does NOT index — the image was pullable (verified anonymously) but hub.docker.com/r/ basekicklabs/arc/tags showed count:0. GHCR indexes registry-API pushes fine; Docker Hub only indexes the standard buildx --push path. Fix: split Docker Hub into its own job (docker-build-dockerhub) that does ONE multi-platform `docker buildx build --push` straight to docker.io/basekicklabs/arc with all tags. Layers come from the same gha cache the GHCR build populates, so it's mostly cache-hit + push. This goes through the path Hub's UI indexes, so published tags show up on the Tags page. GHCR stays on the fast per-platform digest-and-merge (docker-build + docker-merge) — its package UI indexes those correctly. test_mode latest-suppression preserved on both registries. Draft release now also `needs` docker-build-dockerhub so a Hub push failure blocks the release.
Member
Author
|
@gemini-code-assist review please |
Contributor
|
Note Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported. |
1 similar comment
Contributor
|
Note Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported. |
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.
Summary
Two release-pipeline changes, both verified with live
test_modedispatches (no reallatestclobbered):1. Publish the release image to Docker Hub alongside GHCR
docker-build-dockerhubjob does a single multi-platformdocker buildx build --pushstraight todocker.io/basekicklabs/arc(version, short_version, latest).docker-build+docker-merge) because GHCR's package UI indexes registry-API pushes. Docker Hub's Tags page does NOT indeximagetools createpushes — the image was pullable buthub.docker.com/r/basekicklabs/arc/tagsshowed empty. A directbuildx --pushgoes through the path Hub's UI indexes, so published tags actually appear. Verified: test run populated the Tags page correctly.create-draft-releasenowneedsthe Docker Hub job, so a Hub push failure blocks the release.2.
test_modeworkflow_dispatch inputtrue, suppresses thelatesttag end-to-end on both registries so a CI verification run can't overwrite the reallatest. Branch-push releases are never test mode. Used to validate this whole change against00.00.1/00.00.2without touching production tags.3. Bump every JS action to its Node-24 major
GitHub forces Node-24 for JS actions 2026-06-02 and removes Node-20 from runners 2026-09-16. Each version verified node24 from release notes (not guessed):
checkout v4→v5,setup-go v5→v6,upload-artifact v4→v6,download-artifact v4→v7,setup-helm v4→v5,setup-kubectl v4→v5,docker/setup-qemu v3→v4,docker/setup-buildx v3→v4,docker/login v3→v4,docker/metadata v5→v6,docker/build-push v5/v6→v7,action-gh-release v1→v3. Lefthelm/kind-action@v1(already node24) andclaude-code-action@v1(composite, no JS).Test plan
test_modedispatch (00.00.1): confirmed dual-registry push works; multi-arch image index live on both GHCR + Docker Hub.test_modedispatch (00.00.2): confirmed Docker Hub Tags page populates with the directbuildx --pushapproach.Required repo secrets (already configured)
DOCKERHUB_USERNAME+DOCKERHUB_TOKEN(Docker Hub access token, Read & Write).Post-merge cleanup
Test tags
00.00.1/00.00.2/00.00should be deleted from both GHCR and Docker Hub (harmless00.00.xtest versions; my CLI token lackeddelete:packages).🤖 Generated with Claude Code