Skip to content
This repository was archived by the owner on Jan 22, 2022. It is now read-only.

Commit fcee790

Browse files
authored
Merge pull request #73 from janeyx99/expand-auto-labeling
auto-label-bot: add logic to label based on issue/pr title
2 parents 3ee8f0e + 97276aa commit fcee790

File tree

4 files changed

+267
-17
lines changed

4 files changed

+267
-17
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ CC people when labels are added to an issue.
2626
**triage review**
2727
* If an issue is labeled **topic: flaky-tests**, also label it
2828
**high priority** and **triage review**
29+
* If an issue or pull request contains a regex in its title, label
30+
it accordingly, e.g., a title containing 'ROCm' would yield the
31+
**module: rocm** label.
2932
3033
## trigger-circleci-workflows
3134

src/auto-label-bot.ts

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
import * as probot from 'probot';
22

3+
const regexToLabel: [RegExp, string][] = [[/rocm/gi, 'module: rocm']];
4+
35
function myBot(app: probot.Application): void {
6+
function addLabel(
7+
labelSet: Set<string>,
8+
newLabels: string[],
9+
l: string
10+
): void {
11+
if (!labelSet.has(l)) {
12+
newLabels.push(l);
13+
labelSet.add(l);
14+
}
15+
}
16+
417
app.on('issues.labeled', async context => {
518
// Careful! For most labels, we only apply actions *when the issue
619
// is added*; not if the issue is pre-existing (for example, high
@@ -9,18 +22,13 @@ function myBot(app: probot.Application): void {
922
// time the issue is labeled).
1023

1124
const label = context.payload['label']['name'];
12-
const labels = context.payload['issue']['labels'].map(e => e['name']);
25+
const labels: string[] = context.payload['issue']['labels'].map(
26+
e => e['name']
27+
);
1328
context.log({label, labels});
1429

1530
const labelSet = new Set(labels);
16-
1731
const newLabels = [];
18-
function addLabel(l: string): void {
19-
if (!labelSet.has(l)) {
20-
newLabels.push(l);
21-
labelSet.add(l);
22-
}
23-
}
2432

2533
// NB: Added labels here will trigger more issues.labeled actions,
2634
// so be careful about accidentally adding a cycle. With just label
@@ -29,18 +37,56 @@ function myBot(app: probot.Application): void {
2937
switch (label) {
3038
case 'high priority':
3139
case 'critical':
32-
addLabel('triage review');
40+
addLabel(labelSet, newLabels, 'triage review');
3341
break;
3442
case 'module: flaky-tests':
35-
addLabel('high priority');
36-
addLabel('triage review');
43+
addLabel(labelSet, newLabels, 'high priority');
44+
addLabel(labelSet, newLabels, 'triage review');
3745
break;
3846
}
3947

4048
if (newLabels.length) {
4149
await context.github.issues.addLabels(context.issue({labels: newLabels}));
4250
}
4351
});
52+
53+
async function addLabelsFromTitle(
54+
existingLabels: string[],
55+
title: string,
56+
context
57+
): Promise<void> {
58+
const labelSet = new Set(existingLabels);
59+
const newLabels = [];
60+
61+
for (const [regex, label] of regexToLabel) {
62+
if (title.match(regex)) {
63+
addLabel(labelSet, newLabels, label);
64+
}
65+
}
66+
67+
if (newLabels.length) {
68+
await context.github.issues.addLabels(context.issue({labels: newLabels}));
69+
}
70+
}
71+
72+
app.on(['issues.opened', 'issues.edited'], async context => {
73+
const labels: string[] = context.payload['issue']['labels'].map(
74+
e => e['name']
75+
);
76+
const title = context.payload['issue']['title'];
77+
context.log({labels, title});
78+
await addLabelsFromTitle(labels, title, context);
79+
});
80+
81+
app.on(['pull_request.opened', 'pull_request.edited'], async context => {
82+
const labels: string[] = context.payload['pull_request']['labels'].map(
83+
e => e['name']
84+
);
85+
const title = context.payload['pull_request']['title'];
86+
context.log({labels, title});
87+
88+
await addLabelsFromTitle(labels, title, context);
89+
});
4490
}
4591

4692
export default myBot;

test/auto-label-bot.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,52 @@ describe('auto-label-bot', () => {
3636

3737
scope.done();
3838
});
39+
40+
test('add rocm label when issue title contains ROCm', async () => {
41+
nock('https://api.github.com')
42+
.post('/app/installations/2/access_tokens')
43+
.reply(200, {token: 'test'});
44+
45+
const payload = require('./fixtures/issues.opened');
46+
payload['issue']['title'] = 'Issue regarding ROCm';
47+
payload['issue']['labels'] = [];
48+
49+
const scope = nock('https://api.github.com')
50+
.post(
51+
'/repos/ezyang/testing-ideal-computing-machine/issues/5/labels',
52+
body => {
53+
expect(body).toMatchObject(['module: rocm']);
54+
return true;
55+
}
56+
)
57+
.reply(200);
58+
59+
await probot.receive({name: 'issues', payload: payload, id: '2'});
60+
61+
scope.done();
62+
});
63+
64+
test('add rocm label when PR title contains ROCm', async () => {
65+
nock('https://api.github.com')
66+
.post('/app/installations/2/access_tokens')
67+
.reply(200, {token: 'test'});
68+
69+
const payload = require('./fixtures/pull_request.opened')['payload'];
70+
payload['pull_request']['title'] = 'Issue regarding ROCm';
71+
payload['pull_request']['labels'] = [];
72+
73+
const scope = nock('https://api.github.com')
74+
.post(
75+
'/repos/zhouzhuojie/gha-ci-playground/issues/31/labels',
76+
body => {
77+
expect(body).toMatchObject(['module: rocm']);
78+
return true;
79+
}
80+
)
81+
.reply(200);
82+
83+
await probot.receive({name: 'pull_request', payload: payload, id: '2'});
84+
85+
scope.done();
86+
});
3987
});

