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}"`);

            async function createComment(comment) {
              // Format
              comment = comment
                .split("\n")
                .map((line) => line.trim())
                .join("\n")
                .trim();

              await github.issues.createComment({
                issue_number: context.issue.number,
                owner: context.repo.owner,
                repo: context.repo.repo,
                body: comment,
              });
            }

            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 updateIssue(state, assignees = []) {
              await github.issues.update({
                issue_number: context.issue.number,
                owner: context.repo.owner,
                repo: context.repo.repo,
                state,
                assignees,
              });
            }

            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 createComment(comment);
              await updateIssue('closed', [user]);
            }

            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 createComment(comment);
              await updateIssue('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.
              `);
            }
