Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ name: Release

on:
workflow_call:
inputs:
auto-merge-level:
description: "Automatically merge the Release Please PR when CI passes, up to this bump level. One of: none, patch, minor, major."
type: string
required: false
default: none
secrets:
RELEASE_PLEASE_CLIENT_ID:
description: Client ID for create-github-app-token
Expand Down Expand Up @@ -65,3 +71,83 @@ jobs:
token: ${{ steps.generate_token.outputs.token }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json

# Reconcile auto-merge on the open Release Please PR every run. release-please
# keeps a single PR open and rewrites it as commits land, so its bump level can
# change over time; we enable or disable auto-merge to match the current bump.
# The bump is derived from .release-please-manifest.json (next version on the PR
# head branch vs. current version on the base branch), which is authoritative
# regardless of how each caller configures its PR title.
- name: Reconcile auto-merge on the Release Please PR
if: ${{ steps.release_please.outputs.pr != '' && inputs.auto-merge-level != 'none' }}
env:
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
GH_REPO: ${{ github.repository }}
AUTO_MERGE_LEVEL: ${{ inputs.auto-merge-level }}
PR_JSON: ${{ steps.release_please.outputs.pr }}
run: |
set -euo pipefail

level_num() {
case "$1" in
none) echo 0 ;;
patch) echo 1 ;;
minor) echo 2 ;;
major) echo 3 ;;
*) echo "Invalid level '$1' (expected none, patch, minor or major)" >&2; exit 1 ;;
esac
}
# Fail fast on an invalid auto-merge-level input.
level_num "$AUTO_MERGE_LEVEL" >/dev/null

pr_number=$(jq -r '.number' <<<"$PR_JSON")
head_branch=$(jq -r '.headBranchName' <<<"$PR_JSON")
base_branch=$(jq -r '.baseBranchName' <<<"$PR_JSON")

# Read the single root (".") entry of the release-please manifest at a ref.
manifest_version() {
gh api "repos/${GH_REPO}/contents/.release-please-manifest.json?ref=$1" \
-H "Accept: application/vnd.github.raw" | jq -r '.["."]'
}

current=$(manifest_version "$base_branch")
next=$(manifest_version "$head_branch")

IFS=. read -r cmaj cmin cpat <<<"$current"
IFS=. read -r nmaj nmin npat <<<"$next"

if [ "$nmaj" -gt "$cmaj" ]; then bump=major
elif [ "$nmin" -gt "$cmin" ]; then bump=minor
elif [ "$npat" -gt "$cpat" ]; then bump=patch
else bump=none
fi

echo "Release PR #${pr_number}: ${current} -> ${next} (${bump} bump); auto-merge-level=${AUTO_MERGE_LEVEL}"

# Merge when the PR's bump is a real release and is no larger than the
# configured ceiling (none < patch < minor < major).
if [ "$(level_num "$bump")" -ge 1 ] && [ "$(level_num "$bump")" -le "$(level_num "$AUTO_MERGE_LEVEL")" ]; then
want_merge=true
else
want_merge=false
fi

# Only mutate when the desired state differs from the current one, to avoid
# redundant enable/disable calls (and the errors a redundant one can raise).
enabled=$(gh pr view "$pr_number" --json autoMergeRequest --jq '.autoMergeRequest != null')

if [ "$want_merge" = true ] && [ "$enabled" != true ]; then
echo "Enabling auto-merge (squash) on PR #${pr_number}"
# Soft-fail: a repo that hasn't enabled "Allow auto-merge" or hasn't granted
# the App branch-protection bypass shouldn't break its whole release run.
gh pr merge "$pr_number" --auto --squash \
|| echo "::warning::Could not enable auto-merge on PR #${pr_number}. Check that 'Allow auto-merge' is enabled and the release-please App can bypass branch protection."
elif [ "$want_merge" = false ] && [ "$enabled" = true ]; then
echo "Disabling auto-merge on PR #${pr_number}"
# Soft-fail symmetrically with the enable path: a transient API error or a
# race shouldn't break the release run.
gh pr merge "$pr_number" --disable-auto \
|| echo "::warning::Could not disable auto-merge on PR #${pr_number}."
else
echo "Auto-merge already in desired state (enabled=${enabled}, want=${want_merge}); nothing to do"
fi
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
however this project does not use Semantic Versioning and there are no releases.
Instead this file uses a date-based structure.

## 2026-05-21
## 2026-05-27

### Added

- `release.yaml` (release-please reusable workflow) gained an `auto-merge-level` input (`none`, `patch`, `minor`, `major`; default `none`). When set, the workflow enables GitHub auto-merge (`gh pr merge --auto --squash`) on the open release-please PR if the PR's bump is no larger than the configured ceiling, so the PR merges automatically once CI passes. The bump is derived from `.release-please-manifest.json` (next version on the PR head branch vs. current version on the base branch), so it is independent of each caller's PR-title configuration. Auto-merge is reconciled on every run — if a release-please PR's bump grows past the ceiling (e.g. from `patch` to `major`) before it is merged, auto-merge is disabled again. The default `none` preserves the previous behaviour (no auto-merge). The merge is performed with the `release-please` GitHub App token, so the merge is attributed to the App; the App must be granted bypass on any branch protection and the repository must have "Allow auto-merge" enabled.

### Changed

Expand Down