From f075857f56ae4dce9759902e5cb4067110cef12f Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sat, 17 Oct 2026 03:28:23 +0200 Subject: [PATCH] ci: move the floating major tag to each new release `uses: Mergifyio/setup-cli@v1` resolves the `v1` tag, and nothing has moved that tag since v1.0.0: it still points at the first release, which installs mergify-cli from PyPI through setup-python and uv. Every later release (v1.1.0's prebuilt binary, v1.2.0, v1.3.0) is invisible to anyone following the README's own advice to pin the major. This adds a release workflow that, when a release is published, points the major tag at the newest published release of that major. It picks the newest one rather than the release that triggered it, so a patch on an older minor cannot move `v1` backwards, and prereleases are skipped. The tag is updated through the refs API, so a consumer never sees `v1` missing mid-update. It can also be run by hand with a release tag, which is how `v1` gets moved to v1.3.0 once this lands. The README now says that `v1` follows the v1.x releases and how to stay on one. Co-Authored-By: Claude Opus 5.5 Change-Id: I879539b0c861a7d1d1a9f2f8cfd66b64419e4361 --- .github/workflows/release.yaml | 65 ++++++++++++++++++++++++++++++++++ README.md | 4 ++- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/release.yaml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..4dc1ab0 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,65 @@ +name: Release +permissions: {} + +on: + release: + types: + - published + workflow_dispatch: + inputs: + tag: + description: A vX.Y.Z release tag; its major tag (vX) is moved + required: true + type: string + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + +jobs: + move-major-tag: + # `uses: Mergifyio/setup-cli@v1` resolves the v1 tag, so it has to follow + # every v1.x.y release or users silently stay on an old one. + if: ${{ github.event_name == 'workflow_dispatch' || !github.event.release.prerelease }} + timeout-minutes: 5 + runs-on: ubuntu-26.04 + permissions: + contents: write + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + TAG: ${{ inputs.tag || github.event.release.tag_name }} + steps: + - name: Point the major tag at the latest release of that major + run: | + set -euo pipefail + if [[ ! "$TAG" =~ ^(v[0-9]+)\.[0-9]+\.[0-9]+$ ]]; then + echo "::error::$TAG is not a vX.Y.Z release tag" + exit 1 + fi + major="${BASH_REMATCH[1]}" + + # Use the newest published release of the major rather than $TAG, so + # a patch release on an older minor never moves the tag backwards. + latest=$( + gh api --paginate "repos/$REPO/releases" \ + --jq '.[] | select((.draft or .prerelease) | not) | .tag_name' \ + | { grep -E "^${major}\.[0-9]+\.[0-9]+$" || true; } \ + | sort -V | tail -n 1 + ) + if [ -z "$latest" ]; then + echo "::error::No published $major.x.y release found" + exit 1 + fi + sha=$(gh api "repos/$REPO/commits/$latest" --jq .sha) + + if gh api "repos/$REPO/git/ref/tags/$major" > /dev/null 2>&1; then + gh api -X PATCH "repos/$REPO/git/refs/tags/$major" \ + -f sha="$sha" -F force=true > /dev/null + else + gh api -X POST "repos/$REPO/git/refs" \ + -f ref="refs/tags/$major" -f sha="$sha" > /dev/null + fi + + test "$(gh api "repos/$REPO/git/ref/tags/$major" --jq .object.sha)" = "$sha" + echo "$major -> $latest ($sha)" | tee -a "$GITHUB_STEP_SUMMARY" diff --git a/README.md b/README.md index aa9af51..4410b23 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,9 @@ More information on https://mergify.com ## Usage -Pin the action to a released major (see the [releases](https://github.com/Mergifyio/setup-cli/releases)): +Pin the action to a released major (see the [releases](https://github.com/Mergifyio/setup-cli/releases)). +The `v1` tag moves to each new `v1.x.y` release; pin a full version such as +`v1.3.0` to stay on one release: ```yaml - uses: Mergifyio/setup-cli@v1