@@ -6,6 +6,12 @@ Dockerized tool to scan GitHub organizations for repository health metrics. Opti
66
77- ** Orphaned Branch Detection** : Identifies branches without open PRs (includes merged/closed PR branches)
88- ** Closed/Merged PR Branch Tracking** : Identifies branches that still exist after their PRs were closed or merged
9+ - ** Automated Cleanup** : Delete orphaned branches and close stale PRs with dedicated commands
10+ - ** Auto-Delete Mode** : Automatically delete branches with closed/merged PRs via environment variable
11+ - ** Smart Branch Protection** : Automatically excludes standard branches (main, staging, dev, prod, etc.)
12+ - ** Archived Repository Handling** : Automatically skips archived repositories from analysis
13+ - ** API Error Resilience** : Automatic retry with backoff for transient 403 errors
14+ - ** Duplicate Branch Handling** : Deduplicates branches with multiple closed/merged PRs
915- ** Old PR Analysis** : Configurable threshold for identifying stale pull requests
1016- ** Pretty-Print Table Format** : Human-friendly table output for stale PRs and orphaned branches
1117- ** Discord Integration** : Automated report uploads to Discord via GitHub Actions
@@ -26,6 +32,7 @@ Dockerized tool to scan GitHub organizations for repository health metrics. Opti
2632 GITHUB_ORG=your-org-name
2733 GITHUB_TOKEN=ghp_your_token_here
2834 OLD_PR_THRESHOLD_DAYS=30
35+ DELETE_ORPHANED_BRANCHES=false
2936 ```
3037
3138### Creating GitHub Token with Minimal Permissions
@@ -67,6 +74,8 @@ To create a GitHub Personal Access Token with minimal required permissions:
6774 ``` bash
6875 make scan # Build and run (JSON output)
6976 make pretty # Build and run with pretty table output
77+ make dbr # Delete all orphaned branches (requires confirmation)
78+ make dpr # Close all stale PRs (requires confirmation)
7079 make fresh # Force rebuild and run
7180 make build # Build only
7281 make clean # Clean up
@@ -119,19 +128,30 @@ make fresh
119128| ` GITHUB_TOKEN ` | Recommended | - | GitHub personal access token |
120129| ` GITHUB_REPO ` | No | - | Specific repository name (scans only this repo instead of entire org) |
121130| ` OLD_PR_THRESHOLD_DAYS ` | No | 30 | Days to consider PRs as "old" |
131+ | ` DELETE_ORPHANED_BRANCHES ` | No | false | Auto-delete branches with closed/merged PRs during scan |
132+
133+ ** Note:** The scanner automatically excludes:
134+ - Archived repositories (read-only)
135+ - Inactive repositories (no activity in last year)
136+ - Standard branches: ` main ` , ` master ` , ` develop ` , ` development ` , ` dev ` , ` staging ` , ` stage ` , ` prod ` , ` production ` , ` test ` , ` testing ` , ` qa ` , ` uat ` , ` preprod ` , ` pre-prod ` , ` release ` , ` hotfix ` , ` stable `
122137
123138### GitHub Token
124139
125140- ** Without token** : 60 requests/hour (rate limited)
126141- ** With token** : 5000 requests/hour
127- - ** Permissions needed** : ` repo ` (for private repos) or ` public_repo ` (for public repos only)
142+ - ** Permissions needed** :
143+ - ` repo ` - Full control of private repositories (required for deletion operations)
144+ - ` read:org ` - Read organization membership (required for org scanning)
145+ - For read-only scanning of public repos: ` public_repo ` + ` read:org `
128146
129147## Makefile Commands
130148
131149| Command | Description |
132150| ---------| -------------|
133151| ` make scan ` | Build and run scanner (JSON output) |
134152| ` make pretty ` | Build and run with pretty table output |
153+ | ` make dbr ` | ** Delete orphaned branches** (requires confirmation) |
154+ | ` make dpr ` | ** Close stale PRs** (requires confirmation) |
135155| ` make build ` | Build Docker image |
136156| ` make rebuild ` | Force rebuild (no cache) |
137157| ` make run ` | Run existing image |
@@ -240,6 +260,55 @@ The Markdown file can be:
240260- Converted to PDF or other formats
241261- Included in documentation or reports
242262
263+ ## Cleanup Operations
264+
265+ ### Delete Orphaned Branches (` make dbr ` )
266+
267+ Deletes all branches that don't have open PRs (excluding default and protected branches):
268+
269+ ``` bash
270+ make dbr
271+ ```
272+
273+ ** What it does:**
274+ - Scans all repositories for orphaned branches
275+ - Excludes default branches (main, master, etc.)
276+ - Excludes protected branches
277+ - Prompts for confirmation before deletion
278+ - Shows real-time deletion status for each branch
279+
280+ ** ⚠️ Warning:** This is a destructive operation. Deleted branches cannot be recovered unless you have local copies.
281+
282+ ### Close Stale PRs (` make dpr ` )
283+
284+ Closes all pull requests that exceed the configured threshold:
285+
286+ ``` bash
287+ make dpr
288+ ```
289+
290+ ** What it does:**
291+ - Identifies PRs older than ` OLD_PR_THRESHOLD_DAYS `
292+ - Prompts for confirmation before closing
293+ - Closes PRs with status update
294+ - Shows real-time closure status for each PR
295+
296+ ** Note:** Closed PRs can be reopened if needed.
297+
298+ ### Auto-Delete Closed/Merged PR Branches
299+
300+ Set the ` DELETE_ORPHANED_BRANCHES ` environment variable to automatically delete branches with closed or merged PRs during scanning:
301+
302+ ``` bash
303+ DELETE_ORPHANED_BRANCHES=true make scan
304+ ```
305+
306+ ** What it does:**
307+ - Automatically deletes branches whose PRs have been closed or merged
308+ - Runs during normal scan operation
309+ - No confirmation prompt (use with caution)
310+ - Useful for automated cleanup in CI/CD pipelines
311+
243312### Closed/Merged PR Branches Section
244313
245314The report now includes a dedicated section for branches that still exist even though their PRs have been closed or merged:
@@ -271,6 +340,36 @@ The workflow automatically uploads the generated Markdown report to Discord:
271340- Includes organization name in the message
272341- Webhook URL is configured in the workflow file
273342
343+ ## Command-Line Options
344+
345+ The scanner supports the following command-line flags:
346+
347+ ``` bash
348+ python scanner.py [OPTIONS]
349+
350+ Options:
351+ -p, --pretty Output human-friendly table format
352+ --delete-branches Delete all orphaned branches
353+ --delete-prs Close all stale PRs exceeding threshold
354+ -h, --help Show help message
355+ ```
356+
357+ ** Examples:**
358+
359+ ``` bash
360+ # Generate pretty report
361+ python scanner.py --pretty
362+
363+ # Delete orphaned branches (with warning)
364+ python scanner.py --delete-branches
365+
366+ # Close stale PRs (with warning)
367+ python scanner.py --delete-prs
368+
369+ # Combine operations
370+ python scanner.py --pretty --delete-branches
371+ ```
372+
274373## Security
275374
276375- ** Docker isolation** : Runs in isolated container environment
@@ -279,14 +378,46 @@ The workflow automatically uploads the generated Markdown report to Discord:
279378- ** Environment variables** : Secure credential management
280379- ** Local reports** : Reports saved to mounted volume only
281380- ** No data persistence** : No data stored in container
381+ - ** Deletion safeguards** : Confirmation prompts for destructive operations
382+ - ** Protected branches** : Never deletes default or protected branches
282383
283384## Performance
284385
285386- ** Optimized API calls** : Reduced API requests for better performance
286387- ** Pagination handling** : Automatic handling of large datasets
287388- ** Progress indicators** : Real-time feedback for long-running scans
288- - ** Error handling** : Graceful handling of API failures
389+ - ** Error handling** : Graceful handling of API failures with automatic retry
390+ - ** 403 Error Retry** : Automatic 5-second delay and retry for transient access errors
289391- ** Rate limit aware** : Respects GitHub API rate limits
392+ - ** Batch operations** : Efficient deletion of multiple branches/PRs
393+ - ** Smart filtering** : Early exclusion of archived and inactive repositories
394+
395+ ## Best Practices
396+
397+ ### Before Running Cleanup Operations
398+
399+ 1 . ** Run a scan first** : Always run ` make scan ` or ` make pretty ` to see what will be affected
400+ 2 . ** Review the report** : Check the generated report to understand what will be deleted
401+ 3 . ** Backup important branches** : Ensure you have local copies of any branches you might need
402+ 4 . ** Test on a single repo** : Use ` GITHUB_REPO=test-repo make dbr ` to test on one repository first
403+ 5 . ** Use in CI/CD carefully** : Only enable ` DELETE_ORPHANED_BRANCHES=true ` if you're confident in the logic
404+
405+ ### Recommended Workflow
406+
407+ ``` bash
408+ # 1. Scan and review
409+ make pretty
410+
411+ # 2. Review the Markdown report
412+ cat reports/scan_* .md
413+
414+ # 3. If satisfied, run cleanup
415+ make dbr # Delete orphaned branches
416+ make dpr # Close stale PRs
417+
418+ # 4. Verify results
419+ make pretty
420+ ```
290421
291422## Troubleshooting
292423
@@ -304,3 +435,19 @@ The workflow automatically uploads the generated Markdown report to Discord:
304435
305436- Ensure your GitHub token has access to all repositories in the organization
306437- Private repositories require ` repo ` scope, public repositories need ` public_repo `
438+
439+ ### Deletion Failures
440+
441+ - Ensure your token has ` repo ` scope (not just ` public_repo ` )
442+ - Protected branches cannot be deleted (this is intentional)
443+ - Standard branches (main, staging, dev, prod, etc.) are automatically excluded
444+ - Archived repositories are skipped entirely (read-only)
445+ - Check that branches still exist before attempting deletion
446+ - Verify organization permissions allow branch deletion
447+
448+ ### 403 Errors During Scan
449+
450+ - The scanner automatically retries 403 errors after a 5-second delay
451+ - Transient 403 errors are common during rapid API requests and are handled automatically
452+ - Persistent 403 errors are silently skipped (usually archived repos or permission issues)
453+ - Check rate limit status if you see many 403 errors: ` curl -H "Authorization: token YOUR_TOKEN" https://api.github.com/rate_limit `
0 commit comments