ci: serialize bump-version and gate releases on actual version bump

Prevent concurrent version bumps and spurious releases in the release
pipeline:

- Add a workflow-level concurrency group (cancel-in-progress: false) so
  only one bump-version run executes at a time. Concurrent runs have
  previously raced to bump the version and push tags, causing release
  failures. Subsequent pushes now queue instead of cancelling an
  in-flight bump/release.

- Make commitizen the single source of truth for whether a release is
  warranted. The previous grep heuristic counted commits matching
  feat|fix|docs|refactor|perf|test|build|ci|chore, but commitizen only
  bumps for feat/fix/breaking changes. A CI- or docs-only push therefore
  set bumped=true and fired release+docker against the old, already
  released tag. Now we compare the latest tag before/after running
  bump-mcp.sh and only set bumped=true (and emit the new tag) when it
  actually changes, so release/docker exit early on non-release pushes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-03 02:19:26 +02:00
co-authored by Claude Opus 4.8
parent e39574e5d6
commit 72a698dfe2
+24 -16
View File
@@ -5,6 +5,13 @@ on:
branches:
- master
# Ensure only one version bump runs at a time. Concurrent runs would race to
# bump the version and push tags, which has caused release failures in the past.
# Queue subsequent pushes instead of cancelling an in-flight bump/release.
concurrency:
group: bump-version
cancel-in-progress: false
jobs:
bump-version:
if: "!startsWith(github.event.head_commit.message, 'bump:') && !startsWith(github.event.head_commit.message, 'chore(release):')"
@@ -43,27 +50,28 @@ jobs:
echo "Checking for version bump..."
# Get the most recent tag
last_tag=$(git tag --sort=-creatordate | grep -E "^v[0-9]" | head -n 1 || echo "")
# Record the current version tag before attempting a bump. commitizen
# is the single source of truth for whether a release is warranted: it
# only bumps for feat/fix/breaking changes and emits
# [NO_COMMITS_TO_BUMP] (exit 0) for release-irrelevant commits such as
# ci:, docs:, chore:, etc. We therefore let it decide and detect a
# release by whether the latest tag actually changed.
tag_before=$(git tag --sort=-creatordate | grep -E '^v[0-9]' | head -n 1 || echo "")
echo "Latest tag before bump: ${tag_before:-<none>}"
if [ -z "$last_tag" ]; then
commit_range="master"
else
commit_range="${last_tag}..HEAD"
fi
# Run the bump. The script exits 0 both when it bumps and when there
# is nothing to bump, so we compare tags rather than trusting exit code.
./scripts/bump-mcp.sh
# Count conventional commits
commit_count=$(git log "$commit_range" --oneline --grep="^(feat|fix|docs|refactor|perf|test|build|ci|chore)" -E | wc -l)
tag_after=$(git tag --sort=-creatordate | grep -E '^v[0-9]' | head -n 1 || echo "")
echo "Latest tag after bump: ${tag_after:-<none>}"
if [ "$commit_count" -gt 0 ]; then
echo "Found $commit_count commits since $last_tag"
echo "Bumping version..."
./scripts/bump-mcp.sh
if [ -n "$tag_after" ] && [ "$tag_after" != "$tag_before" ]; then
echo "Version bumped to $tag_after"
echo "bumped=true" >> $GITHUB_OUTPUT
tag=$(git tag --sort=-creatordate | grep -E '^v[0-9]' | head -n 1)
echo "tag=$tag" >> $GITHUB_OUTPUT
echo "tag=$tag_after" >> $GITHUB_OUTPUT
else
echo "No commits found since $last_tag"
echo "No version bump required (no release-relevant commits)"
echo "bumped=false" >> $GITHUB_OUTPUT
fi