Skip to content

Commit ee632d4

Browse files
authored
ci: auto-label issues (#14792)
Add auto-labeling of issues based upon "area" section in issue template.
1 parent 4f03016 commit ee632d4

File tree

5 files changed

+132
-3
lines changed

5 files changed

+132
-3
lines changed

.github/ISSUE_TEMPLATE/1.bug_report_v3.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,20 @@ body:
3333
- 'Not sure'
3434
- 'area: core'
3535
- 'area: docs'
36+
- 'area: graphql'
37+
- 'area: live-preview'
3638
- 'area: templates'
3739
- 'area: ui'
3840
- 'db: d1-sqlite'
3941
- 'db: mongodb'
4042
- 'db: postgres'
4143
- 'db: sqlite'
4244
- 'db: vercel-postgres'
43-
- 'email-nodemailer'
4445
- 'plugin: cloud-storage'
4546
- 'plugin: ecommerce'
4647
- 'plugin: form-builder'
4748
- 'plugin: import-export'
49+
- 'plugin: mcp'
4850
- 'plugin: multi-tenant'
4951
- 'plugin: nested-docs'
5052
- 'plugin: redirects'

.github/actions/triage/action.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ inputs:
2020
actions-to-perform:
2121
description: 'Comma-separated list of actions to perform on the issue. Example: "tag,comment,close"'
2222
default: 'tag,comment,close'
23+
area-label-section:
24+
description: 'Regex to extract area labels from issue body. First capture group should contain comma-separated values.'
25+
default: ''
26+
area-label-skip:
27+
description: 'Comma-separated values to skip (not apply as labels). Example: "Not sure"'
28+
default: ''
2329

2430
runs:
2531
using: 'composite'
@@ -38,3 +44,5 @@ runs:
3844
'INPUT_REPRODUCTION_ISSUE_LABELS': ${{inputs.reproduction-issue-labels}}
3945
'INPUT_REPRODUCTION_LINK_SECTION': ${{inputs.reproduction-link-section}}
4046
'INPUT_ACTIONS_TO_PERFORM': ${{inputs.actions-to-perform}}
47+
'INPUT_AREA_LABEL_SECTION': ${{inputs.area-label-section}}
48+
'INPUT_AREA_LABEL_SKIP': ${{inputs.area-label-skip}}

.github/actions/triage/dist/index.js

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33854,6 +33854,13 @@ var config = {
3385433854
label: (0,core.getInput)('reproduction_invalid_label') || 'invalid-reproduction',
3385533855
linkSection: (0,core.getInput)('reproduction_link_section') || '### Link to reproduction(.*)### To reproduce',
3385633856
},
33857+
areaLabels: {
33858+
section: (0,core.getInput)('area_label_section') || '',
33859+
skip: ((0,core.getInput)('area_label_skip') || '')
33860+
.split(',')
33861+
.map(function (s) { return s.trim(); })
33862+
.filter(Boolean),
33863+
},
3385733864
actionsToPerform: ((0,core.getInput)('actions_to_perform') || validActionsToPerform.join(','))
3385833865
.split(',')
3385933866
.map(function (a) {
@@ -33925,7 +33932,7 @@ function checkValidReproduction() {
3392533932
case 4:
3392633933
// Adjust labels
3392733934
_f.sent();
33928-
if (!!config.actionsToPerform.includes('tag')) return [3 /*break*/, 6];
33935+
if (!config.actionsToPerform.includes('tag')) return [3 /*break*/, 6];
3392933936
(0,core.info)("Added label: ".concat(config.invalidLink.label));
3393033937
return [4 /*yield*/, client.issues.addLabels(__assign(__assign({}, common), { labels: [config.invalidLink.label] }))];
3393133938
case 5:
@@ -34042,6 +34049,56 @@ function getCommentBody(pathOrComment) {
3404234049
});
3404334050
});
3404434051
}
34052+
/**
34053+
* Apply area labels from the issue body dropdown selection
34054+
*/
34055+
function checkAreaLabels() {
34056+
var _a, _b;
34057+
return __awaiter(this, void 0, Promise, function () {
34058+
var _c, issue, action, sectionRegex, match, labels, client, common, err_1;
34059+
return __generator(this, function (_d) {
34060+
switch (_d.label) {
34061+
case 0:
34062+
if (!config.areaLabels.section) {
34063+
(0,core.info)('Area labels - skipped, no section regex configured');
34064+
return [2 /*return*/];
34065+
}
34066+
_c = github.context.payload, issue = _c.issue, action = _c.action;
34067+
if (action !== 'opened' || !(issue === null || issue === void 0 ? void 0 : issue.body))
34068+
return [2 /*return*/];
34069+
sectionRegex = new RegExp(config.areaLabels.section, 'is');
34070+
match = (_b = (_a = issue.body.match(sectionRegex)) === null || _a === void 0 ? void 0 : _a[1]) === null || _b === void 0 ? void 0 : _b.trim();
34071+
if (!match) {
34072+
(0,core.info)('Area labels - no matching section found in issue body');
34073+
return [2 /*return*/];
34074+
}
34075+
labels = match
34076+
.split(',')
34077+
.map(function (l) { return l.trim(); })
34078+
.filter(function (l) { return l && !config.areaLabels.skip.includes(l); });
34079+
if (labels.length === 0) {
34080+
(0,core.info)('Area labels - no labels to apply after filtering');
34081+
return [2 /*return*/];
34082+
}
34083+
client = (0,github.getOctokit)(config.token).rest;
34084+
common = __assign(__assign({}, github.context.repo), { issue_number: issue.number });
34085+
_d.label = 1;
34086+
case 1:
34087+
_d.trys.push([1, 3, , 4]);
34088+
return [4 /*yield*/, client.issues.addLabels(__assign(__assign({}, common), { labels: labels }))];
34089+
case 2:
34090+
_d.sent();
34091+
(0,core.info)("Applied area labels: ".concat(labels.join(', ')));
34092+
return [3 /*break*/, 4];
34093+
case 3:
34094+
err_1 = _d.sent();
34095+
(0,core.error)("Failed to apply area labels: ".concat(err_1 instanceof Error ? err_1.message : err_1));
34096+
return [3 /*break*/, 4];
34097+
case 4: return [2 /*return*/];
34098+
}
34099+
});
34100+
});
34101+
}
3404534102
function run() {
3404634103
return __awaiter(this, void 0, void 0, function () {
3404734104
var token, workspace, safeConfig;
@@ -34051,8 +34108,11 @@ function run() {
3405134108
token = config.token, workspace = config.workspace, safeConfig = __rest(config, ["token", "workspace"]);
3405234109
(0,core.info)('Configuration:');
3405334110
(0,core.info)(JSON.stringify(safeConfig, null, 2));
34054-
return [4 /*yield*/, checkValidReproduction()];
34111+
return [4 /*yield*/, checkAreaLabels()];
3405534112
case 1:
34113+
_a.sent();
34114+
return [4 /*yield*/, checkValidReproduction()];
34115+
case 2:
3405634116
_a.sent();
3405734117
return [2 /*return*/];
3405834118
}

.github/actions/triage/src/index.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ interface Config {
2020
label: string
2121
linkSection: string
2222
}
23+
areaLabels: {
24+
section: string
25+
skip: string[]
26+
}
2327
actionsToPerform: ActionsToPerform[]
2428
token: string
2529
workspace: string
@@ -36,6 +40,13 @@ const config: Config = {
3640
linkSection:
3741
getInput('reproduction_link_section') || '### Link to reproduction(.*)### To reproduce',
3842
},
43+
areaLabels: {
44+
section: getInput('area_label_section') || '',
45+
skip: (getInput('area_label_skip') || '')
46+
.split(',')
47+
.map((s) => s.trim())
48+
.filter(Boolean),
49+
},
3950
actionsToPerform: (getInput('actions_to_perform') || validActionsToPerform.join(','))
4051
.split(',')
4152
.map((a) => {
@@ -204,11 +215,57 @@ async function getCommentBody(pathOrComment: string) {
204215
}
205216
}
206217

218+
/**
219+
* Apply area labels from the issue body dropdown selection
220+
*/
221+
async function checkAreaLabels(): Promise<void> {
222+
if (!config.areaLabels.section) {
223+
info('Area labels - skipped, no section regex configured')
224+
return
225+
}
226+
227+
const { issue, action } = context.payload as {
228+
issue: { number: number; body: string } | undefined
229+
action: string
230+
}
231+
232+
if (action !== 'opened' || !issue?.body) return
233+
234+
const sectionRegex = new RegExp(config.areaLabels.section, 'is')
235+
const match = issue.body.match(sectionRegex)?.[1]?.trim()
236+
237+
if (!match) {
238+
info('Area labels - no matching section found in issue body')
239+
return
240+
}
241+
242+
const labels = match
243+
.split(',')
244+
.map((l) => l.trim())
245+
.filter((l) => l && !config.areaLabels.skip.includes(l))
246+
247+
if (labels.length === 0) {
248+
info('Area labels - no labels to apply after filtering')
249+
return
250+
}
251+
252+
const { rest: client } = getOctokit(config.token)
253+
const common = { ...context.repo, issue_number: issue.number }
254+
255+
try {
256+
await client.issues.addLabels({ ...common, labels })
257+
info(`Applied area labels: ${labels.join(', ')}`)
258+
} catch (err) {
259+
error(`Failed to apply area labels: ${err instanceof Error ? err.message : err}`)
260+
}
261+
}
262+
207263
async function run() {
208264
const { token, workspace, ...safeConfig } = config
209265
info('Configuration:')
210266
info(JSON.stringify(safeConfig, null, 2))
211267

268+
await checkAreaLabels()
212269
await checkValidReproduction()
213270
}
214271

.github/workflows/triage.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,5 @@ jobs:
100100
reproduction-link-section: '### Link to the code that reproduces this issue(.*)### Reproduction Steps'
101101
reproduction-issue-labels: 'validate-reproduction'
102102
actions-to-perform: 'tag,comment'
103+
area-label-section: '### Which area\(s\) are affected\?(.*)### Environment Info'
104+
area-label-skip: 'Not sure'

0 commit comments

Comments
 (0)