Last active
April 5, 2022 22:43
-
-
Save mryhryki/d901e54ccf07145a556975ae4d1be016 to your computer and use it in GitHub Desktop.
1年以上更新がないIssueを抽出するスクリプト
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
| .idea | |
| node_modules | |
| package-lock.json |
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
| const fetch = require('node-fetch') | |
| const Organization = "Connehito" | |
| const FirstCount = 100; | |
| const getGitHubToken = () => { | |
| const envVar = process.env.GITHUB_ACCESS_TOKEN | |
| if (envVar) { | |
| return envVar | |
| } | |
| throw new Error('GITHUB_ACCESS_TOKEN が設定されていません。') | |
| } | |
| const getAfterQuery = (nextToken) => { | |
| if (!nextToken) { | |
| return '' | |
| } | |
| return `, after: "${nextToken}"` | |
| } | |
| const fetchRepositories = async (nextToken = null) => { | |
| const result = await fetchGitHubV4(` | |
| { | |
| organization(login: "${Organization}") { | |
| repositories(first: ${FirstCount}${getAfterQuery(nextToken)}) { | |
| nodes { | |
| name | |
| isArchived | |
| } | |
| edges{ | |
| cursor | |
| } | |
| } | |
| } | |
| } | |
| `) | |
| const {nodes, edges} = result.data.organization.repositories | |
| const repositories = nodes.filter(({isArchived}) => !isArchived).map(({name}) => name) | |
| const lastCursor = (edges[FirstCount - 1] || {}).cursor || null | |
| return { | |
| repositories, | |
| nextToken: lastCursor, | |
| } | |
| } | |
| const fetchAllRepositories = async () => { | |
| let nextToken = null | |
| const repositories = [] | |
| do { | |
| const result = await fetchRepositories(nextToken) | |
| result.repositories.forEach((repository) => { | |
| repositories.push(repository) | |
| }) | |
| nextToken = result.nextToken | |
| } while(nextToken != null) | |
| return repositories | |
| } | |
| const fetchOpenIssues =async (repository, nextToken = null) => { | |
| const result = await fetchGitHubV4( | |
| ` | |
| query($repository: String!){ | |
| organization(login: "Connehito") { | |
| repository(name: $repository) { | |
| issues(first: 100, states: [OPEN]${getAfterQuery(nextToken)}) { | |
| nodes { | |
| url | |
| title | |
| updatedAt | |
| } | |
| edges { | |
| cursor | |
| } | |
| } | |
| } | |
| } | |
| } | |
| `, | |
| {repository} | |
| ) | |
| const {nodes, edges} = result.data.organization.repository.issues | |
| const repositories = nodes | |
| const lastCursor = (edges[FirstCount - 1] || {}).cursor || null | |
| return { | |
| repositories, | |
| nextToken: lastCursor, | |
| } | |
| } | |
| const fetchAllOpenIssues = async (repository) => { | |
| let nextToken = null | |
| const issues = [] | |
| do { | |
| const result = await fetchOpenIssues(repository, nextToken) | |
| result.repositories.forEach((issue) => { | |
| issues.push(issue) | |
| }) | |
| nextToken = result.nextToken | |
| } while(nextToken != null) | |
| return issues | |
| } | |
| const fetchGitHubV4 = async (query, variables = {}) => { | |
| const response = await fetch('https://api.github.com/graphql', { | |
| method: 'post', | |
| headers: { | |
| Authorization: `Bearer ${getGitHubToken()}`, | |
| }, | |
| body: JSON.stringify({query, variables}), | |
| }) | |
| return response.json() | |
| } | |
| module.exports = { | |
| fetchAllRepositories, | |
| fetchAllOpenIssues, | |
| } |
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
| const dayjs = require('dayjs') | |
| const {fetchAllRepositories, fetchAllOpenIssues} = require('./github_api') | |
| const baseDate = dayjs().add(-1, 'year') | |
| const issueFilter = (targetDatetime) => dayjs(targetDatetime) < baseDate | |
| const main = async () => { | |
| const repositories = await fetchAllRepositories() | |
| const issues = await Promise.all( | |
| repositories.map(async (repository) => { | |
| const issues = (await fetchAllOpenIssues(repository)).filter(({updatedAt}) => issueFilter(updatedAt)) | |
| return {repository, issues} | |
| }) | |
| ) | |
| // console.log(JSON.stringify(issues, null, 2)) | |
| issues.forEach(({repository, issues}) => { | |
| if (issues.length === 0) { | |
| return | |
| } | |
| console.log('## %s', repository) | |
| console.log('') | |
| issues.forEach(({title, url}) => { | |
| console.log('- [%s](%s)', title, url) | |
| }) | |
| console.log('') | |
| }) | |
| } | |
| main(); | |
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": "github_issues", | |
| "private": true, | |
| "scripts": { | |
| "start": "node index.js" | |
| }, | |
| "author": "hyiromori", | |
| "license": "MIT", | |
| "dependencies": { | |
| "dayjs": "^1.10.4", | |
| "node-fetch": "^2.6.1" | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment