From 580524cfd6b1e10161b108809c5654f2404224fd Mon Sep 17 00:00:00 2001 From: Bradley Taylor Date: Tue, 26 May 2026 15:19:35 -0700 Subject: [PATCH] ci(release): break infinite-loop chain on auto-bump merges The post-publish commit-back step creates a chore(release): bump version to vX.Y.Z PR; merging that PR is a push to master, which triggers ANOTHER release run, which publishes vX.Y.(Z+1) and creates ANOTHER bump-PR. Repeats forever. This adds a guard at the top of Determine version: if the latest commit matches the bot's bump-back subject pattern, set skip=true and exit before any version computation. The rest of the workflow short-circuits via the existing 'if: steps.version.outputs.skip != true' guards. Regex covers both the raw form ('chore(release): bump version to v2.0.3') and the GitHub-squash-merge-decorated form ('... (#274)'). --- .github/workflows/release.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dd3d0f8..424b410 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,9 +56,25 @@ jobs: # Determine version from git tags (source of truth) + commit messages. # The stamped package.json is committed back to master after publish so # `--version` on a fresh source clone matches what's published on npm. + # + # Loop guard: if the latest commit on master IS the auto-generated + # release-bump-back commit, skip this run entirely. Otherwise the + # bump-PR's own merge would trigger another release, which would + # generate another bump-PR, in a perpetual chain. - name: Determine version id: version run: | + # Loop guard — skip when the latest commit is the bot's + # auto-bump merge. Match the squash-merged form too: + # "chore(release): bump version to v2.0.3 (#274)". + LATEST_MSG=$(git log -1 --format="%s") + if echo "$LATEST_MSG" | grep -qE '^chore\(release\): bump version to v[0-9]+\.[0-9]+\.[0-9]+( \(#[0-9]+\))?$'; then + echo "Latest commit is the bot's auto-bump — skipping this release to avoid an infinite loop." + echo "Subject: $LATEST_MSG" + echo "skip=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + # Get latest tag — this is the source of truth, NOT package.json LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") if [ -z "$LAST_TAG" ]; then