Skip to content

Label images with the build.gradle version and stop older patches moving :latest - #692

Merged
coopernetes merged 1 commit into
mainfrom
ci/release-tag-publish
Oct 3, 2026
Merged

coopernetes merged 1 commit into
mainfrom
ci/release-tag-publish

Conversation

@coopernetes

@coopernetes coopernetes commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Every stable release tag moved :X.Y, :X and :latest, so a 1.4.x patch cut after 1.5.0 would have pointed :latest and :1 back at 1.4.x. Images were also labelled org.opencontainers.image.version=build-<sha>, so a released image never reported its own version.

  • docker-publish sets org.opencontainers.image.version from build.gradle (X.Y.Z on a release commit, X.Y.Z-SNAPSHOT otherwise).
  • Tag promotion moves to release-publish.yml. scripts/release_image_tags.py refuses an image whose label is not the tag's version, and moves each convenience tag only when the release is at least as new as the version on the image it points at now. A hand rollback stays put until something newer ships; tags on unlabelled (pre-change) images move.
  • Promotions are serialised; cleanup-interim-images shares that concurrency group (its old group matched no running workflow).
  • The scripts' unit tests run in CI's Build & Test (required for merges and tags) instead of inside the workflows that use them.

Worth a look: this PR's image build should carry org.opencontainers.image.version=1.5.0-SNAPSHOT, confirming metadata-action's labels: input overrides its generated value. Re-running the release workflow for v1.4.3 or earlier now fails the label check by design; retag.yml remains the manual path.

release/1.4.x needs this cherry-picked before its next release commit, since tag runs use the workflows at the tagged commit.

Test plan (personal fork)

Run in coopernetes/fogwall with exact copies of the Release gate tag ruleset (same 12 required checks, no bypass) and the Protect release branches ruleset. Fork main = upstream/main + this commit; fork release/9.1.x = upstream/release/1.4.x + this commit cherry-picked. Dummy 9.x versions; every step checked on both images by version label and digest.

  • Starting state: ghcr.io/rbc/fogwall{,-server}:1.4.3 copied in as :9.1.0, :9.1, :9, :latest (legacy build-9244818 label, same digests as upstream).
  • Label: builds carry org.opencontainers.image.version from build.gradle (9.1.0-SNAPSHOT, 9.2.0, 9.1.2-SNAPSHOT, …), so metadata-action's labels: override works.
  • Tag gate: v9.1.0 pushed while checks were running → rejected, "12 of 12 required status checks have not succeeded".
  • v9.2.0 from main → moves 9.2.0 9.2 9 latest, replacing the legacy-labelled 9 and latest; 9.1 untouched.
  • v9.1.1 from release/9.1.x after 9.2.0 → moves 9.1.1 9.1 only; 9 and latest keep the 9.2.0 digest.
  • v9.1.9 on the 9.1.1 commit → refused on both images (labelled '9.1.1', not '9.1.9'); nothing written.
  • v9.1.2 on a 9.1.2-SNAPSHOT commit → refused (labelled '9.1.2-SNAPSHOT', not '9.1.2'); nothing written.
  • v9.3.0-rc.1 → moves 9.3.0-rc.1 only; no 9.3; 9 and latest unchanged.
  • Re-run of the v9.2.0 publish → same tags, same digests.
  • Rollback: retag.yml points 9 and latest at 9.1.1, then v9.1.2 → moves 9.1.2 9.1 9 latest.
  • Serialisation: v9.1.3 and v9.3.0 in one git push → v9.3.0 published first and v9.1.3 waited for it; v9.1.3 then moved 9.1.3 9.1 only. latest and 9 end at 9.3.0, 9.3 created, 9.1 at 9.1.3.
  • Teardown: delete the fork rulesets, release/9.* branches, v9.* tags and fork packages; reset fork main.

Backporting to release/1.4.x:

  • The cherry-pick conflicts in cleanup-interim-images.yml (that branch still has the bash cleanup script). Keep the branch's version; scheduled workflows only run from the default branch.
  • 1.4.3 ships Jackson 2.22.x / 3.2.2 with new advisories (GHSA-cxp5-3px4-pw24, GHSA-wv8q-qhhj-9h54, GHSA-7hhh-6rmp-j9qf). The 1.4.x line passed the scan gate once Jackson 2.x was pinned to 2.22.3 and the 3.x BOM set to 3.2.3; main's commits for these do not cherry-pick cleanly, so 1.4.4 needs them by hand.

🤖 Generated with Claude Code

@coopernetes
coopernetes marked this pull request as draft September 24, 2026 04:25
…ing :latest

Every stable tag moved :X.Y, :X and :latest to its image, so a 1.4.x patch cut after 1.5.0 would have pointed :latest and :1 back at 1.4.x. Images also carried org.opencontainers.image.version=build-<sha>, so a released image never reported its own version.

docker-publish now sets org.opencontainers.image.version from the build.gradle version (X.Y.Z on a release commit, X.Y.Z-SNAPSHOT otherwise). Tag-triggered promotion moves to release-publish.yml, where scripts/release_image_tags.py refuses an image whose label is not the tag's version, and moves each convenience tag only when the release is at least as new as the version labelled on the image it points at now. A tag rolled back by hand stays put until something newer ships; tags on images without a semver label move. Pre-releases still get their exact version only. Promotions are serialised so two releases cannot interleave their read-then-write, and cleanup-interim-images now shares that group (its old group matched no running workflow).

The scripts' unit tests move from the workflows that run them into CI's Build & Test job, a required check for merges and release tags, so a broken script fails before a tag is pushed rather than after. README and CONTRIBUTING describe the current tags and release flow.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coopernetes
coopernetes force-pushed the ci/release-tag-publish branch from 57fb413 to 89f60ea Compare October 3, 2026 04:22
@coopernetes
coopernetes marked this pull request as ready for review October 3, 2026 04:39
@coopernetes
coopernetes merged commit 48fb268 into main Oct 3, 2026
22 checks passed
@coopernetes
coopernetes deleted the ci/release-tag-publish branch October 3, 2026 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant