From 86811cafa0763f249d4cf0535d04c0d12815fb85 Mon Sep 17 00:00:00 2001 From: ancplua Date: Sat, 4 Jul 2026 08:28:04 +0200 Subject: [PATCH] fix(auto-merge): delete head branch after app-merged PRs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit delete_branch_on_merge fires for user merges but not for merges landed by the github-actions app via native auto-merge — observed fleet-wide (qyl claude/ branches from #452-#456 and #477-#479 all survived their merges; the user-merged #476 was deleted). Add a delete-merged-branch job on the closed event, scoped to same-repo claude/ and copilot/ heads, with the ref passed via env so pull_request_target cannot be shell-injected. Co-Authored-By: Claude Fable 5 --- .github/workflows/auto-merge.yml | 29 ++++++++++++++++++++++++++++- templates/auto-merge.yml | 29 ++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 29b908d..b17d756 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -13,6 +13,14 @@ # auto-merge waits for. enforce-repo-settings.yml flips allow_auto_merge # automatically across the fleet. # +# delete-merged-branch: repo-level delete_branch_on_merge reliably fires for +# user-initiated merges but not for merges landed by the github-actions app +# via native auto-merge (observed fleet-wide, e.g. qyl #452–#456, #477–#479 +# survived; user-merged #476 was deleted). This job closes that gap for the +# automation prefixes. HEAD_REF is passed via env, never interpolated into +# the script, so a crafted branch name cannot inject into the shell under +# pull_request_target's write token. +# # Branch-prefix policy: # - claude/ — Claude Code agents # - copilot/ — GitHub Copilot agents when enabled @@ -21,7 +29,7 @@ name: Auto-merge on: pull_request_target: - types: [opened, synchronize, reopened, ready_for_review] + types: [opened, synchronize, reopened, ready_for_review, closed] permissions: contents: write @@ -31,6 +39,7 @@ jobs: enable-auto-merge: runs-on: ubuntu-latest if: | + github.event.action != 'closed' && github.event.pull_request.draft == false && ( startsWith(github.event.pull_request.head.ref, 'claude/') || startsWith(github.event.pull_request.head.ref, 'copilot/') @@ -40,3 +49,21 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh pr merge ${{ github.event.pull_request.number }} --auto --squash --repo ${{ github.repository }} + + delete-merged-branch: + runs-on: ubuntu-latest + if: | + github.event.action == 'closed' && + github.event.pull_request.merged == true && + github.event.pull_request.head.repo.full_name == github.repository && ( + startsWith(github.event.pull_request.head.ref, 'claude/') || + startsWith(github.event.pull_request.head.ref, 'copilot/') + ) + steps: + - name: Delete merged head branch + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HEAD_REF: ${{ github.event.pull_request.head.ref }} + run: | + gh api -X DELETE "repos/${{ github.repository }}/git/refs/heads/$HEAD_REF" \ + || echo "head branch already deleted" diff --git a/templates/auto-merge.yml b/templates/auto-merge.yml index 29b908d..b17d756 100644 --- a/templates/auto-merge.yml +++ b/templates/auto-merge.yml @@ -13,6 +13,14 @@ # auto-merge waits for. enforce-repo-settings.yml flips allow_auto_merge # automatically across the fleet. # +# delete-merged-branch: repo-level delete_branch_on_merge reliably fires for +# user-initiated merges but not for merges landed by the github-actions app +# via native auto-merge (observed fleet-wide, e.g. qyl #452–#456, #477–#479 +# survived; user-merged #476 was deleted). This job closes that gap for the +# automation prefixes. HEAD_REF is passed via env, never interpolated into +# the script, so a crafted branch name cannot inject into the shell under +# pull_request_target's write token. +# # Branch-prefix policy: # - claude/ — Claude Code agents # - copilot/ — GitHub Copilot agents when enabled @@ -21,7 +29,7 @@ name: Auto-merge on: pull_request_target: - types: [opened, synchronize, reopened, ready_for_review] + types: [opened, synchronize, reopened, ready_for_review, closed] permissions: contents: write @@ -31,6 +39,7 @@ jobs: enable-auto-merge: runs-on: ubuntu-latest if: | + github.event.action != 'closed' && github.event.pull_request.draft == false && ( startsWith(github.event.pull_request.head.ref, 'claude/') || startsWith(github.event.pull_request.head.ref, 'copilot/') @@ -40,3 +49,21 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh pr merge ${{ github.event.pull_request.number }} --auto --squash --repo ${{ github.repository }} + + delete-merged-branch: + runs-on: ubuntu-latest + if: | + github.event.action == 'closed' && + github.event.pull_request.merged == true && + github.event.pull_request.head.repo.full_name == github.repository && ( + startsWith(github.event.pull_request.head.ref, 'claude/') || + startsWith(github.event.pull_request.head.ref, 'copilot/') + ) + steps: + - name: Delete merged head branch + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HEAD_REF: ${{ github.event.pull_request.head.ref }} + run: | + gh api -X DELETE "repos/${{ github.repository }}/git/refs/heads/$HEAD_REF" \ + || echo "head branch already deleted"