Repository navigation
ci: delete a PR's head branch after it merges, with an allowlist - #15
Conversation
GitHub has no account-wide setting for this, the per-repo toggle deletes every merged head branch, and Free-plan private repos cannot protect long-lived branches such as develop. This self-contained workflow runs on merged same-repo PRs and deletes the head branch unless it is the default branch, one of main/master/develop/staging/test/gh-pages/ deploy-*/release/*, or the base of another open PR. A branch that is already gone counts as success. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rYJxu978iUSGFZ1UuqTsi
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 57 minutes. View limit detailsLimit details: You’ve used the included review currently available. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🧪 Runtime gate✅ Runtime crawl: no runtime errors1 page(s) opened in a real browser (desktop + phone), safe controls exercised, forms tried with dummy data, links followed client-side, missing-route probe run. 38s. Coverage: 1/1 routes · 0/0 controls operated · 0/0 forms submitted · 29.3% of the app's own JavaScript executed Against the default branch: routes ±0, controls ±0, JS ±0 pts. No visual changes against the last default-branch run. Pages visited
AI explorer not run: no major/framework signal in this PR. Add the Screenshots, diffs and the app log: runtime-gate artifact. |
rishitank
left a comment
There was a problem hiding this comment.
Self-review by Claude. CodeRabbit is rate-limited on this repo (free OSS review limit), so it gave no line-by-line review.
What I checked (the one changed file, .github/workflows/branch-cleanup.yml, read in full):
- Injection. No
${{ }}insiderun:. The head ref, default branch, repo and token reach the shell only throughenv:, and every expansion is quoted. The ref is URL-encoded withjq @uribefore it goes into the API path. - Permissions. The workflow default is
{}. The job gets onlycontents: write(to delete the ref) andpull-requests: read(forgh pr list). No secrets beyondgithub.token. - Scope. The job runs only on merged PRs whose head is in this repository, so a fork's branch can never be targeted.
- Fail-safe.
set -euo pipefailmeans any API error in the open-PR check fails the job and keeps the branch. Only "Reference does not exist" (422) or a 404 is treated as already deleted. A 403 fails red, so a permission problem is never silent. - Allowlist. Covers the default branch,
main,master,develop,staging,test,gh-pages,deploy-*andrelease/*, plus any branch that an open PR uses as its base. - Lint. actionlint and shellcheck are clean locally and in CI (the
actionlintcheck is green). The script was also run against a stubghfor every branch above.
Fixed: nothing needed.
Left for Rishi: like GitHub's own auto-delete, this doesn't check whether commits were pushed to the branch after the merge. It deletes the ref regardless, though the commits stay reachable through refs/pull/<n>/head.
Why
Merged PR branches pile up. GitHub has no account-wide setting to delete them: "Automatically delete head branches" is a per-repository toggle, and it deletes every merged head branch with no exceptions. Private repositories on the Free plan can't protect branches, so that toggle could delete a long-lived branch such as
developthe first time it is merged as a PR head.This workflow does the cleanup with an explicit allowlist instead.
What changed
.github/workflows/branch-cleanup.yml. Self-contained, no reusable workflow (rishitank/.githubmain is ruleset-blocked, so a shared copy can't land yet).pull_requestclosed. The one job runs only when the PR was merged and its head is in this repository (never a fork's branch).::notice::, when it is the default branch, or one ofmain,master,develop,staging,test,gh-pages,deploy-*,release/*, or when any open PR still uses it as its base.gh api -X DELETE repos/$REPO/git/refs/heads/<ref>, the ref URL-encoded withjq @uri. "Reference does not exist" (422) or a 404 counts as success, since the branch is already gone.{}; the job getscontents: write(delete the ref) andpull-requests: read(the open-PR check).timeout-minutes: 2.${{ }}inrun:. Every event value reaches the shell throughenv:and is quoted.ghfor the default branch, each allowlisted name, a branch with open child PRs, a ref containing/, a space and#, an already-deleted ref (422 and 404), and a 403, which fails the job.Proof on this repo
This repo is the live test: merging this very PR should delete
ci/branch-cleanup(a ref with a/, so the URL-encoding is exercised too).🤖 Generated with Claude Code
https://claude.ai/code/session_012rYJxu978iUSGFZ1UuqTsi