fix(plugin-release): handle clean-status PR merge gracefully (#77)

* fix(plugin-release): handle clean-status PR merge gracefully

- Check MERGED state before attempting merge (early exit)
- Use mergeableState-based strategy: blocked=auto, others=direct squash
- Remove invalid 'pending' mergeable_state value (was dead code)
- Document 'unknown' state fallback behavior

Rebase of PR #77 to resolve conflicts with main (PR #76)

* fix(plugin-release): fix return syntax and handle unknown mergeableState

- Replace invalid 'return 0 || true' with 'exit 0' for proper step exit
- Add explicit handling for 'unknown' mergeableState with retry logic
- QA feedback: PRI-1049

---------

Co-authored-by: Hugh Hackman <hugh@privilegedescalation>
Co-authored-by: privilegedescalation-ceo[bot] <269721483+privilegedescalation-ceo[bot]@users.noreply.github.com>
This commit is contained in:
privilegedescalation-engineer[bot]
2026-04-15 01:56:28 +00:00
committed by GitHub
parent b4973cc129
commit 175ed1e87c
+25 -6
View File
@@ -304,15 +304,34 @@ jobs:
else
echo "::notice::PR for release/v${VERSION} already exists — skipping creation."
fi
# Try auto-merge first (works on repos with required status checks pending).
# Fall back to direct squash merge on repos without required status checks
# (auto-merge is rejected when there are no pending required checks to wait for).
# If PR is already merged, skip entirely to avoid "branch not found" errors.
# Check if PR is already merged first (skip if so).
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."
elif ! gh pr merge "release/v${VERSION}" --auto --squash --delete-branch 2>&1; then
echo "Auto-merge not available (no pending required status checks or other constraint). Falling back to direct squash merge."
exit 0
fi
# Use auto-merge only when there are pending status checks to wait for.
# Valid mergeableState values from GitHub REST API:
# behind, blocked, clean, dirty, draft, has_hooks, unknown, unstable
# Note: "pending" is NOT a valid mergeable_state value — it was dead code.
MERGE_STATE=$(gh pr view "release/v${VERSION}" --json mergeableState --jq '.mergeableState')
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 mergeableState --jq '.mergeableState')
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
fi
else
echo "PR is $MERGE_STATE — merging directly."
gh pr merge "release/v${VERSION}" --squash --delete-branch
fi
env: