Skip to content

Commit 102ada2

Browse files
ClaudeStensel8
andauthored
Enable automerge and automatic branch cleanup for automated PRs (#56)
* Initial plan * Add automerge and auto-delete branch workflows Agent-Logs-Url: https://github.com/Stensel8/Scripts/sessions/df6edc3b-7b62-4694-b1ab-8e1558816123 Co-authored-by: Stensel8 <102481635+Stensel8@users.noreply.github.com> * Add comprehensive automerge documentation Agent-Logs-Url: https://github.com/Stensel8/Scripts/sessions/df6edc3b-7b62-4694-b1ab-8e1558816123 Co-authored-by: Stensel8 <102481635+Stensel8@users.noreply.github.com> --------- Co-authored-by: anthropic-code-agent[bot] <242468646+Claude@users.noreply.github.com> Co-authored-by: Stensel8 <102481635+Stensel8@users.noreply.github.com>
1 parent f960b34 commit 102ada2

4 files changed

Lines changed: 515 additions & 0 deletions

File tree

.github/AUTOMERGE.md

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
# Automerge and Branch Cleanup Documentation
2+
3+
This document describes the automatic PR approval, merge, and branch cleanup workflows in the Scripts repository.
4+
5+
## Overview
6+
7+
The repository includes two workflows that automate the lifecycle of Pull Requests created by trusted automation:
8+
9+
1. **Automerge Workflow** (`.github/workflows/automerge.yml`) - Automatically approves and enables automerge for PRs
10+
2. **Auto Delete Branch Workflow** (`.github/workflows/auto-delete-branch.yml`) - Automatically deletes branches after PRs are merged
11+
12+
## Automerge Workflow
13+
14+
### Purpose
15+
16+
Automatically approves and enables automerge for Pull Requests created by trusted automation sources, reducing manual overhead while maintaining quality control.
17+
18+
### Triggers
19+
20+
- **Automatic**: When a PR is opened, reopened, or marked ready for review
21+
- **Manual**: Via workflow dispatch with a PR number input
22+
23+
### Eligible PRs
24+
25+
A PR is eligible for automerge if it meets ALL of the following criteria:
26+
27+
1. **Created by trusted automation**:
28+
- Author is `Claude` (Anthropic AI agent)
29+
- Author is `github-actions[bot]`
30+
- Branch name starts with `automated-update/`
31+
- Branch name starts with `claude/`
32+
33+
2. **Not a draft PR**: Draft PRs are skipped
34+
35+
3. **All checks passed**: All required status checks must pass
36+
37+
### Behavior
38+
39+
1. **Check Eligibility**: Verifies the PR meets automerge criteria
40+
2. **Approve PR**: Automatically approves the PR with a standardized message
41+
3. **Enable Automerge**: Uses GitHub's automerge feature with squash merge method
42+
4. **Error Handling**: Comments on the PR if automerge fails
43+
44+
### Configuration
45+
46+
The workflow uses the following merge method:
47+
- **Default**: `SQUASH` - Combines all commits into a single commit
48+
49+
To change the merge method, edit line 124 in `.github/workflows/automerge.yml`:
50+
```yaml
51+
mergeMethod: 'SQUASH' # Options: MERGE, SQUASH, REBASE
52+
```
53+
54+
### Permissions Required
55+
56+
- `contents: write` - To enable automerge
57+
- `pull-requests: write` - To approve PRs and add comments
58+
59+
## Auto Delete Branch Workflow
60+
61+
### Purpose
62+
63+
Automatically cleans up branches after their Pull Requests are merged, keeping the repository tidy and preventing branch accumulation.
64+
65+
### Triggers
66+
67+
- **Automatic**: When a PR is closed (only deletes if merged)
68+
- **Manual**: Via workflow dispatch with a branch name input
69+
70+
### Protected Branches
71+
72+
The following branches are NEVER deleted:
73+
- `main`
74+
- `master`
75+
- `development`
76+
- `staging`
77+
- `production`
78+
79+
### Behavior
80+
81+
1. **Verify Merge**: Confirms the PR was actually merged (not just closed)
82+
2. **Check Protection**: Ensures the branch is not in the protected list
83+
3. **Delete Branch**: Removes the branch from the repository
84+
4. **Add Comment**: Posts a comment on the PR confirming deletion
85+
5. **Error Handling**: Gracefully handles cases where the branch doesn't exist
86+
87+
### Fork Handling
88+
89+
Branches from forked repositories are NOT deleted, as the workflow only has permissions in the main repository.
90+
91+
### Permissions Required
92+
93+
- `contents: write` - To delete branches
94+
95+
## Integration with Existing Workflows
96+
97+
### Auto-Update Dependencies Workflow
98+
99+
The automerge workflow works seamlessly with the existing dependency update automation:
100+
101+
1. `check-dependencies.yml` creates an issue when a new version is detected
102+
2. `auto-update-dependencies.yml` creates a PR to update the dependency
103+
3. **NEW**: `automerge.yml` automatically approves and enables automerge
104+
4. GitHub merges the PR when all checks pass
105+
5. **NEW**: `auto-delete-branch.yml` deletes the branch after merge
106+
6. The original issue is automatically closed via `Closes #XX` in PR body
107+
108+
### Dependabot PRs
109+
110+
Dependabot PRs are also eligible for automerge if:
111+
- They pass all status checks
112+
- The workflow approves them automatically
113+
114+
To disable automerge for Dependabot PRs, you can modify the eligibility check in `automerge.yml`.
115+
116+
## Manual Intervention
117+
118+
### When Manual Review is Required
119+
120+
Certain PRs require manual review and will NOT be automatically merged:
121+
122+
1. **NGINX Updates**: Marked as draft until SHA256 checksums are manually verified
123+
2. **PRs from untrusted sources**: Only automation from trusted sources is auto-merged
124+
3. **Failed checks**: PRs with failing status checks must be fixed before merge
125+
126+
### Manual Workflow Triggers
127+
128+
Both workflows support manual triggering:
129+
130+
#### Enable Automerge for a Specific PR
131+
```bash
132+
gh workflow run automerge.yml -f pr_number=123
133+
```
134+
135+
#### Delete a Specific Branch
136+
```bash
137+
gh workflow run auto-delete-branch.yml -f branch_name=my-feature-branch
138+
```
139+
140+
## Monitoring and Troubleshooting
141+
142+
### View Workflow Runs
143+
144+
Check workflow execution in the GitHub Actions tab:
145+
```
146+
https://github.com/Stensel8/Scripts/actions
147+
```
148+
149+
### Common Issues
150+
151+
#### Automerge Not Enabled
152+
153+
**Possible causes**:
154+
1. Repository settings don't allow automerge
155+
2. Branch protection rules require additional approvals
156+
3. PR is from an untrusted source
157+
4. Status checks are failing
158+
159+
**Solution**: Check the workflow logs and verify repository settings.
160+
161+
#### Branch Not Deleted
162+
163+
**Possible causes**:
164+
1. PR was closed without merging
165+
2. Branch is in the protected list
166+
3. Branch is from a fork
167+
4. Branch was already deleted
168+
169+
**Solution**: These are expected behaviors. Check the workflow logs for details.
170+
171+
## Security Considerations
172+
173+
### Trusted Sources
174+
175+
The workflows only operate on PRs from:
176+
- `Claude` (Anthropic AI agent)
177+
- `github-actions[bot]`
178+
- Branches matching specific patterns
179+
180+
This prevents unauthorized users from triggering automerge on malicious PRs.
181+
182+
### Required Checks
183+
184+
Automerge only enables if all required status checks pass, ensuring:
185+
- Code validation (ShellCheck, PSScriptAnalyzer)
186+
- Security scanning
187+
- Any other configured checks
188+
189+
### Approval Trail
190+
191+
All auto-approved PRs include a comment indicating they were automatically approved, maintaining an audit trail.
192+
193+
## Disabling the Workflows
194+
195+
To temporarily disable automerge or branch cleanup:
196+
197+
1. **Via GitHub UI**: Go to Actions → Select workflow → Disable workflow
198+
2. **Via Code**: Add `if: false` to the job in the workflow file
199+
200+
Example:
201+
```yaml
202+
jobs:
203+
automerge:
204+
name: Enable Automerge
205+
runs-on: ubuntu-latest
206+
if: false # Temporarily disable
207+
```
208+
209+
## Future Enhancements
210+
211+
Potential improvements for consideration:
212+
213+
1. **Merge Method Selection**: Different merge methods based on PR type
214+
2. **Approval Requirements**: Configurable approval count before automerge
215+
3. **Label-Based Control**: Use labels to enable/disable automerge per PR
216+
4. **Notification System**: Slack/Discord notifications for automated merges
217+
5. **Rollback Mechanism**: Automatic revert if merged PR causes issues
218+
219+
## Related Documentation
220+
221+
- [Auto-Update Dependencies Workflow](../workflows/auto-update-dependencies.yml)
222+
- [Check Dependencies Workflow](../workflows/check-dependencies.yml)
223+
- [GitHub Automerge Documentation](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/automatically-merging-a-pull-request)
224+
- [GitHub Branch Protection Rules](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches)
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
name: Auto Delete Merged Branches
2+
3+
# This workflow automatically deletes branches after their PRs are merged
4+
5+
on:
6+
pull_request:
7+
types: [closed]
8+
workflow_dispatch:
9+
inputs:
10+
branch_name:
11+
description: 'Branch name to delete'
12+
required: true
13+
type: string
14+
15+
permissions:
16+
contents: write
17+
18+
jobs:
19+
delete-branch:
20+
name: Delete Merged Branch
21+
runs-on: ubuntu-latest
22+
if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
23+
steps:
24+
- name: Delete branch
25+
uses: actions/github-script@v8
26+
env:
27+
BRANCH_NAME: ${{ github.event.inputs.branch_name }}
28+
with:
29+
script: |
30+
let branchName;
31+
32+
if (context.payload.pull_request) {
33+
// Get branch name from PR
34+
branchName = context.payload.pull_request.head.ref;
35+
const prNumber = context.payload.pull_request.number;
36+
const merged = context.payload.pull_request.merged;
37+
38+
console.log(`PR #${prNumber} was closed`);
39+
console.log(`Branch: ${branchName}`);
40+
console.log(`Merged: ${merged}`);
41+
42+
if (!merged) {
43+
console.log('PR was closed without merging, skipping branch deletion');
44+
return;
45+
}
46+
} else {
47+
// Get branch name from workflow input
48+
branchName = process.env.BRANCH_NAME;
49+
console.log(`Manual branch deletion requested for: ${branchName}`);
50+
}
51+
52+
// Don't delete protected branches
53+
const protectedBranches = ['main', 'master', 'development', 'staging', 'production'];
54+
if (protectedBranches.includes(branchName)) {
55+
console.log(`Branch ${branchName} is protected, skipping deletion`);
56+
return;
57+
}
58+
59+
// Check if it's a head branch from a fork
60+
const isFork = context.payload.pull_request?.head.repo?.full_name !== context.payload.repository?.full_name;
61+
if (isFork) {
62+
console.log('Branch is from a fork, cannot delete from this repository');
63+
return;
64+
}
65+
66+
try {
67+
// Delete the branch
68+
await github.rest.git.deleteRef({
69+
owner: context.repo.owner,
70+
repo: context.repo.repo,
71+
ref: `heads/${branchName}`
72+
});
73+
74+
console.log(`✅ Successfully deleted branch: ${branchName}`);
75+
76+
// Add comment to the PR if available
77+
if (context.payload.pull_request) {
78+
await github.rest.issues.createComment({
79+
owner: context.repo.owner,
80+
repo: context.repo.repo,
81+
issue_number: context.payload.pull_request.number,
82+
body: `🗑️ Branch \`${branchName}\` has been automatically deleted after merge.`
83+
});
84+
}
85+
86+
} catch (error) {
87+
console.error(`Error deleting branch: ${error.message}`);
88+
89+
// Don't fail the workflow if branch doesn't exist or is already deleted
90+
if (error.status === 404) {
91+
console.log('Branch does not exist or was already deleted');
92+
} else if (error.status === 422) {
93+
console.log('Branch cannot be deleted (may be default branch)');
94+
} else {
95+
throw error;
96+
}
97+
}

0 commit comments

Comments
 (0)