feat(ci): advance v1 automatically once the gate is green on main

Nothing moved v1 when main advanced, so a merged change was inert
until someone remembered to retag by hand — it happened on 2026-09-22
(PR #25 merged, v1 stayed on the previous release) and was only caught
because a person asked whether the tag had moved.

Option 1 from gitdan-actions#27 (automate it) over option 2 (fail loud
while it lags): a `release-tag` job, gated with `needs: selftest` so a
broken build never reaches it, force-moves v1 to the pushed commit
using the run's built-in GITHUB_TOKEN. If that token turns out not to
have write access, the push fails and the job goes red in the Actions
UI — a loud failure either way, not the silent one this replaces.
Whether the token actually has write access here is unverified short
of a real merge; that merge is the next step for this branch.

README's Versioning section documented the old manual step as a
deliberate decision "never something a merge does by itself" — that
claim is now false, so it's rewritten to describe the automated job
and keeps the manual command as the recovery path for when the job
can't push.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkSjXXtU6JYcN2vPntWhfb
This commit is contained in:
2026-09-22 11:51:51 -05:00
co-authored by Claude Sonnet 5
parent 21dffdb725
commit 7f18cb2436
2 changed files with 46 additions and 10 deletions
+30
View File
@@ -101,3 +101,33 @@ jobs:
# file.
- name: Selftests
run: bash scripts/selftest.sh
release-tag:
name: move v1 to main
# `needs:` is what makes this "after the gate is green" rather than
# merely "after a push": a failed selftest skips this job outright, so
# v1 can never advance onto a broken build. The `if:` restricts it to an
# actual push to main -- a pull_request run targeting main shares this
# workflow but has no ref worth tagging.
needs: selftest
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
runs-on: ubuntu-latest
timeout-minutes: 2
# Requests write access from the run's built-in token (see README's
# Versioning section for what's actually verified about it). Without
# this the checkout below still succeeds -- it's the push that would be
# rejected, which is a red job, not a silent no-op.
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
# Lightweight tag, matching what v1 already is (`git cat-file -t v1`
# reports `commit`, not `tag`) -- no identity needed to move it, only
# to push it.
- name: Force v1 to this commit
run: |
git tag -f v1 "${{ github.sha }}"
git push --force origin v1