facebook/react

24 workflows · maturity 67% · 10 patterns · GitHub ↗

Security 45/100

Practices

✓ Matrix✓ Permissions○ Security scan○ AI review✓ Cache✓ Concurrency✓ Reusable workflows

Detected patterns

Security dimensions

permissions
25
security scan
0
supply chain
20
secret handling
0
harden runner
0

Workflows (24)

compiler_discord_notify perms .github/workflows/compiler_discord_notify.yml
Triggers
pull_request_target
Runs on
ubuntu-latest, ubuntu-latest
Jobs
check_access, check_maintainer, notify
Actions
tsickert/discord-webhook
Commands
  • echo ${{ github.event.pull_request.author_association }}
  • echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"
View raw YAML
name: (Compiler) Discord Notify

on:
  pull_request_target:
    types: [opened, ready_for_review]
    paths:
      - compiler/**
      - .github/workflows/compiler_**.yml

permissions: {}

jobs:
  check_access:
    if: ${{ github.event.pull_request.draft == false }}
    runs-on: ubuntu-latest
    outputs:
      is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }}
    steps:
      - run: echo ${{ github.event.pull_request.author_association }}
      - name: Check is member or collaborator
        id: check_is_member_or_collaborator
        if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }}
        run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"

  check_maintainer:
    if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }}
    needs: [check_access]
    uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main
    permissions:
      # Used by check_maintainer
      contents: read
    with:
      actor: ${{ github.event.pull_request.user.login }}

  notify:
    if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }}
    needs: check_maintainer
    runs-on: ubuntu-latest
    steps:
      - name: Discord Webhook Action
        uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
        with:
          webhook-url: ${{ secrets.COMPILER_DISCORD_WEBHOOK_URL }}
          embed-author-name: ${{ github.event.pull_request.user.login }}
          embed-author-url: ${{ github.event.pull_request.user.html_url }}
          embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }}
          embed-title: '#${{ github.event.number }} (+${{github.event.pull_request.additions}} -${{github.event.pull_request.deletions}}): ${{ github.event.pull_request.title }}'
          embed-description: ${{ github.event.pull_request.body }}
          embed-url: ${{ github.event.pull_request.html_url }}
compiler_playground perms .github/workflows/compiler_playground.yml
Triggers
push, pull_request
Runs on
ubuntu-latest
Jobs
playground
Commands
  • yarn install --frozen-lockfile
  • yarn install --frozen-lockfile
  • echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT"
  • npx playwright install --with-deps chromium
  • CI=true yarn test
  • ls -R test-results
View raw YAML
name: (Compiler) Playground

on:
  push:
    branches: [main]
  pull_request:
    paths:
      - compiler/**
      - .github/workflows/compiler_playground.yml

permissions: {}

concurrency:
  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
  cancel-in-progress: true

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1

defaults:
  run:
    working-directory: compiler/apps/playground

jobs:
  playground:
    name: Test playground
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: compiler/**/yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: compiler-and-playground-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
        working-directory: compiler
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Check Playwright version
        id: playwright_version
        run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT"
      - name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }}
        id: cache_playwright_browsers
        uses: actions/cache@v4
        with:
          path: ~/.cache/ms-playwright
          key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }}
      - run: npx playwright install --with-deps chromium
        if: steps.cache_playwright_browsers.outputs.cache-hit != 'true'
      - run: CI=true yarn test
      - run: ls -R test-results
        if: '!cancelled()'
      - name: Archive test results
        if: '!cancelled()'
        uses: actions/upload-artifact@v4
        with:
          name: test-results
          path: compiler/apps/playground/test-results
          if-no-files-found: ignore
compiler_prereleases perms .github/workflows/compiler_prereleases.yml
Triggers
workflow_call
Runs on
ubuntu-latest
Jobs
publish_prerelease
Commands
  • yarn install --frozen-lockfile
  • cp ./scripts/release/ci-npmrc ~/.npmrc scripts/release/publish.js --frfr --debug --ci --versionName=${{ inputs.version_name }} --tag=${{ inputs.dist_tag }} ${{ inputs.tag_version && format('--tagVersion={0}', inputs.tag_version) || '' }}
  • cp ./scripts/release/ci-npmrc ~/.npmrc scripts/release/publish.js --frfr --ci --versionName=${{ inputs.version_name }} --tag=${{ inputs.dist_tag }} ${{ inputs.tag_version && format('--tagVersion={0}', inputs.tag_version) || '' }}
View raw YAML
name: (Compiler) Publish Prereleases

on:
  workflow_call:
    inputs:
      commit_sha:
        required: true
        default: ''
        type: string
      release_channel:
        required: true
        type: string
      dist_tag:
        required: true
        type: string
      version_name:
        required: true
        type: string
      tag_version:
        required: false
        type: string
      dry_run:
        required: false
        type: boolean
    secrets:
      NPM_TOKEN:
        required: true

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

defaults:
  run:
    working-directory: compiler

jobs:
  publish_prerelease:
    name: Publish prelease (${{ inputs.release_channel }}) ${{ inputs.commit_sha }} @${{ inputs.dist_tag }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: compiler/yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - if: inputs.dry_run == true
        name: Publish packages to npm (dry run)
        run: |
          cp ./scripts/release/ci-npmrc ~/.npmrc
          scripts/release/publish.js --frfr --debug --ci --versionName=${{ inputs.version_name }} --tag=${{ inputs.dist_tag }} ${{ inputs.tag_version && format('--tagVersion={0}', inputs.tag_version) || '' }}
      - if: inputs.dry_run != true
        name: Publish packages to npm
        run: |
          cp ./scripts/release/ci-npmrc ~/.npmrc
          scripts/release/publish.js --frfr --ci --versionName=${{ inputs.version_name }} --tag=${{ inputs.dist_tag }} ${{ inputs.tag_version && format('--tagVersion={0}', inputs.tag_version) || '' }}
compiler_prereleases_manual perms .github/workflows/compiler_prereleases_manual.yml
Triggers
workflow_dispatch
Runs on
Jobs
publish_prerelease_experimental
View raw YAML
name: (Compiler) Publish Prereleases Manual

on:
  workflow_dispatch:
    inputs:
      prerelease_commit_sha:
        required: false
      release_channel:
        required: true
        type: string
      dist_tag:
        required: true
        type: string
      version_name:
        required: true
        type: string
      tag_version:
        required: false
        type: string
      dry_run:
        required: false
        type: boolean

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles

jobs:
  publish_prerelease_experimental:
    name: Publish to Experimental channel
    uses: facebook/react/.github/workflows/compiler_prereleases.yml@main
    with:
      commit_sha: ${{ inputs.prerelease_commit_sha || github.sha }}
      release_channel: ${{ inputs.release_channel }}
      dist_tag: ${{ inputs.dist_tag }}
      version_name: ${{ inputs.version_name }}
      tag_version: ${{ inputs.tag_version }}
      dry_run: ${{ inputs.dry_run }}
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
compiler_prereleases_nightly perms .github/workflows/compiler_prereleases_nightly.yml
Triggers
schedule
Runs on
Jobs
publish_prerelease_experimental
View raw YAML
name: (Compiler) Publish Prereleases Nightly

on:
  schedule:
    # At 10 minutes past 16:00 on Mon, Tue, Wed, Thu, and Fri
    - cron: 10 16 * * 1,2,3,4,5

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles

jobs:
  publish_prerelease_experimental:
    name: Publish to Experimental channel
    uses: facebook/react/.github/workflows/compiler_prereleases.yml@main
    with:
      commit_sha: ${{ github.sha }}
      release_channel: experimental
      dist_tag: experimental
      version_name: '0.0.0'
      dry_run: false
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
compiler_typescript matrix perms .github/workflows/compiler_typescript.yml
Triggers
push, pull_request
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
discover_yarn_workspaces, lint, jest, test
Matrix
workspace_name→ ${{ fromJSON(needs.discover_yarn_workspaces.outputs.matrix) }}
Commands
  • echo "matrix=$(find packages -mindepth 1 -maxdepth 1 -type d | sed 's!packages/!!g' | tr '\n' ',' | sed s/.$// | jq -Rsc '. / "," - [""]')" >> $GITHUB_OUTPUT
  • yarn install --frozen-lockfile
  • yarn workspace babel-plugin-react-compiler lint
  • yarn install --frozen-lockfile
  • yarn workspace babel-plugin-react-compiler jest
  • yarn install --frozen-lockfile
  • xvfb-run -a yarn workspace ${{ matrix.workspace_name }} test
  • yarn workspace ${{ matrix.workspace_name }} test
View raw YAML
name: (Compiler) TypeScript

on:
  push:
    branches: [main]
  pull_request:
    paths:
      - compiler/**
      - .github/workflows/compiler_typescript.yml

permissions: {}

concurrency:
  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
  cancel-in-progress: true

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1

defaults:
  run:
    working-directory: compiler

jobs:
  discover_yarn_workspaces:
    name: Discover yarn workspaces
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - uses: actions/checkout@v4
      - id: set-matrix
        run: echo "matrix=$(find packages -mindepth 1 -maxdepth 1 -type d | sed 's!packages/!!g' | tr '\n' ',' | sed s/.$// | jq -Rsc '. / "," - [""]')" >> $GITHUB_OUTPUT

  # Hardcoded to improve parallelism
  lint:
    name: Lint babel-plugin-react-compiler
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: compiler/yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn workspace babel-plugin-react-compiler lint

  # Hardcoded to improve parallelism
  jest:
    name: Jest babel-plugin-react-compiler
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: compiler/yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn workspace babel-plugin-react-compiler jest

  test:
    name: Test ${{ matrix.workspace_name }}
    needs: discover_yarn_workspaces
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        workspace_name: ${{ fromJSON(needs.discover_yarn_workspaces.outputs.matrix) }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: compiler/yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: xvfb-run -a yarn workspace ${{ matrix.workspace_name }} test
        if: runner.os == 'Linux' && matrix.workspace_name == 'react-forgive'
      - run: yarn workspace ${{ matrix.workspace_name }} test
        if: matrix.workspace_name != 'react-forgive'
devtools_discord_notify perms .github/workflows/devtools_discord_notify.yml
Triggers
pull_request_target
Runs on
ubuntu-latest, ubuntu-latest
Jobs
check_access, check_maintainer, notify
Actions
tsickert/discord-webhook
Commands
  • echo ${{ github.event.pull_request.author_association }}
  • echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"
View raw YAML
name: (DevTools) Discord Notify

on:
  pull_request_target:
    types: [opened, ready_for_review]
    paths:
      - packages/react-devtools**
      - .github/workflows/devtools_**.yml

permissions: {}

jobs:
  check_access:
    if: ${{ github.event.pull_request.draft == false }}
    runs-on: ubuntu-latest
    outputs:
      is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }}
    steps:
      - run: echo ${{ github.event.pull_request.author_association }}
      - name: Check is member or collaborator
        id: check_is_member_or_collaborator
        if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }}
        run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"

  check_maintainer:
    if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }}
    needs: [check_access]
    uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main
    permissions:
      # Used by check_maintainer
      contents: read
    with:
      actor: ${{ github.event.pull_request.user.login }}

  notify:
    if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }}
    needs: check_maintainer
    runs-on: ubuntu-latest
    steps:
      - name: Discord Webhook Action
        uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
        with:
          webhook-url: ${{ secrets.DEVTOOLS_DISCORD_WEBHOOK_URL }}
          embed-author-name: ${{ github.event.pull_request.user.login }}
          embed-author-url: ${{ github.event.pull_request.user.html_url }}
          embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }}
          embed-title: '#${{ github.event.number }} (+${{github.event.pull_request.additions}} -${{github.event.pull_request.deletions}}): ${{ github.event.pull_request.title }}'
          embed-description: ${{ github.event.pull_request.body }}
          embed-url: ${{ github.event.pull_request.html_url }}
devtools_regression_tests matrix perms .github/workflows/devtools_regression_tests.yml
Triggers
schedule, workflow_dispatch
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
download_build, build_devtools_and_process_artifacts, run_devtools_tests_for_versions, run_devtools_e2e_tests_for_versions
Matrix
version→ 16.0, 16.5, 16.8, 17.0, 18.0, 18.2
Commands
  • rm -rf build
  • yarn install --frozen-lockfile
  • yarn --cwd scripts/release install --frozen-lockfile
  • git fetch origin main GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || '$(git rev-parse origin/main)' }}
  • ls -R build
  • rm -rf build
  • yarn install --frozen-lockfile
  • ./scripts/ci/pack_and_store_devtools_artifacts.sh
View raw YAML
name: (DevTools) Regression Tests

on:
  schedule:
    - cron: 0 0 * * *
  workflow_dispatch:
    inputs:
      commit_sha:
        required: false
        type: string

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1

jobs:
  download_build:
    name: Download base build
    runs-on: ubuntu-latest
    permissions:
      # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
      actions: read
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn --cwd scripts/release install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Download react-devtools artifacts for base revision
        run: |
          git fetch origin main
          GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || '$(git rev-parse origin/main)' }}
      - name: Display structure of build
        run: ls -R build
      - name: Archive build
        uses: actions/upload-artifact@v4
        with:
          name: build
          path: build
          if-no-files-found: error

  build_devtools_and_process_artifacts:
    name: Build DevTools and process artifacts
    needs: download_build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Restore archived build
        uses: actions/download-artifact@v4
        with:
          name: build
          path: build
      - run: ./scripts/ci/pack_and_store_devtools_artifacts.sh
        env:
          RELEASE_CHANNEL: experimental
      - name: Display structure of build
        run: ls -R build
      - name: Archive devtools build
        uses: actions/upload-artifact@v4
        with:
          name: react-devtools
          path: build/devtools
          if-no-files-found: error
      # Simplifies getting the extension for local testing
      - name: Archive chrome extension
        uses: actions/upload-artifact@v4
        with:
          name: react-devtools-chrome-extension
          path: build/devtools/chrome-extension.zip
          if-no-files-found: error
      - name: Archive firefox extension
        uses: actions/upload-artifact@v4
        with:
          name: react-devtools-firefox-extension
          path: build/devtools/firefox-extension.zip
          if-no-files-found: error

  run_devtools_tests_for_versions:
    name: Run DevTools tests for versions
    needs: build_devtools_and_process_artifacts
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        version:
          - "16.0"
          - "16.5" # schedule package
          - "16.8" # hooks
          - "17.0"
          - "18.0"
          - "18.2" # compiler polyfill
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Restore all archived build artifacts
        uses: actions/download-artifact@v4
      - name: Display structure of build
        run: ls -R build
      - run: ./scripts/ci/download_devtools_regression_build.js ${{ matrix.version }} --replaceBuild
      - run: node ./scripts/jest/jest-cli.js --build --project devtools --release-channel=experimental --reactVersion ${{ matrix.version }} --ci

  run_devtools_e2e_tests_for_versions:
    name: Run DevTools e2e tests for versions
    needs: build_devtools_and_process_artifacts
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        version:
          - "16.0"
          - "16.5" # schedule package
          - "16.8" # hooks
          - "17.0"
          - "18.0"
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Restore all archived build artifacts
        uses: actions/download-artifact@v4
      - name: Display structure of build
        run: ls -R build
      - name: Check Playwright version
        id: playwright_version
        run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT"
      - name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }}
        id: cache_playwright_browsers
        uses: actions/cache@v4
        with:
          path: ~/.cache/ms-playwright
          key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }}
      - run: npx playwright install --with-deps
        if: steps.cache_playwright_browsers.outputs.cache-hit != 'true'
      - run: npx playwright install-deps
        if: steps.cache_playwright_browsers.outputs.cache-hit == 'true'
      - run: ./scripts/ci/download_devtools_regression_build.js ${{ matrix.version }}
      - run: ls -R build-regression
      - run: ./scripts/ci/run_devtools_e2e_tests.js ${{ matrix.version }}
        env:
          RELEASE_CHANNEL: experimental
      - name: Cleanup build regression folder
        run: rm -r ./build-regression
      - uses: actions/upload-artifact@v4
        with:
          name: screenshots
          path: ./tmp/playwright-artifacts
          if-no-files-found: warn
runtime_build_and_test matrix perms .github/workflows/runtime_build_and_test.yml
Triggers
push, pull_request, workflow_dispatch
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
runtime_node_modules_cache, runtime_compiler_node_modules_cache, discover_flow_inline_configs, flow, check_generated_fizz_runtime, flags, test, test-linter, build_and_lint, test_build, test_build_devtools, process_artifacts_combined, check_error_codes, check_release_dependencies, RELEASE_CHANNEL_stable_yarn_test_dom_fixtures, run_fixtures_flight_tests, build_devtools_and_process_artifacts, merge_devtools_artifacts, run_devtools_e2e_tests, sizebot
Matrix
browser, flow_inline_config_shortname, params, release_channel, shard, test_params, worker_id→ ${{ fromJSON(needs.discover_flow_inline_configs.outputs.matrix) }}, -r=experimental --env=development, -r=experimental --env=development --persistent, -r=experimental --env=production, -r=stable --env=development, -r=stable --env=development --persistent, -r=stable --env=production, -r=www-classic --env=development --variant=false, -r=www-classic --env=development --variant=true, -r=www-classic --env=production --variant=false, -r=www-classic --env=production --variant=true, -r=www-modern --env=development --variant=false, -r=www-modern --env=development --variant=true, -r=www-modern --env=production --variant=false, -r=www-modern --env=production --variant=true, -r=xplat --env=development --variant=false, -r=xplat --env=development --variant=true, -r=xplat --env=production --variant=false, -r=xplat --env=production --variant=true, 0, 1, 1/10, 1/5, 10, 10/10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 2/10, 2/5, 20, 21, 22, 23, 24, 3, 3/10, 3/5, 4, 4/10, 4/5, 5, 5/10, 5/5, 6, 6/10, 7, 7/10, 8, 8/10, 9, 9/10, chrome, edge, experimental, firefox, stable
Actions
actions/attest-build-provenance, actions/upload-artifact/merge
Commands
  • yarn install --frozen-lockfile
  • yarn install --frozen-lockfile
  • yarn --cwd compiler install --frozen-lockfile
  • rm -rf build
  • yarn install --frozen-lockfile
  • node ./scripts/tasks/flow-ci ${{ matrix.flow_inline_config_shortname }}
  • rm -rf build
  • yarn install --frozen-lockfile
View raw YAML
name: (Runtime) Build and Test

on:
  push:
    branches: [main]
    tags:
      # To get CI for backport releases.
      # This will duplicate CI for releases from main which is acceptable
      - "v*"
  pull_request:
    paths-ignore:
      - compiler/**
  workflow_dispatch:
    inputs:
      commit_sha:
        required: false
        type: string
        default: ''

permissions: {}

concurrency:
  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
  cancel-in-progress: true

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1

jobs:
  # ----- NODE_MODULES CACHE -----
  # Centralize the node_modules cache so it is saved once and each subsequent job only needs to
  # restore the cache. Prevents race conditions where multiple workflows try to write to the cache.
  runtime_node_modules_cache:
    name: Cache Runtime node_modules
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - name: Check cache hit
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
          lookup-only: true
      - uses: actions/setup-node@v4
        if: steps.node_modules.outputs.cache-hit != 'true'
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Warm with old cache
        if: steps.node_modules.outputs.cache-hit != 'true'
        uses: actions/cache/restore@v4
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Save cache
        if: steps.node_modules.outputs.cache-hit != 'true'
        uses: actions/cache/save@v4
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}

  runtime_compiler_node_modules_cache:
    name: Cache Runtime, Compiler node_modules
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - name: Check cache hit
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-and-compiler-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
          lookup-only: true
      - uses: actions/setup-node@v4
        if: steps.node_modules.outputs.cache-hit != 'true'
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: |
            yarn.lock
            compiler/yarn.lock
      - name: Warm with old cache
        if: steps.node_modules.outputs.cache-hit != 'true'
        uses: actions/cache/restore@v4
        with:
          path: |
            **/node_modules
          key: runtime-and-compiler-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn --cwd compiler install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Save cache
        if: steps.node_modules.outputs.cache-hit != 'true'
        uses: actions/cache/save@v4
        with:
          path: |
            **/node_modules
          key: runtime-and-compiler-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}

  # ----- FLOW -----
  discover_flow_inline_configs:
    name: Discover flow inline configs
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.result }}
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/github-script@v7
        id: set-matrix
        with:
          script: |
            const inlinedHostConfigs = require('./scripts/shared/inlinedHostConfigs.js');
            return inlinedHostConfigs.map(config => config.shortName);

  flow:
    name: Flow check ${{ matrix.flow_inline_config_shortname }}
    needs: [discover_flow_inline_configs, runtime_node_modules_cache]
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        flow_inline_config_shortname: ${{ fromJSON(needs.discover_flow_inline_configs.outputs.matrix) }}
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: node ./scripts/tasks/flow-ci ${{ matrix.flow_inline_config_shortname }}

  # ----- FIZZ -----
  check_generated_fizz_runtime:
    name: Confirm generated inline Fizz runtime is up to date
    needs: [runtime_node_modules_cache]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: |
          yarn generate-inline-fizz-runtime
          git diff --exit-code || (echo "There was a change to the Fizz runtime. Run \`yarn generate-inline-fizz-runtime\` and check in the result." && false)

  # ----- FEATURE FLAGS -----
  flags:
    name: Check flags
    needs: [runtime_node_modules_cache]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn flags

  # ----- TESTS -----
  test:
    name: yarn test ${{ matrix.params }} (Shard ${{ matrix.shard }})
    needs: [runtime_compiler_node_modules_cache]
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        params:
          - "-r=stable --env=development"
          - "-r=stable --env=production"
          - "-r=experimental --env=development"
          - "-r=experimental --env=production"
          - "-r=www-classic --env=development --variant=false"
          - "-r=www-classic --env=production --variant=false"
          - "-r=www-classic --env=development --variant=true"
          - "-r=www-classic --env=production --variant=true"
          - "-r=www-modern --env=development --variant=false"
          - "-r=www-modern --env=production --variant=false"
          - "-r=www-modern --env=development --variant=true"
          - "-r=www-modern --env=production --variant=true"
          - "-r=xplat --env=development --variant=false"
          - "-r=xplat --env=development --variant=true"
          - "-r=xplat --env=production --variant=false"
          - "-r=xplat --env=production --variant=true"
          # TODO: Test more persistent configurations?
          - "-r=stable --env=development --persistent"
          - "-r=experimental --env=development --persistent"
        shard:
          - 1/5
          - 2/5
          - 3/5
          - 4/5
          - 5/5
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: |
            yarn.lock
            compiler/yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-and-compiler-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn --cwd compiler install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: node --version
      - run: yarn test ${{ matrix.params }} --ci --shard=${{ matrix.shard }}

  # Hardcoded to improve parallelism
  test-linter:
    name: Test eslint-plugin-react-hooks
    needs: [runtime_compiler_node_modules_cache]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path:  |
            yarn.lock
            compiler/yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-and-compiler-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
      - name: Install runtime dependencies
        run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Install compiler dependencies
        run: yarn install --frozen-lockfile
        working-directory: compiler
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: ./scripts/react-compiler/build-compiler.sh && ./scripts/react-compiler/link-compiler.sh
      - run: yarn workspace eslint-plugin-react-hooks test

  # ----- BUILD -----
  build_and_lint:
    name: yarn build and lint
    needs: [runtime_compiler_node_modules_cache]
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        # yml is dumb. update the --total arg to yarn build if you change the number of workers
        worker_id: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
        release_channel: [stable, experimental]
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: |
            yarn.lock
            compiler/yarn.lock
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: 11.0.22
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-and-compiler-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn --cwd compiler install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn build --index=${{ matrix.worker_id }} --total=25 --r=${{ matrix.release_channel }} --ci
        env:
          CI: github
          RELEASE_CHANNEL: ${{ matrix.release_channel }}
          NODE_INDEX: ${{ matrix.worker_id }}
      - name: Lint build
        run: yarn lint-build
      - name: Display structure of build
        run: ls -R build
      - name: Archive build
        uses: actions/upload-artifact@v4
        with:
          name: _build_${{ matrix.worker_id }}_${{ matrix.release_channel }}
          path: build
          if-no-files-found: error

  test_build:
    name: yarn test-build
    needs: [build_and_lint, runtime_compiler_node_modules_cache]
    strategy:
      fail-fast: false
      matrix:
        test_params: [
          # Intentionally passing these as strings instead of creating a
          # separate parameter per CLI argument, since it's easier to
          # control/see which combinations we want to run.
          -r=stable --env=development,
          -r=stable --env=production,
          -r=experimental --env=development,
          -r=experimental --env=production,

          # TODO: Update test config to support www build tests
          # - "-r=www-classic --env=development --variant=false"
          # - "-r=www-classic --env=production --variant=false"
          # - "-r=www-classic --env=development --variant=true"
          # - "-r=www-classic --env=production --variant=true"
          # - "-r=www-modern --env=development --variant=false"
          # - "-r=www-modern --env=production --variant=false"
          # - "-r=www-modern --env=development --variant=true"
          # - "-r=www-modern --env=production --variant=true"

          # TODO: Update test config to support xplat build tests
          # - "-r=xplat --env=development --variant=false"
          # - "-r=xplat --env=development --variant=true"
          # - "-r=xplat --env=production --variant=false"
          # - "-r=xplat --env=production --variant=true"

          # TODO: Test more persistent configurations?
        ]
        shard:
          - 1/10
          - 2/10
          - 3/10
          - 4/10
          - 5/10
          - 6/10
          - 7/10
          - 8/10
          - 9/10
          - 10/10
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: |
            yarn.lock
            compiler/yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-and-compiler-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn --cwd compiler install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Restore archived build
        uses: actions/download-artifact@v4
        with:
          pattern: _build_*
          path: build
          merge-multiple: true
      - name: Display structure of build
        run: ls -R build
      - run: node --version
      - run: yarn test --build ${{ matrix.test_params }} --shard=${{ matrix.shard }} --ci

  test_build_devtools:
    name: yarn test-build (devtools)
    needs: [build_and_lint, runtime_node_modules_cache]
    strategy:
      fail-fast: false
      matrix:
        shard:
          - 1/5
          - 2/5
          - 3/5
          - 4/5
          - 5/5
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Restore archived build
        uses: actions/download-artifact@v4
        with:
          pattern: _build_*
          path: build
          merge-multiple: true
      - name: Display structure of build
        run: ls -R build
      - run: node --version
      - run: yarn test --build --project=devtools -r=experimental --shard=${{ matrix.shard }} --ci

  process_artifacts_combined:
    name: Process artifacts combined
    needs: [build_and_lint, runtime_node_modules_cache]
    permissions:
      # https://github.com/actions/attest-build-provenance
      id-token: write
      attestations: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Restore archived build
        uses: actions/download-artifact@v4
        with:
          pattern: _build_*
          path: build
          merge-multiple: true
      - name: Display structure of build
        run: ls -R build
      - run: echo ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA
      - name: Scrape warning messages
        run: |
          mkdir -p ./build/__test_utils__
          node ./scripts/print-warnings/print-warnings.js > build/__test_utils__/ReactAllWarnings.js
        # Compress build directory into a single tarball for easy download
      - run: tar -zcvf ./build.tgz ./build
        # TODO: Migrate scripts to use `build` directory instead of `build2`
      - run: cp ./build.tgz ./build2.tgz
      - name: Archive build artifacts
        id: upload_artifacts_combined
        uses: actions/upload-artifact@v4
        with:
          name: artifacts_combined
          path: |
            ./build.tgz
            ./build2.tgz
          if-no-files-found: error
      - uses: actions/attest-build-provenance@v2
        # We don't verify builds generated from pull requests not originating from facebook/react.
        # However, if the PR lands, the run on `main` will generate the attestation which can then
        # be used to download a build via scripts/release/download-experimental-build.js.
        #
        # Note that this means that scripts/release/download-experimental-build.js must be run with
        # --no-verify when downloading a build from a fork.
        if: github.event_name == 'push' && github.ref_name == 'main' || github.event.pull_request.head.repo.full_name == github.repository
        with:
          subject-name: artifacts_combined.zip
          subject-digest: sha256:${{ steps.upload_artifacts_combined.outputs.artifact-digest }}

  check_error_codes:
    name: Search build artifacts for unminified errors
    needs: [build_and_lint, runtime_node_modules_cache]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Restore archived build
        uses: actions/download-artifact@v4
        with:
          pattern: _build_*
          path: build
          merge-multiple: true
      - name: Display structure of build
        run: ls -R build
      - name: Search build artifacts for unminified errors
        run: |
          yarn extract-errors
          git diff --exit-code || (echo "Found unminified errors. Either update the error codes map or disable error minification for the affected build, if appropriate." && false)

  check_release_dependencies:
    name: Check release dependencies
    needs: [build_and_lint, runtime_node_modules_cache]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Restore archived build
        uses: actions/download-artifact@v4
        with:
          pattern: _build_*
          path: build
          merge-multiple: true
      - name: Display structure of build
        run: ls -R build
      - run: yarn check-release-dependencies

  RELEASE_CHANNEL_stable_yarn_test_dom_fixtures:
    name: Check fixtures DOM (stable)
    needs: build_and_lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4 # note: this does not reuse centralized cache since it has unique cache key
        id: node_modules
        with:
          path: |
            **/node_modules
          key: fixtures_dom-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'fixtures/dom/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn --cwd fixtures/dom install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Restore archived build
        uses: actions/download-artifact@v4
        with:
          pattern: _build_*
          path: build
          merge-multiple: true
      - name: Display structure of build
        run: ls -R build
      - name: Run DOM fixture tests
        run: |
          yarn predev
          yarn test
        working-directory: fixtures/dom
        env:
          RELEASE_CHANNEL: stable

  # ----- FLIGHT -----
  run_fixtures_flight_tests:
    name: Run fixtures Flight tests
    needs: build_and_lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      # Fixture copies some built packages from the workroot after install.
      # That means dependencies of the built packages are not installed.
      # We need to install dependencies of the workroot to fulfill all dependency constraints
      - name: Restore cached node_modules
        uses: actions/cache@v4 # note: this does not reuse centralized cache since it has unique cache key
        id: node_modules
        with:
          path: |
            **/node_modules
          key: fixtures_flight-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'fixtures/flight/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn --cwd fixtures/flight install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Check Playwright version
        id: playwright_version
        run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT"
      - name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }}
        id: cache_playwright_browsers
        uses: actions/cache@v4
        with:
          path: ~/.cache/ms-playwright
          key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }}
      - name: Playwright install deps
        if: steps.cache_playwright_browsers.outputs.cache-hit != 'true'
        working-directory: fixtures/flight
        run: npx playwright install --with-deps chromium
      - name: Restore archived build
        uses: actions/download-artifact@v4
        with:
          pattern: _build_*
          path: build
          merge-multiple: true
      - name: Display structure of build
        run: ls -R build
      - name: Run tests
        working-directory: fixtures/flight
        run: yarn test
        env:
          # Otherwise the webserver is a blackbox
          DEBUG: pw:webserver
      - name: Archive Flight fixture artifacts
        uses: actions/upload-artifact@v4
        with:
          name: flight-playwright-report
          path: fixtures/flight/playwright-report
          if-no-files-found: warn
      - name: Archive Flight fixture artifacts
        uses: actions/upload-artifact@v4
        with:
          name: flight-test-results
          path: fixtures/flight/test-results
          if-no-files-found: ignore

  # ----- DEVTOOLS -----
  build_devtools_and_process_artifacts:
    name: Build DevTools and process artifacts
    needs: [build_and_lint, runtime_node_modules_cache]
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        browser: [chrome, firefox, edge]
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Restore archived build
        uses: actions/download-artifact@v4
        with:
          pattern: _build_*
          path: build
          merge-multiple: true
      - run: ./scripts/ci/pack_and_store_devtools_artifacts.sh ${{ matrix.browser }}
        env:
          RELEASE_CHANNEL: experimental
      - name: Display structure of build
        run: ls -R build
      # Simplifies getting the extension for local testing
      - name: Archive ${{ matrix.browser }} extension
        uses: actions/upload-artifact@v4
        with:
          name: react-devtools-${{ matrix.browser }}-extension
          path: build/devtools/${{ matrix.browser }}-extension.zip
          if-no-files-found: error
      - name: Archive ${{ matrix.browser }} metadata
        uses: actions/upload-artifact@v4
        with:
          name: react-devtools-${{ matrix.browser }}-metadata
          path: build/devtools/webpack-stats.*.json

  merge_devtools_artifacts:
    name: Merge DevTools artifacts
    needs: build_devtools_and_process_artifacts
    runs-on: ubuntu-latest
    steps:
      - name: Merge artifacts
        uses: actions/upload-artifact/merge@v4
        with:
          name: react-devtools
          pattern: react-devtools-*

  run_devtools_e2e_tests:
    name: Run DevTools e2e tests
    needs: [build_and_lint, runtime_node_modules_cache]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache/restore@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
          # Don't use restore-keys here. Otherwise the cache grows indefinitely.
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Restore archived build
        uses: actions/download-artifact@v4
        with:
          pattern: _build_*
          path: build
          merge-multiple: true
      - name: Check Playwright version
        id: playwright_version
        run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT"
      - name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }}
        id: cache_playwright_browsers
        uses: actions/cache@v4
        with:
          path: ~/.cache/ms-playwright
          key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }}
      - name: Playwright install deps
        if: steps.cache_playwright_browsers.outputs.cache-hit != 'true'
        run: npx playwright install --with-deps chromium
      - run: ./scripts/ci/run_devtools_e2e_tests.js
        env:
          RELEASE_CHANNEL: experimental
      - name: Archive Playwright report
        uses: actions/upload-artifact@v4
        with:
          name: devtools-playwright-artifacts
          path: tmp/playwright-artifacts
          if-no-files-found: warn

  # ----- SIZEBOT -----
  sizebot:
    if: ${{ github.event_name == 'pull_request' && github.ref_name != 'main' && github.event.pull_request.base.ref == 'main' }}
    name: Run sizebot
    needs: [build_and_lint]
    permissions:
      # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
      actions: read
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4 # note: this does not reuse centralized cache since it has unique cache key
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn --cwd scripts/release install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Download artifacts for base revision
        # The build could have been generated from a fork, so we must download the build without
        # any verification. This is safe since we only use this for sizebot calculation and the
        # unverified artifact is not used. Additionally this workflow runs in the pull_request
        # trigger so only restricted permissions are available.
        run: |
          GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=$(git rev-parse ${{ github.event.pull_request.base.sha }}) ${{ (github.event.pull_request.head.repo.full_name != github.repository && '--noVerify') || ''}}
          mv ./build ./base-build
      - name: Delete extraneous files
        # TODO: The `download-experimental-build` script copies the npm
        # packages into the `node_modules` directory. This is a historical
        # quirk of how the release script works. Let's pretend they
        # don't exist.
        run: rm -rf ./base-build/node_modules
      - name: Display structure of base-build from origin/main
        run: ls -R base-build
      - name: Ensure clean build directory
        run: rm -rf build
      - name: Restore archived build for PR
        uses: actions/download-artifact@v4
        with:
          pattern: _build_*
          path: build
          merge-multiple: true
      - name: Scrape warning messages
        run: |
          mkdir -p ./build/__test_utils__
          node ./scripts/print-warnings/print-warnings.js > build/__test_utils__/ReactAllWarnings.js
      - name: Display structure of build for PR
        run: ls -R build
      - run: echo ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA
      - run: node ./scripts/tasks/danger
      - name: Archive sizebot results
        uses: actions/upload-artifact@v4
        with:
          name: sizebot-message
          path: sizebot-message.md
          if-no-files-found: ignore
runtime_commit_artifacts perms .github/workflows/runtime_commit_artifacts.yml
Triggers
workflow_run, workflow_dispatch
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
download_artifacts, process_artifacts, commit_www_artifacts, commit_fbsource_artifacts
Commands
  • rm -rf build
  • yarn install --frozen-lockfile
  • yarn --cwd scripts/release install --frozen-lockfile
  • GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }}
  • ls -R build
  • # Empty checks only needed for backwards compatibility,can remove later. VERSION_CLASSIC=$( [ -f ./compiled/facebook-www/VERSION_CLASSIC ] && cat ./compiled/facebook-www/VERSION_CLASSIC || echo '' ) VERSION_MODERN=$( [ -f ./compiled/facebook-www/VERSION_MODERN ] && cat ./compiled/facebook-www/VERSION_MODERN || echo '' ) echo "Last classic version is $VERSION_CLASSIC" echo "Last modern version is $VERSION_MODERN" echo "last_version_classic=$VERSION_CLASSIC" >> "$GITHUB_OUTPUT" echo "last_version_modern=$VERSION_MODERN" >> "$GITHUB_OUTPUT"
  • # Empty checks only needed for backwards compatibility,can remove later. VERSION_NATIVE_FB=$( [ -f ./compiled-rn/VERSION_NATIVE_FB ] && cat ./compiled-rn/VERSION_NATIVE_FB || echo '' ) echo "Last rn version is $VERSION_NATIVE_FB" echo "last_version_rn=$VERSION_NATIVE_FB" >> "$GITHUB_OUTPUT"
  • echo "www_branch_count=$(git ls-remote --heads origin "refs/heads/meta-www" | wc -l)" >> "$GITHUB_OUTPUT" echo "fbsource_branch_count=$(git ls-remote --heads origin "refs/heads/meta-fbsource" | wc -l)" >> "$GITHUB_OUTPUT"
