From a731a51696239a69a6cd89cdd34f23ce2fc39099 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 21 May 2021 12:48:12 -0700 Subject: [PATCH] Add GitHub action to check for bug repro (#21542) --- .github/workflows/devtools_check_repro.yml | 209 +++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 .github/workflows/devtools_check_repro.yml diff --git a/.github/workflows/devtools_check_repro.yml b/.github/workflows/devtools_check_repro.yml new file mode 100644 index 0000000000..0a32ff691f --- /dev/null +++ b/.github/workflows/devtools_check_repro.yml @@ -0,0 +1,209 @@ +name: DevTools Check for bug repro +on: + issues: + types: [opened, edited] + issue_comment: + types: [created, edited] + +jobs: + check-repro: + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v3 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const URL_REGEXP = /### Website or app[\r\n]+([^#]+)###/m; + const REPRO_STEPS_REGEXP = /### Repro steps[\r\n]+([^#]+)###/m; + const LABEL_NEEDS_MORE_INFORMATION = "Resolution: Needs More Information"; + const LABEL_UNCONFIRMED = "Status: Unconfirmed"; + + function debug(...args) { + core.info(args.map(JSON.stringify).join(' ')); + } + + if (context.payload.comment) { + debug('Ignoring comment update.'); + return; + } + + const user = context.payload.sender.login; + const issue = context.payload.issue; + const body = issue.body; + + const urlMatch = body.match(URL_REGEXP); + const reproStepsMatch = body.match(REPRO_STEPS_REGEXP); + + const url = urlMatch !== null ? urlMatch[1].trim() : null; + const reproSteps = reproStepsMatch !== null ? reproStepsMatch[1].trim() : null; + + if (!url || !reproSteps) { + debug('This issue is not a DevTools bug report.'); + return; + } + + debug(`found URL "${url}"`); + debug(`found repro steps "${reproSteps}"`); + + function formatComment(comment) { + return comment + .split("\n") + .map((line) => line.trim()) + .join("\n") + .trim(); + } + + async function getGitHubActionComments() { + debug(`Loading existing comments...`); + + const comments = await github.issues.listComments({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + }); + + return comments.data.filter(comment => { + debug(`comment by user: "${comment.user.login}"`); + return comment.user.login === 'github-actions[bot]'; + }); + } + + async function getIssueLabels() { + const issues = await github.issues.listLabelsOnIssue({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + }); + + return issues.data; + } + + async function closeWithComment(comment) { + if (issue.state !== 'open') { + debug(`Issue is not open`); + return; + } + + const labels = await getIssueLabels(); + const label = labels.find(label => label.name === LABEL_UNCONFIRMED); + if (!label) { + debug(`Issue was not opened via DevTools bug report template`); + return; + } + + const comments = await getGitHubActionComments(); + if (comments.length > 0) { + debug(`Already commented on issue; won't comment again`); + return; + } + + debug(`Missing required information`); + + await github.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: [LABEL_NEEDS_MORE_INFORMATION], + }); + + await github.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: formatComment(comment), + }); + + await github.issues.update({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + state: 'closed', + }); + } + + async function openWithComment(comment) { + if (issue.state !== 'closed') { + debug(`Issue is already open`); + return; + } + + const labels = await getIssueLabels(); + const label = labels.find(label => label.name === LABEL_NEEDS_MORE_INFORMATION); + if (!label) { + debug(`Issue was not tagged as needs information`); + return; + } + + const comments = await getGitHubActionComments(); + if (comments.length === 0) { + debug(`Issue was closed by someone else; won't reopen`); + return; + } + + debug(`Re-opening closed issue`); + + await github.issues.removeLabel({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + name: LABEL_NEEDS_MORE_INFORMATION, + }); + + await github.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: formatComment(comment), + }); + + await github.issues.update({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + }); + } + + const PROBABLY_NOT_A_URL_REGEX = /(^Chrome$|^Firefox$| Website)/i; + + const COMMENT_HEADER = ` + @${user}: We're sorry you've seen this error. ❤️ + `.trim(); + + const COMMENT_FOOTER = ` + 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.) + + Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve + + Issues without repros are automatically closed but we will re-open if you update with repro info. + `.trim(); + + if (url.includes("/localhost")) { + closeWithComment(` + ${COMMENT_HEADER} + + 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.) + + ${COMMENT_FOOTER} + `); + } else if (url.length < 10 || url.match(PROBABLY_NOT_A_URL_REGEX)) { + closeWithComment(` + ${COMMENT_HEADER} + + 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.) + + ${COMMENT_FOOTER} + `); + } else if (reproSteps.length < 25) { + closeWithComment(` + ${COMMENT_HEADER} + + Unfortunately, it doesn't look like this issue has enough info for one of us to reproduce and fix it though. + + ${COMMENT_FOOTER} + `); + } else { + openWithComment(` + Thank you for providing repro steps! Re-opening issue now for triage. + `); + }