From 6e2e4c5055103e666ee5d4c702dd56a507df2e62 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 24 Jul 2026 16:10:09 +0000 Subject: [PATCH] ci: auto-tag releases from the CHANGELOG on merge to main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merging a release PR now ships the release with no manual tag push: on every push to main, autotag.yml reads the newest '## vX.Y.Z' heading from internal/ui/assets/CHANGELOG.md (the same source release.yml renders the release notes from), tags the pushed commit if that version is untagged, and dispatches the Release pipeline on the tag ref. The explicit dispatch exists because refs pushed with a workflow's own GITHUB_TOKEN never trigger other workflows (GitHub's recursion guard) — a pushed tag alone would sit unbuilt. workflow_dispatch on the tag ref sets github.ref to refs/tags/, satisfying release.yml's publish gate and --verify-tag. Manual tag pushes keep working unchanged; the workflow is idempotent (existing tag = no-op). Merging this commit itself tags v1.81.6 (the current CHANGELOG head, still untagged) and cuts that release. --- .github/workflows/autotag.yml | 61 +++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/autotag.yml diff --git a/.github/workflows/autotag.yml b/.github/workflows/autotag.yml new file mode 100644 index 0000000..703fa52 --- /dev/null +++ b/.github/workflows/autotag.yml @@ -0,0 +1,61 @@ +# Auto-tag releases from the CHANGELOG — the "merge a PR = ship a release" glue. +# +# On every push to main this reads the NEWEST "## vX.Y.Z" heading in +# internal/ui/assets/CHANGELOG.md (the same file release.yml builds the release +# notes from, so the two can never disagree about what a version is called). If +# that version has no tag yet, the pushed commit is tagged with it and the +# Release pipeline is dispatched ON that tag ref. Releasing therefore becomes: +# add the new "## vX.Y.Z" CHANGELOG section in the PR (already the convention), +# merge, done — no manual tag push. +# +# Why the explicit dispatch instead of letting the tag push trigger release.yml: +# refs created with a workflow's own GITHUB_TOKEN deliberately do NOT fire other +# workflows (GitHub's recursive-workflow guard), so a GITHUB_TOKEN-pushed tag +# would sit there and never build. An API workflow_dispatch IS allowed, and +# dispatching with --ref runs release.yml with github.ref = +# refs/tags/ — exactly what its publish gate (startsWith refs/tags/) and +# `gh release create --verify-tag` require. Manually-pushed tags still work +# exactly as before (they trigger release.yml directly; this workflow then sees +# the tag exists and does nothing). +# +# Idempotent by construction: an already-existing tag exits 0, so ordinary +# pushes to main between releases are no-ops, and re-running is always safe. +name: Auto-tag release + +on: + push: + branches: [main] + # Manual re-run (e.g. the guard skipped a fire, or dispatch hiccuped). + workflow_dispatch: + +permissions: + contents: write # push the version tag + actions: write # dispatch the Release workflow + +jobs: + tag: + name: Tag from CHANGELOG + dispatch Release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Create the version tag if new, then dispatch the build + env: + GH_TOKEN: ${{ github.token }} + run: | + # Newest-first file: the first "## vX.Y.Z — date" heading is the + # current version. $2 is the bare "vX.Y.Z" token. + ver=$(awk '/^## v/ { print $2; exit }' internal/ui/assets/CHANGELOG.md) + if [ -z "$ver" ]; then + echo "::error::No '## vX.Y.Z' heading found in internal/ui/assets/CHANGELOG.md" + exit 1 + fi + if git ls-remote --exit-code origin "refs/tags/$ver" >/dev/null 2>&1; then + echo "::notice::$ver is already tagged — nothing to do." + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git tag "$ver" "$GITHUB_SHA" + git push origin "refs/tags/$ver" + echo "::notice::Tagged $ver at $GITHUB_SHA — dispatching the Release pipeline." + gh workflow run release.yml --ref "$ver"