diff --git a/.github/workflows/pr-reviewdog.yml b/.github/workflows/pr-reviewdog.yml new file mode 100644 index 00000000000000..2bd5090dffecaf --- /dev/null +++ b/.github/workflows/pr-reviewdog.yml @@ -0,0 +1,143 @@ +name: PR Reviewdog + +on: + workflow_run: + workflows: + - "Test" + types: + - completed + +permissions: + # Download artifact from lint workflow. + actions: read + # Post inline review comments via reviewdog. + pull-requests: write + # Report commit status. + statuses: write + +jobs: + reviewdog: + runs-on: ubuntu-latest + env: + STATUS_PATH: repos/${{ github.repository }}/statuses/${{ github.event.workflow_run.head_sha }} + STATUS_CONTEXT: ${{ github.workflow }} + STATUS_TARGET: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + steps: + - name: Mark status as pending + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh api "$STATUS_PATH" \ + -f state=pending \ + -f context="$STATUS_CONTEXT" \ + -f description='Running' \ + -f target_url="$STATUS_TARGET" + + - name: Identify PR + id: identify-pr + env: + BASE_REPO: ${{ github.repository }} + GITHUB_TOKEN: ${{ github.token }} + HEAD_REPO: ${{ github.event.workflow_run.head_repository.full_name }} + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + run: | + PR_NUMBER=$(gh api "repos/$HEAD_REPO/commits/$HEAD_SHA/pulls" \ + --jq ".[] | select(.base.repo.full_name == \"$BASE_REPO\") | .number") + echo "number=$PR_NUMBER" >> $GITHUB_OUTPUT + + - name: Download artifact + if: steps.identify-pr.outputs.number + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: lint-results + path: lint-results + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + + - name: Check for artifact + id: check + if: steps.identify-pr.outputs.number && hashFiles('lint-results/') != '' + run: echo "HAS_ARTIFACT=true" >> "$GITHUB_OUTPUT" + + - name: Checkout + if: steps.identify-pr.outputs.number + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + path: browser-compat-data + ref: main + persist-credentials: false + + - name: Setup reviewdog + if: steps.check.outputs.HAS_ARTIFACT == 'true' + uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.5.0 + with: + reviewdog_version: v0.21.0 + + - name: Add PR review with suggested changes using `git diff` output + if: steps.check.outputs.HAS_ARTIFACT == 'true' && hashFiles('lint-results/lint.diff') != '' + working-directory: browser-compat-data + env: + CI_PULL_REQUEST: ${{ steps.identify-pr.outputs.number }} + CI_COMMIT: ${{ github.event.workflow_run.head_sha }} + CI_REPO_OWNER: ${{ github.repository_owner }} + CI_REPO_NAME: ${{ github.event.repository.name }} + CI_BRANCH: ${{ github.event.workflow_run.head_branch }} + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + env -u GITHUB_ACTIONS reviewdog \ + -guess \ + -name="bcd-linter" \ + -f=diff \ + -f.diff.strip=1 \ + -filter-mode=diff_context \ + -reporter=github-pr-review < ../lint-results/lint.diff + + - name: Post or update PR comment with context + if: steps.check.outputs.HAS_ARTIFACT == 'true' && hashFiles('lint-results/lint.diff') != '' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + PR_NUMBER: ${{ steps.identify-pr.outputs.number }} + TEST_RUN_ID: ${{ github.event.workflow_run.id }} + TEST_RUN_URL: ${{ github.event.workflow_run.html_url }} + run: | + LINT_JOB_URL=$(gh api --paginate "repos/$REPO/actions/runs/$TEST_RUN_ID/jobs" \ + --jq '.jobs[] | select(.name == "lint") | .html_url' | head -1) + LINT_JOB_URL=${LINT_JOB_URL:-$TEST_RUN_URL} + + BODY=" + The [lint check]($LINT_JOB_URL) found auto-fixable issues. Apply suggested changes (attributed to \`bcd-linter\`), or to fix all at once, run \`npm run lint:fix\` locally. + + See also: [Automated lint suggestions on pull requests](https://github.com/$REPO/blob/main/docs/testing.md#automated-lint-suggestions-on-pull-requests)" + + COMMENT_ID=$(gh api --paginate "repos/$REPO/issues/$PR_NUMBER/comments" \ + --jq '.[] | select(.user.login == "github-actions[bot]" and (.body | startswith(""))) | .id' | head -1) + + if [ -n "$COMMENT_ID" ]; then + gh api -X PATCH "repos/$REPO/issues/comments/$COMMENT_ID" -f body="$BODY" + else + gh api "repos/$REPO/issues/$PR_NUMBER/comments" -f body="$BODY" + fi + + - name: Mark status as success + if: success() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh api "$STATUS_PATH" \ + -f state=success \ + -f context="$STATUS_CONTEXT" \ + -f description='Successful' \ + -f target_url="$STATUS_TARGET" + + - name: Mark status as failure + if: failure() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh api "$STATUS_PATH" \ + -f state=failure \ + -f context="$STATUS_CONTEXT" \ + -f description='Failing' \ + -f target_url="$STATUS_TARGET" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 52441910783733..814d383bdbb643 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -55,7 +55,31 @@ jobs: - run: npm ci - - run: npm run lint -- --fail-on-warnings + - name: Lint + id: lint + run: npm run lint -- --fail-on-warnings + + - name: Fix lint issues + id: lint-fix + if: failure() && steps.lint.conclusion == 'failure' + run: | + npm run lint:fix + if [[ -n $(git diff) ]]; then + echo "files_modified=true" >> "$GITHUB_OUTPUT" + fi + + - name: Collect artifact files + if: failure() && steps.lint-fix.outputs.files_modified == 'true' + run: | + mkdir -p lint-results + git diff > lint-results/lint.diff + + - name: Upload artifact + if: failure() && steps.lint-fix.outputs.files_modified == 'true' + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: lint-results + path: lint-results test: runs-on: ubuntu-latest diff --git a/docs/testing.md b/docs/testing.md index be16403e705fa5..025d514ece3e40 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -22,6 +22,12 @@ For more information on the schema for feature data, see [`compat-data-schema.md For more information on the schema for browser data, see [`browsers-schema.md`](../schemas/browsers-schema.md) and [`browsers.schema.json`](../schemas/browsers.schema.json). +## Automated lint suggestions on pull requests + +When the lint check fails on a pull request, CI runs `npm run lint:fix` and posts the auto-fixable changes as inline review suggestions, attributed to `bcd-linter`. You can accept individual suggestions through GitHub's review UI, or apply all of them at once by running `npm run lint:fix` locally and committing the result. + +If a suggestion looks wrong (for example, the linter is reporting a false positive), reply on the suggestion explaining why — a maintainer can help. + ## Generate statistics To see how changes will affect the statistics of exact (formerly "real") and ranged values, you can run `npm run stats [folder]`. This generates a Markdown-formatted table of the percentages of exact and ranged values for the eight primary browsers that browser-compat-data is focusing on. The script also takes an optional argument regarding a specific folder (such as `api` or `javascript`), which will print statistics result for only that folder. Additionally, you can run the script with `--all` to get statistics for all browsers tracked in BCD, not just the primary eight.