fix(plugin-release): correct PR merge logic for BLOCKED state (#133)
* fix(plugin-release): correct PR merge logic for BLOCKED state Prior releases failed with 'Resource not accessible by integration' when gh pr merge was called with a branch name on a BLOCKED PR. The root cause is that --auto requires the PR to have a pending status check that can be satistfied by auto-merge. Without --auto, gh attempts an immediate merge but the BLOCKED state (from branch protection requiring status checks) causes GitHub to reject the push. Fix: always use --auto for BLOCKED PRs, and refactor the polling loop so it properly loops until mergeStateStatus is no longer UNKNOWN (up to 3 retries with exponential back-off) before deciding whether to use --auto or merge directly. Also fix the case where gh pr create is called without --json output, so OPEN_PR is always captured correctly regardless of whether we created a new PR or found a pre-existing one. Co-Authored-By: Paperclip <noreply@paperclip.ing> * fix: restore MERGED check and use PR number in retry loop - Restore idempotent exit 0 when PR is already MERGED (regression from prior fix) - Use $OPEN_PR instead of hardcoded branch name in gh pr view retry loop - Fallback to --auto when UNKNOWN persists after exhausting retries (safe: auto-merge waits for branch protection) Fixes bugs reported by Regression Regina on PR #133. --------- Co-authored-by: Chris Farhood <chris@farhood.org> Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
committed by
GitHub
parent
490128a044
commit
73d91725a9
@@ -334,6 +334,7 @@ jobs:
|
||||
|
||||
- name: Create PR for version bump
|
||||
run: |
|
||||
set -o pipefail
|
||||
VERSION="${{ inputs.version }}"
|
||||
BODY=$(printf "Automated version bump and checksum update for v%s.\n\ncc @cpfarhood" "${VERSION}")
|
||||
# Create PR only if an OPEN one doesn't already exist.
|
||||
@@ -345,43 +346,50 @@ jobs:
|
||||
--title "release: v${VERSION}" \
|
||||
--body "$BODY" \
|
||||
--base main \
|
||||
--head "release/v${VERSION}"
|
||||
--head "release/v${VERSION}" \
|
||||
--json number --jq '.number'
|
||||
# Pull the number again to handle both create and pre-existing cases
|
||||
OPEN_PR=$(gh pr list --base main --head "release/v${VERSION}" --state open --json number --jq '.[0].number' 2>/dev/null)
|
||||
else
|
||||
echo "::notice::Open PR #${OPEN_PR} for release/v${VERSION} already exists — skipping creation."
|
||||
fi
|
||||
# Re-fetch open PR number (handles both new and pre-existing open PRs).
|
||||
PR_STATE=$(gh pr list --base main --head "release/v${VERSION}" --state open --json state --jq '.[0].state' 2>/dev/null || echo "unknown")
|
||||
if [ "$PR_STATE" != "OPEN" ]; then
|
||||
echo "No open PR for release/v${VERSION} — it may have already merged. Checking."
|
||||
PR_STATE=$(gh pr view "release/v${VERSION}" --json state --jq '.state' 2>/dev/null || echo "unknown")
|
||||
if [ "$PR_STATE" = "MERGED" ]; then
|
||||
echo "PR release/v${VERSION} is already merged. Skipping merge step."
|
||||
exit 0
|
||||
fi
|
||||
# Guard: ensure we have a PR number before proceeding
|
||||
if [ -z "$OPEN_PR" ]; then
|
||||
echo "::error::Could not determine PR number for release/v${VERSION}."
|
||||
exit 1
|
||||
fi
|
||||
# Use auto-merge only when there are pending status checks to wait for.
|
||||
# Valid mergeStateStatus values (gh GraphQL):
|
||||
# BEHIND, BLOCKED, CLEAN, DIRTY, DRAFT, HAS_HOOKS, UNKNOWN, UNSTABLE
|
||||
# Note: Field was renamed from mergeableState to mergeStateStatus in gh CLI.
|
||||
MERGE_STATE=$(gh pr view "release/v${VERSION}" --json mergeStateStatus --jq '.mergeStateStatus')
|
||||
if [ "$MERGE_STATE" = "BLOCKED" ]; then
|
||||
echo "PR is $MERGE_STATE — enabling auto-merge."
|
||||
gh pr merge "release/v${VERSION}" --auto --squash --delete-branch
|
||||
elif [ "$MERGE_STATE" = "UNKNOWN" ]; then
|
||||
# GitHub is still computing mergeability. Retry once after a brief wait.
|
||||
echo "PR is $MERGE_STATE — GitHub is computing mergeability. Retrying in 5s."
|
||||
sleep 5
|
||||
MERGE_STATE=$(gh pr view "release/v${VERSION}" --json mergeStateStatus --jq '.mergeStateStatus')
|
||||
if [ "$MERGE_STATE" = "BLOCKED" ]; then
|
||||
echo "PR is now $MERGE_STATE — enabling auto-merge."
|
||||
gh pr merge "release/v${VERSION}" --auto --squash --delete-branch
|
||||
else
|
||||
echo "PR is still $MERGE_STATE after retry — merging directly."
|
||||
gh pr merge "release/v${VERSION}" --squash --delete-branch
|
||||
echo "::notice::Working with PR #${OPEN_PR}"
|
||||
|
||||
# Check if PR was already merged (idempotency — safe to re-trigger after a stale branch)
|
||||
MERGED_CHECK=$(gh pr view "$OPEN_PR" --json state --jq '.state' 2>/dev/null)
|
||||
if [ "$MERGED_CHECK" = "MERGED" ]; then
|
||||
echo "::notice::PR #${OPEN_PR} was already merged. Nothing to do."
|
||||
exit 0
|
||||
fi
|
||||
# Determine whether to use --auto or not based on current status.
|
||||
# Retry the status check up to 3 times with exponential back-off when
|
||||
# GitHub is still computing the merge state (UNKNOWN state).
|
||||
MAX_RETRIES=3
|
||||
BACKOFF=3
|
||||
MERGE_STATE=""
|
||||
for i in $(seq 1 $MAX_RETRIES); do
|
||||
MERGE_STATE=$(gh pr view "$OPEN_PR" --json mergeStateStatus --jq '.mergeStateStatus' 2>/dev/null)
|
||||
if [ "$MERGE_STATE" != "UNKNOWN" ]; then
|
||||
break
|
||||
fi
|
||||
if [ $i -lt $MAX_RETRIES ]; then
|
||||
echo "PR merge state is UNKNOWN (GitHub still computing). Retry ${i}/${MAX_RETRIES} in ${BACKOFF}s..."
|
||||
sleep $BACKOFF
|
||||
BACKOFF=$((BACKOFF * 2))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$MERGE_STATE" = "BLOCKED" ] || [ "$MERGE_STATE" = "UNKNOWN" ]; then
|
||||
echo "PR is $MERGE_STATE — enabling auto-merge (safe fallback, waits for branch protection checks)."
|
||||
gh pr merge "$OPEN_PR" --auto --squash --delete-branch
|
||||
else
|
||||
echo "PR is $MERGE_STATE — merging directly."
|
||||
gh pr merge "release/v${VERSION}" --squash --delete-branch
|
||||
gh pr merge "$OPEN_PR" --squash --delete-branch
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
Reference in New Issue
Block a user