Action size: Add a PR check that comments on significant repo size changes #15450
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Checks | |
| on: | |
| push: | |
| pull_request: | |
| # Run checks on reopened draft PRs to support triggering PR checks on draft PRs that were opened | |
| # by other workflows. | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| merge_group: | |
| types: [checks_requested] | |
| workflow_dispatch: | |
| defaults: | |
| run: | |
| shell: bash | |
| jobs: | |
| unit-tests: | |
| name: Unit Tests | |
| if: github.triggering_actor != 'dependabot[bot]' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| node-version: [20, 24] | |
| permissions: | |
| contents: read | |
| security-events: write # needed to upload ESLint results | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 45 | |
| concurrency: | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' || false }} | |
| group: pr-checks-unit-tests-${{ github.ref }}-${{ github.event_name }}-${{ matrix.os }}-node${{ matrix['node-version'] }} | |
| steps: | |
| - name: Prepare git (Windows) | |
| if: runner.os == 'Windows' | |
| run: git config --global core.autocrlf false | |
| - uses: actions/checkout@v6 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ matrix.node-version }} | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: | | |
| # Use the system Bash shell to ensure we can run commands like `npm ci` | |
| # that are not available in the default shell on Windows. | |
| npm config set script-shell bash | |
| npm ci | |
| - name: Verify compiled JS up to date | |
| run: .github/workflows/script/check-js.sh | |
| - name: Run unit tests | |
| if: always() | |
| run: npm test | |
| - name: Lint | |
| if: always() && matrix.os != 'windows-latest' | |
| run: npm run lint-ci | |
| - name: Upload sarif | |
| uses: github/codeql-action/upload-sarif@v4 | |
| if: matrix.os == 'ubuntu-latest' && matrix.node-version == 24 | |
| with: | |
| sarif_file: eslint.sarif | |
| category: eslint | |
| # These checks do not need to be run as part of the same matrix that we use for the `unit-tests` | |
| # job. | |
| pr-checks: | |
| name: PR Checks | |
| if: github.triggering_actor != 'dependabot[bot]' | |
| permissions: | |
| contents: read | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| concurrency: | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' || false }} | |
| group: pr-checks-pr-checks-${{ github.ref }}-${{ github.event_name }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24 | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Verify PR checks up to date | |
| run: .github/workflows/script/verify-pr-checks.sh | |
| - name: Run pr-checks tests | |
| working-directory: pr-checks | |
| run: npx tsx --test | |
| - name: Verify all Actions use the same Node version | |
| id: head-version | |
| run: | | |
| NODE_VERSION=$(find . -path "*/node_modules" -prune -o -name "action.yml" -exec yq -o=json '.runs.using' {} \; | jq -rs '[.[] | select(. != null and startswith("node"))] | unique | .[]') | |
| echo "NODE_VERSION: ${NODE_VERSION}" | |
| if [[ $(echo "$NODE_VERSION" | wc -l) -gt 1 ]]; then | |
| echo "::error::More than one node version used in 'action.yml' files." | |
| exit 1 | |
| fi | |
| echo "node_version=${NODE_VERSION}" >> $GITHUB_OUTPUT | |
| - name: Fetch base commit | |
| # Forks and Dependabot PRs don't have permission to write comments, so skip the repo size | |
| # check in those cases. | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| github.event.pull_request.head.repo.full_name == github.repository && | |
| github.event.pull_request.user.login != 'dependabot[bot]' | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| run: git fetch --no-tags --depth=1 origin "$BASE_SHA" | |
| - name: Check repo size | |
| # Forks and Dependabot PRs don't have permission to write comments, so skip the repo size | |
| # check in those cases. | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| github.event.pull_request.head.repo.full_name == github.repository && | |
| github.event.pull_request.user.login != 'dependabot[bot]' | |
| working-directory: pr-checks | |
| env: | |
| BASE_REF: ${{ github.event.pull_request.base.ref }} | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| run: npx tsx check-repo-size.ts --output-dir "$RUNNER_TEMP/repo-size" | |
| - name: Upload repo size comment | |
| # Forks and Dependabot PRs don't have permission to write comments, so skip the repo size | |
| # check in those cases. | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| github.event.pull_request.head.repo.full_name == github.repository && | |
| github.event.pull_request.user.login != 'dependabot[bot]' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: repo-size-comment | |
| path: ${{ runner.temp }}/repo-size/ | |
| if-no-files-found: error | |
| - name: 'Backport: Check out base ref' | |
| id: checkout-base | |
| if: ${{ startsWith(github.head_ref, 'backport-') }} | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.base_ref }} | |
| - name: 'Backport: Verify Node versions unchanged' | |
| if: steps.checkout-base.outcome == 'success' | |
| env: | |
| HEAD_VERSION: ${{ steps.head-version.outputs.node_version }} | |
| run: | | |
| BASE_VERSION=$(find . -path "*/node_modules" -prune -o -name "action.yml" -exec yq -o=json '.runs.using' {} \; | jq -rs '[.[] | select(. != null and startswith("node"))] | unique | .[]') | |
| echo "HEAD_VERSION: ${HEAD_VERSION}" | |
| echo "BASE_VERSION: ${BASE_VERSION}" | |
| if [[ "$BASE_VERSION" != "$HEAD_VERSION" ]]; then | |
| echo "::error::Cannot change the Node version of an Action in a backport PR." | |
| exit 1 | |
| fi | |
| post-repo-size-comment: | |
| name: Post repo size comment | |
| needs: pr-checks | |
| # Keep write permissions isolated from the job that checks out and tests PR code. This job only | |
| # posts the candidate comment body produced by the read-only `pr-checks` job. | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| github.event.pull_request.head.repo.full_name == github.repository && | |
| github.event.pull_request.user.login != 'dependabot[bot]' && | |
| needs.pr-checks.result == 'success' | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 10 | |
| concurrency: | |
| cancel-in-progress: true | |
| group: check-repo-size-${{ github.event.pull_request.number }} | |
| steps: | |
| - name: Download repo size comment | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: repo-size-comment | |
| path: repo-size-comment | |
| - name: Post repo size comment | |
| env: | |
| COMMENT_MARKER: "<!-- repo-size-diff-bot -->" | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| run: | | |
| significant=$(jq -r '.significant' repo-size-comment/metadata.json) | |
| comment_id=$( | |
| gh api "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments" \ | |
| --paginate \ | |
| --jq ".[] | select(.body | contains(\"$COMMENT_MARKER\")) | .id" \ | |
| | head -n 1 | |
| ) | |
| if [[ -n "$comment_id" ]]; then | |
| echo "Updating existing comment $comment_id." | |
| gh api --method PATCH "repos/$GITHUB_REPOSITORY/issues/comments/$comment_id" --field body=@repo-size-comment/body.md | |
| elif [[ "$significant" == "true" ]]; then | |
| echo "Creating new repo size comment." | |
| gh api --method POST "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments" --field body=@repo-size-comment/body.md | |
| else | |
| echo "Skipping repo size comment because the delta is below the threshold and no sticky comment exists." | |
| fi |