Created
December 15, 2025 14:39
-
-
Save xHeaven/a7563255be823a29f1b72a72ccdf864d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Duplicate PR Detection | |
| on: | |
| pull_request: | |
| types: [opened] | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| detect-duplicates: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Ensure labels exist | |
| run: | | |
| gh label create "duplicate" --color "cfd3d7" --description "This PR duplicates another" 2>/dev/null || true | |
| gh label create "potential-duplicate" --color "FBCA04" --description "PR may duplicate another open PR" 2>/dev/null || true | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: anthropics/claude-code-action@v1 | |
| with: | |
| track_progress: true | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| prompt: | | |
| You are a duplicate PR detector. Analyze if PR #${{ github.event.pull_request.number }} duplicates any existing open PRs. | |
| **CRITICAL RULE:** Always flag/close the PR that was opened LATER. Never flag or close the PR that came in earlier. Use the `createdAt` timestamp to determine which PR is older. | |
| ## Step 1: Get the current PR's details including creation time | |
| ```bash | |
| gh pr view ${{ github.event.pull_request.number }} --json number,files,createdAt --jq '{number: .number, createdAt: .createdAt, files: [.files[].path]}' | |
| ``` | |
| ## Step 2: Get all other open PRs with creation times | |
| ```bash | |
| gh pr list --state open --json number,title,author,files,createdAt --jq '.[] | select(.number != ${{ github.event.pull_request.number }})' | |
| ``` | |
| ## Step 3: Filter to PRs with overlapping files | |
| From the list above, identify PRs that modify ANY of the same files as the current PR. | |
| If no PRs touch overlapping files, skip to Step 6 (no duplicates). | |
| ## Step 4: Deep comparison | |
| For each PR with overlapping files, get its diff: | |
| ```bash | |
| gh pr diff <PR_NUMBER> | |
| ``` | |
| Compare against the current PR's diff: | |
| ```bash | |
| gh pr diff ${{ github.event.pull_request.number }} | |
| ``` | |
| ## Step 5: Evaluate similarity | |
| **BE STRICT:** If a later PR solves the same problem as an earlier PR, it is a copycat regardless of implementation differences. The first PR has priority. | |
| **DUPLICATE (auto-close)** - ANY of these: | |
| - Changes are logically equivalent (same fix/feature) | |
| - Same problem being solved, even if implementation differs | |
| - The newer PR is clearly a copycat (solves what the older PR already solves) | |
| - No meaningful NEW functionality beyond what the older PR provides | |
| **POTENTIAL DUPLICATE (label + comment)** - If unsure, DEFAULT TO THIS: | |
| - Similar changes but uncertain if truly equivalent | |
| - Same problem, different approach (flag it - let maintainers decide) | |
| - One PR is a subset of the other | |
| - Any doubt about whether this is a copycat | |
| - Overlapping intent even if code looks different | |
| **NOT DUPLICATE (requires high confidence):** | |
| - Genuinely different features that happen to touch same files | |
| - The newer PR adds substantial NEW functionality not in the older PR | |
| - Completely unrelated logical changes despite file overlap | |
| ## Step 6: Take action | |
| **IMPORTANT:** Compare `createdAt` timestamps to determine which PR is newer. Always act on the NEWER PR (the one created later). | |
| **If DUPLICATE (high confidence):** | |
| If current PR #${{ github.event.pull_request.number }} is NEWER (created after the other PR): | |
| ```bash | |
| gh pr close ${{ github.event.pull_request.number }} --comment "Closing as duplicate of #<OTHER_PR>. | |
| **Reason:** <brief explanation of why this is a duplicate> | |
| The existing PR #<OTHER_PR> was opened earlier and addresses the same issue. Please review that PR instead, or reopen this one if you believe it offers a meaningfully different approach." | |
| gh pr edit ${{ github.event.pull_request.number }} --add-label "duplicate" | |
| ``` | |
| If current PR #${{ github.event.pull_request.number }} is OLDER (created before the other PR): | |
| ```bash | |
| gh pr close <OTHER_PR_NUMBER> --comment "Closing as duplicate of #${{ github.event.pull_request.number }}. | |
| **Reason:** <brief explanation of why this is a duplicate> | |
| PR #${{ github.event.pull_request.number }} was opened earlier and addresses the same issue. Please review that PR instead, or reopen this one if you believe it offers a meaningfully different approach." | |
| gh pr edit <OTHER_PR_NUMBER> --add-label "duplicate" | |
| ``` | |
| **If POTENTIAL DUPLICATE (medium/low confidence):** | |
| If current PR #${{ github.event.pull_request.number }} is NEWER: | |
| ```bash | |
| gh pr edit ${{ github.event.pull_request.number }} --add-label "potential-duplicate" | |
| gh pr comment ${{ github.event.pull_request.number }} --body "**Potential Duplicate Detected** | |
| This PR may duplicate #<OTHER_PR> (opened earlier). | |
| **Similarity:** <percentage>% | |
| **Reason:** <brief explanation> | |
| Please review the existing PR and clarify if this PR offers a different approach or additional changes." | |
| ``` | |
| If current PR #${{ github.event.pull_request.number }} is OLDER: | |
| ```bash | |
| gh pr edit <OTHER_PR_NUMBER> --add-label "potential-duplicate" | |
| gh pr comment <OTHER_PR_NUMBER> --body "**Potential Duplicate Detected** | |
| This PR may duplicate #${{ github.event.pull_request.number }} (opened earlier). | |
| **Similarity:** <percentage>% | |
| **Reason:** <brief explanation> | |
| Please review the existing PR and clarify if this PR offers a different approach or additional changes." | |
| ``` | |
| **If NO DUPLICATES:** | |
| No action needed. Do not comment. | |
| claude_args: | | |
| --allowedTools "Bash(gh pr diff:*),Bash(gh pr list:*),Bash(gh pr edit:*),Bash(gh pr comment:*),Bash(gh pr view:*),Bash(gh pr close:*)" | |
| --model opus | |
| github_token: ${{ secrets.GITHUB_TOKEN }} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment