diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b28106857b..e63de19c73 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -29,7 +29,6 @@ jobs: 'typecheck:ios', 'typecheck:android', 'typecheck:web', - 'react-compiler:report', ] steps: - name: ⬇️ Check out Git repository diff --git a/.github/workflows/react-compiler-report.yml b/.github/workflows/react-compiler-report.yml new file mode 100644 index 0000000000..a26b90eecb --- /dev/null +++ b/.github/workflows/react-compiler-report.yml @@ -0,0 +1,43 @@ +name: React Compiler report + +on: + pull_request: + +concurrency: + group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}' + cancel-in-progress: true + +# Permissions are granted per-job below; anything unlisted defaults to none. +permissions: {} + +jobs: + report: + name: React Compiler report + runs-on: ubuntu-latest + # Fork guard: posting the sticky comment needs pull-requests: write, which + # the GITHUB_TOKEN of a fork-originated run never gets. + if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} + permissions: + contents: read + # Needed by sticky-pull-request-comment to post the report. + pull-requests: write + steps: + - name: ⬇️ Check out Git repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10 + - name: 🔧 Install node + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version-file: package.json + cache: pnpm + - name: 📦 pnpm install + run: pnpm install --frozen-lockfile + - name: ⚛️ Generate React Compiler report + env: + REACT_COMPILER_REPORT_PATH: ${{ runner.temp }}/react-compiler-report.md + run: pnpm react-compiler:report + - name: 💬 Drop a comment + uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5 + with: + header: react-compiler-report + path: ${{ runner.temp }}/react-compiler-report.md diff --git a/scripts/README.md b/scripts/README.md index a9e84db653..4edb471872 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -4,7 +4,8 @@ Reports which components and hooks React Compiler skipped optimizing, grouped by the compiler's own diagnostic category. Run with `pnpm react-compiler:report`; -also runs in the Lint workflow, where it writes the report to the job summary. +the React Compiler report workflow also runs it on every pull request and posts +the report as a sticky PR comment. ## updateExtensions.sh diff --git a/scripts/react-compiler-report.ts b/scripts/react-compiler-report.ts index f497a0675c..a59e6e1402 100755 --- a/scripts/react-compiler-report.ts +++ b/scripts/react-compiler-report.ts @@ -21,11 +21,19 @@ * Runs under Node's type stripping, so keep the syntax erasable - no enums, no * namespaces, and type-only imports must say `import type`. * - * Prints the same report to stdout and, under GitHub Actions, to the job - * summary. Always exits 0 - this is a metric, not a gate. + * Prints the report to stdout, and writes a markdown version to the job + * summary under GitHub Actions and to REACT_COMPILER_REPORT_PATH when set + * (the React Compiler report workflow posts that file as a sticky PR + * comment). Always exits 0 - this is a metric, not a gate. */ -import {appendFileSync, readdirSync, readFileSync, statSync} from 'node:fs' +import { + appendFileSync, + readdirSync, + readFileSync, + statSync, + writeFileSync, +} from 'node:fs' import {dirname, join, relative, resolve} from 'node:path' import {fileURLToPath} from 'node:url' @@ -179,40 +187,44 @@ for (const [file, message] of unreadable) { ) } +/* + * The markdown report goes to the job summary when running under GitHub + * Actions, and to REACT_COMPILER_REPORT_PATH when set - the React Compiler + * report workflow posts that file as a sticky PR comment. + */ const summaryPath = process.env.GITHUB_STEP_SUMMARY -if (summaryPath) { - appendFileSync( - summaryPath, - [ - `## React Compiler`, - ``, - `**${headline}** ${subhead}`, - ``, - `| category | severity | components and hooks |`, - `| --- | --- | --- |`, - ...ranked.map( - ([category, {severity, count}]) => - `| ${category} | ${severity} | ${count} |`, +const reportPath = process.env.REACT_COMPILER_REPORT_PATH +if (summaryPath || reportPath) { + const markdown = [ + `## React Compiler`, + ``, + `**${headline}** ${subhead}`, + ``, + `| category | severity | components and hooks |`, + `| --- | --- | --- |`, + ...ranked.map( + ([category, {severity, count}]) => + `| ${category} | ${severity} | ${count} |`, + ), + ``, + `\`Hint\` is a \`Todo\`: syntax React Compiler does not support yet.`, + `\`Error\` is code the compiler cannot safely optimize.`, + ``, + `
All ${rows.length + optedOut.size} skipped components and hooks`, + ``, + ...rows.map( + ([key, diagnostics]) => + `- \`${key}\` - ${diagnostics.map(d => `${d.category}: ${d.reason}`).join('; ')}`, + ), + ...[...optedOut] + .sort() + .map( + key => `- \`${key}\` - CompileSkip: opted out via ${OPT_OUT_DIRECTIVE}`, ), - ``, - `\`Hint\` is a \`Todo\`: syntax React Compiler does not support yet.`, - `\`Error\` is code the compiler cannot safely optimize.`, - ``, - `
All ${rows.length + optedOut.size} skipped components and hooks`, - ``, - ...rows.map( - ([key, diagnostics]) => - `- \`${key}\` - ${diagnostics.map(d => `${d.category}: ${d.reason}`).join('; ')}`, - ), - ...[...optedOut] - .sort() - .map( - key => - `- \`${key}\` - CompileSkip: opted out via ${OPT_OUT_DIRECTIVE}`, - ), - ``, - `
`, - ``, - ].join('\n'), - ) + ``, + `
`, + ``, + ].join('\n') + if (summaryPath) appendFileSync(summaryPath, markdown) + if (reportPath) writeFileSync(reportPath, markdown) }