# Scripts ## cleanup-duplicate-prs.sh Automated detection and cleanup of duplicate open PRs. ### Purpose This script identifies PRs that are duplicates (same issue number or very similar titles) and closes the older ones. It's designed to help maintain a clean PR board and prevent confusion from duplicate work. ### Features - **Issue-based grouping**: Groups PRs by issue number extracted from titles - **Date-based selection**: Keeps the newest PR, closes older duplicates - **Dry-run mode**: Shows what would be done without making changes - **Stale PR detection**: Identifies PRs older than 30 days with no activity - **Explanatory comments**: Adds comments when closing PRs to explain why ### Usage ```bash # Dry run (default) - shows what would be done ./scripts/cleanup-duplicate-prs.sh # Actually close duplicates ./scripts/cleanup-duplicate-prs.sh --close # Set environment variables export GITEA_TOKEN="your_token_here" export REPO="Timmy_Foundation/the-nexus" export GITEA_URL="https://forge.alexanderwhitestone.com" ``` ### Configuration The script uses the following environment variables: | Variable | Default | Description | |----------|---------|-------------| | `GITEA_TOKEN` | (required) | Gitea API token with repo access | | `GITEA_URL` | `https://forge.alexanderwhitestone.com` | Gitea instance URL | | `REPO` | `Timmy_Foundation/the-nexus` | Repository in `owner/repo` format | | `DRY_RUN` | `true` | Set to `false` to actually close PRs | ### How It Works 1. **Fetch open PRs**: Gets all open PRs from the repository 2. **Extract issue numbers**: Parses issue numbers from PR titles (e.g., `#123`) 3. **Group by issue**: Groups PRs that address the same issue 4. **Identify duplicates**: Finds issues with multiple open PRs 5. **Select newest**: For each duplicate group, keeps the newest PR 6. **Close older PRs**: Closes older duplicates with explanatory comments 7. **Check for stale PRs**: Identifies PRs older than 30 days ### Example Output ``` [2026-04-14T00:57:05Z] Checking open PRs for Timmy_Foundation/the-nexus (dry_run: true) [2026-04-14T00:57:17Z] Found 14 open PRs [2026-04-14T00:57:17Z] Issue #1338 has 2 open PRs [2026-04-14T00:57:17Z] Keeping PR #1392 (newest) [2026-04-14T00:57:17Z] DRY RUN: Would close PR #1388 [2026-04-14T00:57:17Z] Issue #1354 has 2 open PRs [2026-04-14T00:57:17Z] Keeping PR #1391 (newest) [2026-04-14T00:57:17Z] DRY RUN: Would close PR #1384 [2026-04-14T00:57:17Z] Cleanup complete: [2026-04-14T00:57:17Z] Duplicate issue groups found: 4 [2026-04-14T00:57:17Z] PRs closed: 0 [2026-04-14T00:57:17Z] Dry run: true ``` ### Safety Features - **Dry-run by default**: Won't close PRs unless explicitly told to - **Explanatory comments**: Adds comments before closing to explain why - **Newest PR preserved**: Always keeps the most recent PR for each issue - **No force deletion**: Only closes PRs, doesn't delete branches ### Integration This script can be integrated into CI/CD pipelines or run manually as part of regular maintenance. It's designed to be run weekly to keep the PR board clean. ### Related Issues - **Issue #1128**: Forge Cleanup — PRs Closed, Milestones Deduplicated, Policy Issues Filed - **Issue #1127**: Evening triage pass (predecessor to #1128)