Skip to content

Commit a731a51

Browse files
author
Brian Vaughn
authored
Add GitHub action to check for bug repro (#21542)
1 parent 51ebccc commit a731a51

File tree

1 file changed

+209
-0
lines changed

1 file changed

+209
-0
lines changed
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

0 commit comments

Comments
 (0)