View raw YAML
name: (Runtime) Commit Artifacts for Meta WWW and fbsource V2

on:
  workflow_run:
    workflows: ["(Runtime) Build and Test"]
    types: [completed]
    branches:
      - main
  workflow_dispatch:
    inputs:
      commit_sha:
        required: false
        type: string
      force:
        description: 'Force a commit to the builds/... branches'
        required: true
        default: false
        type: boolean
      dry_run:
        description: Perform a dry run (run everything except push)
        required: true
        default: false
        type: boolean

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1

jobs:
  download_artifacts:
    runs-on: ubuntu-latest
    permissions:
      # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
      actions: read
    steps:
      - uses: actions/checkout@v4
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn --cwd scripts/release install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Download artifacts for base revision
        run: |
          GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }}
      - name: Display structure of build
        run: ls -R build
      - name: Archive build
        uses: actions/upload-artifact@v4
        with:
          name: build
          path: build/
          if-no-files-found: error


  process_artifacts:
    runs-on: ubuntu-latest
    needs: [download_artifacts]
    outputs:
      www_branch_count: ${{ steps.check_branches.outputs.www_branch_count }}
      fbsource_branch_count: ${{ steps.check_branches.outputs.fbsource_branch_count }}
      last_version_classic: ${{ steps.get_last_version_www.outputs.last_version_classic }}
      last_version_modern: ${{ steps.get_last_version_www.outputs.last_version_modern }}
      last_version_rn: ${{ steps.get_last_version_rn.outputs.last_version_rn }}
      current_version_classic: ${{ steps.get_current_version.outputs.current_version_classic }}
      current_version_modern: ${{ steps.get_current_version.outputs.current_version_modern }}
      current_version_rn: ${{ steps.get_current_version.outputs.current_version_rn }}
    steps:
      - uses: actions/checkout@v4
        with:
          ref: builds/facebook-www
      - name: "Get last version string for www"
        id: get_last_version_www
        run: |
          # Empty checks only needed for backwards compatibility,can remove later.
          VERSION_CLASSIC=$( [ -f ./compiled/facebook-www/VERSION_CLASSIC ] && cat ./compiled/facebook-www/VERSION_CLASSIC || echo '' )
          VERSION_MODERN=$( [ -f ./compiled/facebook-www/VERSION_MODERN ] && cat ./compiled/facebook-www/VERSION_MODERN || echo '' )
          echo "Last classic version is $VERSION_CLASSIC"
          echo "Last modern version is $VERSION_MODERN"
          echo "last_version_classic=$VERSION_CLASSIC" >> "$GITHUB_OUTPUT"
          echo "last_version_modern=$VERSION_MODERN" >> "$GITHUB_OUTPUT"
      - uses: actions/checkout@v4
        with:
          ref: builds/facebook-fbsource
      - name: "Get last version string for rn"
        id: get_last_version_rn
        run: |
          # Empty checks only needed for backwards compatibility,can remove later.
          VERSION_NATIVE_FB=$( [ -f ./compiled-rn/VERSION_NATIVE_FB ] && cat ./compiled-rn/VERSION_NATIVE_FB || echo '' )
          echo "Last rn version is $VERSION_NATIVE_FB"
          echo "last_version_rn=$VERSION_NATIVE_FB" >> "$GITHUB_OUTPUT"
      - uses: actions/checkout@v4
      - name: "Check branches"
        id: check_branches
        run: |
          echo "www_branch_count=$(git ls-remote --heads origin "refs/heads/meta-www" | wc -l)" >> "$GITHUB_OUTPUT"
          echo "fbsource_branch_count=$(git ls-remote --heads origin "refs/heads/meta-fbsource" | wc -l)" >> "$GITHUB_OUTPUT"
      - name: Restore downloaded build
        uses: actions/download-artifact@v4
        with:
          name: build
          path: build
      - name: Display structure of build
        run: ls -R build
      - name: Strip @license from eslint plugin and react-refresh
        run: |
          sed -i -e 's/ @license React*//' \
            build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \
            build/facebook-www/ESLintPluginReactHooks-dev.modern.js \
            build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js
      - name: Insert @headers into eslint plugin and react-refresh
        run: |
          sed -i -e 's/ LICENSE file in the root directory of this source tree./ LICENSE file in the root directory of this source tree.\n *\n * @noformat\n * @nolint\n * @lightSyntaxTransform\n * @preventMunge\n * @oncall react_core/' \
            build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \
            build/facebook-www/ESLintPluginReactHooks-dev.modern.js \
            build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js
      - name: Move relevant files for React in www into compiled
        run: |
          # Move the facebook-www folder into compiled
          mkdir ./compiled
          mv build/facebook-www ./compiled

          # Move ReactAllWarnings.js to facebook-www
          mkdir ./compiled/facebook-www/__test_utils__
          mv build/__test_utils__/ReactAllWarnings.js ./compiled/facebook-www/__test_utils__/ReactAllWarnings.js

          # Copy eslint-plugin-react-hooks (www build with feature flags)
          mkdir ./compiled/eslint-plugin-react-hooks
          cp ./compiled/facebook-www/ESLintPluginReactHooks-dev.modern.js \
            ./compiled/eslint-plugin-react-hooks/index.js

          # Move unstable_server-external-runtime.js into facebook-www
          mv build/oss-experimental/react-dom/unstable_server-external-runtime.js \
            ./compiled/facebook-www/unstable_server-external-runtime.js

          # Move react-refresh-babel.development.js into babel-plugin-react-refresh
          mkdir ./compiled/babel-plugin-react-refresh
          mv build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js \
            ./compiled/babel-plugin-react-refresh/index.js

          ls -R ./compiled
      - name: Move relevant files for React in fbsource into compiled-rn
        run: |
          BASE_FOLDER='compiled-rn/facebook-fbsource/xplat/js'
          mkdir -p ${BASE_FOLDER}/react-native-github/Libraries/Renderer/
          mkdir -p ${BASE_FOLDER}/RKJSModules/vendor/react/{scheduler,react,react-dom,react-is,react-test-renderer}/

          # Move React Native renderer
          mv build/react-native/implementations/ $BASE_FOLDER/react-native-github/Libraries/Renderer/
          mv build/react-native/shims/ $BASE_FOLDER/react-native-github/Libraries/Renderer/
          mv build/facebook-react-native/scheduler/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/scheduler/
          mv build/facebook-react-native/react/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react/
          mv build/facebook-react-native/react-dom/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-dom/
          mv build/facebook-react-native/react-is/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-is/
          mv build/facebook-react-native/react-test-renderer/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-test-renderer/

          # Delete the OSS renderers, these are sync'd to RN separately.
          RENDERER_FOLDER=$BASE_FOLDER/react-native-github/Libraries/Renderer/implementations/
          rm $RENDERER_FOLDER/ReactFabric-{dev,prod,profiling}.js
          
          # Delete the legacy renderer shim, this is not sync'd and will get deleted in the future.
          SHIM_FOLDER=$BASE_FOLDER/react-native-github/Libraries/Renderer/shims/
          rm $SHIM_FOLDER/ReactNative.js

          # Copy eslint-plugin-react-hooks
          # NOTE: This is different from www, here we include the full package
          #       including package.json to include dependencies in fbsource.
          mkdir "$BASE_FOLDER/tools"
          cp -r build/oss-experimental/eslint-plugin-react-hooks "$BASE_FOLDER/tools"

          # Move React Native version file
          mv build/facebook-react-native/VERSION_NATIVE_FB ./compiled-rn/VERSION_NATIVE_FB

          ls -R ./compiled-rn
      - name: Add REVISION files
        run: |
          echo ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} >> ./compiled/facebook-www/REVISION
          cp ./compiled/facebook-www/REVISION ./compiled/facebook-www/REVISION_TRANSFORMS
          echo ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} >> ./compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION
      - name: "Get current version string"
        id: get_current_version
        run: |
          VERSION_CLASSIC=$(cat ./compiled/facebook-www/VERSION_CLASSIC)
          VERSION_MODERN=$(cat ./compiled/facebook-www/VERSION_MODERN)
          VERSION_NATIVE_FB=$(cat ./compiled-rn/VERSION_NATIVE_FB)
          echo "Current classic version is $VERSION_CLASSIC"
          echo "Current modern version is $VERSION_MODERN"
          echo "Current rn version is $VERSION_NATIVE_FB"
          echo "current_version_classic=$VERSION_CLASSIC" >> "$GITHUB_OUTPUT"
          echo "current_version_modern=$VERSION_MODERN" >> "$GITHUB_OUTPUT"
          echo "current_version_rn=$VERSION_NATIVE_FB" >> "$GITHUB_OUTPUT"
      - uses: actions/upload-artifact@v4
        with:
          name: compiled
          path: compiled/
          if-no-files-found: error
      - uses: actions/upload-artifact@v4
        with:
          name: compiled-rn
          path: compiled-rn/
          if-no-files-found: error

  commit_www_artifacts:
    needs: [download_artifacts, process_artifacts]
    if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.process_artifacts.outputs.www_branch_count == '0')
    runs-on: ubuntu-latest
    permissions:
      # Used to push a commit to builds/facebook-www
      contents: write
    steps:
      - uses: actions/checkout@v4
        with:
          ref: builds/facebook-www
      - name: Ensure clean directory
        run: rm -rf compiled
      - uses: actions/download-artifact@v4
        with:
          name: compiled
          path: compiled/
      - name: Revert version changes
        if: needs.process_artifacts.outputs.last_version_classic != '' && needs.process_artifacts.outputs.last_version_modern != ''
        env:
          CURRENT_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.current_version_classic }}
          CURRENT_VERSION_MODERN: ${{ needs.process_artifacts.outputs.current_version_modern }}
          LAST_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.last_version_classic }}
          LAST_VERSION_MODERN: ${{ needs.process_artifacts.outputs.last_version_modern }}
        run: |
          echo "Reverting $CURRENT_VERSION_CLASSIC to $LAST_VERSION_CLASSIC"
          grep -rl "$CURRENT_VERSION_CLASSIC" ./compiled || echo "No files found with $CURRENT_VERSION_CLASSIC"
          grep -rl "$CURRENT_VERSION_CLASSIC" ./compiled | xargs -r sed -i -e "s/$CURRENT_VERSION_CLASSIC/$LAST_VERSION_CLASSIC/g"
          grep -rl "$CURRENT_VERSION_CLASSIC" ./compiled || echo "Classic version reverted"
          echo "===================="
          echo "Reverting $CURRENT_VERSION_MODERN to $LAST_VERSION_MODERN"
          grep -rl "$CURRENT_VERSION_MODERN" ./compiled || echo "No files found with $CURRENT_VERSION_MODERN"
          grep -rl "$CURRENT_VERSION_MODERN" ./compiled | xargs -r sed -i -e "s/$CURRENT_VERSION_MODERN/$LAST_VERSION_MODERN/g"
          grep -rl "$CURRENT_VERSION_MODERN" ./compiled || echo "Modern version reverted"
      - name: Check for changes
        if: inputs.force != true
        id: check_should_commit
        run: |
          echo "Full git status"
          git add .
          git status
          echo "===================="
          if git status --porcelain | grep -qv '/REVISION'; then
            echo "Changes detected"
            echo "===== Changes ====="
            git --no-pager diff -U0 | grep '^[+-]' | head -n 50
            echo "==================="
            echo "should_commit=true" >> "$GITHUB_OUTPUT"
          else
            echo "No Changes detected"
            echo "should_commit=false" >> "$GITHUB_OUTPUT"
          fi
      - name: Re-apply version changes
        if: inputs.force == true || (steps.check_should_commit.outputs.should_commit == 'true' && needs.process_artifacts.outputs.last_version_classic != '' && needs.process_artifacts.outputs.last_version_modern != '')
        env:
          CURRENT_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.current_version_classic }}
          CURRENT_VERSION_MODERN: ${{ needs.process_artifacts.outputs.current_version_modern }}
          LAST_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.last_version_classic }}
          LAST_VERSION_MODERN: ${{ needs.process_artifacts.outputs.last_version_modern }}
        run: |
          echo "Re-applying $LAST_VERSION_CLASSIC to $CURRENT_VERSION_CLASSIC"
          grep -rl "$LAST_VERSION_CLASSIC" ./compiled || echo "No files found with $LAST_VERSION_CLASSIC"
          grep -rl "$LAST_VERSION_CLASSIC" ./compiled | xargs -r sed -i -e "s/$LAST_VERSION_CLASSIC/$CURRENT_VERSION_CLASSIC/g"
          grep -rl "$LAST_VERSION_CLASSIC" ./compiled || echo "Classic version re-applied"
          echo "===================="
          echo "Re-applying $LAST_VERSION_MODERN to $CURRENT_VERSION_MODERN"
          grep -rl "$LAST_VERSION_MODERN" ./compiled || echo "No files found with $LAST_VERSION_MODERN"
          grep -rl "$LAST_VERSION_MODERN" ./compiled | xargs -r sed -i -e "s/$LAST_VERSION_MODERN/$CURRENT_VERSION_MODERN/g"
          grep -rl "$LAST_VERSION_MODERN" ./compiled || echo "Classic version re-applied"
      - name: Will commit these changes
        if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
        run: |
          git add .
          git status
      - name: Check commit message
        if: inputs.dry_run
        run: |
          git fetch origin --quiet
          git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:"%B"
      - name: Commit changes to branch
        if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
        run: |
          git config --global user.email "${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}"
          git config --global user.name "${{ github.triggering_actor }}"

          git fetch origin --quiet
          git commit -m "$(git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:'%B%n%nDiffTrain build for [${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha}})')" || echo "No changes to commit"
      - name: Push changes to branch
        if: inputs.dry_run == false && (inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true')
        run: git push

  commit_fbsource_artifacts:
    needs: [download_artifacts, process_artifacts]
    permissions:
      # Used to push a commit to builds/facebook-fbsource
      contents: write
    if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.process_artifacts.outputs.fbsource_branch_count == '0')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: builds/facebook-fbsource
      - name: Ensure clean directory
        run: rm -rf compiled-rn
      - uses: actions/download-artifact@v4
        with:
          name: compiled-rn
          path: compiled-rn/
      - name: Revert version changes
        if: needs.process_artifacts.outputs.last_version_rn != ''
        env:
          CURRENT_VERSION: ${{ needs.process_artifacts.outputs.current_version_rn }}
          LAST_VERSION: ${{ needs.process_artifacts.outputs.last_version_rn }}
        run: |
          echo "Reverting $CURRENT_VERSION to $LAST_VERSION"
          grep -rl "$CURRENT_VERSION" ./compiled-rn || echo "No files found with $CURRENT_VERSION"
          grep -rl "$CURRENT_VERSION" ./compiled-rn | xargs -r sed -i -e "s/$CURRENT_VERSION/$LAST_VERSION/g"
          grep -rl "$CURRENT_VERSION" ./compiled-rn || echo "Version reverted"
      - name: Check for changes
        if: inputs.force != 'true'
        id: check_should_commit
        run: |
          echo "Full git status"
          git add .
          git --no-pager diff -U0 --cached | grep '^[+-]' | head -n 100
          echo "===================="
          # Ignore REVISION or lines removing @generated headers.
          if git diff --cached ':(exclude)*REVISION' ':(exclude)*/eslint-plugin-react-hooks/package.json' | grep -vE "^(@@|diff|index|\-\-\-|\+\+\+|\- \* @generated SignedSource)" | grep "^[+-]" > /dev/null; then
            echo "Changes detected"
            echo "===== Changes ====="
            git --no-pager diff --cached ':(exclude)*REVISION' ':(exclude)*/eslint-plugin-react-hooks/package.json' | grep -vE "^(@@|diff|index|\-\-\-|\+\+\+|\- \* @generated SignedSource)" | grep "^[+-]" | head -n 50
            echo "==================="
            echo "should_commit=true" >> "$GITHUB_OUTPUT"
          else
            echo "No Changes detected"
            echo "should_commit=false" >> "$GITHUB_OUTPUT"
          fi
      - name: Re-apply version changes
        if: inputs.force == true || (steps.check_should_commit.outputs.should_commit == 'true' && needs.process_artifacts.outputs.last_version_rn != '')
        env:
          CURRENT_VERSION: ${{ needs.process_artifacts.outputs.current_version_rn }}
          LAST_VERSION: ${{ needs.process_artifacts.outputs.last_version_rn }}
        run: |
          echo "Re-applying $LAST_VERSION to $CURRENT_VERSION"
          grep -rl "$LAST_VERSION" ./compiled-rn || echo "No files found with $LAST_VERSION"
          grep -rl "$LAST_VERSION" ./compiled-rn | xargs -r sed -i -e "s/$LAST_VERSION/$CURRENT_VERSION/g"
          grep -rl "$LAST_VERSION" ./compiled-rn || echo "Version re-applied"
      - name: Add files for signing
        if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
        run: |
          echo ":"
          git add .
      - name: Signing files
        if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
        uses: actions/github-script@v7
        with:
          script: |
            // TODO: Move this to a script file.
            // We currently can't call scripts from the repo because
            // at this point in the workflow, we're on the compiled
            // artifact branch (so the scripts don't exist).
            // We can fix this with a composite action in the main repo.
            // This script is duplicated above.
            const fs = require('fs');
            const crypto = require('crypto');
            const {execSync} = require('child_process');

            // TODO: when we move this to a script, we can use this from npm.
            // Copy of signedsource since we can't install deps on this branch.
            const GENERATED = '@' + 'generated';
            const NEWTOKEN = '<<SignedSource::*O*zOeWoEQle#+L!plEphiEmie@IsG>>';
            const PATTERN = new RegExp(`${GENERATED} (?:SignedSource<<([a-f0-9]{32})>>)`);

            const TokenNotFoundError = new Error(
              `SignedSource.signFile(...): Cannot sign file without token: ${NEWTOKEN}`
            );

            function hash(data, encoding) {
              const md5sum = crypto.createHash('md5');
              md5sum.update(data, encoding);
              return md5sum.digest('hex');
            }

            const SignedSource = {
              getSigningToken() {
                return `${GENERATED} ${NEWTOKEN}`;
              },
              isSigned(data) {
                return PATTERN.exec(data) != null;
              },
              signFile(data) {
                if (!data.includes(NEWTOKEN)) {
                  if (SignedSource.isSigned(data)) {
                    // Signing a file that was previously signed.
                   data = data.replace(PATTERN, SignedSource.getSigningToken());
                  } else {
                    throw TokenNotFoundError;
                  }
                }
                return data.replace(NEWTOKEN, `SignedSource<<${hash(data, 'utf8')}>>`);
              },
            };

            const directory = './compiled-rn';
            console.log('Signing files in directory:', directory);
            try {
              const result = execSync(`git status --porcelain ${directory}`, {encoding: 'utf8'});
              console.log(result);

              // Parse the git status output to get file paths!
              const files = result.split('\n').filter(file => file.endsWith('.js'));

              if (files.length === 0) {
                throw new Error(
                  'git status returned no files to sign. this job should not have run.'
                );
              } else {
                files.forEach(line => {
                  let file = null;
                  if (line.startsWith('D ')) {
                    return;
                  } else if (line.startsWith('R ')) {
                    file = line.slice(line.indexOf('->') + 3);
                  } else {
                    file = line.slice(3).trim();
                  }
                  if (file) {
                    console.log('  Signing file:', file);
                    const originalContents = fs.readFileSync(file, 'utf8');
                    const signedContents = SignedSource.signFile(
                      originalContents
                        // Need to add the header in, since it's not inserted at build time.
                        .replace(' */\n', ` * ${SignedSource.getSigningToken()}\n */\n`)
                    );

                    fs.writeFileSync(file, signedContents, 'utf8');
                  }
                });
              }
            } catch (e) {
              process.exitCode = 1;
              console.error('Error signing files:', e);
            }
      - name: Will commit these changes
        if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
        run: |
          git add .
          git status
      - name: Check commit message
        if: inputs.dry_run
        run: |
          git fetch origin --quiet
          git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:"%B"
      - name: Commit changes to branch
        if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
        run: |
          git config --global user.email "${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}"
          git config --global user.name "${{ github.triggering_actor }}"

          git fetch origin --quiet
          git commit -m "$(git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:'%B%n%nDiffTrain build for [${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha}})')" || echo "No changes to commit"
      - name: Push changes to branch
        if: inputs.dry_run == false && (inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true')
        run: git push
runtime_discord_notify perms .github/workflows/runtime_discord_notify.yml
Triggers
pull_request_target
Runs on
ubuntu-latest, ubuntu-latest
Jobs
check_access, check_maintainer, notify
Actions
tsickert/discord-webhook
Commands
  • echo ${{ github.event.pull_request.author_association }}
  • echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"
View raw YAML
name: (Runtime) Discord Notify

on:
  pull_request_target:
    types: [opened, ready_for_review]
    paths-ignore:
      - packages/react-devtools**
      - compiler/**
      - .github/workflows/compiler_**.yml
      - .github/workflows/devtools**.yml

permissions: {}

jobs:
  check_access:
    if: ${{ github.event.pull_request.draft == false }}
    runs-on: ubuntu-latest
    outputs:
      is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }}
    steps:
      - run: echo ${{ github.event.pull_request.author_association }}
      - name: Check is member or collaborator
        id: check_is_member_or_collaborator
        if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }}
        run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"

  check_maintainer:
    if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }}
    needs: [check_access]
    uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main
    permissions:
      # Used by check_maintainer
      contents: read
    with:
      actor: ${{ github.event.pull_request.user.login }}

  notify:
    if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }}
    needs: check_maintainer
    runs-on: ubuntu-latest
    steps:
      - name: Discord Webhook Action
        uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
        with:
          webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
          embed-author-name: ${{ github.event.pull_request.user.login }}
          embed-author-url: ${{ github.event.pull_request.user.html_url }}
          embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }}
          embed-title: '#${{ github.event.number }} (+${{github.event.pull_request.additions}} -${{github.event.pull_request.deletions}}): ${{ github.event.pull_request.title }}'
          embed-description: ${{ github.event.pull_request.body }}
          embed-url: ${{ github.event.pull_request.html_url }}
runtime_eslint_plugin_e2e matrix perms .github/workflows/runtime_eslint_plugin_e2e.yml
Triggers
push, pull_request
Runs on
ubuntu-latest
Jobs
test
Matrix
eslint_major→ 10, 6, 7, 8, 9
Commands
  • rm -rf build
  • yarn install --frozen-lockfile
  • yarn --cwd compiler install --frozen-lockfile
  • yarn --frozen-lockfile
  • node build.mjs
  • yarn lint
View raw YAML
name: (Runtime) ESLint Plugin E2E

on:
  push:
    branches: [main]
  pull_request:
    paths-ignore:
      - compiler/**

permissions: {}

concurrency:
  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
  cancel-in-progress: true

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles

jobs:
  # ----- TESTS -----
  test:
    name: ESLint v${{ matrix.eslint_major }}
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        eslint_major:
          - "6"
          - "7"
          - "8"
          - "9"
          - "10"
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: |
            yarn.lock
            compiler/yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-and-compiler-eslint_e2e-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock', 'fixtures/eslint-v*/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn --cwd compiler install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Install fixture dependencies
        working-directory: ./fixtures/eslint-v${{ matrix.eslint_major }}
        run: yarn --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - name: Build plugin
        working-directory: fixtures/eslint-v${{ matrix.eslint_major }}
        run: node build.mjs
      - name: Run lint test
        working-directory: ./fixtures/eslint-v${{ matrix.eslint_major }}
        run: yarn lint
runtime_fuzz_tests perms .github/workflows/runtime_fuzz_tests.yml
Triggers
schedule, push, workflow_dispatch
Runs on
ubuntu-latest
Jobs
test_fuzz
Commands
  • yarn install --frozen-lockfile
  • FUZZ_TEST_SEED=$RANDOM yarn test fuzz --ci FUZZ_TEST_SEED=$RANDOM yarn test --prod fuzz --ci
View raw YAML
name: (Runtime) Fuzz tests

on:
  schedule:
    - cron: 0 * * * *
  push:
    branches:
      - main
  workflow_dispatch:

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles

jobs:
  test_fuzz:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4.1.0
    - uses: actions/setup-node@v4
      with:
        node-version-file: '.nvmrc'
        cache: 'yarn'
    - name: Install dependencies
      run: yarn install --frozen-lockfile
      env:
        ELECTRON_SKIP_BINARY_DOWNLOAD: "1"
      shell: bash
    - name: Run fuzz tests
      run: |-
        FUZZ_TEST_SEED=$RANDOM yarn test fuzz --ci
        FUZZ_TEST_SEED=$RANDOM yarn test --prod fuzz --ci
runtime_prereleases perms .github/workflows/runtime_prereleases.yml
Triggers
workflow_call
Runs on
ubuntu-latest
Jobs
publish_prerelease
Actions
tsickert/discord-webhook
Commands
  • rm -rf build
  • yarn install --frozen-lockfile
  • yarn --cwd scripts/release install --frozen-lockfile
  • cp ./scripts/release/ci-npmrc ~/.npmrc
  • GH_TOKEN=${{ secrets.GH_TOKEN }} scripts/release/prepare-release-from-ci.js --skipTests -r ${{ inputs.release_channel }} --commit=${{ inputs.commit_sha }}
  • ls -R build/node_modules
  • scripts/release/publish.js \ --ci \ --tags=${{ inputs.dist_tag }} \ --onlyPackages=${{ inputs.only_packages }} ${{ (inputs.dry && '') || '\'}} ${{ inputs.dry && '--dry' || '' }}
  • scripts/release/publish.js \ --ci \ --tags=${{ inputs.dist_tag }} \ --skipPackages=${{ inputs.skip_packages }} ${{ (inputs.dry && '') || '\'}} ${{ inputs.dry && '--dry' || '' }}
View raw YAML
name: (Runtime) Publish Prereleases

on:
  workflow_call:
    inputs:
      commit_sha:
        required: true
        default: ''
        type: string
      release_channel:
        required: true
        type: string
      dist_tag:
        required: true
        type: string
      enableFailureNotification:
        description: 'Whether to notify the team on Discord when the release fails. Useful if this workflow is called from an automation.'
        required: false
        type: boolean
      only_packages:
        description: Packages to publish (space separated)
        type: string
      skip_packages:
        description: Packages to NOT publish (space separated)
        type: string
      dry:
        required: true
        description: Dry run instead of publish?
        type: boolean
        default: true
    secrets:
      DISCORD_WEBHOOK_URL:
        description: 'Discord webhook URL to notify on failure. Only required if enableFailureNotification is true.'
        required: false
      GH_TOKEN:
        required: true
      NPM_TOKEN:
        required: true

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

jobs:
  publish_prerelease:
    name: Publish prelease (${{ inputs.release_channel }}) ${{ inputs.commit_sha }} @${{ inputs.dist_tag }}
    runs-on: ubuntu-latest
    permissions:
      # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
      actions: read
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn --cwd scripts/release install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: cp ./scripts/release/ci-npmrc ~/.npmrc
      - run: |
          GH_TOKEN=${{ secrets.GH_TOKEN }} scripts/release/prepare-release-from-ci.js --skipTests -r ${{ inputs.release_channel }} --commit=${{ inputs.commit_sha }}
      - name: Check prepared files
        run: ls -R build/node_modules
      - if: '${{ inputs.only_packages }}'
        name: 'Publish ${{ inputs.only_packages }}'
        run: |
          scripts/release/publish.js \
            --ci \
            --tags=${{ inputs.dist_tag }} \
            --onlyPackages=${{ inputs.only_packages }} ${{ (inputs.dry && '') || '\'}}
            ${{ inputs.dry && '--dry' || '' }}
      - if: '${{ inputs.skip_packages }}'
        name: 'Publish all packages EXCEPT ${{ inputs.skip_packages }}'
        run: |
          scripts/release/publish.js \
            --ci \
            --tags=${{ inputs.dist_tag }} \
            --skipPackages=${{ inputs.skip_packages }} ${{ (inputs.dry && '') || '\'}}
            ${{ inputs.dry && '--dry' || '' }}
      - if: '${{ !inputs.skip_packages && !inputs.only_packages }}'
        name: 'Publish all packages'
        run: |
          scripts/release/publish.js \
            --ci \
            --tags=${{ inputs.dist_tag }} ${{ (inputs.dry && '') || '\'}}
            ${{ inputs.dry && '--dry' || '' }}
      - name: Notify Discord on failure
        if: failure() && inputs.enableFailureNotification == true
        uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
        with:
          webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
          embed-author-name: "GitHub Actions"
          embed-title: '[Runtime] Publish of ${{ inputs.release_channel }}@${{ inputs.dist_tag}} release failed'
          embed-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}
runtime_prereleases_manual perms .github/workflows/runtime_prereleases_manual.yml
Triggers
workflow_dispatch
Runs on
ubuntu-latest
Jobs
notify, publish_prerelease_canary, publish_prerelease_experimental
Actions
tsickert/discord-webhook
View raw YAML
name: (Runtime) Publish Prereleases Manual

on:
  workflow_dispatch:
    inputs:
      prerelease_commit_sha:
        required: true
      only_packages:
        description: Packages to publish (space separated)
        type: string
      skip_packages:
        description: Packages to NOT publish (space separated)
        type: string
      dry:
        required: true
        description: Dry run instead of publish?
        type: boolean
        default: true
      experimental_only:
        type: boolean
        description: Only publish to the experimental tag
        default: false
      force_notify:
        description: Force a Discord notification?
        type: boolean
        default: false

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles

jobs:
  notify:
    if: ${{ inputs.force_notify || inputs.dry == false || inputs.dry == 'false' }}
    runs-on: ubuntu-latest
    steps:
      - name: Discord Webhook Action
        uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
        with:
          webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
          embed-author-name: ${{ github.event.sender.login }}
          embed-author-url: ${{ github.event.sender.html_url }}
          embed-author-icon-url: ${{ github.event.sender.avatar_url }}
          embed-title: "⚠️ Publishing ${{ inputs.experimental_only && 'EXPERIMENTAL' || 'CANARY & EXPERIMENTAL' }} release ${{ (inputs.dry && ' (dry run)') || '' }}"
          embed-description: |
            ```json
            ${{ toJson(inputs) }}
            ```
          embed-url: https://github.com/facebook/react/actions/runs/${{ github.run_id }}

  publish_prerelease_canary:
    if: ${{ !inputs.experimental_only }}
    name: Publish to Canary channel
    uses: facebook/react/.github/workflows/runtime_prereleases.yml@main
    permissions:
      # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
      actions: read
    with:
      commit_sha: ${{ inputs.prerelease_commit_sha }}
      release_channel: stable
      # The tags to use when publishing canaries. The main one we should
      # always include is "canary" but we can use multiple (e.g. alpha,
      # beta, rc). To declare multiple, use a comma-separated string, like
      # this:
      #   dist_tag: "canary,alpha,beta,rc"
      #
      # TODO: We currently tag canaries with "next" in addition to "canary"
      # because this used to be called the "next" channel and some
      # downstream consumers might still expect that tag. We can remove this
      # after some time has elapsed and the change has been communicated.
      dist_tag: canary,next
      only_packages: ${{ inputs.only_packages }}
      skip_packages: ${{ inputs.skip_packages }}
      dry: ${{ inputs.dry }}
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  publish_prerelease_experimental:
    name: Publish to Experimental channel
    uses: facebook/react/.github/workflows/runtime_prereleases.yml@main
    permissions:
      # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
      actions: read
    # NOTE: Intentionally running these jobs sequentially because npm
    # will sometimes fail if you try to concurrently publish two
    # different versions of the same package, even if they use different
    # dist tags.
    needs: publish_prerelease_canary
    # Ensures the job runs even if canary is skipped
    if: always()
    with:
      commit_sha: ${{ inputs.prerelease_commit_sha }}
      release_channel: experimental
      dist_tag: experimental
      only_packages: ${{ inputs.only_packages }}
      skip_packages: ${{ inputs.skip_packages }}
      dry: ${{ inputs.dry }}
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runtime_prereleases_nightly perms .github/workflows/runtime_prereleases_nightly.yml
Triggers
schedule
Runs on
Jobs
publish_prerelease_canary, publish_prerelease_experimental
View raw YAML
name: (Runtime) Publish Prereleases Nightly

on:
  schedule:
    # At 10 minutes past 16:00 on Mon, Tue, Wed, Thu, and Fri
    - cron: 10 16 * * 1,2,3,4,5

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles

jobs:
  publish_prerelease_canary:
    name: Publish to Canary channel
    uses: facebook/react/.github/workflows/runtime_prereleases.yml@main
    permissions:
      # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
      actions: read
    with:
      commit_sha: ${{ github.sha }}
      release_channel: stable
      dist_tag: canary,next
      enableFailureNotification: true
      dry: false
    secrets:
      DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  publish_prerelease_experimental:
    name: Publish to Experimental channel
    uses: facebook/react/.github/workflows/runtime_prereleases.yml@main
    permissions:
      # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
      actions: read
    # NOTE: Intentionally running these jobs sequentially because npm
    # will sometimes fail if you try to concurrently publish two
    # different versions of the same package, even if they use different
    # dist tags.
    needs: publish_prerelease_canary
    with:
      commit_sha: ${{ github.sha }}
      release_channel: experimental
      dist_tag: experimental
      enableFailureNotification: true
      dry: false
    secrets:
      DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runtime_releases_from_npm_manual perms .github/workflows/runtime_releases_from_npm_manual.yml
Triggers
workflow_dispatch
Runs on
ubuntu-latest, ubuntu-latest
Jobs
notify, publish
Actions
tsickert/discord-webhook
Commands
  • rm -rf build
  • yarn install --frozen-lockfile
  • yarn --cwd scripts/release install --frozen-lockfile
  • cp ./scripts/release/ci-npmrc ~/.npmrc
  • scripts/release/prepare-release-from-npm.js \ --ci \ --skipTests \ --version=${{ inputs.version_to_promote }} \ --publishVersion=${{ inputs.version_to_publish }} \ --onlyPackages=${{ inputs.only_packages }}
  • scripts/release/prepare-release-from-npm.js \ --ci \ --skipTests \ --version=${{ inputs.version_to_promote }} \ --publishVersion=${{ inputs.version_to_publish }} \ --skipPackages=${{ inputs.skip_packages }}
  • ls -R build/node_modules
  • scripts/release/publish.js \ --ci \ --tags=${{ inputs.tags }} \ --publishVersion=${{ inputs.version_to_publish }} \ --onlyPackages=${{ inputs.only_packages }} ${{ (inputs.dry && '') || '\'}} ${{ inputs.dry && '--dry' || '' }}
View raw YAML
name: (Runtime) Publish Releases from NPM Manual

on:
  workflow_dispatch:
    inputs:
      version_to_promote:
        required: true
        description: Current npm version (non-experimental) to promote
        type: string
      version_to_publish:
        required: true
        description: Version to publish for the specified packages
        type: string
      only_packages:
        description: Packages to publish (space separated)
        type: string
      skip_packages:
        description: Packages to NOT publish (space separated)
        type: string
      tags:
        description: NPM tags (space separated)
        type: string
        default: untagged
      dry:
        required: true
        description: Dry run instead of publish?
        type: boolean
        default: true
      force_notify:
        description: Force a Discord notification?
        type: boolean
        default: false

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

jobs:
  notify:
    if: ${{ inputs.force_notify || inputs.dry == false || inputs.dry == 'false' }}
    runs-on: ubuntu-latest
    steps:
      - name: Discord Webhook Action
        uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
        with:
          webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
          embed-author-name: ${{ github.event.sender.login }}
          embed-author-url: ${{ github.event.sender.html_url }}
          embed-author-icon-url: ${{ github.event.sender.avatar_url }}
          embed-title: "⚠️ Publishing release from NPM${{ (inputs.dry && ' (dry run)') || '' }}"
          embed-description: |
            ```json
            ${{ toJson(inputs) }}
            ```
          embed-url: https://github.com/facebook/react/actions/runs/${{ github.run_id }}

  publish:
    name: Publish releases
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn --cwd scripts/release install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: cp ./scripts/release/ci-npmrc ~/.npmrc
      - if: '${{ inputs.only_packages }}'
        name: 'Prepare ${{ inputs.only_packages }} from NPM'
        run: |
          scripts/release/prepare-release-from-npm.js \
            --ci \
            --skipTests \
            --version=${{ inputs.version_to_promote }} \
            --publishVersion=${{ inputs.version_to_publish }} \
            --onlyPackages=${{ inputs.only_packages }}
      - if: '${{ inputs.skip_packages }}'
        name: 'Prepare all packages EXCEPT ${{ inputs.skip_packages }} from NPM'
        run: |
          scripts/release/prepare-release-from-npm.js \
            --ci \
            --skipTests \
            --version=${{ inputs.version_to_promote }} \
            --publishVersion=${{ inputs.version_to_publish }} \
            --skipPackages=${{ inputs.skip_packages }}
      - name: Check prepared files
        run: ls -R build/node_modules
      - if: '${{ inputs.only_packages }}'
        name: 'Publish ${{ inputs.only_packages }}'
        run: |
          scripts/release/publish.js \
            --ci \
            --tags=${{ inputs.tags }} \
            --publishVersion=${{ inputs.version_to_publish }} \
            --onlyPackages=${{ inputs.only_packages }} ${{ (inputs.dry && '') || '\'}}
            ${{ inputs.dry && '--dry' || '' }}
      - if: '${{ inputs.skip_packages }}'
        name: 'Publish all packages EXCEPT ${{ inputs.skip_packages }}'
        run: |
          scripts/release/publish.js \
            --ci \
            --tags=${{ inputs.tags }} \
            --publishVersion=${{ inputs.version_to_publish }} \
            --skipPackages=${{ inputs.skip_packages }} ${{ (inputs.dry && '') || '\'}}
            ${{ inputs.dry && '--dry' || '' }}
      - name: Archive released package for debugging
        uses: actions/upload-artifact@v4
        with:
          name: build
          path: |
            ./build/node_modules
shared_check_maintainer perms .github/workflows/shared_check_maintainer.yml
Triggers
workflow_call
Runs on
ubuntu-latest
Jobs
check_maintainer
View raw YAML
name: (Shared) Check maintainer

on:
  workflow_call:
    inputs:
      actor:
        required: true
        type: string
    outputs:
      is_core_team:
        value: ${{ jobs.check_maintainer.outputs.is_core_team }}

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1

jobs:
  check_maintainer:
    runs-on: ubuntu-latest
    permissions:
      # We fetch the contents of the MAINTAINERS file
      contents: read
    outputs:
      is_core_team: ${{ steps.check_if_actor_is_maintainer.outputs.result }}
    steps:
      - name: Check if actor is maintainer
        id: check_if_actor_is_maintainer
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const actor = '${{ inputs.actor }}';
            const res = await github.rest.repos.getContent({
              owner: 'facebook',
              repo: 'react',
              path: 'MAINTAINERS',
              ref: 'main',
              headers: { Accept: 'application/vnd.github+json' }
            });
            if (res.status !== 200) {
              console.error(res);
              throw new Error('Unable to fetch MAINTAINERS file');
            }
            content = Buffer.from(res.data.content, 'base64').toString();
            if (content == null || typeof content !== 'string') {
              throw new Error('Unable to retrieve MAINTAINERS file');
            }

            const maintainers = new Set(content.split('\n'));
            if (maintainers.has(actor)) {
              console.log(`🟢 ${actor} is a maintainer`);
              return true;
            }
            console.log(`🔴 ${actor} is NOT a maintainer`);
            return null;
shared_cleanup_merged_branch_caches perms .github/workflows/shared_cleanup_merged_branch_caches.yml
Triggers
pull_request, workflow_dispatch
Runs on
ubuntu-latest
Jobs
cleanup
Commands
  • echo "Fetching list of cache key" cacheKeysForPR=$(gh cache list --ref $BRANCH --limit 100 --json id --jq '.[].id') ## Setting this to not fail the workflow while deleting cache keys. set +e for cacheKey in $cacheKeysForPR do gh cache delete $cacheKey echo "Deleting $cacheKey" done echo "Done"
View raw YAML
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#force-deletion-of-caches-overriding-default-cache-eviction-policy

name: (Shared) Cleanup Merged Branch Caches
on:
  pull_request:
    types:
      - closed
  workflow_dispatch:
    inputs:
      pr_number:
        required: true
        type: string

permissions: {}

jobs:
  cleanup:
    runs-on: ubuntu-latest
    permissions:
      # `actions:write` permission is required to delete caches
      #   See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id
      actions: write
      contents: read
    steps:
      - name: Cleanup
        run: |
          echo "Fetching list of cache key"
          cacheKeysForPR=$(gh cache list --ref $BRANCH --limit 100 --json id --jq '.[].id')

          ## Setting this to not fail the workflow while deleting cache keys.
          set +e
          for cacheKey in $cacheKeysForPR
          do
              gh cache delete $cacheKey
              echo "Deleting $cacheKey"
          done
          echo "Done"
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GH_REPO: ${{ github.repository }}
          BRANCH: refs/pull/${{ inputs.pr_number || github.event.pull_request.number }}/merge
shared_cleanup_stale_branch_caches perms .github/workflows/shared_cleanup_stale_branch_caches.yml
Triggers
schedule, workflow_dispatch
Runs on
ubuntu-latest
Jobs
cleanup
Commands
  • echo "Fetching list of cache keys" cacheKeysForPR=$(gh cache list --limit 100 --json id,ref --jq '.[] | select(.ref != "refs/heads/main") | .id') ## Setting this to not fail the workflow while deleting cache keys. set +e for cacheKey in $cacheKeysForPR do gh cache delete $cacheKey echo "Deleting $cacheKey" done echo "Done"
View raw YAML
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#force-deletion-of-caches-overriding-default-cache-eviction-policy

name: (Shared) Cleanup Stale Branch Caches
on:
  schedule:
    # Every 6 hours
    - cron: 0 */6 * * *
  workflow_dispatch:

permissions: {}

jobs:
  cleanup:
    runs-on: ubuntu-latest
    permissions:
      # `actions:write` permission is required to delete caches
      #   See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id
      actions: write
      contents: read
    steps:
      - name: Cleanup
        run: |
          echo "Fetching list of cache keys"
          cacheKeysForPR=$(gh cache list --limit 100 --json id,ref --jq '.[] | select(.ref != "refs/heads/main") | .id')

          ## Setting this to not fail the workflow while deleting cache keys.
          set +e
          for cacheKey in $cacheKeysForPR
          do
              gh cache delete $cacheKey
              echo "Deleting $cacheKey"
          done
          echo "Done"
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GH_REPO: ${{ github.repository }}
shared_close_direct_sync_branch_prs perms .github/workflows/shared_close_direct_sync_branch_prs.yml
Triggers
pull_request
Runs on
ubuntu-latest
Jobs
close_pr
View raw YAML
name: (Shared) Close Direct Sync Branch PRs

on:
  pull_request:
    branches:
      - 'builds/facebook-**'

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1

jobs:
  close_pr:
    runs-on: ubuntu-latest
    permissions:
      # Used to create a review and close PRs
      pull-requests: write
      contents: write
    steps:
      - name: Close PR
        uses: actions/github-script@v7
        with:
          script: |
            const owner = context.repo.owner;
            const repo = context.repo.repo;
            const pullNumber = ${{ github.event.number }};

            await github.rest.pulls.createReview({
              owner,
              repo,
              pull_number: pullNumber,
              body: 'Do not land changes to `${{ github.event.pull_request.base.ref }}`. Please re-open your PR targeting `main` instead.',
              event: 'REQUEST_CHANGES'
            });
            await github.rest.pulls.update({
              owner,
              repo,
              pull_number: pullNumber,
              state: 'closed'
            });
shared_label_core_team_prs perms .github/workflows/shared_label_core_team_prs.yml
Triggers
pull_request_target
Runs on
ubuntu-latest, ubuntu-latest
Jobs
check_access, check_maintainer, label
Commands
  • echo ${{ github.event.pull_request.author_association }}
  • echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"
View raw YAML
name: (Shared) Label Core Team PRs

on:
  pull_request_target:
    types: [opened]

permissions: {}

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1

jobs:
  check_access:
    runs-on: ubuntu-latest
    outputs:
      is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }}
    steps:
      - run: echo ${{ github.event.pull_request.author_association }}
      - name: Check is member or collaborator
        id: check_is_member_or_collaborator
        if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }}
        run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"

  check_maintainer:
    if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }}
    needs: [check_access]
    uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main
    permissions:
      # Used by check_maintainer
      contents: read
    with:
      actor: ${{ github.event.pull_request.user.login }}

  label:
    if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }}
    runs-on: ubuntu-latest
    needs: check_maintainer
    permissions:
      # Used to add labels on issues
      issues: write
      # Used to add labels on PRs
      pull-requests: write
    steps:
      - name: Label PR as React Core Team
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.addLabels({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: ${{ github.event.number }},
              labels: ['React Core Team']
            });
shared_lint perms .github/workflows/shared_lint.yml
Triggers
push, pull_request
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
prettier, eslint, check_license, test_print_warnings
Commands
  • rm -rf build
  • yarn install --frozen-lockfile
  • yarn prettier-check
  • rm -rf build
  • yarn install --frozen-lockfile
  • node ./scripts/tasks/eslint
  • rm -rf build
  • yarn install --frozen-lockfile
View raw YAML
name: (Shared) Lint

on:
  push:
    branches: [main]
  pull_request:

permissions: {}

concurrency:
  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
  cancel-in-progress: true

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles
  # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
  SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1

jobs:
  prettier:
    name: Run prettier
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: yarn prettier-check

  eslint:
    name: Run eslint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: node ./scripts/tasks/eslint

  check_license:
    name: Check license
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: ./scripts/ci/check_license.sh

  test_print_warnings:
    name: Test print warnings
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          cache: yarn
          cache-dependency-path: yarn.lock
      - name: Restore cached node_modules
        uses: actions/cache@v4
        id: node_modules
        with:
          path: |
            **/node_modules
          key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
      - name: Ensure clean build directory
        run: rm -rf build
      - run: yarn install --frozen-lockfile
        if: steps.node_modules.outputs.cache-hit != 'true'
      - run: ./scripts/ci/test_print_warnings.sh
shared_stale perms .github/workflows/shared_stale.yml
Triggers
schedule, workflow_dispatch
Runs on
ubuntu-latest
Jobs
stale
Actions
actions/stale
View raw YAML
# Configuration for stale action workflow - https://github.com/actions/stale
name: (Shared) Manage stale issues and PRs
on:
  schedule:
    # Run hourly
    - cron: '0 * * * *'
  workflow_dispatch:

permissions:
  # https://github.com/actions/stale/tree/v9/?tab=readme-ov-file#recommended-permissions
  issues: write
  pull-requests: write

env:
  TZ: /usr/share/zoneinfo/America/Los_Angeles

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/stale@v9
        with:
          # --- Issues & PRs ---
          # Number of days of inactivity before an issue or PR becomes stale
          days-before-stale: 90
          # Number of days of inactivity before a stale issue or PR is closed
          days-before-close: 7
          # API calls per run
          operations-per-run: 100

          # --- Issues ---
          stale-issue-label: "Resolution: Stale"
          # Comment to post when marking an issue as stale
          stale-issue-message: >
            This issue has been automatically marked as stale.
            **If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open.
            We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
          # Comment to post when closing a stale issue
          close-issue-message: >
            Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you!
          # Issues with these labels will never be considered stale
          exempt-issue-labels: "Partner,React Core Team,Resolution: Backlog,Type: Bug,Type: Discussion,Type: Needs Investigation,Type: Regression,Type: Feature Request,Type: Enhancement"

          # --- PRs ---
          stale-pr-label: "Resolution: Stale"
          # Comment to post when marking a pull request as stale
          stale-pr-message: >
            This pull request has been automatically marked as stale.
            **If this pull request is still relevant, please leave any comment** (for example, "bump"), and we'll keep it open.
            We are sorry that we haven't been able to prioritize reviewing it yet. Your contribution is very much appreciated.
          # Comment to post when closing a stale pull request
          close-pr-message: >
            Closing this pull request after a prolonged period of inactivity. If this issue is still present in the latest release, please ask for this pull request to be reopened. Thank you!
          # PRs with these labels will never be considered stale
          exempt-pr-labels: "Partner,React Core Team,Resolution: Backlog,Type: Bug,Type: Discussion,Type: Needs Investigation,Type: Regression,Type: Feature Request,Type: Enhancement"