mirror of
https://github.com/anthropics/claude-code.git
synced 2025-10-19 03:17:50 +03:00
Update auto-close-duplicates script to actually close issues
- Remove dry run mode and implement actual issue closing - Extract duplicate issue number from bot comments - Close issues via GitHub API with proper state and comments - Add error handling for API failures - Use Claude Code comment format with reopening instructions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -28,9 +28,10 @@ Found 3 possible duplicate issues:
|
|||||||
2. <link to issue>
|
2. <link to issue>
|
||||||
3. <link to issue>
|
3. <link to issue>
|
||||||
|
|
||||||
If your issue is a duplicate, please close it and 👍 the existing issue instead.
|
This issue will be automatically closed as a duplicate in 3 days.
|
||||||
|
|
||||||
<sub>This issue will be automatically closed as a duplicate in 3 days if there are no additional comments. To prevent auto-closure, please 👎 this comment.</sub>
|
- If your issue is a duplicate, please close it and 👍 the existing issue instead
|
||||||
|
- To prevent auto-closure, add a comment or 👎 this comment
|
||||||
|
|
||||||
🤖 Generated with [Claude Code](https://claude.ai/code)
|
🤖 Generated with [Claude Code](https://claude.ai/code)
|
||||||
|
|
||||||
|
|||||||
@@ -25,13 +25,16 @@ interface GitHubReaction {
|
|||||||
content: string;
|
content: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function githubRequest<T>(endpoint: string, token: string): Promise<T> {
|
async function githubRequest<T>(endpoint: string, token: string, method: string = 'GET', body?: any): Promise<T> {
|
||||||
const response = await fetch(`https://api.github.com${endpoint}`, {
|
const response = await fetch(`https://api.github.com${endpoint}`, {
|
||||||
|
method,
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
Accept: "application/vnd.github.v3+json",
|
Accept: "application/vnd.github.v3+json",
|
||||||
"User-Agent": "auto-close-duplicates-script",
|
"User-Agent": "auto-close-duplicates-script",
|
||||||
|
...(body && { "Content-Type": "application/json" }),
|
||||||
},
|
},
|
||||||
|
...(body && { body: JSON.stringify(body) }),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -43,6 +46,42 @@ async function githubRequest<T>(endpoint: string, token: string): Promise<T> {
|
|||||||
return response.json();
|
return response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractDuplicateIssueNumber(commentBody: string): number | null {
|
||||||
|
const match = commentBody.match(/#(\d+)/);
|
||||||
|
return match ? parseInt(match[1], 10) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function closeIssueAsDuplicate(
|
||||||
|
owner: string,
|
||||||
|
repo: string,
|
||||||
|
issueNumber: number,
|
||||||
|
duplicateOfNumber: number,
|
||||||
|
token: string
|
||||||
|
): Promise<void> {
|
||||||
|
await githubRequest(
|
||||||
|
`/repos/${owner}/${repo}/issues/${issueNumber}`,
|
||||||
|
token,
|
||||||
|
'PATCH',
|
||||||
|
{
|
||||||
|
state: 'closed',
|
||||||
|
state_reason: 'not_planned'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await githubRequest(
|
||||||
|
`/repos/${owner}/${repo}/issues/${issueNumber}/comments`,
|
||||||
|
token,
|
||||||
|
'POST',
|
||||||
|
{
|
||||||
|
body: `This issue has been automatically closed as a duplicate of #${duplicateOfNumber}.
|
||||||
|
|
||||||
|
If this is incorrect, please re-open this issue or create a new one.
|
||||||
|
|
||||||
|
🤖 Generated with [Claude Code](https://claude.ai/code)`
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async function autoCloseDuplicates(): Promise<void> {
|
async function autoCloseDuplicates(): Promise<void> {
|
||||||
console.log("[DEBUG] Starting auto-close duplicates script");
|
console.log("[DEBUG] Starting auto-close duplicates script");
|
||||||
|
|
||||||
@@ -187,11 +226,30 @@ async function autoCloseDuplicates(): Promise<void> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const duplicateIssueNumber = extractDuplicateIssueNumber(lastDupeComment.body);
|
||||||
|
if (!duplicateIssueNumber) {
|
||||||
|
console.log(
|
||||||
|
`[DEBUG] Issue #${issue.number} - could not extract duplicate issue number from comment, skipping`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
candidateCount++;
|
candidateCount++;
|
||||||
const issueUrl = `https://github.com/${owner}/${repo}/issues/${issue.number}`;
|
const issueUrl = `https://github.com/${owner}/${repo}/issues/${issue.number}`;
|
||||||
console.log(
|
|
||||||
`[DRY RUN] Would auto-close issue #${issue.number} as duplicate: ${issueUrl}`
|
try {
|
||||||
);
|
console.log(
|
||||||
|
`[INFO] Auto-closing issue #${issue.number} as duplicate of #${duplicateIssueNumber}: ${issueUrl}`
|
||||||
|
);
|
||||||
|
await closeIssueAsDuplicate(owner, repo, issue.number, duplicateIssueNumber, token);
|
||||||
|
console.log(
|
||||||
|
`[SUCCESS] Successfully closed issue #${issue.number} as duplicate of #${duplicateIssueNumber}`
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
`[ERROR] Failed to close issue #${issue.number} as duplicate: ${error}`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
|
|||||||
Reference in New Issue
Block a user