From b5f9cbbc5555acb06f666368ce315ce3082d7777 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Sun, 26 Apr 2026 00:53:55 -0700 Subject: [PATCH] ci(retarget): handle 422 'duplicate PR' by closing redundant main-PR (closes #1884) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a bot opens a PR against main and there's already another PR on the same head branch targeting staging, GitHub's PATCH /pulls returns 422 with: "A pull request already exists for base branch 'staging' and head branch ''" Pre-fix: the retarget Action exited 1 with no further action. The target-main PR sat there as a duplicate, the workflow run showed red, and someone had to manually close the duplicate. Today's case (#1881 duplicate of #1820) had to be closed manually. Fix: catch that specific 422 message and close the main-PR as redundant instead of failing. Any OTHER 422 (or other error) still fails loud — the grep matches the specific duplicate-base text, not a blanket "any 422 means duplicate". Behaviour matrix: PATCH succeeds → retargeted, explainer comment posted PATCH 422 "already exists for staging" → close main-PR with explainer (NEW) PATCH any other failure → workflow fails (preserves loud-fail for real bugs) Tests: GitHub Actions don't have an inline unit-test framework here. The workflow YAML parses (validated locally) and the bash logic is straightforward. Real verification will be the next duplicate-PR scenario in production. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../workflows/retarget-main-to-staging.yml | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/.github/workflows/retarget-main-to-staging.yml b/.github/workflows/retarget-main-to-staging.yml index 90fd3d55..0c59ca98 100644 --- a/.github/workflows/retarget-main-to-staging.yml +++ b/.github/workflows/retarget-main-to-staging.yml @@ -33,18 +33,49 @@ jobs: || github.event.pull_request.user.login == 'molecule-ai[bot]' steps: - name: Retarget PR base to staging + id: retarget env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} PR_AUTHOR: ${{ github.event.pull_request.user.login }} + # Issue #1884: when the bot opens a PR against main and there's + # already another PR on the same head branch targeting staging, + # GitHub's PATCH /pulls returns 422 with + # "A pull request already exists for base branch 'staging' …". + # The retarget can't proceed — but the right response is to + # close the now-redundant main-PR, not to fail the workflow + # noisily. Detect that specific 422 and close instead. run: | + set +e echo "Retargeting PR #${PR_NUMBER} (author: ${PR_AUTHOR}) from main → staging" - gh api -X PATCH \ + PATCH_OUTPUT=$(gh api -X PATCH \ "repos/${{ github.repository }}/pulls/${PR_NUMBER}" \ -f base=staging \ - --jq '.base.ref' + --jq '.base.ref' 2>&1) + PATCH_EXIT=$? + set -e + if [ "$PATCH_EXIT" -eq 0 ]; then + echo "::notice::Retargeted PR #${PR_NUMBER} → staging" + echo "outcome=retargeted" >> "$GITHUB_OUTPUT" + exit 0 + fi + # Specifically match the 422 duplicate-base/head error so + # any OTHER PATCH failure (auth, deleted PR, etc.) still + # surfaces as a real workflow failure. + if echo "$PATCH_OUTPUT" | grep -q "pull request already exists for base branch 'staging'"; then + echo "::notice::PR #${PR_NUMBER}: duplicate target-staging PR exists on same head — closing this main-PR as redundant." + gh pr close "$PR_NUMBER" \ + --repo "${{ github.repository }}" \ + --comment "[retarget-bot] Closing — another PR on the same head branch already targets \`staging\`. This PR is redundant. See issue #1884 for the rationale." + echo "outcome=closed-as-duplicate" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "::error::Retarget PATCH failed and was NOT a duplicate-base error:" + echo "$PATCH_OUTPUT" >&2 + exit 1 - name: Post explainer comment + if: steps.retarget.outputs.outcome == 'retargeted' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }}