-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
123 additions
and
3 deletions.
There are no files selected for viewing
This file contains 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Duplicate issues removal script | ||
|
||
This script helps remove duplicate issues from a GitHub repository by closing issues that have the same title as any older issue. | ||
|
||
## Prerequisites | ||
|
||
1. Set up environment variables: | ||
- Create a `.env` file in the root directory | ||
- Add the GitHub personal access token of the bot that manages issues on your collection, with `repo` permissions: | ||
|
||
```shell | ||
OTA_ENGINE_GITHUB_TOKEN=your_github_token | ||
``` | ||
|
||
2. Configure the target repository in your chosen configuration file within the `config` folder: | ||
|
||
```json | ||
{ | ||
"@opentermsarchive/engine": { | ||
"reporter": { | ||
"githubIssues": { | ||
"repositories": { | ||
"declarations": "owner/repository" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Usage | ||
|
||
Run the script using: | ||
|
||
```shell | ||
node scripts/reporter/duplicate/index.js | ||
``` |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import 'dotenv/config'; | ||
import config from 'config'; | ||
import { Octokit } from 'octokit'; | ||
|
||
async function removeDuplicateIssues() { | ||
const repository = config.get('@opentermsarchive/engine.reporter.githubIssues.repositories.declarations'); | ||
|
||
if (!repository.includes('/') || repository.includes('https://')) { | ||
throw new Error(`Configuration entry "reporter.githubIssues.repositories.declarations" is expected to be a string in the format <owner>/<repo>, but received: "${repository}"`); | ||
} | ||
|
||
const [ owner, repo ] = repository.split('/'); | ||
|
||
const octokit = new Octokit({ auth: process.env.OTA_ENGINE_GITHUB_TOKEN }); | ||
|
||
console.log(`Getting issues from repository ${repository}…`); | ||
|
||
const issues = await octokit.paginate('GET /repos/{owner}/{repo}/issues', { | ||
owner, | ||
repo, | ||
state: 'open', | ||
per_page: 100, | ||
}); | ||
|
||
const onlyIssues = issues.filter(issue => !issue.pull_request); | ||
const issuesByTitle = new Map(); | ||
let counter = 0; | ||
|
||
console.log(`Found ${onlyIssues.length} issues`); | ||
|
||
for (const issue of onlyIssues) { | ||
if (!issuesByTitle.has(issue.title)) { | ||
issuesByTitle.set(issue.title, [issue]); | ||
} else { | ||
issuesByTitle.get(issue.title).push(issue); | ||
} | ||
} | ||
|
||
for (const [ title, duplicateIssues ] of issuesByTitle) { | ||
if (duplicateIssues.length === 1) continue; | ||
|
||
const originalIssue = duplicateIssues.reduce((oldest, current) => (new Date(current.created_at) < new Date(oldest.created_at) ? current : oldest)); | ||
|
||
console.log(`\nFound ${duplicateIssues.length - 1} duplicates for issue #${originalIssue.number} "${title}"`); | ||
|
||
for (const issue of duplicateIssues) { | ||
if (issue.number === originalIssue.number) { | ||
continue; | ||
} | ||
|
||
await octokit.request('PATCH /repos/{owner}/{repo}/issues/{issue_number}', { /* eslint-disable-line no-await-in-loop */ | ||
owner, | ||
repo, | ||
issue_number: issue.number, | ||
state: 'closed', | ||
}); | ||
|
||
await octokit.request('POST /repos/{owner}/{repo}/issues/{issue_number}/comments', { /* eslint-disable-line no-await-in-loop */ | ||
owner, | ||
repo, | ||
issue_number: issue.number, | ||
body: `This issue is detected as duplicate as it has the same title as #${originalIssue.number}. It most likely was created accidentally by an engine older than [v2.3.2](https://github.com/OpenTermsArchive/engine/releases/tag/v2.3.2). Closing automatically.`, | ||
}); | ||
|
||
counter++; | ||
console.log(`Closed issue #${issue.number}: ${issue.html_url}`); | ||
} | ||
} | ||
|
||
console.log(`\nDuplicate removal process completed; ${counter} issues closed`); | ||
} | ||
|
||
removeDuplicateIssues(); |