From d6dc813290680231e90cf7954d99ec60055750dd Mon Sep 17 00:00:00 2001 From: Luke Tornquist Date: Tue, 13 Oct 2026 15:47:53 -0400 Subject: [PATCH] ci(docker): publish a sortable main-- relay tag (#8240) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Each push to main adds one more tag to the relay image manifest that `docker.yml` already publishes: - `:main--` (UTC commit time) - `:debug-main--` on the debug manifest `:main`, `:sha-<7>`, and the release tags don't change. **Why:** `:sha-<7>` has no ordering, so a deploy tool that wants "the newest main build" has to fetch metadata for every tag before it can sort. Our staging promotion warehouse (Kargo, `NewestBuild`) does that on every discovery cycle, against about 1,700 `sha-*` tags (4,800 total) in `ghcr.io/block/buzz`. That's slow, it hits registry rate limits, and one failed fetch aborts the whole cycle. The timestamp prefix makes the tag sort lexically in build order. A `Lexical` selector with `^main-\d{14}-[0-9a-f]{7}$` can then pick the newest build from the tag list alone and fetch only the tags it keeps. Details, checked against the pinned `docker/metadata-action` v6.1.0 (`80c7e94d`): - `{{sha}}` is the 7-char short sha (`defaultShortShaLength = 7`), the same value as `:sha-<7>`. - `{{commit_date}}` formats in UTC by default. On a push it uses the event's `commits[].timestamp`, so rerunning a commit produces the same tag. - `type=raw` inherits the flavor prefix, so the merge job's debug leg emits `debug-main-…`. That's the same mechanism that produces `debug-main` today. - `enable=` limits the tag to `push` on `refs/heads/main`. Release tags, rescue dispatches, and PRs never get it. On main's last 40 commits, author time and committer time are the same instant, and both increase monotonically. A commit pushed with a backdated timestamp would sort below newer builds and just wouldn't be auto-picked; the next push supersedes it. **What got simpler:** this adds one tag line in each of the two places that already mirror the tag matrix, plus header docs. In return, downstream tooling no longer needs per-tag metadata fetches to find the newest build. ### Related issue N/A (staging rollout tooling). The downstream warehouse and tag-guard changes land separately and don't switch over until this tag has been published. ### Testing - `scripts/test-relay-image-eligibility-workflow.sh` and `scripts/test-release-ref-contract.sh` pass at `9ba1d8b7f`. - PR runs don't push images (`push: false`), so the first real tag appears on the first main push after merge. I'll check the registry for `main-<14 digits>-` and `debug-main-…` on that manifest. --------- Signed-off-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz> Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz> --- .github/workflows/docker.yml | 12 ++++++++++-- deploy/charts/buzz/README.md | 4 ++-- scripts/test-release-ref-contract.sh | 8 ++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 3d824bfc56..596c247eee 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -16,8 +16,8 @@ name: Docker image # the relay image version tracks crates/buzz-relay/Cargo.toml, never desktop. # # Triggers: -# - push to main → :main + :sha-<7> -# + :debug-main + :debug-sha-<7> +# - push to main → :main + :sha-<7> + :main--<7> +# + the matching :debug-* tags # - push tags relay-v*.*.* → :{version} + :{major}.{minor} + :{major} # + matching :debug-* tags # (+ :latest/:debug-latest for stable releases) @@ -34,6 +34,12 @@ name: Docker image # intact) and the bare version flows straight to the semver parser. On a # real push event value= is empty and the match strips relay-v from the ref. # +# :main--<7> names the same main build as :sha-<7>, prefixed +# with its UTC commit time so the tag sorts by build order. Kargo's Lexical +# strategy picks the newest from the tag list alone; :sha-<7> cannot be +# ordered without fetching every image's metadata. It uses the commit date, +# not the run date, so a rerun of the same commit re-pushes the same tag. +# # The :latest tag tracks the latest STABLE relay release: metadata-action's # `flavor.latest=auto` (its default) emits :latest only for non-prerelease # semver, so relay-v0.3.0-rc.1 publishes :0.3.0-rc.1 without moving :latest, @@ -162,6 +168,7 @@ jobs: type=semver,pattern={{version}},match=^relay-v(.*)$,value=${{ inputs.version }} type=semver,pattern={{major}}.{{minor}},match=^relay-v(.*)$,value=${{ inputs.version }} type=semver,pattern={{major}},match=^relay-v(.*)$,value=${{ inputs.version }} + type=raw,value=main-{{commit_date 'YYYYMMDDHHmmss'}}-{{sha}},enable=${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} labels: | org.opencontainers.image.title=Buzz org.opencontainers.image.description=WebSocket relay server for the Buzz communications platform @@ -371,6 +378,7 @@ jobs: type=semver,pattern={{version}},match=^relay-v(.*)$,value=${{ inputs.version }} type=semver,pattern={{major}}.{{minor}},match=^relay-v(.*)$,value=${{ inputs.version }} type=semver,pattern={{major}},match=^relay-v(.*)$,value=${{ inputs.version }} + type=raw,value=main-{{commit_date 'YYYYMMDDHHmmss'}}-{{sha}},enable=${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - name: Create and push manifest list id: manifest diff --git a/deploy/charts/buzz/README.md b/deploy/charts/buzz/README.md index eb9e3bdb32..5704a7622b 100644 --- a/deploy/charts/buzz/README.md +++ b/deploy/charts/buzz/README.md @@ -480,8 +480,8 @@ Every Pod the chart renders — relay, pairing relay, storage accounting, and th deletion drain operator job — carries a chart-owned `tags.datadoghq.com/version` label derived from the deployed image: `image.tag` when set, otherwise `image.digest`, otherwise `Chart.AppVersion`. -The tag is preferred because it is the readable build name (`sha-`) -dashboards already use; promotion tooling writes it together with the digest +The tag is preferred because it is the readable build name (`sha-`, or +`main--` for Kargo-promoted main builds) dashboards use; promotion tooling writes it together with the digest that actually pins the image. ```yaml diff --git a/scripts/test-release-ref-contract.sh b/scripts/test-release-ref-contract.sh index 73e37e7955..5b11a71087 100755 --- a/scripts/test-release-ref-contract.sh +++ b/scripts/test-release-ref-contract.sh @@ -52,6 +52,14 @@ fi grep -q 'verify-release-ref\.sh' "$repo_root/.github/workflows/release.yml" grep -q 'verify-release-ref\.sh' "$repo_root/.github/workflows/docker.yml" +# Kargo's buzz-image warehouse selects Lexical over ^main-[0-9]{14}-[0-9a-f]{7}$; +# a drifted format stops Freight discovery silently, so pin both image legs. +sortable_main_tag=" type=raw,value=main-{{commit_date 'YYYYMMDDHHmmss'}}-{{sha}},enable=\${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}" +sortable_count="$(grep -Fxc "$sortable_main_tag" "$repo_root/.github/workflows/docker.yml" || true)" +if [ "$sortable_count" != 2 ]; then + echo "docker.yml must publish the sortable main-- tag on both image legs (found $sortable_count)" >&2 + exit 1 +fi grep -q 'test-release-ref-contract\.sh' "$repo_root/.github/workflows/ci.yml" "$repo_root/scripts/test-signed-canary-contract.sh" "$repo_root/scripts/test-desktop-release-cache-key.sh"