diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 89d8d81a9ca0c..aadc572b76f6f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -85,3 +85,73 @@ jobs: # We want to ensure that static exports for all locales do not occur on `pull_request` events # TODO: The output of this is too large, and it crashes the GitHub Runner NEXT_PUBLIC_STATIC_EXPORT_LOCALE: false # ${{ github.event_name == 'push' }} + + compare-bundle-size: + name: Compare Bundle Size + runs-on: ubuntu-latest + needs: build + if: github.event_name == 'pull_request' + + steps: + - name: Harden Runner + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + + - name: Git Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Download Stats (HEAD) + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: webpack-stats + path: head-stats + + - name: Get Run ID from BASE + id: base-run + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + GH_TOKEN: ${{ github.token }} + run: | + ID=$(gh run list -c "$BASE_SHA" -w build.yml -s success -L 1 --json databaseId --jq ".[].databaseId") + echo "run_id=$ID" >> "$GITHUB_OUTPUT" + + - name: Download Stats (BASE) + id: base-stats + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: webpack-stats + path: base-stats + run-id: ${{ steps.base-run.outputs.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Compare Bundle Size + id: compare-bundle-size + if: steps.base-stats.outcome == 'success' + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + env: + HEAD_STATS_PATH: ./head-stats/webpack-stats.json + BASE_STATS_PATH: ./base-stats/webpack-stats.json + with: + script: | + const { compare } = await import('${{github.workspace}}/apps/site/scripts/compare-size/index.mjs') + await compare({core}) + + - name: Prepare Comment + if: steps.base-stats.outcome == 'success' + env: + COMMENT: ${{ steps.compare-bundle-size.outputs.comment }} + run: | + mkdir -p pr-comment + printf '%s' "$COMMENT" > pr-comment/comment.md + printf '%s' 'compare_bundle_size' > pr-comment/tag.txt + + - name: Upload Comment + if: steps.base-stats.outcome == 'success' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: pr-comment + path: pr-comment/ diff --git a/.github/workflows/bundle-compare.yml b/.github/workflows/bundle-compare.yml deleted file mode 100644 index d728c022cf30a..0000000000000 --- a/.github/workflows/bundle-compare.yml +++ /dev/null @@ -1,77 +0,0 @@ -name: Compare Bundle Size - -on: - workflow_run: - workflows: ['Build'] - types: [completed] - -permissions: - contents: read - actions: read - -concurrency: - group: ${{ github.workflow }}-${{ github.event.workflow_run.id }} - cancel-in-progress: true - -jobs: - compare: - name: Compare Bundle Stats - runs-on: ubuntu-latest - permissions: - # Required to comment on pull requests - pull-requests: write - if: github.event.workflow_run.event == 'pull_request' - - steps: - - name: Harden Runner - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 - with: - egress-policy: audit - - - name: Git Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - - name: Download Stats (HEAD) - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: webpack-stats - path: head-stats - run-id: ${{ github.event.workflow_run.id }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Get Run ID from BASE - id: base-run - env: - WORKFLOW_ID: ${{ github.event.workflow_run.workflow_id }} - GH_TOKEN: ${{ github.token }} - run: | - ID=$(gh run list -c $GITHUB_SHA -w $WORKFLOW_ID -L 1 --json databaseId --jq ".[].databaseId") - echo "run_id=$ID" >> $GITHUB_OUTPUT - - - name: Download Stats (BASE) - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: webpack-stats - path: base-stats - run-id: ${{ steps.base-run.outputs.run_id }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Compare Bundle Size - id: compare-bundle-size - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - HEAD_STATS_PATH: ./head-stats/webpack-stats.json - BASE_STATS_PATH: ./base-stats/webpack-stats.json - with: - script: | - const { compare } = await import('${{github.workspace}}/apps/site/scripts/compare-size/index.mjs') - await compare({core}) - - - name: Add Comment to PR - uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9 # v3.0.0 - with: - comment-tag: 'compare_bundle_size' - message: ${{ steps.compare-bundle-size.outputs.comment }} - pr-number: ${{ github.event.workflow_run.pull_requests[0].number }} diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml index 4092c4897d981..6283c73aceef4 100644 --- a/.github/workflows/chromatic.yml +++ b/.github/workflows/chromatic.yml @@ -14,14 +14,12 @@ on: paths: - packages/ui-components/** - .github/workflows/chromatic.yml - pull_request_target: + pull_request: branches: - main paths: - packages/ui-components/** - .github/workflows/chromatic.yml - types: - - labeled workflow_dispatch: defaults: @@ -42,9 +40,8 @@ jobs: # We only need to run Storybook Builds and Storybook Visual Regression Tests within Pull Requests that actually # introduce changes to the Storybook. Hence, we skip running these on Crowdin PRs and Dependabot PRs if: | - github.event_name != 'pull_request_target' || + github.event_name != 'pull_request' || ( - github.event.label.name == 'github_actions:pull-request' && github.actor != 'dependabot[bot]' && github.event.pull_request.head.ref != 'chore/crowdin' ) @@ -70,6 +67,6 @@ jobs: with: workingDir: packages/ui-components buildScriptName: storybook:build - projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + projectToken: ${{ vars.CHROMATIC_PROJECT_TOKEN }} exitOnceUploaded: true onlyChanged: true diff --git a/.github/workflows/leave-comment.yml b/.github/workflows/leave-comment.yml new file mode 100644 index 0000000000000..0b054af4d6983 --- /dev/null +++ b/.github/workflows/leave-comment.yml @@ -0,0 +1,89 @@ +name: Leave Comment + +on: + workflow_run: + # Any Workflow that uploads a `pr-comment` artifact should be listed here + workflows: ['Build', 'Lighthouse'] + types: [completed] + +permissions: + contents: read + actions: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.workflow_run.id }} + cancel-in-progress: true + +jobs: + leave-comment: + name: Leave Comment + runs-on: ubuntu-latest + permissions: + pull-requests: write + + steps: + - name: Harden Runner + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + + - name: Download Comment Artifact + # The Workflow may not have produced a comment (e.g. the comparison was skipped), so this is + # allowed to fail and every subsequent step is gated on it having succeeded. + id: download + continue-on-error: true + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: pr-comment + path: pr-comment + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Resolve Pull Request Number + id: pr + if: steps.download.outcome == 'success' + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + const run = context.payload.workflow_run; + + // 1. For same-repo Pull Requests the run is already linked to its PR(s). + if (run.pull_requests && run.pull_requests.length) { + core.setOutput('number', run.pull_requests[0].number); + return; + } + + // 2. For forks that list is empty, so find the open Pull Request whose HEAD SHA matches + // the commit that triggered the run. + const pulls = await github.paginate(github.rest.pulls.list, { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + per_page: 100, + }); + + const match = pulls.find(pull => pull.head.sha === run.head_sha); + + if (!match) { + core.info(`No open pull request found for HEAD ${run.head_sha}`); + return; + } + + core.setOutput('number', match.number); + + - name: Read Comment Tag + id: meta + if: steps.download.outcome == 'success' + run: | + tag="$(tr -cd 'A-Za-z0-9_-' < pr-comment/tag.txt)" + echo "tag=$tag" >> "$GITHUB_OUTPUT" + + - name: Add Comment to PR + # The comment body is untrusted markdown, so it is passed as a file (data) rather than + # interpolated into an expression or shell command. + if: steps.download.outcome == 'success' && steps.pr.outputs.number != '' + uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9 # v3.0.0 + with: + file-path: pr-comment/comment.md + comment-tag: ${{ steps.meta.outputs.tag }} + pr-number: ${{ steps.pr.outputs.number }} diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml index e7b0ad2b713b0..2eeca1e51227a 100644 --- a/.github/workflows/lighthouse.yml +++ b/.github/workflows/lighthouse.yml @@ -1,5 +1,7 @@ # Security Notes -# This workflow uses `pull_request_target`, so will run against all PRs automatically (without approval), be careful with allowing any user-provided code to be run here +# This Workflow runs in the untrusted `pull_request` context and therefore must not rely on any +# repository secrets. It does not comment on the Pull Request itself; instead it uploads a +# `pr-comment` artifact which the trusted `Leave Comment` Workflow posts once this Workflow completes. # Only selected Actions are allowed within this repository. Please refer to (https://github.com/nodejs/nodejs.org/settings/actions) # for the full list of available actions. If you want to add a new one, please reach out a maintainer with Admin permissions. # REVIEWERS, please always double-check security practices before merging a PR that contains Workflow changes!! @@ -9,7 +11,7 @@ name: Lighthouse on: - pull_request_target: + pull_request: branches: - main types: @@ -36,9 +38,6 @@ jobs: github.event.label.name == 'github_actions:pull-request' name: Lighthouse Report runs-on: ubuntu-latest - permissions: - # Required by `thollander/actions-comment-pull-request` - pull-requests: write steps: - name: Harden Runner @@ -55,21 +54,11 @@ jobs: check_interval: 10 # check every 10 seconds - name: Git Checkout + # Only needed for the Lighthouse formatting script; no credentials are persisted. uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - # Provides the Pull Request commit SHA or the GitHub merge group ref - ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.ref }} persist-credentials: false - - name: Add Comment to PR - # Signal that a lighthouse run is about to start - uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9 # v3.0.0 - with: - message: | - Running Lighthouse audit... - # Used later to edit the existing comment - comment-tag: 'lighthouse_audit' - - name: Audit Preview URL with Lighthouse # Conduct the lighthouse audit id: lighthouse_audit @@ -105,11 +94,16 @@ jobs: const { formatLighthouseResults } = await import('${{github.workspace}}/apps/site/scripts/lighthouse/index.mjs') await formatLighthouseResults({core}) - - name: Add Comment to PR - # Replace the previous message with our formatted lighthouse results - uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9 # v3.0.0 + - name: Prepare Comment + env: + COMMENT: ${{ steps.format_lighthouse_score.outputs.comment }} + run: | + mkdir -p pr-comment + printf '%s' "$COMMENT" > pr-comment/comment.md + printf '%s' 'lighthouse_audit' > pr-comment/tag.txt + + - name: Upload Comment + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - # Reference the previously created comment - comment-tag: 'lighthouse_audit' - message: | - ${{ steps.format_lighthouse_score.outputs.comment }} + name: pr-comment + path: pr-comment/