Add GitHub action to check for bug repro (#21542)
Brian Vaughn committed
May 21, 2021 at 12:48 UTC
a731a51696239a69a6cd89cdd34f23ce2fc39099
1 file changed
+209
.github/workflows/devtools_check_repro.yml
new
+209
@@ -0,0 +1,209 @@
1
+name: DevTools Check for bug repro
2
+on:
3
+ issues:
4
+ types: [opened, edited]
5
+ issue_comment:
6
+ types: [created, edited]
7
+
8
+jobs:
9
+ check-repro:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/github-script@v3
13
+ with:
14
+ github-token: ${{ secrets.GITHUB_TOKEN }}
15
+ script: |
16
+ const URL_REGEXP = /### Website or app[\r\n]+([^#]+)###/m;
17
+ const REPRO_STEPS_REGEXP = /### Repro steps[\r\n]+([^#]+)###/m;
18
+ const LABEL_NEEDS_MORE_INFORMATION = "Resolution: Needs More Information";
19
+ const LABEL_UNCONFIRMED = "Status: Unconfirmed";
20
+
21
+ function debug(...args) {
22
+ core.info(args.map(JSON.stringify).join(' '));
23
+ }
24
+
25
+ if (context.payload.comment) {
26
+ debug('Ignoring comment update.');
27
+ return;
28
+ }
29
+
30
+ const user = context.payload.sender.login;
31
+ const issue = context.payload.issue;
32
+ const body = issue.body;
33
+
34
+ const urlMatch = body.match(URL_REGEXP);
35
+ const reproStepsMatch = body.match(REPRO_STEPS_REGEXP);
36
+
37
+ const url = urlMatch !== null ? urlMatch[1].trim() : null;
38
+ const reproSteps = reproStepsMatch !== null ? reproStepsMatch[1].trim() : null;
39
+
40
+ if (!url || !reproSteps) {
41
+ debug('This issue is not a DevTools bug report.');
42
+ return;
43
+ }
44
+
45
+ debug(`found URL "${url}"`);
46
+ debug(`found repro steps "${reproSteps}"`);
47
+
48
+ function formatComment(comment) {
49
+ return comment
50
+ .split("\n")
51
+ .map((line) => line.trim())
52
+ .join("\n")
53
+ .trim();
54
+ }
55
+
56
+ async function getGitHubActionComments() {
57
+ debug(`Loading existing comments...`);
58
+
59
+ const comments = await github.issues.listComments({
60
+ issue_number: context.issue.number,
61
+ owner: context.repo.owner,
62
+ repo: context.repo.repo,
63
+ });
64
+
65
+ return comments.data.filter(comment => {
66
+ debug(`comment by user: "${comment.user.login}"`);
67
+ return comment.user.login === 'github-actions[bot]';
68
+ });
69
+ }
70
+
71
+ async function getIssueLabels() {
72
+ const issues = await github.issues.listLabelsOnIssue({
73
+ issue_number: context.issue.number,
74
+ owner: context.repo.owner,
75
+ repo: context.repo.repo,
76
+ });
77
+
78
+ return issues.data;
79
+ }
80
+
81
+ async function closeWithComment(comment) {
82
+ if (issue.state !== 'open') {
83
+ debug(`Issue is not open`);
84
+ return;
85
+ }
86
+
87
+ const labels = await getIssueLabels();
88
+ const label = labels.find(label => label.name === LABEL_UNCONFIRMED);
89
+ if (!label) {
90
+ debug(`Issue was not opened via DevTools bug report template`);
91
+ return;
92
+ }
93
+
94
+ const comments = await getGitHubActionComments();
95
+ if (comments.length > 0) {
96
+ debug(`Already commented on issue; won't comment again`);
97
+ return;
98
+ }
99
+
100
+ debug(`Missing required information`);
101
+
102
+ await github.issues.addLabels({
103
+ issue_number: context.issue.number,
104
+ owner: context.repo.owner,
105
+ repo: context.repo.repo,
106
+ labels: [LABEL_NEEDS_MORE_INFORMATION],
107
+ });
108
+
109
+ await github.issues.createComment({
110
+ issue_number: context.issue.number,
111
+ owner: context.repo.owner,
112
+ repo: context.repo.repo,
113
+ body: formatComment(comment),
114
+ });
115
+
116
+ await github.issues.update({
117
+ issue_number: context.issue.number,
118
+ owner: context.repo.owner,
119
+ repo: context.repo.repo,
120
+ state: 'closed',
121
+ });
122
+ }
123
+
124
+ async function openWithComment(comment) {
125
+ if (issue.state !== 'closed') {
126
+ debug(`Issue is already open`);
127
+ return;
128
+ }
129
+
130
+ const labels = await getIssueLabels();
131
+ const label = labels.find(label => label.name === LABEL_NEEDS_MORE_INFORMATION);
132
+ if (!label) {
133
+ debug(`Issue was not tagged as needs information`);
134
+ return;
135
+ }
136
+
137
+ const comments = await getGitHubActionComments();
138
+ if (comments.length === 0) {
139
+ debug(`Issue was closed by someone else; won't reopen`);
140
+ return;
141
+ }
142
+
143
+ debug(`Re-opening closed issue`);
144
+
145
+ await github.issues.removeLabel({
146
+ issue_number: context.issue.number,
147
+ owner: context.repo.owner,
148
+ repo: context.repo.repo,
149
+ name: LABEL_NEEDS_MORE_INFORMATION,
150
+ });
151
+
152
+ await github.issues.createComment({
153
+ issue_number: context.issue.number,
154
+ owner: context.repo.owner,
155
+ repo: context.repo.repo,
156
+ body: formatComment(comment),
157
+ });
158
+
159
+ await github.issues.update({
160
+ issue_number: context.issue.number,
161
+ owner: context.repo.owner,
162
+ repo: context.repo.repo,
163
+ state: 'open',
164
+ });
165
+ }
166
+
167
+ const PROBABLY_NOT_A_URL_REGEX = /(^Chrome$|^Firefox$| Website)/i;
168
+
169
+ const COMMENT_HEADER = `
170
+ @${user}: We're sorry you've seen this error. ❤️
171
+ `.trim();
172
+
173
+ const COMMENT_FOOTER = `
174
+ Please help us by providing a link to a CodeSandbox (https://codesandbox.io/s/new), a repository on GitHub, or a minimal code example that reproduces the problem. (Screenshots or videos can also be helpful if they help provide context on how to repro the bug.)
175
+
176
+ Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve
177
+
178
+ Issues without repros are automatically closed but we will re-open if you update with repro info.
179
+ `.trim();
180
+
181
+ if (url.includes("/localhost")) {
182
+ closeWithComment(`
183
+ ${COMMENT_HEADER}
184
+
185
+ Unfortunately the URL you provided ("localhost") is not publicly accessible. (This means that we will not be able to reproduce the problem you're reporting.)
186
+
187
+ ${COMMENT_FOOTER}
188
+ `);
189
+ } else if (url.length < 10 || url.match(PROBABLY_NOT_A_URL_REGEX)) {
190
+ closeWithComment(`
191
+ ${COMMENT_HEADER}
192
+
193
+ It looks like you forgot to specify a valid URL. (This means that we will not be able to reproduce the problem you're reporting.)
194
+
195
+ ${COMMENT_FOOTER}
196
+ `);
197
+ } else if (reproSteps.length < 25) {
198
+ closeWithComment(`
199
+ ${COMMENT_HEADER}
200
+
201
+ Unfortunately, it doesn't look like this issue has enough info for one of us to reproduce and fix it though.
202
+
203
+ ${COMMENT_FOOTER}
204
+ `);
205
+ } else {
206
+ openWithComment(`
207
+ Thank you for providing repro steps! Re-opening issue now for triage.
208
+ `);
209
+ }