/
autolabel.mjs
114 lines (92 loc) · 3.19 KB
/
autolabel.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/**
* This action will automatically add labels to issues based on the area(s) of Next.js that are affected.
*/
// @ts-check
import { setFailed, debug } from '@actions/core'
import { context, getOctokit } from '@actions/github'
/** @typedef {ReturnType<typeof getOctokit>['rest']} GitHubClient */
async function run() {
const token = process.env.GITHUB_TOKEN
if (!token) throw new Error('No GITHUB_TOKEN provided')
const { issue } = context.payload
if (!issue) return console.log('Not an issue, exiting')
const { body: issue_body, number: issue_number, title: issue_title } = issue
if (!issue_number) return console.log('Could not get issue number, exiting')
if (!issue_body) return console.log('Could not get issue body, exiting')
if (!issue_title) return console.log('Could not get issue title, exiting')
// A client to load data from GitHub
const { rest: client } = getOctokit(token)
// Load our regex rules from the repo labels
const labels = await loadAreaLabels(client)
debug(`Loaded labels: ${Array.from(labels.keys()).join(', ')}`)
/**
* List of labels to add
* @type {string[]}
*/
const toAdd = []
// https://github.com/vercel/next.js/blob/canary/.github/ISSUE_TEMPLATE/1.bug_report.yml?plain=1
const matchSection = issue_body
.split('Which area(s) are affected? (Select all that apply)')[1]
?.split('### Additional context')[0]
if (!matchSection) {
console.log(
`Issue #${issue_number} does not contain a match section, likely not a bug template, exiting`
)
return
}
debug(`Match section: ${matchSection}`)
for (const [label, description] of labels.entries()) {
if (matchSection.includes(description)) {
toAdd.push(label)
}
}
debug(`Labels to add: ${toAdd.join(', ')}`)
if (!toAdd.length) return console.log('No labels to add, exiting')
await addLabels(client, issue_number, toAdd)
debug(`Added labels to issue #${issue_number}: ${toAdd.join(', ')}`)
}
/** Load label descriptions from the repo.
* @param {GitHubClient} client
*/
async function loadAreaLabels(client) {
try {
const { data } = await client.issues.listLabelsForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
})
/** @type {Map<string, string>}*/
const labels = new Map()
// Only load labels that start with `area:` and have a description
for (const label of data) {
if (label.name.startsWith('area:') && label.description) {
labels.set(label.name, label.description)
}
}
return labels
} catch (error) {
console.error('Error loading labels: ' + error)
throw error
}
}
/**
* @param {GitHubClient} client
* @param {number} issue_number
* @param {string[]} labels
*/
async function addLabels(client, issue_number, labels) {
try {
const formatted = labels.map((l) => `"${l}"`).join(', ')
debug(`Adding label(s) (${formatted}) to issue #${issue_number}`)
return await client.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number,
labels,
})
} catch (error) {
console.error(`Could not add label(s) ${labels} to issue #${issue_number}`)
throw error
}
}
run().catch(setFailed)