test/fixtures/issues.opened.json

Lines changed: 159 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,168 @@
11
{
22
"action": "opened",
33
"issue": {
4-
"number": 1,
4+
"url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/issues/5",
5+
"repository_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine",
6+
"labels_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/issues/5/labels{/name}",
7+
"comments_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/issues/5/comments",
8+
"events_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/issues/5/events",
9+
"html_url": "https://github.com/ezyang/testing-ideal-computing-machine/issues/5",
10+
"id": 480359954,
11+
"node_id": "MDU6SXNzdWU0ODAzNTk5NTQ=",
12+
"number": 5,
13+
"title": "ROCm",
514
"user": {
6-
"login": "hiimbex"
7-
}
15+
"login": "ezyang",
16+
"id": 13564,
17+
"node_id": "MDQ6VXNlcjEzNTY0",
18+
"avatar_url": "https://avatars0.githubusercontent.com/u/13564?v=4",
19+
"gravatar_id": "",
20+
"url": "https://api.github.com/users/ezyang",
21+
"html_url": "https://github.com/ezyang",
22+
"followers_url": "https://api.github.com/users/ezyang/followers",
23+
"following_url": "https://api.github.com/users/ezyang/following{/other_user}",
24+
"gists_url": "https://api.github.com/users/ezyang/gists{/gist_id}",
25+
"starred_url": "https://api.github.com/users/ezyang/starred{/owner}{/repo}",
26+
"subscriptions_url": "https://api.github.com/users/ezyang/subscriptions",
27+
"organizations_url": "https://api.github.com/users/ezyang/orgs",
28+
"repos_url": "https://api.github.com/users/ezyang/repos",
29+
"events_url": "https://api.github.com/users/ezyang/events{/privacy}",
30+
"received_events_url": "https://api.github.com/users/ezyang/received_events",
31+
"type": "User",
32+
"site_admin": false
33+
},
34+
"labels": [
35+
],
36+
"state": "open",
37+
"locked": false,
38+
"assignee": null,
39+
"assignees": [
40+
41+
],
42+
"milestone": null,
43+
"comments": 1,
44+
"created_at": "2019-08-13T20:44:49Z",
45+
"updated_at": "2019-08-14T16:58:26Z",
46+
"closed_at": null,
47+
"author_association": "OWNER",
48+
"body": "Arf arf\n\ncc @moo @mar\nxxxx"
849
},
950
"repository": {
10-
"name": "testing-things",
51+
"id": 156317224,
52+
"node_id": "MDEwOlJlcG9zaXRvcnkxNTYzMTcyMjQ=",
53+
"name": "testing-ideal-computing-machine",
54+
"full_name": "ezyang/testing-ideal-computing-machine",
55+
"private": false,
1156
"owner": {
12-
"login": "hiimbex"
13-
}
57+
"login": "ezyang",
58+
"id": 13564,
59+
"node_id": "MDQ6VXNlcjEzNTY0",
60+
"avatar_url": "https://avatars0.githubusercontent.com/u/13564?v=4",
61+
"gravatar_id": "",
62+
"url": "https://api.github.com/users/ezyang",
63+
"html_url": "https://github.com/ezyang",
64+
"followers_url": "https://api.github.com/users/ezyang/followers",
65+
"following_url": "https://api.github.com/users/ezyang/following{/other_user}",
66+
"gists_url": "https://api.github.com/users/ezyang/gists{/gist_id}",
67+
"starred_url": "https://api.github.com/users/ezyang/starred{/owner}{/repo}",
68+
"subscriptions_url": "https://api.github.com/users/ezyang/subscriptions",
69+
"organizations_url": "https://api.github.com/users/ezyang/orgs",
70+
"repos_url": "https://api.github.com/users/ezyang/repos",
71+
"events_url": "https://api.github.com/users/ezyang/events{/privacy}",
72+
"received_events_url": "https://api.github.com/users/ezyang/received_events",
73+
"type": "User",
74+
"site_admin": false
75+
},
76+
"html_url": "https://github.com/ezyang/testing-ideal-computing-machine",
77+
"description": "Testing repo",
78+
"fork": false,
79+
"url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine",
80+
"forks_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/forks",
81+
"keys_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/keys{/key_id}",
82+
"collaborators_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/collaborators{/collaborator}",
83+
"teams_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/teams",
84+
"hooks_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/hooks",
85+
"issue_events_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/issues/events{/number}",
86+
"events_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/events",
87+
"assignees_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/assignees{/user}",
88+
"branches_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/branches{/branch}",
89+
"tags_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/tags",
90+
"blobs_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/git/blobs{/sha}",
91+
"git_tags_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/git/tags{/sha}",
92+
"git_refs_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/git/refs{/sha}",
93+
"trees_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/git/trees{/sha}",
94+
"statuses_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/statuses/{sha}",
95+
"languages_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/languages",
96+
"stargazers_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/stargazers",
97+
"contributors_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/contributors",
98+
"subscribers_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/subscribers",
99+
"subscription_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/subscription",
100+
"commits_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/commits{/sha}",
101+
"git_commits_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/git/commits{/sha}",
102+
"comments_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/comments{/number}",
103+
"issue_comment_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/issues/comments{/number}",
104+
"contents_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/contents/{+path}",
105+
"compare_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/compare/{base}...{head}",
106+
"merges_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/merges",
107+
"archive_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/{archive_format}{/ref}",
108+
"downloads_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/downloads",
109+
"issues_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/issues{/number}",
110+
"pulls_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/pulls{/number}",
111+
"milestones_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/milestones{/number}",
112+
"notifications_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/notifications{?since,all,participating}",
113+
"labels_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/labels{/name}",
114+
"releases_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/releases{/id}",
115+
"deployments_url": "https://api.github.com/repos/ezyang/testing-ideal-computing-machine/deployments",
116+
"created_at": "2018-11-06T02:57:39Z",
117+
"updated_at": "2018-11-06T02:57:42Z",
118+
"pushed_at": "2018-11-06T03:58:56Z",
119+
"git_url": "git://github.com/ezyang/testing-ideal-computing-machine.git",
120+
"ssh_url": "git@github.com:ezyang/testing-ideal-computing-machine.git",
121+
"clone_url": "https://github.com/ezyang/testing-ideal-computing-machine.git",
122+
"svn_url": "https://github.com/ezyang/testing-ideal-computing-machine",
123+
"homepage": null,
124+
"size": 3,
125+
"stargazers_count": 0,
126+
"watchers_count": 0,
127+
"language": null,
128+
"has_issues": true,
129+
"has_projects": true,
130+
"has_downloads": true,
131+
"has_wiki": true,
132+
"has_pages": false,
133+
"forks_count": 0,
134+
"mirror_url": null,
135+
"archived": false,
136+
"disabled": false,
137+
"open_issues_count": 5,
138+
"license": null,
139+
"forks": 0,
140+
"open_issues": 5,
141+
"watchers": 0,
142+
"default_branch": "master"
143+
},
144+
"sender": {
145+
"login": "ezyang",
146+
"id": 13564,
147+
"node_id": "MDQ6VXNlcjEzNTY0",
148+
"avatar_url": "https://avatars0.githubusercontent.com/u/13564?v=4",
149+
"gravatar_id": "",
150+
"url": "https://api.github.com/users/ezyang",
151+
"html_url": "https://github.com/ezyang",
152+
"followers_url": "https://api.github.com/users/ezyang/followers",
153+
"following_url": "https://api.github.com/users/ezyang/following{/other_user}",
154+
"gists_url": "https://api.github.com/users/ezyang/gists{/gist_id}",
155+
"starred_url": "https://api.github.com/users/ezyang/starred{/owner}{/repo}",
156+
"subscriptions_url": "https://api.github.com/users/ezyang/subscriptions",
157+
"organizations_url": "https://api.github.com/users/ezyang/orgs",
158+
"repos_url": "https://api.github.com/users/ezyang/repos",
159+
"events_url": "https://api.github.com/users/ezyang/events{/privacy}",
160+
"received_events_url": "https://api.github.com/users/ezyang/received_events",
161+
"type": "User",
162+
"site_admin": false
163+
},
164+
"installation": {
165+
"id": 1492531,
166+
"node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMTQ5MjUzMQ=="
14167
}
15168
}

0 commit comments

Comments
 (0)