From 1de4448425bab264ac935efd2e660dfe669138a7 Mon Sep 17 00:00:00 2001 From: robobun Date: Wed, 29 Oct 2025 15:41:44 -0700 Subject: [PATCH] =?UTF-8?q?Fix=20duplicate=20issue=20bot=20to=20respect=20?= =?UTF-8?q?=F0=9F=91=8E=20reactions=20and=20not=20re-close=20reopened=20is?= =?UTF-8?q?sues=20(#24203)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixed two bugs in the auto-close-duplicates bot: - **Respect 👎 reactions from ANY user**: Previously only the issue author's thumbs down would prevent auto-closing. Now any user can indicate disagreement with the duplicate detection. - **Don't re-close reopened issues**: The bot now checks if an issue was previously reopened and skips auto-closing to respect user intent. ## Changes 1. Modified `fetchAllReactions` call to check all reactions, not just the author's 2. Changed `authorThumbsDown` logic to `hasThumbsDown` (checks any user's reaction) 3. Added `wasIssueReopened()` function to query issue events timeline 4. Added check to skip issues with "reopened" events in their history ## Test plan - [ ] Manually test the script doesn't close issues with 👎 reactions from non-authors - [ ] Verify reopened issues are not auto-closed again - [ ] Check that legitimate duplicates without objections still get closed properly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Bot Co-authored-by: Claude --- scripts/auto-close-duplicates.ts | 33 +++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/scripts/auto-close-duplicates.ts b/scripts/auto-close-duplicates.ts index d565ad2b9a..996a9d5f6d 100644 --- a/scripts/auto-close-duplicates.ts +++ b/scripts/auto-close-duplicates.ts @@ -26,6 +26,11 @@ interface GitHubReaction { content: string; } +interface GitHubEvent { + event: string; + created_at: string; +} + async function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } @@ -153,6 +158,13 @@ async function fetchAllReactions( return allReactions; } +async function wasIssueReopened(owner: string, repo: string, issueNumber: number, token: string): Promise { + const events: GitHubEvent[] = await githubRequest(`/repos/${owner}/${repo}/issues/${issueNumber}/events`, token); + + // Check if there's a "reopened" event in the issue's timeline + return events.some(event => event.event === "reopened"); +} + function escapeRegExp(str: string): string { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } @@ -299,16 +311,23 @@ async function autoCloseDuplicates(): Promise { } console.log(`[DEBUG] Issue #${issue.number} - checking reactions on duplicate comment...`); - const reactions = await fetchAllReactions(owner, repo, lastDupeComment.id, token, issue.user.id); + const reactions = await fetchAllReactions(owner, repo, lastDupeComment.id, token); console.log(`[DEBUG] Issue #${issue.number} - duplicate comment has ${reactions.length} reactions`); - const authorThumbsDown = reactions.some( - reaction => reaction.user.id === issue.user.id && reaction.content === "-1", - ); - console.log(`[DEBUG] Issue #${issue.number} - author thumbs down reaction: ${authorThumbsDown}`); + const hasThumbsDown = reactions.some(reaction => reaction.content === "-1"); + console.log(`[DEBUG] Issue #${issue.number} - has thumbs down reaction: ${hasThumbsDown}`); - if (authorThumbsDown) { - console.log(`[DEBUG] Issue #${issue.number} - author disagreed with duplicate detection, skipping`); + if (hasThumbsDown) { + console.log(`[DEBUG] Issue #${issue.number} - someone disagreed with duplicate detection, skipping`); + continue; + } + + console.log(`[DEBUG] Issue #${issue.number} - checking if issue was reopened...`); + const wasReopened = await wasIssueReopened(owner, repo, issue.number, token); + console.log(`[DEBUG] Issue #${issue.number} - was reopened: ${wasReopened}`); + + if (wasReopened) { + console.log(`[DEBUG] Issue #${issue.number} - issue was previously reopened, skipping auto-close`); continue; }