From 7df8510bde1ab0ac3a28fe23c0c18fad7c8a112e Mon Sep 17 00:00:00 2001 From: BukeLy Date: Mon, 2 Mar 2026 17:23:33 +0800 Subject: [PATCH] Simplify scripts: unify bot detection, remove redundant API calls and TOCTOU checks --- .claude/commands/dedupe.md | 2 +- README.md | 65 ----------------------------- scripts/autoclose-labeled-issues.js | 17 +++----- scripts/comment-on-duplicates.sh | 26 ++---------- 4 files changed, 11 insertions(+), 99 deletions(-) diff --git a/.claude/commands/dedupe.md b/.claude/commands/dedupe.md index d649bb1..8a07908 100644 --- a/.claude/commands/dedupe.md +++ b/.claude/commands/dedupe.md @@ -41,7 +41,7 @@ Launch 5 parallel searches using different keyword strategies to maximize covera For each search, use: ``` -gh search issues "" --repo $REPOSITORY --limit 20 +gh search issues " state:open" --repo $REPOSITORY --limit 20 ``` ### 4. Analyze candidates diff --git a/README.md b/README.md index 131cded..7180efd 100644 --- a/README.md +++ b/README.md @@ -267,69 +267,4 @@ Leave us a star ๐ŸŒŸ if you like our project. Thank you! --- -## ๐Ÿค– GitHub Automation - -This repository uses automated GitHub Actions workflows to keep the issue tracker tidy. - -### Overview - -| Workflow | Trigger | Purpose | -|---|---|---| -| `issue-dedupe.yml` | Issue opened ยท `workflow_dispatch` | Detects duplicate issues using Claude and labels them | -| `backfill-dedupe.yml` | `workflow_dispatch` | Runs duplicate detection over historical issues | -| `autoclose-labeled-issues.yml` | Daily schedule ยท `workflow_dispatch` | Closes issues labelled `autoclose` after N days of inactivity | -| `remove-autoclose-label.yml` | Issue comment created | Removes the `autoclose` label when a human posts a new comment | - -### Required Secrets - -Add the following secret to the repository (**Settings โ†’ Secrets and variables โ†’ Actions**): - -| Secret | Description | -|---|---| -| `AUTHROPIC_API_KEY` | Your Anthropic API key (used by `anthropics/claude-code-action`) | - -`GITHUB_TOKEN` is provided automatically by GitHub Actions and does not need to be added manually. - -### Labels - -The workflows create the following labels automatically if they do not exist: - -| Label | Description | -|---|---| -| `duplicate` | Marks issues identified as duplicates | -| `autoclose` | Marks issues that will be automatically closed after inactivity | - -### Running the Backfill - -To scan historical issues for duplicates, trigger the **Backfill Duplicate Detection** workflow manually from the **Actions** tab: - -- **`days_back`** (default `30`) โ€” how many days into the past to scan -- **`dry_run`** (default `false`) โ€” set to `true` to preview results without modifying issues - -``` -Actions โ†’ Backfill Duplicate Detection โ†’ Run workflow -``` - -### Changing the Inactivity Threshold - -The default inactivity period before an `autoclose`-labelled issue is closed is **7 days**. - -To change it for a one-off run, trigger **Auto-close Inactive Labeled Issues** with the `inactivity_days` input. - -To change the default permanently, edit the `INACTIVITY_DAYS` env variable default in `.github/workflows/autoclose-labeled-issues.yml`: - -```yaml -INACTIVITY_DAYS: ${{ inputs.inactivity_days || '7' }} # โ† change '7' here -``` - -### How Duplicate Detection Works - -1. When a new issue is opened, keywords from the title are used to search for the top 10 most relevant existing open issues via the GitHub Search API. -2. The issue title, body, and candidate list are passed to **Claude** (`anthropics/claude-code-action`) with a structured prompt. -3. Claude posts a comment on the issue (if it is highly confident it is a duplicate), including links to the original issue(s) and a brief explanation. -4. A follow-up step reads the comment, extracts the machine-readable result, and applies the `duplicate` and `autoclose` labels. -5. If Claude is not confident, no comment or labels are applied. - ---- - ยฉ 2025 [Vectify AI](https://vectify.ai) diff --git a/scripts/autoclose-labeled-issues.js b/scripts/autoclose-labeled-issues.js index e3c07f8..615d146 100644 --- a/scripts/autoclose-labeled-issues.js +++ b/scripts/autoclose-labeled-issues.js @@ -92,13 +92,16 @@ async function fetchDuplicateIssues() { return issues.filter(i => new Date(i.created_at) < cutoff); } +function isBot(user) { + return user.type === 'Bot' || user.login.endsWith('[bot]') || user.login === 'github-actions'; +} + /** * Finds the bot's duplicate comment on an issue (contains "possible duplicate"). */ function findDuplicateComment(comments) { return comments.find(c => - (c.user.type === 'Bot' || c.user.login === 'github-actions[bot]') && - c.body.includes('possible duplicate') + isBot(c.user) && c.body.includes('possible duplicate') ); } @@ -107,9 +110,7 @@ function findDuplicateComment(comments) { */ function hasHumanCommentAfter(comments, afterDate) { return comments.some(c => { - if (c.user.type === 'Bot' || c.user.login.endsWith('[bot]') || c.user.login === 'github-actions') { - return false; - } + if (isBot(c.user)) return false; return new Date(c.created_at) > afterDate; }); } @@ -145,12 +146,6 @@ async function closeAsDuplicate(issueNumber) { `/repos/${REPO_OWNER}/${REPO_NAME}/issues/${issueNumber}`, { state: 'closed', state_reason: 'completed' } ); - - await githubRequest( - 'POST', - `/repos/${REPO_OWNER}/${REPO_NAME}/issues/${issueNumber}/labels`, - { labels: ['duplicate'] } - ); } async function processIssue(issue) { diff --git a/scripts/comment-on-duplicates.sh b/scripts/comment-on-duplicates.sh index 6f3ff36..05c93d9 100755 --- a/scripts/comment-on-duplicates.sh +++ b/scripts/comment-on-duplicates.sh @@ -66,32 +66,16 @@ if [ ${#DUPLICATES[@]} -gt 3 ]; then DUPLICATES=("${DUPLICATES[@]:0:3}") fi -# Validate that the base issue exists and is open -if ! gh issue view "$BASE_ISSUE" --repo "$REPO" --json state -q '.state' | grep -qi 'open'; then - echo "Error: Issue #$BASE_ISSUE is not open or does not exist" >&2 - exit 1 -fi - # Build the duplicate links list -LINKS="" COUNT=0 +LINKS="" for dup in "${DUPLICATES[@]}"; do - # Validate duplicate issue exists - if gh issue view "$dup" --repo "$REPO" --json number -q '.number' > /dev/null 2>&1; then - COUNT=$((COUNT + 1)) - LINKS="${LINKS}${COUNT}. https://github.com/${REPO}/issues/${dup} + COUNT=$((COUNT + 1)) + LINKS="${LINKS}${COUNT}. https://github.com/${REPO}/issues/${dup} " - else - echo "Warning: Issue #$dup does not exist, skipping" >&2 - fi done -if [ "$COUNT" -eq 0 ]; then - echo "Error: None of the specified duplicate issues exist" >&2 - exit 1 -fi - -# Build and post the comment +# Build and post the comment โ€” if the issue is closed or doesn't exist, gh will error out COMMENT="Found ${COUNT} possible duplicate issue(s): ${LINKS} @@ -99,8 +83,6 @@ This issue will be automatically closed as a duplicate in 3 days. - To prevent auto-closure, add a comment or react with :thumbsdown: on this comment." gh issue comment "$BASE_ISSUE" --repo "$REPO" --body "$COMMENT" - -# Add the duplicate label gh issue edit "$BASE_ISSUE" --repo "$REPO" --add-label "duplicate" echo "Posted duplicate comment on issue #$BASE_ISSUE with $COUNT potential duplicate(s)"