Skip to content

Commit f867987

Browse files
authored
Merge pull request #6 from devonartis/fix/branch-cleanup-guard
Add branch cleanup guard — delete only after post-merge CI passes
2 parents 0c98681 + 8fb4a7f commit f867987

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: Branch Cleanup
2+
3+
# Only runs after CI passes on a push to develop or main.
4+
# Deletes the source branch of the merged PR — but ONLY if post-merge CI succeeded.
5+
# If CI fails after merge, the branch stays so you can fix and re-merge.
6+
7+
on:
8+
workflow_run:
9+
workflows: ["CI"]
10+
types: [completed]
11+
branches: [develop, main]
12+
13+
permissions:
14+
contents: write
15+
pull-requests: read
16+
17+
jobs:
18+
cleanup:
19+
name: Delete merged branch
20+
runs-on: ubuntu-latest
21+
if: >-
22+
github.event.workflow_run.conclusion == 'success' &&
23+
github.event.workflow_run.event == 'push'
24+
steps:
25+
- name: Find merged PR and delete source branch
26+
uses: actions/github-script@v7
27+
with:
28+
script: |
29+
const sha = context.payload.workflow_run.head_sha;
30+
const repo = context.repo;
31+
32+
// Find PRs that were merged with this commit
33+
const { data: prs } = await github.rest.pulls.list({
34+
...repo,
35+
state: 'closed',
36+
sort: 'updated',
37+
direction: 'desc',
38+
per_page: 10
39+
});
40+
41+
const merged = prs.filter(pr =>
42+
pr.merged_at && pr.merge_commit_sha === sha
43+
);
44+
45+
if (merged.length === 0) {
46+
console.log('No merged PR found for this push — nothing to clean up.');
47+
return;
48+
}
49+
50+
for (const pr of merged) {
51+
const branch = pr.head.ref;
52+
const base = pr.base.ref;
53+
54+
// Never delete develop or main
55+
if (['develop', 'main', 'master'].includes(branch)) {
56+
console.log(`Skipping protected branch: ${branch}`);
57+
continue;
58+
}
59+
60+
// Only delete if the branch is in this repo (not a fork)
61+
if (pr.head.repo.full_name !== repo.owner + '/' + repo.repo) {
62+
console.log(`Skipping fork branch: ${pr.head.repo.full_name}/${branch}`);
63+
continue;
64+
}
65+
66+
try {
67+
await github.rest.git.deleteRef({
68+
...repo,
69+
ref: `heads/${branch}`
70+
});
71+
console.log(`Deleted branch ${branch} (PR #${pr.number} merged to ${base}, post-merge CI passed)`);
72+
} catch (e) {
73+
if (e.status === 422) {
74+
console.log(`Branch ${branch} already deleted`);
75+
} else {
76+
throw e;
77+
}
78+
}
79+
}
80+
81+
- name: Report if CI failed (branch preserved)
82+
if: github.event.workflow_run.conclusion == 'failure'
83+
run: |
84+
echo "⚠️ Post-merge CI FAILED — source branch NOT deleted."
85+
echo "Fix the issue, then the branch will be cleaned up on the next successful run."

0 commit comments

Comments
 (0)