Skip to content

fix(ci): make a mistyped release tag visible, and buildable - #239

Open
bnsoni wants to merge 3 commits into
mainfrom
fix/tag-guard-and-build-dispatch
Open

fix(ci): make a mistyped release tag visible, and buildable#239
bnsoni wants to merge 3 commits into
mainfrom
fix/tag-guard-and-build-dispatch

Conversation

@bnsoni

@bnsoni bnsoni commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

A manually pushed tag that does not match the Docker Build trigger produces nothing — no run, no annotation, nothing in the Actions tab.

On 2026-09-03, os 0.139.0-patch-1 and lms 0.76.1-patch-1 were pushed manually. trigger-docker-build.yml fires only on v*, so GitHub never created a run. It presented as "the build workflow didn't pick up", with an empty Actions tab and nowhere to look.

Root cause

Missing v prefix. That is the whole of it — v0.36.9-patch-1 already exists in lms, so the -patch-N convention was right.

The version bumps were correct too: package.json at both tags already carried the -patch-1 suffix, and since the image is named from package.json rather than the tag, they would have published as new ECR tags without overwriting 0.139.0 or 0.76.1.

The deeper defect is that there was no recovery path. The tag filter was the only trigger on this workflow, so a mistyped tag could not be built at all — the only fix was to push another tag — and the mistake generated zero signal.

Changes

tag-guard.yml (new) — fires on tags: ['**']. A version-shaped tag that cannot build now fails loudly:

::error title=Tag will not build::'0.139.0-patch-1' looks like a release version but does NOT
match the Docker Build trigger ('v*'), so NO image will be built and no other run will appear.
Re-tag as 'v0.139.0-patch-1': git tag v0.139.0-patch-1 <sha> && git push origin v0.139.0-patch-1

It builds nothing and needs no secrets. Non-version tags are ignored.

workflow_dispatch on trigger-docker-build.yml — lets you build any existing ref, including a mistyped tag, by picking it in the ref dropdown.

What I deliberately did not do

Broaden the tag filter to accept bare semver. That fragments the convention and permits a double build if both X and vX get pushed. One convention, enforced visibly, is the safer shape.

Verification

check result
YAML parse passes
actionlint no new findings (both repos had 1 pre-existing)
bash -n on the guard script passes
guard executed, TAG=v0.139.0 exit 0, "matches a build trigger"
guard executed, TAG=0.139.0-patch-1 exit 1, error with the re-tag command
all 7 tag shapes (v*, skills-v*, app-v*, bare semver, non-version) classified correctly

🤖 Generated with Claude Code

bnsoni and others added 2 commits September 3, 2026 19:51
A manually pushed tag that does not match the Docker Build trigger produced
NOTHING — no run, no annotation, nothing in the Actions tab. On 2026-09-03
`os 0.139.0-patch-1` and `lms 0.76.1-patch-1` were pushed without the `v`
prefix; `trigger-docker-build.yml` only fires on `v*`, so GitHub never created
a run and it presented as "the build workflow didn't pick up" with nowhere to
look.

The version bumps themselves were correct — package.json at both tags already
carried the `-patch-1` suffix, so the images would have published as new tags
without clobbering anything. Only the prefix was missing.

Two changes:

- tag-guard.yml (new) fires on EVERY tag. A version-shaped tag that cannot
  build now fails loudly with the exact re-tag command in the annotation,
  instead of failing silently. Builds nothing, needs no secrets.

- workflow_dispatch on trigger-docker-build.yml. The tag filter was the only
  trigger, so a mistyped tag left no way to build at all. Dispatch can build
  any existing ref, including the mistyped tag, via the ref dropdown.

Deliberately NOT broadening the tag filter to accept bare semver: that would
fragment the convention and allow a double build when both `X` and `vX` are
pushed. One convention, enforced visibly, is the safer shape.

Verified: YAML parses, actionlint reports no new findings, the guard script
passes `bash -n`, and it was executed for real — exit 0 on `v0.139.0`, exit 1
with the re-tag command on `0.139.0-patch-1`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@bnsoni
bnsoni requested a review from mamigot as a code owner September 3, 2026 16:51
Adding workflow_dispatch introduced a hazard that the tag-only trigger did not
have. reusable-spa-docker-build.yml names the image from package.json AND also
pushes `latest`:

    FULL_URI="$REGISTRY/$IMAGE_NAME:$VERSION"
    docker tag "$FULL_URI" "$REGISTRY/$IMAGE_NAME:latest"

So dispatching against `main` would rebuild an already-released image tag and
repoint `latest` at it. Before workflow_dispatch existed the only way in was a
`v*` tag push, a deliberate release act.

The guard keeps that property: dispatch is a RECOVERY path for a ref that is
already tagged, not a way to build a branch.

    push              refs/tags/v0.139.0          -> allowed
    workflow_dispatch refs/tags/0.139.0-patch-1   -> allowed  (the recovery case)
    workflow_dispatch refs/heads/main             -> REFUSED
    workflow_dispatch refs/heads/feature/x        -> REFUSED

Verified by executing the step's script body: exit 1 with the error annotation
on a branch ref. actionlint back to main's single pre-existing finding.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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