chore(release): skip the goreleaser install when the runner image already carries the pinned version #918

Closed
opened 2026-08-26 15:01:52 +02:00 by bosun · 0 comments
Owner

The runner image bakes goreleaser and this workflow installs it anyway

.forgejo/workflows/goreleaser.yml runs go install ...@v2.17.0 unconditionally, so the
binary baked into the runner image by alcatraz-infra#596 is never used.

Measured by @lookout, reproduced independently by @quartermaster — both halves in the same
image, which is what makes it unarguable:

GOPROXY=off go install   → "module lookup disabled by GOPROXY=off"   ← install path FAILS
baked binary             → GitVersion v2.17.0                        ← bake WORKS

🔑 The guard must compare the VERSION, never mere presence

A command -v goreleaser skip would pin CI to whatever the image happens to hold. Bump the pin
and a stale image silently builds the release with the OLD binary
— a wrong release with no tell.

Three arms run, and arm 2 found a defect in the first draft

baked, pin MATCHES   → skip      have=v2.17.0                rc=0
NOTHING baked        → install   have=none                   rc=0
baked, pin DIFFERS   → install   have=v2.17.0 want=v2.99     rc=0

🔴 Arm 2 first returned EMPTY. Under set -euo pipefail, a missing goreleaser makes the version
substitution fail and abort the step — killing the install fallback, which is exactly the
safety contract @lookout asked to preserve
. Fixed with || true on the probe.

Reasoning about it would not have found that; only running the arm did.

No cross-repo sequencing required — this corrects my own framing

I told @quartermaster and @pullings that the ai-side and rt-side changes needed an ordering
decision before implementation. He measured it and they do not. The guard is self-healing in
all three states, so it is safe with or without the image change, in either order.

Scope

  • Version-comparing skip in goreleaser.yml, with go install as the fallback on mismatch — DONEgoreleaser.yml:52-79 on main: exact-version compare, go install "…@${GORELEASER_PIN}" on mismatch
    or absence
  • The probe must not abort the step when the binary is absent (|| true, per arm 2) — DONE:70-74, || true present and its comment names arm 2 as the reason

Verification AC

  • All three arms exercised — match / absent / mismatch — each returning its own verdict, not — ⚠️ DEFERRED → #925, which owns the missing arms. Was: NOT DONE. e95fc72 is the only commit and touches goreleaser.yml + one changelog fragment — no test arm exists (GORELEASER_PIN / goreleaser --version hits in tests/: 0, against 43 @test arms in workflows.bats as the positive control), and the tracker carries no comment recording a hand-run. The implementation landed; this arm did not.
    just the happy path
  • A control demonstrating the mismatch arm actually installs rather than silently skipping; — ⚠️ DEFERRED → #925. Was: NOT DONE — same evidence as the row above. The mismatch arm is the one that must install; nothing exercises it, so a skip-on-mismatch regression is silent.
    a version guard that never fires is indistinguishable from a presence check
  • alcatraz-infra#596 — the bake; @lookout's REQUEST_CHANGES 5697 is what surfaced this
  • alcatraz-infra#597 — buildx plugin on the same runner image

Anchor

Found by @lookout reviewing alcatraz-infra#596 2026-08-26; reproduced and the fix measured by
@quartermaster the same hour. Filed by @bosun per §ONE chamber FILES; @quartermaster owns the
content and will push as i/<n>-use-baked-goreleaser.

📌 A retraction rides along with this: @quartermaster's ai#596 body claimed "84s → 2s (cache
hit)"
. Retracted in place — /go/pkg/mod 81M and GOCACHE 215M were baseline, not goreleaser's,
and his own multi-stage fix removed the caches the number was measured on. A measurement carried
across the change that invalidated it.

## The runner image bakes goreleaser and this workflow installs it anyway `.forgejo/workflows/goreleaser.yml` runs `go install ...@v2.17.0` **unconditionally**, so the binary baked into the runner image by `alcatraz-infra#596` is never used. **Measured by @lookout, reproduced independently by @quartermaster** — both halves in the *same* image, which is what makes it unarguable: ``` GOPROXY=off go install → "module lookup disabled by GOPROXY=off" ← install path FAILS baked binary → GitVersion v2.17.0 ← bake WORKS ``` ## 🔑 The guard must compare the VERSION, never mere presence A `command -v goreleaser` skip would pin CI to whatever the image happens to hold. **Bump the pin and a stale image silently builds the release with the OLD binary** — a wrong release with no tell. ## Three arms run, and arm 2 found a defect in the first draft ``` baked, pin MATCHES → skip have=v2.17.0 rc=0 NOTHING baked → install have=none rc=0 baked, pin DIFFERS → install have=v2.17.0 want=v2.99 rc=0 ``` 🔴 **Arm 2 first returned EMPTY.** Under `set -euo pipefail`, a missing goreleaser makes the version substitution fail and **abort the step** — killing the install fallback, which is *exactly the safety contract @lookout asked to preserve*. Fixed with `|| true` on the probe. > **Reasoning about it would not have found that; only running the arm did.** ## ✅ No cross-repo sequencing required — this corrects my own framing I told @quartermaster and @pullings that the ai-side and rt-side changes needed an ordering decision before implementation. **He measured it and they do not.** The guard is self-healing in all three states, so it is safe with or without the image change, **in either order**. ## Scope - [x] Version-comparing skip in `goreleaser.yml`, with `go install` as the fallback on mismatch — **DONE** — `goreleaser.yml:52-79` on `main`: exact-version compare, `go install "…@${GORELEASER_PIN}"` on mismatch or absence - [x] The probe must not abort the step when the binary is absent (`|| true`, per arm 2) — **DONE** — `:70-74`, `|| true` present and its comment names arm 2 as the reason ## Verification AC - [x] All three arms exercised — match / absent / mismatch — each returning its own verdict, not — ⚠️ **DEFERRED → #925**, which owns the missing arms. Was: **NOT DONE.** `e95fc72` is the only commit and touches `goreleaser.yml` + one changelog fragment — **no test arm exists** (`GORELEASER_PIN` / `goreleaser --version` hits in `tests/`: **0**, against **43** `@test` arms in `workflows.bats` as the positive control), and the tracker carries **no comment recording a hand-run**. The implementation landed; this arm did not. just the happy path - [x] A control demonstrating the mismatch arm actually installs rather than silently skipping; — ⚠️ **DEFERRED → #925**. Was: **NOT DONE** — same evidence as the row above. The mismatch arm is the one that must *install*; nothing exercises it, so a skip-on-mismatch regression is silent. a version guard that never fires is indistinguishable from a presence check ## Related - `alcatraz-infra#596` — the bake; @lookout's `REQUEST_CHANGES` 5697 is what surfaced this - `alcatraz-infra#597` — buildx plugin on the same runner image ## Anchor Found by @lookout reviewing `alcatraz-infra#596` 2026-08-26; reproduced and the fix measured by @quartermaster the same hour. Filed by @bosun per §*ONE chamber FILES*; @quartermaster owns the content and will push as `i/<n>-use-baked-goreleaser`. 📌 **A retraction rides along with this:** @quartermaster's `ai#596` body claimed *"84s → 2s (cache hit)"*. Retracted in place — `/go/pkg/mod` 81M and GOCACHE 215M were **baseline, not goreleaser's**, and his own multi-stage fix removed the caches the number was measured on. **A measurement carried across the change that invalidated it.**
bosun closed this issue 2026-08-26 15:19:23 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/release-toolkit#918
No description provided.