diff --git a/.github/workflows/move-major-tag.yml b/.github/workflows/move-major-tag.yml new file mode 100644 index 0000000..fd2c4aa --- /dev/null +++ b/.github/workflows/move-major-tag.yml @@ -0,0 +1,47 @@ +name: Move Major Tag + +# Callers reference this repo as @v2, a moving tag that must be repointed at +# every release. Doing that by hand is easy to forget: v2 sat on the pre-#12 +# commit for two days after the fix merged, so every consumer kept running the +# broken auto-review gate. This job moves it automatically. +# +# Push v2.3.2 -> v2 is force-updated to the same commit. +# Pre-release tags (v2.4.0-rc1) are ignored; they should not move v2. +# +# A first release on a new major (v3.0.0) creates v3; nothing here is specific +# to v2. The tag filter deliberately avoids the `+` glob operator: if it were +# ever treated as a literal, this workflow would silently never fire, which is +# the same quiet staleness it exists to prevent. `[0-9]*` needs only plain +# glob semantics. + +on: + push: + tags: + - 'v[0-9]*.[0-9]*.[0-9]*' + +jobs: + move-major-tag: + name: Move Major Tag + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - name: Move major tag to this release + env: + TAG: ${{ github.ref_name }} + run: | + set -euo pipefail + + # v2.3.2-rc1 -> skip. Only finished releases move the major tag. + case "$TAG" in + *-*) echo "::notice::$TAG is a pre-release; leaving the major tag alone."; exit 0 ;; + esac + + major="${TAG%%.*}" # v2.3.2 -> v2 + + git tag -f "$major" "$GITHUB_SHA" + git push -f origin "$major" + + echo "::notice::Moved $major to $GITHUB_SHA ($TAG)." diff --git a/README.md b/README.md index 9dbc98e..106e1b6 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,27 @@ v2 callers should set `permissions: { contents: read, actions: read }`. The `con - Adding inputs with backward-compatible defaults is minor/patch - Pin to a specific SHA (e.g., `@abc1234`) for strict reproducibility +### Releasing + +Tag the merge commit with a full version and push it. Nothing else is needed — `.github/workflows/move-major-tag.yml` force-moves the major tag (`v2`) to match. + +```bash +git tag v2.3.2 +git push origin v2.3.2 +``` + +The full version tag is the only one you create by hand. Never create or move a major tag (`v2`, `v3`) yourself — that is the job's whole purpose, and doing it manually is what gets forgotten. + +`@v2` is a moving tag, so a release reaches every caller on their next PR event with no change on their side. That only works if `v2` actually moves: when it is left behind, callers keep running the older workflow and there is no signal that anything is stale. Pre-release tags (`v2.4.0-rc1`) do not move `v2`. + +#### Starting a new major + +Nothing extra to do. Push `v3.0.0` and the job creates `v3` at that commit — creating and moving a major tag are the same operation, so there is no special first release. `v3` is usable by callers immediately; you do not need to ship a patch to bring it into existence. + +Two things the job does *not* do on a major bump: update the `@v2` references in this README and in `examples/`, and tell existing callers. `@v2` callers stay on v2 by design and only move when they edit their own workflow. + +Note that a tag push runs the workflow file as it exists *on the tagged commit*. Tagging a commit from before this job was added does nothing at all. + ## Security The following guards are hardcoded in the reusable workflow and **cannot be overridden** by callers: