facebook/react-native

22 workflows · maturity 50% · 7 patterns · GitHub ↗

Security 6.82/100

Practices

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

Detected patterns

Security dimensions

permissions
6.8
security scan
0
supply chain
0
secret handling
0
harden runner
0

Workflows (22)

analyze-pr perms .github/workflows/analyze-pr.yml
Triggers
pull_request_target
Runs on
ubuntu-latest
Jobs
analyze_pr
Commands
  • exit 1
View raw YAML
name: Analyze Pull Request

on:
  pull_request_target:
    types: [opened, edited, reopened, synchronize]

permissions:
  pull-requests: write
  issues: write

jobs:
  analyze_pr:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    steps:
      - name: Check out main branch
        uses: actions/checkout@v6
      - name: Setup Node.js
        uses: ./.github/actions/setup-node
      - name: Run yarn install
        uses: ./.github/actions/yarn-install
      - name: Check PR body
        id: check-pr-body
        uses: actions/github-script@v8
        with:
          script: |
            const validatePRBody = require('./.github/workflow-scripts/validatePRBody.js');
            const {message, status} = validatePRBody(context.payload.pull_request.body);
            core.setOutput('message', message);
            core.setOutput('status', status);
      - name: Check branch target
        id: check-branch-target
        uses: actions/github-script@v8
        with:
          script: |
            const checkBranchTarget = require('./.github/workflow-scripts/checkBranchTarget.js');
            const baseRef = context.payload.pull_request.base.ref;
            const {message, status, shouldAddPickLabel} = checkBranchTarget(baseRef);

            if (shouldAddPickLabel) {
              await github.rest.issues.addLabels({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                labels: ['Pick Request'],
              });
            }

            core.setOutput('message', message);
            core.setOutput('status', status);
      - name: Post PR comment
        uses: ./.github/actions/post-pr-comment
        with:
          marker: '<!-- analyze-pr -->'
          sections: '[${{ toJSON(steps.check-pr-body.outputs.message) }}, ${{ toJSON(steps.check-branch-target.outputs.message) }}]'
      - name: Fail if validation errors
        if: steps.check-pr-body.outputs.status == 'FAIL' || steps.check-branch-target.outputs.status == 'FAIL'
        run: exit 1
api-changes perms .github/workflows/api-changes.yml
Triggers
pull_request_target
Runs on
ubuntu-latest
Jobs
api_changes
View raw YAML
name: Analyze API Changes

on:
  pull_request_target:
    types: [opened, edited, reopened, synchronize]

permissions:
  pull-requests: write

jobs:
  api_changes:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    steps:
      - name: Check out main branch
        uses: actions/checkout@v6
      - name: Setup Node.js
        uses: ./.github/actions/setup-node
      - name: Run yarn install
        uses: ./.github/actions/yarn-install
      - name: Run diff-js-api-changes
        id: diff-js-api-changes
        uses: ./.github/actions/diff-js-api-changes
      - name: Post PR comment
        uses: ./.github/actions/post-pr-comment
        with:
          marker: '<!-- api-changes -->'
          sections: '[${{ toJSON(steps.diff-js-api-changes.outputs.message) }}]'
autorebase perms .github/workflows/autorebase.yml
Triggers
issue_comment
Runs on
ubuntu-latest
Jobs
rebase
Actions
cirrus-actions/rebase
View raw YAML
name: Automatic Rebase
# This workflow is used to automatically rebase a PR when a comment is made
# containing the text "/rebase". It uses the cirrus-actions/rebase action.
# See https://github.com/cirrus-actions/rebase
on:
  issue_comment:
    types: [created]
permissions:
  contents: read
jobs:
  rebase:
    name: Rebase
    permissions:
      contents: write # for cirrus-actions/rebase to push code to rebase
      pull-requests: read # for cirrus-actions/rebase to get info about PR
    runs-on: ubuntu-latest
    if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
    steps:
      - name: Checkout the latest code
        uses: actions/checkout@v6
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          fetch-depth: 0 # otherwise, you will fail to push refs to dest repo
      - name: Automatic Rebase
        uses: cirrus-actions/rebase@1.8
        env:
          GITHUB_TOKEN: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
bump-podfile-lock .github/workflows/bump-podfile-lock.yml
Triggers
workflow_call
Runs on
macos-latest
Jobs
bump-podfile-lock
Commands
  • git config --local user.email "bot@reactnative.dev" git config --local user.name "React Native Bot"
  • TAG="${{ github.ref_name }}"; BRANCH_NAME=$(echo "$TAG" | sed -E 's/v([0-9]+\.[0-9]+)\.[0-9]+(-rc\.[0-9]+)?/\1-stable/') echo "Branch Name is $BRANCH_NAME" echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
  • git checkout "$BRANCH_NAME" git fetch git pull origin "$BRANCH_NAME"
  • cd packages/rn-tester rm Podfile.lock bundle install bundle exec pod install
  • git add packages/rn-tester/Podfile.lock git commit -m "[LOCAL] Bump Podfile.lock" git push origin "$BRANCH_NAME"
View raw YAML
name: Bump Podfile.lock

on:
  workflow_call: # this directive allow us to call this workflow from other workflows

jobs:
  bump-podfile-lock:
    runs-on: macos-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          fetch-depth: 0
          fetch-tags: true
      - name: Install dependencies
        uses: ./.github/actions/yarn-install
      - name: Configure git
        run: |
          git config --local user.email "bot@reactnative.dev"
          git config --local user.name "React Native Bot"
      - name: Setup xcode
        uses: ./.github/actions/setup-xcode
      - name: Extract branch name
        run: |
          TAG="${{ github.ref_name }}";
          BRANCH_NAME=$(echo "$TAG" | sed -E 's/v([0-9]+\.[0-9]+)\.[0-9]+(-rc\.[0-9]+)?/\1-stable/')
          echo "Branch Name is $BRANCH_NAME"
          echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
      - name: Checkout release branch
        run: |
          git checkout "$BRANCH_NAME"
          git fetch
          git pull origin "$BRANCH_NAME"
      - name: Bump podfile.lock
        run: |
          cd packages/rn-tester
          rm Podfile.lock
          bundle install
          bundle exec pod install
      - name: Commit changes
        run: |
          git add packages/rn-tester/Podfile.lock
          git commit -m "[LOCAL] Bump Podfile.lock"
          git push origin "$BRANCH_NAME"
cache-reaper .github/workflows/cache-reaper.yml
Triggers
workflow_dispatch, schedule
Runs on
ubuntu-latest
Jobs
cache-cleaner
Commands
  • node scripts/clean-gha-cache.js
View raw YAML
name: Keep Github Actions Cache < 10GB

on:
  workflow_dispatch:
  schedule:
    # Run every 2hrs during weekdays
    - cron: "0 0/2 * * 1-5"

jobs:
  cache-cleaner:
    if: github.repository == 'facebook/react-native'
    runs-on: ubuntu-latest
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@v6
      - name: Setup Node.js
        uses: ./.github/actions/setup-node
      - name: Trim the cache
        run: node scripts/clean-gha-cache.js
check-for-reproducer .github/workflows/check-for-reproducer.yml
Triggers
issues
Runs on
ubuntu-latest
Jobs
check-for-reproducer
View raw YAML
name: Check for reproducer
# This workflow is triggered when issue is created or edited.
on:
  issues:
    types: [opened, edited]

jobs:
  check-for-reproducer:
    runs-on: ubuntu-latest
    if: |
      github.repository == 'facebook/react-native' && github.event.issue.pull_request == null && github.event.issue.state == 'open' && !contains(github.event.issue.labels.*.name, ':open_umbrella: Umbrella')
    steps:
      - uses: actions/checkout@v6
      - uses: actions/github-script@v8
        with:
          github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          script: |
            const checkForReproducer = require('./.github/workflow-scripts/checkForReproducer.js')
            await checkForReproducer(github, context)
close-pr perms .github/workflows/close-pr.yml
Triggers
push
Runs on
ubuntu-latest
Jobs
comment-and-label
View raw YAML
name: Label closed PR as merged and leave a comment
on:
  push

permissions:
  contents: read
  pull-requests: write

jobs:
  comment-and-label:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    steps:
      - uses: actions/github-script@v8
        with:
          github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          script: |
            if(!context.payload.commits || !context.payload.commits.length) return;
            const sha = context.payload.commits[0].id;

            const {commit, author} = (await github.rest.repos.getCommit({
              ref: sha,
              owner: context.repo.owner,
              repo: context.repo.repo,
            })).data;

            // Looking at the commit message, checks which PR number, if any, was closed by this commit
            const getClosedPrIfExists = (commit) => {
              if(!commit || !commit.message) return;
              const prClosingRegex = /Closes https:\/\/github.com\/facebook\/react-native\/pull\/([0-9]+)|Pull Request resolved: https:\/\/github.com\/facebook\/react-native\/pull\/([0-9]+)/;
              const prClosingMatch = commit.message.match(prClosingRegex);
              if(!prClosingMatch || (!prClosingMatch[1] && ! prClosingMatch[2])) return;
              return prClosingMatch[1] ?? prClosingMatch[2];
            };

            const closedPrNumber = getClosedPrIfExists(commit);
            if(!closedPrNumber) return;

            const pr = (await github.rest.pulls.get({
              pull_number: closedPrNumber,
              owner: context.repo.owner,
              repo: context.repo.repo,
            })).data;

            const authorName = author?.login ? `@${author.login}` : commit.author.name;

            github.rest.issues.createComment({
              issue_number: closedPrNumber,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `This pull request was successfully merged by ${authorName} in **${sha}**\n\n<sup>[When will my fix make it into a release?](https://github.com/reactwg/react-native-releases/blob/main/docs/faq.md#when-will-my-fix-make-it-into-a-release) | [How to file a pick request?](https://github.com/reactwg/react-native-releases/blob/main/docs/faq.md#how-to-open-a-pick-request)</sup>`
            });

            // If the PR has already been processed (labeled as Merged), skip it
            const mergedLabel = "Merged";
            if(pr.labels && pr.labels.some(label => label.name === mergedLabel)) return;

            github.rest.issues.addLabels({
              issue_number: closedPrNumber,
              owner: context.repo.owner,
              repo: context.repo.repo,
              labels: [mergedLabel]
            });
create-draft-release .github/workflows/create-draft-release.yml
Triggers
workflow_call
Runs on
ubuntu-latest
Jobs
create-draft-release
Commands
  • git config --local user.email "bot@reactnative.dev" git config --local user.name "React Native Bot"
View raw YAML
name: Create Draft Release

on:
  workflow_call:
    inputs:
      hermesVersion:
        required: false
        type: string
        description: The version of Hermes to use for this release (eg. 0.15.0). If not specified, it will use React Native Version
      hermesV1Version:
        required: false
        type: string
        description: The version of Hermes V1 to use for this release (eg. 250829098.0.2). If not specified, it will use React Native Version

jobs:
  create-draft-release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          fetch-depth: 0
          fetch-tags: true
      - name: Install dependencies
        uses: ./.github/actions/yarn-install
      - name: Configure Git
        shell: bash
        run: |
          git config --local user.email "bot@reactnative.dev"
          git config --local user.name "React Native Bot"
      - name: Create draft release
        uses: actions/github-script@v8
        id: create-draft-release
        with:
          script: |
            const {createDraftRelease} = require('./.github/workflow-scripts/createDraftRelease.js');
            const version = '${{ github.ref_name }}';
            const {isLatest} = require('./.github/workflow-scripts/publishTemplate.js');
            return (await createDraftRelease(version, isLatest(), '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}', '${{ inputs.hermesVersion }}', '${{ inputs.hermesV1Version }}')).id;
          result-encoding: string
      - name: Upload release assets for DotSlash
        uses: actions/github-script@v8
        env:
          RELEASE_ID: ${{ steps.create-draft-release.outputs.result }}
        with:
          script: |
            const {uploadReleaseAssetsForDotSlashFiles} = require('./scripts/releases/upload-release-assets-for-dotslash.js');
            const version = '${{ github.ref_name }}';
            await uploadReleaseAssetsForDotSlashFiles({
              version,
              token: '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}',
              releaseId: process.env.RELEASE_ID,
            });
create-release .github/workflows/create-release.yml
Triggers
workflow_dispatch
Runs on
ubuntu-latest
Jobs
create_release
Commands
  • BRANCH="$(git branch --show-current)" PATTERN='^0\.[0-9]+-stable$' if [[ $BRANCH =~ $PATTERN ]]; then echo "On a stable branch" echo "ON_STABLE_BRANCH=true" >> $GITHUB_OUTPUT fi
  • echo "ON_STABLE_BRANCH ${{steps.check_stable_branch.outputs.ON_STABLE_BRANCH}}"
  • TAG="v${{ inputs.version }}" TAG_EXISTS=$(git tag -l "$TAG") if [[ -n "$TAG_EXISTS" ]]; then echo "Version tag already exists!" echo "TAG_EXISTS=true" >> $GITHUB_OUTPUT fi
View raw YAML
name: Create release

on:
  workflow_dispatch:
    inputs:
      version:
        description: "The version of React Native we want to release. For example 0.75.0-rc.0"
        required: true
        type: string
      is-latest-on-npm:
        description: "Whether we want to tag this release as latest on NPM"
        required: true
        type: boolean
        default: false
      dry-run:
        description: "Whether the job should be executed in dry-run mode or not"
        type: boolean
        default: true

jobs:
  create_release:
    if: github.repository == 'facebook/react-native'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          fetch-depth: 0
          fetch-tags: 'true'
      - name: Check if on stable branch
        id: check_stable_branch
        run: |
          BRANCH="$(git branch --show-current)"
          PATTERN='^0\.[0-9]+-stable$'
          if [[ $BRANCH =~ $PATTERN ]]; then
            echo "On a stable branch"
            echo "ON_STABLE_BRANCH=true" >> $GITHUB_OUTPUT
          fi
      - name: Print output
        run: echo "ON_STABLE_BRANCH ${{steps.check_stable_branch.outputs.ON_STABLE_BRANCH}}"
      - name: Check if tag already exists
        id: check_if_tag_exists
        run: |
          TAG="v${{ inputs.version }}"
          TAG_EXISTS=$(git tag -l "$TAG")
          if [[ -n "$TAG_EXISTS" ]]; then
            echo "Version tag already exists!"
            echo "TAG_EXISTS=true" >> $GITHUB_OUTPUT
          fi
      - name: Execute Prepare Release
        if: ${{ steps.check_stable_branch.outputs.ON_STABLE_BRANCH && !steps.check_if_tag_exists.outputs.TAG_EXISTS }}
        uses: ./.github/actions/create-release
        with:
          version: ${{ inputs.version }}
          is-latest-on-npm: ${{ inputs.is-latest-on-npm }}
          dry-run: ${{ inputs.dry-run }}
generate-changelog .github/workflows/generate-changelog.yml
Triggers
workflow_call
Runs on
ubuntu-latest
Jobs
generate-changelog
Commands
  • git config --local user.email "bot@reactnative.dev" git config --local user.name "React Native Bot"
View raw YAML
name: Generate Changelog

on:
  workflow_call:

jobs:
  generate-changelog:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          fetch-depth: 0
          fetch-tags: true
      - name: Install dependencies
        uses: ./.github/actions/yarn-install
      - name: Configure Git
        shell: bash
        run: |
          git config --local user.email "bot@reactnative.dev"
          git config --local user.name "React Native Bot"
      - name: Generate Changelog
        uses: actions/github-script@v8
        with:
          script: |
            const {generateChangelog} = require('./.github/workflow-scripts/generateChangelog');
            const version = '${{ github.ref_name }}';
            await generateChangelog(version, '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}');
monitor-new-issues .github/workflows/monitor-new-issues.yml
Triggers
schedule, workflow_dispatch
Runs on
ubuntu-latest
Jobs
monitor-issues
Actions
react-native-community/repo-monitor
Commands
  • ONCALLS=$(node ./.github/workflow-scripts/extractIssueOncalls.js "${{ secrets.ONCALL_SCHEDULE }}") ONCALL1=$(echo $ONCALLS | cut -d ' ' -f 1) ONCALL2=$(echo $ONCALLS | cut -d ' ' -f 2) echo "oncall1=$ONCALL1" >> $GITHUB_ENV echo "oncall2=$ONCALL2" >> $GITHUB_ENV
View raw YAML
name: Monitor React Native New Issues

on:
  schedule:
    - cron: "0 0,6,12,18 * * *"
  workflow_dispatch:

# Reminder for when we have to update the schedule (before Jan 2026):
# the secrets.ONCALL_SCHEDULE secret must be on a single line and must have all the `"` escaped as `\"`.
# Only a meta engineer can update it through the OSS internal portal.

jobs:
  monitor-issues:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Set up Node.js
        uses: ./.github/actions/setup-node
      - name: Install dependencies
        uses:  ./.github/actions/yarn-install
      - name: Extract next oncall
        run: |
          ONCALLS=$(node ./.github/workflow-scripts/extractIssueOncalls.js "${{ secrets.ONCALL_SCHEDULE }}")
          ONCALL1=$(echo $ONCALLS | cut -d ' ' -f 1)
          ONCALL2=$(echo $ONCALLS | cut -d ' ' -f 2)
          echo "oncall1=$ONCALL1" >> $GITHUB_ENV
          echo "oncall2=$ONCALL2" >> $GITHUB_ENV
      - name: Monitor New Issues
        uses: react-native-community/repo-monitor@v1.0.1
        with:
          task: "monitor-issues"
          git_secret: ${{ secrets.GITHUB_TOKEN }}
          notifier: "discord"
          fetch_data_interval: 6
          repo_owner: "facebook"
          repo_name: "react-native"
          discord_webhook_url: "${{ secrets.DISCORD_WEBHOOK_URL }}"
          discord_id_type: "user"
          discord_ids: "${{ env.oncall1 }},${{ env.oncall2 }}"
needs-attention perms .github/workflows/needs-attention.yml
Triggers
issue_comment
Runs on
ubuntu-latest
Jobs
applyNeedsAttentionLabel
Actions
react-native-community/needs-attention
Commands
  • echo '${{ steps.needs-attention.outputs.result }}'
View raw YAML
name: Issue Needs Attention
# This workflow is triggered on issue comments.
on:
  issue_comment:
    types: [created]

permissions:
  contents: read

jobs:
  applyNeedsAttentionLabel:
    permissions:
      contents: read # for actions/checkout to fetch code
      issues: write # for react-native-community/needs-attention to label issues
    name: Apply Needs Attention Label
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    steps:
      - uses: actions/checkout@v6
      - name: Apply Needs Attention Label
        uses: react-native-community/needs-attention@v2.0.0
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          response-required-label: "Needs: Author Feedback"
          needs-attention-label: "Needs: Attention"
        id: needs-attention
      - name: Result
        run: echo '${{ steps.needs-attention.outputs.result }}'
nightly .github/workflows/nightly.yml
Triggers
workflow_dispatch, schedule
Runs on
ubuntu-latest, 8-core-ubuntu, 8-core-ubuntu
Jobs
set_release_type, prebuild_apple_dependencies, prebuild_react_native_core, build_android, build_npm_package
Commands
  • echo "Setting release type to nightly" echo "RELEASE_TYPE=nightly" >> $GITHUB_OUTPUT
View raw YAML
name: Nightly

on:
  workflow_dispatch:
  # nightly build @ 2:15 AM UTC
  schedule:
    - cron: "15 2 * * *"

jobs:
  set_release_type:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    outputs:
      RELEASE_TYPE: ${{ steps.set_release_type.outputs.RELEASE_TYPE }}
    env:
      EVENT_NAME: ${{ github.event_name }}
      REF: ${{ github.ref }}
    steps:
      - id: set_release_type
        run: |
          echo "Setting release type to nightly"
          echo "RELEASE_TYPE=nightly" >> $GITHUB_OUTPUT

  prebuild_apple_dependencies:
    if: github.repository == 'facebook/react-native'
    uses: ./.github/workflows/prebuild-ios-dependencies.yml
    secrets: inherit

  prebuild_react_native_core:
    uses: ./.github/workflows/prebuild-ios-core.yml
    with:
      use-hermes-nightly: true
      version-type: nightly
    secrets: inherit
    needs: [prebuild_apple_dependencies]

  build_android:
    runs-on: 8-core-ubuntu
    if: github.repository == 'facebook/react-native'
    needs: [set_release_type]
    container:
      image: reactnativecommunity/react-native-android:latest
      env:
        TERM: "dumb"
        # Set the encoding to resolve a known character encoding issue with decompressing tar.gz files in containers
        # via Gradle: https://github.com/gradle/gradle/issues/23391#issuecomment-1878979127
        LC_ALL: C.UTF8
        GRADLE_OPTS: "-Dorg.gradle.daemon=false"
        ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
        ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
        ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_USERNAME }}
        ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_PASSWORD }}
        REACT_NATIVE_DOWNLOADS_DIR: /opt/react-native-downloads
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Build Android
        uses: ./.github/actions/build-android
        with:
          release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
          gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}

  build_npm_package:
    runs-on: 8-core-ubuntu
    needs:
      [
        set_release_type,
        build_android,
        prebuild_apple_dependencies,
        prebuild_react_native_core,
      ]
    container:
      image: reactnativecommunity/react-native-android:latest
      env:
        TERM: "dumb"
        GRADLE_OPTS: "-Dorg.gradle.daemon=false"
        # Set the encoding to resolve a known character encoding issue with decompressing tar.gz files in containers
        # via Gradle: https://github.com/gradle/gradle/issues/23391#issuecomment-1878979127
        LC_ALL: C.UTF8
        # By default we only build ARM64 to save time/resources. For release/nightlies, we override this value to build all archs.
        ORG_GRADLE_PROJECT_reactNativeArchitectures: "arm64-v8a"
        REACT_NATIVE_DOWNLOADS_DIR: /opt/react-native-downloads
    env:
      GHA_NPM_TOKEN: ${{ secrets.GHA_NPM_TOKEN }}
      ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
      ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
      ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_USERNAME }}
      ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_PASSWORD }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Build and Publish NPM Package
        uses: ./.github/actions/build-npm-package
        with:
          release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
          gha-npm-token: ${{ env.GHA_NPM_TOKEN }}
          gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
on-issue-labeled perms .github/workflows/on-issue-labeled.yml
Triggers
issues
Runs on
ubuntu-latest, ubuntu-latest
Jobs
triage-issue, act-on-label
View raw YAML
name: On Issue Labeled
# This workflow is triggered when a label is added to an issue.
on:
  issues:
    types: [labeled]

permissions:
  contents: write
  issues: write

jobs:
  # Runs automatic checks on issues labeled with "Needs: Triage",
  # then invokes actOnLabel to react to any added labels
  triage-issue:
    runs-on: ubuntu-latest
    if: "${{ github.repository == 'facebook/react-native' && contains(github.event.label.name, 'Needs: Triage :mag:') }}"
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Verify RN version
        uses: actions/github-script@v8
        with:
          github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          script: |
            const verifyVersion = require('./.github/workflow-scripts/verifyVersion.js')
            const labelWithContext = await verifyVersion(github, context);

            if(labelWithContext && labelWithContext.label) {
              await github.rest.issues.addLabels({
                issue_number: context.issue.number,
                owner: context.repo.owner,
                repo: context.repo.repo,
                labels: [labelWithContext.label]
              })

              const actOnLabel = require('./.github/workflow-scripts/actOnLabel.js')
              await actOnLabel(github, context, labelWithContext)
            }

      - name: Add descriptive label
        uses: actions/github-script@v8
        with:
          github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          script: |
            const addDescriptiveLabel = require('./.github/workflow-scripts/addDescriptiveLabels.js')
            await addDescriptiveLabel(github, context);

  # Reacts to the label that triggered this workflow (added manually or via other workflows)
  act-on-label:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    steps:
      - uses: actions/checkout@v6
      - uses: actions/github-script@v8
        with:
          github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          script: |
            const actOnLabel = require('./.github/workflow-scripts/actOnLabel.js')
            await actOnLabel(github, context, {label: context.payload.label.name})
prebuild-ios-core matrix .github/workflows/prebuild-ios-core.yml
Triggers
workflow_call
Runs on
macos-15, macos-15
Jobs
build-rn-slice, compose-xcframework
Matrix
flavor, slice→ Debug, Release, ios, ios-simulator, mac-catalyst
Actions
apple-actions/import-codesign-certs
Commands
  • if [ "${{ inputs.use-hermes-nightly }}" == "true" ]; then # We are not publishing nightly versions of Hermes V1 yet. # For now, we can use the latest version of Hermes V1 published on maven and npm. HERMES_VERSION="latest-v1" else HERMES_VERSION=$(sed -n 's/^HERMES_V1_VERSION_NAME=//p' packages/react-native/sdks/hermes-engine/version.properties) fi echo "Using Hermes version: $HERMES_VERSION" echo "HERMES_VERSION=$HERMES_VERSION" >> $GITHUB_ENV
  • if [ "${{ inputs.version-type }}" != "" ]; then node ./scripts/releases/set-rn-artifacts-version.js --build-type "${{ inputs.version-type }}" fi
  • # Extract ReactNativeDependencies tar -xzf /tmp/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz -C /tmp/third-party/ # Create destination folder mkdir -p packages/react-native/third-party/ # Move the XCFramework in the destination directory mv /tmp/third-party/packages/react-native/third-party/ReactNativeDependencies.xcframework packages/react-native/third-party/ReactNativeDependencies.xcframework VERSION=$(jq -r '.version' packages/react-native/package.json) echo "$VERSION-${{matrix.flavor}}" > "packages/react-native/third-party/version.txt" cat "packages/react-native/third-party/version.txt" # Check destination directory ls -lR packages/react-native/third-party/
  • cd packages/react-native node scripts/ios-prebuild.js -s -f "${{ matrix.flavor }}"
  • # This is going to be replaced by a CLI script cd packages/react-native node scripts/ios-prebuild -b -f "${{ matrix.flavor }}" -p "${{ matrix.slice }}"
  • cd packages/react-native node scripts/ios-prebuild -c -f "${{ matrix.flavor }}"
  • cd packages/react-native node scripts/ios-prebuild -c -f "${{ matrix.flavor }}" -i "React Org"
  • cd packages/react-native/.build/output/xcframeworks/${{matrix.flavor}} tar -cz -f ../ReactCore${{matrix.flavor}}.xcframework.tar.gz React.xcframework
View raw YAML
name: Prebuild iOS Core

on:
  workflow_call: # this directive allow us to call this workflow from other workflows
    inputs:
      version-type:
        description: 'The version type to set for the prebuild (nightly or release)'
        type: string
        required: false
        default: ''
      use-hermes-nightly:
        description: 'Whether to use the hermes nightly build or read the version from the versions.properties file'
        type: boolean
        required: false
        default: false

jobs:
  build-rn-slice:
    runs-on: macos-15
    strategy:
      fail-fast: false
      matrix:
        flavor: ['Debug', 'Release']
        slice: [
          'ios',
          'ios-simulator',
          'mac-catalyst',
        ]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Restore cache if present
        id: restore-ios-slice
        uses: actions/cache/restore@v5
        with:
          key: v3-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
          path: packages/react-native/
      - name: Setup node.js
        if: steps.restore-ios-slice.outputs.cache-hit != 'true'
        uses: ./.github/actions/setup-node
      - name: Setup xcode
        if: steps.restore-ios-slice.outputs.cache-hit != 'true'
        uses: ./.github/actions/setup-xcode
      - name: Yarn Install
        if: steps.restore-ios-slice.outputs.cache-hit != 'true'
        uses: ./.github/actions/yarn-install
      - name: Set Hermes version
        shell: bash
        run: |
          if [ "${{ inputs.use-hermes-nightly }}" == "true" ]; then
            # We are not publishing nightly versions of Hermes V1 yet.
            # For now, we can use the latest version of Hermes V1 published on maven and npm.
            HERMES_VERSION="latest-v1"
          else
            HERMES_VERSION=$(sed -n 's/^HERMES_V1_VERSION_NAME=//p' packages/react-native/sdks/hermes-engine/version.properties)
          fi
          echo "Using Hermes version: $HERMES_VERSION"
          echo "HERMES_VERSION=$HERMES_VERSION" >> $GITHUB_ENV
      - name: Set React Native version
        shell: bash
        run: |
          if [ "${{ inputs.version-type }}" != "" ]; then
            node ./scripts/releases/set-rn-artifacts-version.js --build-type "${{ inputs.version-type }}"
          fi
      - name: Download ReactNativeDependencies
        uses: actions/download-artifact@v7
        with:
          name: ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
          path: /tmp/third-party/
      - name: Extract ReactNativeDependencies
        if: steps.restore-ios-slice.outputs.cache-hit != 'true'
        shell: bash
        run: |
          # Extract ReactNativeDependencies
          tar -xzf /tmp/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz -C /tmp/third-party/

          # Create destination folder
          mkdir -p packages/react-native/third-party/

          # Move the XCFramework in the destination directory
          mv /tmp/third-party/packages/react-native/third-party/ReactNativeDependencies.xcframework packages/react-native/third-party/ReactNativeDependencies.xcframework

          VERSION=$(jq -r '.version' packages/react-native/package.json)
          echo "$VERSION-${{matrix.flavor}}" > "packages/react-native/third-party/version.txt"
          cat "packages/react-native/third-party/version.txt"
          # Check destination directory
          ls -lR packages/react-native/third-party/
      - name: Setup the workspace
        if: steps.restore-ios-slice.outputs.cache-hit != 'true'
        shell: bash
        run: |
          cd packages/react-native
          node scripts/ios-prebuild.js -s -f "${{ matrix.flavor }}"
      - name: Build React Native
        if: steps.restore-ios-slice.outputs.cache-hit != 'true'
        shell: bash
        run: |
          # This is going to be replaced by a CLI script
          cd packages/react-native
          node scripts/ios-prebuild -b -f "${{ matrix.flavor }}" -p "${{ matrix.slice }}"
      - name: Upload headers
        uses: actions/upload-artifact@v6
        with:
          name: prebuild-ios-core-headers-${{ matrix.flavor }}-${{ matrix.slice }}
          path:
            packages/react-native/.build/headers
      - name: Upload artifacts
        uses: actions/upload-artifact@v6
        with:
          name: prebuild-ios-core-slice-${{ matrix.flavor }}-${{ matrix.slice }}
          path: |
            packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products
      - name: Save Cache
        uses: actions/cache/save@v5
        if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
        with:
          key: v3-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
          path: |
            packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products
            packages/react-native/.build/headers

  compose-xcframework:
    runs-on: macos-15
    needs: [build-rn-slice]
    strategy:
      fail-fast: false
      matrix:
        flavor: ['Debug', 'Release']
    env:
      REACT_ORG_CODE_SIGNING_P12_CERT: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT }}
      REACT_ORG_CODE_SIGNING_P12_CERT_PWD: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT_PWD }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Restore cache if present
        id: restore-ios-xcframework
        uses: actions/cache/restore@v5
        with:
          path: packages/react-native/.build/output/xcframeworks
          key: v2-ios-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
      - name: Setup node.js
        if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
        uses: ./.github/actions/setup-node
      - name: Setup xcode
        if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
        uses: ./.github/actions/setup-xcode
      - name: Yarn Install
        if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
        uses: ./.github/actions/yarn-install
      - name: Download slice artifacts
        if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
        uses: actions/download-artifact@v7
        with:
          pattern: prebuild-ios-core-slice-${{ matrix.flavor }}-*
          path: packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products
          merge-multiple: true
      - name: Download headers
        if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
        uses: actions/download-artifact@v7
        with:
          pattern: prebuild-ios-core-headers-${{ matrix.flavor }}-*
          path: packages/react-native/.build/headers
          merge-multiple: true
      - name: Setup Keychain
        if: ${{ steps.restore-ios-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT != '' }}
        uses: apple-actions/import-codesign-certs@v3 # https://github.com/marketplace/actions/import-code-signing-certificates
        with:
          p12-file-base64: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT }}
          p12-password: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT_PWD }}
      - name: Create XCFramework
        if: ${{ steps.restore-ios-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT == '' }}
        run: |
          cd packages/react-native
          node scripts/ios-prebuild -c -f "${{ matrix.flavor }}"
      - name: Create and Sign XCFramework
        if: ${{ steps.restore-ios-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT != '' }}
        run: |
          cd packages/react-native
          node scripts/ios-prebuild -c -f "${{ matrix.flavor }}" -i "React Org"
      - name: Compress and Rename XCFramework
        if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
        run: |
          cd packages/react-native/.build/output/xcframeworks/${{matrix.flavor}}
          tar -cz -f ../ReactCore${{matrix.flavor}}.xcframework.tar.gz React.xcframework
      - name: Compress and Rename dSYM
        if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
        run: |
          cd packages/react-native/.build/output/xcframeworks/${{matrix.flavor}}/Symbols
          tar -cz -f ../../ReactCore${{ matrix.flavor }}.framework.dSYM.tar.gz .
      - name: Upload XCFramework Artifact
        uses: actions/upload-artifact@v6
        with:
          name: ReactCore${{ matrix.flavor }}.xcframework.tar.gz
          path: packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.xcframework.tar.gz
      - name: Upload dSYM Artifact
        uses: actions/upload-artifact@v6
        with:
          name: ReactCore${{ matrix.flavor }}.framework.dSYM.tar.gz
          path: packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.framework.dSYM.tar.gz
      - name: Save cache if present
        if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
        uses: actions/cache/save@v5
        with:
          path: |
            packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.xcframework.tar.gz
            packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.framework.dSYM.tar.gz
          key: v2-ios-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
prebuild-ios-dependencies matrix .github/workflows/prebuild-ios-dependencies.yml
Triggers
workflow_call
Runs on
macos-15, macos-15, macos-15
Jobs
prepare_workspace, build-apple-slices, create-xcframework
Matrix
flavor, slice→ Debug, Release, ios, ios-simulator, mac-catalyst, macos, tvos, tvos-simulator, xros, xros-simulator
Actions
apple-actions/import-codesign-certs
Commands
  • node scripts/releases/prepare-ios-prebuilds.js -s
  • node scripts/releases/prepare-ios-prebuilds.js -w
  • ls -lR packages/react-native/third-party
  • node scripts/releases/prepare-ios-prebuilds.js -b -p ${{ matrix.slice }} -r ${{ matrix.flavor }}
  • node scripts/releases/prepare-ios-prebuilds.js -c
  • node scripts/releases/prepare-ios-prebuilds.js -c -i "React Org"
  • tar -cz -f packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz \ packages/react-native/third-party/ReactNativeDependencies.xcframework
  • ls -lR packages/react-native/third-party/Symbols
View raw YAML
name: Prebuild iOS Dependencies

on:
  workflow_call: # this directive allow us to call this workflow from other workflows


jobs:
  prepare_workspace:
    name: Prepare workspace
    runs-on: macos-15
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup node.js
        uses: ./.github/actions/setup-node
      - name: Restore cache if present
        id: restore-ios-prebuilds
        uses: actions/cache/restore@v5
        with:
          path: packages/react-native/third-party/
          key: v3-ios-dependencies-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
          enableCrossOsArchive: true
      - name: Yarn Install
        if: steps.restore-ios-prebuilds.outputs.cache-hit != 'true'
        uses: ./.github/actions/yarn-install
      - name: Prepare Dependencies
        if: steps.restore-ios-prebuilds.outputs.cache-hit != 'true'
        run: |
          node scripts/releases/prepare-ios-prebuilds.js -s
      - name: Generate Package.swift
        if: steps.restore-ios-prebuilds.outputs.cache-hit != 'true'
        run: |
          node scripts/releases/prepare-ios-prebuilds.js -w
      - name: Upload Artifacts
        uses: actions/upload-artifact@v6
        with:
          name: ios-prebuilds-workspace
          path: packages/react-native/third-party/
      - name: Save Cache
        uses: actions/cache/save@v5
        if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
        with:
          key: v3-ios-dependencies-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
          enableCrossOsArchive: true
          path: packages/react-native/third-party/

  build-apple-slices:
    name: Build Apple Slice
    runs-on: macos-15
    needs: [prepare_workspace]
    strategy:
      fail-fast: false
      matrix:
        flavor: ['Debug', 'Release']
        slice: ['ios',
                'ios-simulator',
                'macos',
                'mac-catalyst',
                'tvos',
                'tvos-simulator',
                'xros',
                'xros-simulator']
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup node.js
        uses: ./.github/actions/setup-node
      - name: Restore slice folder
        id: restore-slice-folder
        uses: actions/cache/restore@v5
        with:
          path: packages/react-native/third-party/.build/Build/Products
          key: v3-ios-dependencies-slice-folder-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
      - name: Setup xcode
        if: steps.restore-slice-folder.outputs.cache-hit != 'true'
        uses: ./.github/actions/setup-xcode
      - name: Yarn Install
        if: steps.restore-slice-folder.outputs.cache-hit != 'true'
        uses: ./.github/actions/yarn-install
      - name: Restore workspace
        if: steps.restore-slice-folder.outputs.cache-hit != 'true'
        uses: actions/download-artifact@v7
        with:
          name: ios-prebuilds-workspace
          path: packages/react-native/third-party/
      - name: Print third-party folder structure
        if: steps.restore-slice-folder.outputs.cache-hit != 'true'
        run: ls -lR packages/react-native/third-party
      - name: Build slice ${{ matrix.slice }} for ${{ matrix.flavor }}
        if: steps.restore-slice-folder.outputs.cache-hit != 'true'
        run:  node scripts/releases/prepare-ios-prebuilds.js -b -p ${{ matrix.slice }} -r ${{ matrix.flavor }}
      - name: Upload Artifacts
        uses: actions/upload-artifact@v6
        with:
          name: prebuild-slice-${{ matrix.flavor }}-${{ matrix.slice }}
          path: |
            packages/react-native/third-party/.build/Build/Products
      - name: Save Cache
        uses: actions/cache/save@v5
        if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
        with:
          key: v3-ios-dependencies-slice-folder-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
          enableCrossOsArchive: true
          path: |
            packages/react-native/third-party/.build/Build/Products

  create-xcframework:
    name: Prepare XCFramework
    runs-on: macos-15
    needs: [build-apple-slices]
    strategy:
      fail-fast: false
      matrix:
        flavor: [Debug, Release]
    env:
      REACT_ORG_CODE_SIGNING_P12_CERT: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT }}
      REACT_ORG_CODE_SIGNING_P12_CERT_PWD: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT_PWD }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup node.js
        uses: ./.github/actions/setup-node
      - name: Setup xcode
        uses: ./.github/actions/setup-xcode
      - name: Restore XCFramework
        id: restore-xcframework
        uses: actions/cache/restore@v5
        with:
          path: |
            packages/react-native/third-party/
          key: v3-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
      # If cache hit, we already have our binary. We don't need to do anything.
      - name: Yarn Install
        if: steps.restore-xcframework.outputs.cache-hit != 'true'
        uses: ./.github/actions/yarn-install
      - name: Restore workspace
        if: steps.restore-xcframework.outputs.cache-hit != 'true'
        uses: actions/download-artifact@v7
        with:
          name: ios-prebuilds-workspace
          path: packages/react-native/third-party/
      - name: Download slices
        if: steps.restore-xcframework.outputs.cache-hit != 'true'
        uses: actions/download-artifact@v7
        with:
          pattern: prebuild-slice-${{ matrix.flavor }}-*
          path: packages/react-native/third-party/.build/Build/Products
          merge-multiple: true
      - name: Setup Keychain
        if: ${{ steps.restore-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT != '' }}
        uses: apple-actions/import-codesign-certs@v3 # https://github.com/marketplace/actions/import-code-signing-certificates
        with:
          p12-file-base64: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT }}
          p12-password: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT_PWD }}
      - name: Create XCFramework
        if: ${{ steps.restore-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT == '' }}
        run: node scripts/releases/prepare-ios-prebuilds.js -c
      - name: Create and Sign XCFramework
        if: ${{ steps.restore-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT != '' }}
        run: node scripts/releases/prepare-ios-prebuilds.js -c -i "React Org"
      - name: Compress and Rename XCFramework
        if: steps.restore-xcframework.outputs.cache-hit != 'true'
        run: |
          tar -cz -f packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz \
            packages/react-native/third-party/ReactNativeDependencies.xcframework
      - name: Show Symbol folder content
        if: steps.restore-xcframework.outputs.cache-hit != 'true'
        run: ls -lR packages/react-native/third-party/Symbols
      - name: Compress and Rename dSYM
        if: steps.restore-xcframework.outputs.cache-hit != 'true'
        run: |
          cd packages/react-native/third-party/Symbols/
          tar -cz -f ../ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz .
          mv ../ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz ./ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
      - name: Upload XCFramework Artifact
        uses: actions/upload-artifact@v6
        with:
          name: ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
          path: packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
      - name: Upload dSYM Artifact
        uses: actions/upload-artifact@v6
        with:
          name: ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
          path: |
            packages/react-native/third-party/Symbols/ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
      - name: Save XCFramework in Cache
        if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
        uses: actions/cache/save@v5
        with:
          path: |
            packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
            packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
          key: v3-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
publish-bumped-packages .github/workflows/publish-bumped-packages.yml
Triggers
push
Runs on
ubuntu-latest
Jobs
publish_bumped_packages
Commands
  • yarn build
  • yarn build-types --skip-snapshot
  • echo "//registry.npmjs.org/:_authToken=$GHA_NPM_TOKEN" > ~/.npmrc
  • node ./scripts/releases-ci/publish-updated-packages.js
View raw YAML
name: Publish Bumped Packages

on:
  push:
    branches:
      - "main"
      - "*-stable"

jobs:
  publish_bumped_packages:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    env:
      GHA_NPM_TOKEN: ${{ secrets.GHA_NPM_TOKEN }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup node.js
        uses: ./.github/actions/setup-node
      - name: Run Yarn Install
        uses: ./.github/actions/yarn-install
      - name: Build packages
        run: yarn build
      - name: Build types
        run: yarn build-types --skip-snapshot
      - name: Set NPM auth token
        run: echo "//registry.npmjs.org/:_authToken=$GHA_NPM_TOKEN" > ~/.npmrc
      - name: Find and publish all bumped packages
        run: node ./scripts/releases-ci/publish-updated-packages.js
publish-release .github/workflows/publish-release.yml
Triggers
push
Runs on
ubuntu-latest, ubuntu-latest, 8-core-ubuntu
Jobs
set_release_type, set_hermes_versions, prebuild_apple_dependencies, prebuild_react_native_core, build_npm_package, generate_changelog, bump_podfile_lock, create_draft_release
Commands
  • echo "Setting release type to release" echo "RELEASE_TYPE=release" >> $GITHUB_OUTPUT
  • echo "Setting hermes versions to latest" hermes_version=$(grep -oE 'HERMES_VERSION_NAME=([0-9]+\.[0-9]+\.[0-9]+)' packages/react-native/sdks/hermes-engine/version.properties | cut -d'=' -f2) hermes_v1_version=$(grep -oE 'HERMES_V1_VERSION_NAME=([0-9]+\.[0-9]+\.[0-9]+)' packages/react-native/sdks/hermes-engine/version.properties | cut -d'=' -f2) echo "HERMES_VERSION=$hermes_version" >> $GITHUB_OUTPUT echo "HERMES_V1_VERSION=$hermes_v1_version" >> $GITHUB_OUTPUT
  • echo "HERMES_VERSION=${{ steps.set_hermes_versions.outputs.HERMES_VERSION }}" echo "HERMES_V1_VERSION=${{ steps.set_hermes_versions.outputs.HERMES_V1_VERSION }}"
  • curl -X POST https://api.github.com/repos/react-native-community/rn-diff-purge/dispatches \ -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: Bearer $REACT_NATIVE_BOT_GITHUB_TOKEN" \ -d "{\"event_type\": \"publish\", \"client_payload\": { \"version\": \"${{ github.ref_name }}\" }}"
View raw YAML
name: Publish Release
on:
  push:
    tags:
      - "v0.*.*" # This should match v0.X.Y
      - "v0.*.*-rc.*" # This should match v0.X.Y-RC.0
jobs:
  set_release_type:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    outputs:
      RELEASE_TYPE: ${{ steps.set_release_type.outputs.RELEASE_TYPE }}
    env:
      EVENT_NAME: ${{ github.event_name }}
      REF: ${{ github.ref }}
    steps:
      - id: set_release_type
        run: |
          echo "Setting release type to release"
          echo "RELEASE_TYPE=release" >> $GITHUB_OUTPUT

  set_hermes_versions:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    outputs:
      HERMES_VERSION: ${{ steps.set_hermes_versions.outputs.HERMES_VERSION }}
      HERMES_V1_VERSION: ${{ steps.set_hermes_versions.outputs.HERMES_V1_VERSION }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - id: set_hermes_versions
        run: |
          echo "Setting hermes versions to latest"
          hermes_version=$(grep -oE 'HERMES_VERSION_NAME=([0-9]+\.[0-9]+\.[0-9]+)' packages/react-native/sdks/hermes-engine/version.properties | cut -d'=' -f2)
          hermes_v1_version=$(grep -oE 'HERMES_V1_VERSION_NAME=([0-9]+\.[0-9]+\.[0-9]+)' packages/react-native/sdks/hermes-engine/version.properties | cut -d'=' -f2)

          echo "HERMES_VERSION=$hermes_version" >> $GITHUB_OUTPUT
          echo "HERMES_V1_VERSION=$hermes_v1_version" >> $GITHUB_OUTPUT
      - name: Print hermes versions
        run: |
          echo "HERMES_VERSION=${{ steps.set_hermes_versions.outputs.HERMES_VERSION }}"
          echo "HERMES_V1_VERSION=${{ steps.set_hermes_versions.outputs.HERMES_V1_VERSION }}"

  prebuild_apple_dependencies:
    if: github.repository == 'facebook/react-native'
    uses: ./.github/workflows/prebuild-ios-dependencies.yml
    secrets: inherit

  prebuild_react_native_core:
    uses: ./.github/workflows/prebuild-ios-core.yml
    secrets: inherit
    needs: [prebuild_apple_dependencies]

  build_npm_package:
    runs-on: 8-core-ubuntu
    needs:
      [
        set_release_type,
        prebuild_apple_dependencies,
        prebuild_react_native_core,
      ]
    container:
      image: reactnativecommunity/react-native-android:latest
      env:
        TERM: "dumb"
        # Set the encoding to resolve a known character encoding issue with decompressing tar.gz files in containers
        # via Gradle: https://github.com/gradle/gradle/issues/23391#issuecomment-1878979127
        LC_ALL: C.UTF8
        GRADLE_OPTS: "-Dorg.gradle.daemon=false"
        # By default we only build ARM64 to save time/resources. For release/nightlies, we override this value to build all archs.
        ORG_GRADLE_PROJECT_reactNativeArchitectures: "arm64-v8a"
        REACT_NATIVE_DOWNLOADS_DIR: /opt/react-native-downloads
    env:
      GHA_NPM_TOKEN: ${{ secrets.GHA_NPM_TOKEN }}
      ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
      ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
      ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_USERNAME }}
      ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_PASSWORD }}
      REACT_NATIVE_BOT_GITHUB_TOKEN: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          fetch-tags: true
      - name: Build and Publish NPM Package
        uses: ./.github/actions/build-npm-package
        with:
          release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
          gha-npm-token: ${{ env.GHA_NPM_TOKEN }}
          gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
      - name: Publish @react-native-community/template
        id: publish-template-to-npm
        uses: actions/github-script@v8
        with:
          github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          script: |
            const {publishTemplate} = require('./.github/workflow-scripts/publishTemplate.js')
            const version = "${{ github.ref_name }}"
            const isDryRun = false
            await publishTemplate(github, version, isDryRun);
      - name: Wait for template to be published
        timeout-minutes: 3
        uses: actions/github-script@v8
        with:
          github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          script: |
            const {verifyPublishedTemplate, isLatest} = require('./.github/workflow-scripts/publishTemplate.js')
            const version = "${{ github.ref_name }}"
            await verifyPublishedTemplate(version, isLatest());
      - name: Update rn-diff-purge to generate upgrade-support diff
        run: |
          curl -X POST https://api.github.com/repos/react-native-community/rn-diff-purge/dispatches \
            -H "Accept: application/vnd.github.v3+json" \
            -H "Authorization: Bearer $REACT_NATIVE_BOT_GITHUB_TOKEN" \
            -d "{\"event_type\": \"publish\", \"client_payload\": { \"version\": \"${{ github.ref_name }}\" }}"
      - name: Verify Release is on NPM
        timeout-minutes: 3
        uses: actions/github-script@v8
        with:
          github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          script: |
            const {verifyReleaseOnNpm} = require('./.github/workflow-scripts/verifyReleaseOnNpm.js');
            const {isLatest} = require('./.github/workflow-scripts/publishTemplate.js');
            const version = "${{ github.ref_name }}";
            await verifyReleaseOnNpm(version, isLatest());
      - name: Verify that artifacts are on Maven
        uses: actions/github-script@v8
        with:
          script: |
            const {verifyArtifactsAreOnMaven} = require('./.github/workflow-scripts/verifyArtifactsAreOnMaven.js');
            const version = "${{ github.ref_name }}";
            await verifyArtifactsAreOnMaven(version);

  generate_changelog:
    needs: build_npm_package
    uses: ./.github/workflows/generate-changelog.yml
    secrets: inherit

  bump_podfile_lock:
    needs: build_npm_package
    uses: ./.github/workflows/bump-podfile-lock.yml
    secrets: inherit

  create_draft_release:
    needs: [generate_changelog, set_hermes_versions]
    uses: ./.github/workflows/create-draft-release.yml
    secrets: inherit
    with:
      hermesVersion: ${{ needs.set_hermes_versions.outputs.HERMES_VERSION }}
      hermesV1Version: ${{ needs.set_hermes_versions.outputs.HERMES_V1_VERSION }}
retry-workflow .github/workflows/retry-workflow.yml
Triggers
workflow_dispatch
Runs on
ubuntu-latest
Jobs
rerun
Commands
  • gh run watch ${{ inputs.run_id }} > /dev/null 2>&1 gh run rerun ${{ inputs.run_id }} --failed
View raw YAML
name: Retry workflow
# Based on https://stackoverflow.com/a/78314483

on:
    workflow_dispatch:
        inputs:
            run_id:
                required: true
jobs:
    rerun:
        runs-on: ubuntu-latest
        if: github.repository == 'facebook/react-native'
        steps:
            - name: rerun ${{ inputs.run_id }}
              env:
                  GH_REPO: ${{ github.repository }}
                  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
              run: |
                  gh run watch ${{ inputs.run_id }} > /dev/null 2>&1
                  gh run rerun ${{ inputs.run_id }} --failed
stale-bot .github/workflows/stale-bot.yml
Triggers
schedule
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
stale, stale-asc, stale-needs-author-feedback, stale-needs-author-feedback-asc
Actions
actions/stale, actions/stale, actions/stale, actions/stale
View raw YAML
name: Stale bot
on:
  schedule:
    - cron: "*/10 5 * * *"
jobs:
  stale:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    permissions:
      issues: write
      pull-requests: write
    steps:
      - uses: actions/stale@v10
        with:
          repo-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          days-before-stale: 180
          stale-issue-message: 'This issue is stale because it has been open for 180 days with no activity. It will be closed in 7 days unless you comment on it or remove the "Stale" label.'
          stale-pr-message: 'This PR is stale because it has been open for 180 days with no activity. It will be closed in 7 days unless you comment on it or remove the "Stale" label.'
          close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'
          close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.'
          exempt-issue-labels: 'Help Wanted :octocat:, Good first issue, Never gets stale, Issue: Author Provided Repro'
          exempt-pr-labels: 'Help Wanted :octocat:, Never gets stale'
  stale-asc:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    permissions:
      issues: write
      pull-requests: write
    steps:
      - uses: actions/stale@v10
        with:
          ascending: true
          repo-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          days-before-stale: 180
          stale-issue-message: 'This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
          stale-pr-message: 'This PR is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
          close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'
          close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.'
          exempt-issue-labels: 'Help Wanted :octocat:, Good first issue, Never gets stale, Issue: Author Provided Repro'
          exempt-pr-labels: 'Help Wanted :octocat:, Never gets stale'
  stale-needs-author-feedback:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    permissions:
      issues: write
      pull-requests: write
    steps:
      - uses: actions/stale@v10
        with:
          repo-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          any-of-labels: 'Needs: Author Feedback'
          days-before-stale: 24
          stale-issue-message: "This issue is waiting for author's feedback since 24 days. Please provide the requested feedback or this will be closed in 7 days."
          stale-pr-message: "This PR is waiting for author's feedback since 24 days. Please provide the requested feedback or this will be closed in 7 days"
          close-issue-message: "This issue was closed because the author hasn't provided the requested feedback after 7 days."
          close-pr-message: "This PR was closed because the author hasn't provided the requested feedback after 7 days."
          exempt-issue-labels: "Help Wanted :octocat:, Good first issue, Never gets stale, Issue: Author Provided Repro"
          exempt-pr-labels: "Help Wanted :octocat:, Never gets stale"
  stale-needs-author-feedback-asc:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    permissions:
      issues: write
      pull-requests: write
    steps:
      - uses: actions/stale@v10
        with:
          ascending: true
          repo-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
          any-of-labels: 'Needs: Author Feedback'
          days-before-stale: 24
          stale-issue-message: "This issue is waiting for author's feedback since 24 days. Please provide the requested feedback or this will be closed in 7 days."
          stale-pr-message: "This PR is waiting for author's feedback since 24 days. Please provide the requested feedback or this will be closed in 7 days"
          close-issue-message: "This issue was closed because the author hasn't provided the requested feedback after 7 days."
          close-pr-message: "This PR was closed because the author hasn't provided the requested feedback after 7 days."
          exempt-issue-labels: "Help Wanted :octocat:, Good first issue, Never gets stale, Issue: Author Provided Repro"
          exempt-pr-labels: "Help Wanted :octocat:, Never gets stale"
test-all matrix .github/workflows/test-all.yml
Triggers
workflow_dispatch, pull_request, push
Runs on
ubuntu-latest, ubuntu-latest, macos-15, macos-15-large, macos-15-large, macos-15-large, macos-15-large, 4-core-ubuntu, 8-core-ubuntu, 8-core-ubuntu, 8-core-ubuntu, 4-core-ubuntu, 8-core-ubuntu, 4-core-ubuntu, macos-15, macos-15, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
set_release_type, check_code_changes, prebuild_apple_dependencies, prebuild_react_native_core, test_ios_rntester_ruby_3_2_0, test_ios_rntester_dynamic_frameworks, test_ios_rntester, test_e2e_ios_rntester, test_e2e_ios_templateapp, test_e2e_android_templateapp, build_fantom_runner, run_fantom_tests, build_android, test_e2e_android_rntester, build_npm_package, test_android_helloworld, test_ios_helloworld_with_ruby_3_2_0, test_ios_helloworld, lint, test_js, build_js_types, build_debugger_shell, rerun-failed-jobs
Matrix
exclude, exclude.flavor, exclude.use_frameworks, flavor, frameworks, node-version, use_frameworks→ 20.19.4, 22, 24, Debug, False, Release, StaticLibraries, True, debug, release
Actions
dorny/paths-filter, dorny/paths-filter, ruby/setup-ruby
Commands
  • if [[ $EVENT_NAME == "schedule" ]]; then echo "Setting release type to nightly" echo "RELEASE_TYPE=nightly" >> $GITHUB_OUTPUT elif [[ $EVENT_NAME == "push" && $REF == refs/tags/v* ]]; then echo "Setting release type to release" echo "RELEASE_TYPE=release" >> $GITHUB_OUTPUT else echo "Setting release type to dry-run" echo "RELEASE_TYPE=dry-run" >> $GITHUB_OUTPUT fi echo "Should I run E2E tests? ${{ inputs.run-e2e-tests }}"
  • ls -lR /tmp/RNTesterBuild
  • ls -lR /tmp/react-native-tmp
  • ls -lR /tmp/third-party
  • ls -lR /tmp/ReactCore
  • git config --global user.email "react-native-bot@meta.com" git config --global user.name "React Native Bot"
  • REACT_NATIVE_PKG=$(find /tmp/react-native-tmp -type f -name "*.tgz") echo "React Native tgs is $REACT_NATIVE_PKG" # For stable branches, we want to use the stable branch of the template # In all the other cases, we want to use "main" BRANCH=${{ github.ref_name }} if ! [[ $BRANCH == *-stable* ]]; then BRANCH=main fi node ./scripts/e2e/init-project-e2e.js --projectName RNTestProject --currentBranch $BRANCH --directory /tmp/RNTestProject --pathToLocalReactNative $REACT_NATIVE_PKG cd /tmp/RNTestProject/ios bundle install NEW_ARCH_ENABLED=1 export RCT_USE_LOCAL_RN_DEP=/tmp/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz # Disable prebuilds for now, as they are causing issues with E2E tests for 0.82-stable branch export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ matrix.flavor }}.xcframework.tar.gz" RCT_NEW_ARCH_ENABLED=$NEW_ARCH_ENABLED bundle exec pod install xcodebuild \ -scheme "RNTestProject" \ -workspace RNTestProject.xcworkspace \ -configuration "${{ matrix.flavor }}" \ -sdk "iphonesimulator" \ -destination "generic/platform=iOS Simulator" \ -derivedDataPath "/tmp/RNTestProject"
  • ls -lR /tmp/react-native-tmp
View raw YAML
name: Test All

on:
  workflow_dispatch:
  pull_request:
  push:
    branches:
      - main
      - "*-stable"

jobs:
  set_release_type:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    outputs:
      RELEASE_TYPE: ${{ steps.set_release_type.outputs.RELEASE_TYPE }}
    env:
      EVENT_NAME: ${{ github.event_name }}
      REF: ${{ github.ref }}
    steps:
      - id: set_release_type
        run: |
          if [[ $EVENT_NAME == "schedule" ]]; then
            echo "Setting release type to nightly"
            echo "RELEASE_TYPE=nightly" >> $GITHUB_OUTPUT
          elif [[ $EVENT_NAME == "push" && $REF == refs/tags/v* ]]; then
            echo "Setting release type to release"
            echo "RELEASE_TYPE=release" >> $GITHUB_OUTPUT
          else
            echo "Setting release type to dry-run"
            echo "RELEASE_TYPE=dry-run" >> $GITHUB_OUTPUT
          fi

          echo "Should I run E2E tests? ${{ inputs.run-e2e-tests }}"

  check_code_changes:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    outputs:
      any_code_change: ${{ steps.filter_exclusions.outputs.any_code_change == 'true' || github.event_name != 'pull_request' }}
      should_test_android: ${{ steps.filter_exclusions.outputs.should_test_android == 'true' || github.event_name != 'pull_request' }}
      should_test_ios: ${{ steps.filter_exclusions.outputs.should_test_ios == 'true' || github.event_name != 'pull_request' }}
      debugger_shell: ${{ steps.filter_inclusions.outputs.debugger_shell }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Check for code changes (exclusion patterns)
        uses: dorny/paths-filter@209e61402dbca8aa44f967535da6666b284025ed
        id: filter_exclusions
        with:
          predicate-quantifier: every
          filters: |
            any_code_change:
              - '**'
              - '!**/__docs__/**'
              - '!**/*.md'
            should_test_android:
              # Not an isolated iOS change
              - '**'
              - '!packages/react-native/React/**'
              - '!packages/react-native/ReactApple/**'
              - '!packages/react-native/**/*.m'
              - '!packages/react-native/**/*.mm'
              - '!packages/react-native/**/*.podspec'
              - '!packages/rn-tester/RNTester/**'
              - '!packages/rn-tester/RNTesterPods*/**'
              - '!packages/rn-tester/Podfile*'
            should_test_ios:
              # Not an isolated Android change
              - '**'
              - '!gradle/**'
              - '!gradle*'
              - '!packages/gradle-plugin/**'
              - '!packages/react-native/ReactAndroid/**'
              - '!packages/react-native/**/*.java'
              - '!packages/react-native/**/*.kt'
              - '!packages/react-native/**/*.gradle*'
              - '!packages/react-native-popup-menu-android/**'
              - '!packages/rn-tester/android/**'
      - name: Check for code changes (inclusion patterns)
        uses: dorny/paths-filter@209e61402dbca8aa44f967535da6666b284025ed
        id: filter_inclusions
        with:
          filters: |
            debugger_shell:
              - 'packages/debugger-shell/**'
              - 'scripts/debugger-shell/**'

  prebuild_apple_dependencies:
    needs: check_code_changes
    if: |
      needs.check_code_changes.outputs.any_code_change == 'true' &&
      needs.check_code_changes.outputs.should_test_ios == 'true'
    uses: ./.github/workflows/prebuild-ios-dependencies.yml
    secrets: inherit

  prebuild_react_native_core:
    uses: ./.github/workflows/prebuild-ios-core.yml
    with:
      use-hermes-nightly: ${{ !endsWith(github.ref_name, '-stable') }}
    secrets: inherit
    needs: [prebuild_apple_dependencies]

  test_ios_rntester_ruby_3_2_0:
    runs-on: macos-15
    needs:
      [prebuild_apple_dependencies, prebuild_react_native_core]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Run it
        uses: ./.github/actions/test-ios-rntester
        with:
          ruby-version: "3.2.0"
          flavor: Debug

  test_ios_rntester_dynamic_frameworks:
    runs-on: macos-15-large
    needs: check_code_changes
    if: |
      needs.check_code_changes.outputs.any_code_change == 'true' &&
      needs.check_code_changes.outputs.should_test_ios == 'true'
    strategy:
      fail-fast: false
      matrix:
        flavor: [Debug, Release]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Run it
        uses: ./.github/actions/test-ios-rntester
        with:
          flavor: ${{ matrix.flavor }}
          use-frameworks: true
          run-unit-tests: false # tests for dynamic frameworks are already run in the test_ios_rntester job; this is to just a test build from source (no prebuilds)

  test_ios_rntester:
    runs-on: macos-15-large
    needs:
      [prebuild_apple_dependencies, prebuild_react_native_core]
    continue-on-error: true
    strategy:
      fail-fast: false
      matrix:
        flavor: [Debug, Release]
        frameworks: [false, true]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Run it
        uses: ./.github/actions/test-ios-rntester
        with:
          use-frameworks: ${{ matrix.frameworks }}
          flavor: ${{ matrix.flavor }}

  test_e2e_ios_rntester:
    runs-on: macos-15-large
    needs:
      [test_ios_rntester]
    strategy:
      fail-fast: false
      matrix:
        flavor: [Debug, Release]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup Node.js
        uses: ./.github/actions/setup-node
      - name: Download App
        uses: actions/download-artifact@v7
        with:
          name: RNTesterApp-NewArch-${{ matrix.flavor }}
          path: /tmp/RNTesterBuild/RNTester.app
      - name: Check downloaded folder content
        run: ls -lR /tmp/RNTesterBuild
      - name: Setup xcode
        uses: ./.github/actions/setup-xcode
      - name: Run E2E Tests
        uses: ./.github/actions/maestro-ios
        with:
          app-path: "/tmp/RNTesterBuild/RNTester.app"
          app-id: com.meta.RNTester.localDevelopment
          maestro-flow: ./packages/rn-tester/.maestro/
          flavor: ${{ matrix.flavor }}

  test_e2e_ios_templateapp:
    runs-on: macos-15-large
    needs: [build_npm_package, prebuild_apple_dependencies]
    strategy:
      fail-fast: false
      matrix:
        flavor: [Debug, Release]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup xcode
        uses: ./.github/actions/setup-xcode
      - name: Setup node.js
        uses: ./.github/actions/setup-node
      - name: Run yarn
        uses: ./.github/actions/yarn-install
      - name: Setup ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: 2.6.10
      - name: Download React Native Package
        uses: actions/download-artifact@v7
        with:
          name: react-native-package
          path: /tmp/react-native-tmp
      - name: Print /tmp folder
        run: ls -lR /tmp/react-native-tmp
      - name: Download ReactNativeDependencies
        uses: actions/download-artifact@v7
        with:
          name: ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
          path: /tmp/third-party
      - name: Print third-party folder
        shell: bash
        run: ls -lR /tmp/third-party
      - name: Download React Native Prebuilds
        uses: actions/download-artifact@v7
        with:
          name: ReactCore${{ matrix.flavor }}.xcframework.tar.gz
          path: /tmp/ReactCore
      - name: Print ReactCore folder
        shell: bash
        run: ls -lR /tmp/ReactCore
      - name: Configure git
        shell: bash
        run: |
            git config --global user.email "react-native-bot@meta.com"
            git config --global user.name "React Native Bot"
      - name: Prepare artifacts
        run: |
          REACT_NATIVE_PKG=$(find /tmp/react-native-tmp -type f -name "*.tgz")
          echo "React Native tgs is $REACT_NATIVE_PKG"

          # For stable branches, we want to use the stable branch of the template
          # In all the other cases, we want to use "main"
          BRANCH=${{ github.ref_name }}
          if ! [[ $BRANCH == *-stable* ]]; then
            BRANCH=main
          fi

          node ./scripts/e2e/init-project-e2e.js --projectName RNTestProject --currentBranch $BRANCH --directory /tmp/RNTestProject --pathToLocalReactNative $REACT_NATIVE_PKG

          cd /tmp/RNTestProject/ios
          bundle install
          NEW_ARCH_ENABLED=1

          export RCT_USE_LOCAL_RN_DEP=/tmp/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
          # Disable prebuilds for now, as they are causing issues with E2E tests for 0.82-stable branch
          export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ matrix.flavor }}.xcframework.tar.gz"
          RCT_NEW_ARCH_ENABLED=$NEW_ARCH_ENABLED bundle exec pod install

          xcodebuild \
            -scheme "RNTestProject" \
            -workspace RNTestProject.xcworkspace \
            -configuration "${{ matrix.flavor }}" \
            -sdk "iphonesimulator" \
            -destination "generic/platform=iOS Simulator" \
            -derivedDataPath "/tmp/RNTestProject"
      - name: Run E2E Tests
        uses: ./.github/actions/maestro-ios
        with:
          app-path: "/tmp/RNTestProject/Build/Products/${{ matrix.flavor }}-iphonesimulator/RNTestProject.app"
          app-id: org.reactjs.native.example.RNTestProject
          maestro-flow: ./scripts/e2e/.maestro/
          flavor: ${{ matrix.flavor }}
          working-directory: /tmp/RNTestProject

  test_e2e_android_templateapp:
    runs-on: 4-core-ubuntu
    needs: build_npm_package
    strategy:
      fail-fast: false
      matrix:
        flavor: [debug, release]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup node.js
        uses: ./.github/actions/setup-node
      - name: Run yarn
        uses: ./.github/actions/yarn-install
      - name: Set up JDK 17
        uses: actions/setup-java@v5
        with:
          java-version: '17'
          distribution: 'zulu'
      - name: Download Maven Local
        uses: actions/download-artifact@v7
        with:
          name: maven-local
          path: /tmp/react-native-tmp/maven-local
      - name: Download React Native Package
        uses: actions/download-artifact@v7
        with:
          name: react-native-package
          path: /tmp/react-native-tmp
      - name: Print /tmp folder
        run: ls -lR /tmp/react-native-tmp
      - name: Prepare artifacts
        id: prepare-artifacts
        run: |
          REACT_NATIVE_PKG=$(find /tmp/react-native-tmp -type f -name "*.tgz")
          echo "React Native tgs is $REACT_NATIVE_PKG"

          MAVEN_LOCAL=/tmp/react-native-tmp/maven-local
          echo "Maven local path is $MAVEN_LOCAL"

          # For stable branches, we want to use the stable branch of the template
          # In all the other cases, we want to use "main"
          BRANCH=${{ github.ref_name }}
          if ! [[ $BRANCH == *-stable* ]]; then
            BRANCH=main
          fi
          node ./scripts/e2e/init-project-e2e.js --projectName RNTestProject --currentBranch $BRANCH  --directory /tmp/RNTestProject --pathToLocalReactNative $REACT_NATIVE_PKG

          echo "Feed maven local to gradle.properties"
          cd /tmp/RNTestProject
          echo "react.internal.mavenLocalRepo=$MAVEN_LOCAL" >> android/gradle.properties

          # Build
          cd android
          CAPITALIZED_FLAVOR=$(echo "${{ matrix.flavor }}" | awk '{print toupper(substr($0, 1, 1)) substr($0, 2)}')
          ./gradlew assemble$CAPITALIZED_FLAVOR --no-daemon -PreactNativeArchitectures=x86

      - name: Run E2E Tests
        uses: ./.github/actions/maestro-android
        timeout-minutes: 60
        with:
          app-path: /tmp/RNTestProject/android/app/build/outputs/apk/${{ matrix.flavor }}/app-${{ matrix.flavor }}.apk
          app-id: com.rntestproject
          maestro-flow: ./scripts/e2e/.maestro/
          install-java: 'false'
          flavor: ${{ matrix.flavor }}
          working-directory: /tmp/RNTestProject

  build_fantom_runner:
    runs-on: 8-core-ubuntu
    needs: [set_release_type, check_code_changes, lint]
    if: needs.check_code_changes.outputs.any_code_change == 'true'
    container:
      image: reactnativecommunity/react-native-android:latest
      env:
        # Set the encoding to resolve a known character encoding issue with decompressing tar.gz files in containers
        # via Gradle: https://github.com/gradle/gradle/issues/23391#issuecomment-1878979127
        LC_ALL: C.UTF8
        TERM: "dumb"
        GRADLE_OPTS: "-Dorg.gradle.daemon=false"
        ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
        ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
        REACT_NATIVE_DOWNLOADS_DIR: /opt/react-native-downloads
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Build Fantom Runner
        uses: ./.github/actions/build-fantom-runner
        with:
          release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
          gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}

  run_fantom_tests:
    runs-on: 8-core-ubuntu
    needs: [build_fantom_runner]
    container:
      image: reactnativecommunity/react-native-android:latest
      env:
        TERM: "dumb"
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Run Fantom Tests
        uses: ./.github/actions/run-fantom-tests

  build_android:
    runs-on: 8-core-ubuntu
    needs: [set_release_type, check_code_changes]
    if: |
      needs.check_code_changes.outputs.any_code_change == 'true' &&
      needs.check_code_changes.outputs.should_test_android == 'true'
    container:
      image: reactnativecommunity/react-native-android:latest
      env:
        # Set the encoding to resolve a known character encoding issue with decompressing tar.gz files in containers
        # via Gradle: https://github.com/gradle/gradle/issues/23391#issuecomment-1878979127
        LC_ALL: C.UTF8
        TERM: "dumb"
        GRADLE_OPTS: "-Dorg.gradle.daemon=false"
        ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
        ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
        REACT_NATIVE_DOWNLOADS_DIR: /opt/react-native-downloads
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Build Android
        uses: ./.github/actions/build-android
        with:
          release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
          gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}

  test_e2e_android_rntester:
    runs-on: 4-core-ubuntu
    needs: [build_android]
    strategy:
      fail-fast: false
      matrix:
        flavor: [debug, release]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup node.js
        uses: ./.github/actions/setup-node
      - name: Install node dependencies
        uses: ./.github/actions/yarn-install
      - name: Download APK
        uses: actions/download-artifact@v7
        with:
          name: rntester-${{ matrix.flavor }}
          path: ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.flavor }}/
      - name: Print folder structure
        run: ls -lR ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.flavor }}/
      - name: Run E2E Tests
        uses: ./.github/actions/maestro-android
        timeout-minutes: 60
        with:
          app-path: ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.flavor }}/app-x86-${{ matrix.flavor }}.apk
          app-id: com.facebook.react.uiapp
          maestro-flow: ./packages/rn-tester/.maestro
          flavor: ${{ matrix.flavor }}

  build_npm_package:
    runs-on: 8-core-ubuntu
    needs:
      [
        set_release_type,
        build_android,
        prebuild_apple_dependencies,
        prebuild_react_native_core,
      ]
    container:
      image: reactnativecommunity/react-native-android:latest
      env:
        TERM: "dumb"
        # Set the encoding to resolve a known character encoding issue with decompressing tar.gz files in containers
        # via Gradle: https://github.com/gradle/gradle/issues/23391#issuecomment-1878979127
        LC_ALL: C.UTF8
        GRADLE_OPTS: "-Dorg.gradle.daemon=false"
        REACT_NATIVE_DOWNLOADS_DIR: /opt/react-native-downloads
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Build NPM Package
        uses: ./.github/actions/build-npm-package
        with:
          release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
          gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}

  test_android_helloworld:
    runs-on: 4-core-ubuntu
    needs: build_npm_package
    container:
      image: reactnativecommunity/react-native-android:latest
    env:
      # Set the encoding to resolve a known character encoding issue with decompressing tar.gz files in conatiners
      # via Gradle: https://github.com/gradle/gradle/issues/23391#issuecomment-1878979127
      LC_ALL: C.UTF8
      YARN_ENABLE_IMMUTABLE_INSTALLS: false
      TERM: "dumb"
      GRADLE_OPTS: "-Dorg.gradle.daemon=false"
      TARGET_ARCHITECTURE: "arm64-v8a"
      REACT_NATIVE_DOWNLOADS_DIR: /opt/react-native-downloads
    continue-on-error: true
    strategy:
      fail-fast: false
      matrix:
        flavor: [Debug, Release]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup git safe folders
        run: git config --global --add safe.directory '*'
      - name: Download npm package artifact
        uses: actions/download-artifact@v7
        with:
          name: react-native-package
          path: build
      - name: Download maven-local artifact
        uses: actions/download-artifact@v7
        with:
          name: maven-local
          path: /tmp/maven-local
      - name: Setup gradle
        uses: ./.github/actions/setup-gradle
        with:
          cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
      - name: Run yarn install
        uses: ./.github/actions/yarn-install
      - name: Set nightly Hermes versions
        shell: bash
        run: |
          node ./scripts/releases/use-hermes-nightly.js
      - name: Run yarn install again, with the correct hermes version
        uses: ./.github/actions/yarn-install
      - name: Prepare the Helloworld application
        shell: bash
        run: node ./scripts/e2e/init-project-e2e.js --useHelloWorld --pathToLocalReactNative "$GITHUB_WORKSPACE/build/$(cat build/react-native-package-version)"
      - name: Build the Helloworld application for ${{ matrix.flavor }} with Architecture set to New Architecture.
        shell: bash
        run: |
          cd private/helloworld/android
          args=()
          if [[ ${{ matrix.flavor }} == "Release" ]]; then
            args+=(--prod)
          fi
          yarn build android "${args[@]}" -P reactNativeArchitectures="$TARGET_ARCHITECTURE" -P react.internal.mavenLocalRepo="/tmp/maven-local"
      - name: Upload artifact
        uses: actions/upload-artifact@v6
        with:
          name: helloworld-apk-${{ matrix.flavor }}-NewArch-hermes
          path: ./private/helloworld/android/app/build/outputs/apk/
          compression-level: 0

  test_ios_helloworld_with_ruby_3_2_0:
    runs-on: macos-15
    needs: [prebuild_apple_dependencies, prebuild_react_native_core]
    env:
      PROJECT_NAME: iOSTemplateProject
      YARN_ENABLE_IMMUTABLE_INSTALLS: false
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - uses: ./.github/actions/test-ios-helloworld
        with:
          ruby-version: 3.2.0
          flavor: Debug

  test_ios_helloworld:
    runs-on: macos-15
    needs: [prebuild_apple_dependencies, prebuild_react_native_core]
    strategy:
      matrix:
        flavor: [Debug, Release]
        use_frameworks: [false, true]
        exclude:
          # This config is tested with Ruby 3.2.0. Let's not double test it.
          - flavor: Debug
            use_frameworks: StaticLibraries
    env:
      PROJECT_NAME: iOSTemplateProject
      YARN_ENABLE_IMMUTABLE_INSTALLS: false
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - uses: ./.github/actions/test-ios-helloworld
        with:
          flavor: ${{ matrix.flavor }}
          use-frameworks: ${{ matrix.use_frameworks }}

  lint:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Install dependencies
        uses: ./.github/actions/yarn-install
      - name: Lint file structure
        shell: bash
        run: ./.github/workflow-scripts/lint_files.sh
      - name: Run shellcheck
        shell: bash
        run: ./.github/workflow-scripts/analyze_scripts.sh
      - name: Prettier
        shell: bash
        run: yarn run format-check
      - name: markdownlint
        shell: bash
        run: yarn run lint-markdown
      - name: ESLint
        shell: bash
        run: ./.github/workflow-scripts/exec_swallow_error.sh yarn lint --format junit -o ./reports/junit/eslint/results.xml
      - name: Flow
        shell: bash
        run: yarn flow-check
      - name: TypeScript
        shell: bash
        run: yarn test-typescript

  test_js:
    runs-on: ubuntu-latest
    needs: [check_code_changes, lint]
    if: needs.check_code_changes.outputs.any_code_change == 'true'
    strategy:
      fail-fast: false
      matrix:
        node-version: ["24", "22", "20.19.4"]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Test JS
        uses: ./.github/actions/test-js
        with:
          node-version: ${{ matrix.node-version }}

  build_js_types:
    runs-on: ubuntu-latest
    needs: [check_code_changes, lint]
    if: needs.check_code_changes.outputs.any_code_change == 'true'
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup Node.js
        uses: ./.github/actions/setup-node
      - name: Install dependencies
        uses: ./.github/actions/yarn-install
      - name: Build react-native package types
        shell: bash
        run: yarn build-types --skip-snapshot
      - name: Validate generated types
        shell: bash
        run: yarn test-generated-typescript

  build_debugger_shell:
    runs-on: ubuntu-latest
    needs: check_code_changes
    if: needs.check_code_changes.outputs.debugger_shell == 'true'
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Setup Node.js
        uses: ./.github/actions/setup-node
      - name: Install dependencies
        uses: ./.github/actions/yarn-install
      - name: Build packages
        shell: bash
        run: yarn build --prepack
      - name: Verify debugger-shell build
        shell: bash
        run: node scripts/debugger-shell/build-binary.js

  # This job should help with the E2E flakyness.
  # In case E2E tests fails, it launches a new retry-workflow workflow, passing the current run_id as input.
  # The retry-workflow reruns only the failed jobs of the current test-all workflow using
  # ```
  # gh run rerun ${{ inputs.run_id }} --failed
  # ```
  # From https://stackoverflow.com/a/78314483 it seems like that adding the extra workflow
  # rather then calling directly this command should improve stability of this solution.
  # This is exactly the same as rerunning failed tests from the GH UI, but automated.
  rerun-failed-jobs:
    runs-on: ubuntu-latest
    needs: [test_e2e_ios_rntester, test_e2e_android_rntester, test_e2e_ios_templateapp, test_e2e_android_templateapp, run_fantom_tests]
    if: ${{ github.ref == 'refs/heads/main' && always() }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Rerun failed jobs in the current workflow
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          SHOULD_RETRY=${{fromJSON(github.run_attempt) < 3}}
          if [[ $SHOULD_RETRY == "false" ]]; then
            exit 0
          fi

          RNTESTER_ANDROID_FAILED=${{ needs.test_e2e_android_rntester.result == 'failure' }}
          TEMPLATE_ANDROID_FAILED=${{ needs.test_e2e_android_templateapp.result == 'failure' }}
          RNTESTER_IOS_FAILED=${{ needs.test_e2e_ios_rntester.result == 'failure' }}
          TEMPLATE_IOS_FAILED=${{ needs.test_e2e_ios_templateapp.result == 'failure' }}
          FANTOM_TESTS_FAILED=${{ needs.run_fantom_tests.result == 'failure' }}

          echo "RNTESTER_ANDROID_FAILED: $RNTESTER_ANDROID_FAILED"
          echo "TEMPLATE_ANDROID_FAILED: $TEMPLATE_ANDROID_FAILED"
          echo "RNTESTER_IOS_FAILED: $RNTESTER_IOS_FAILED"
          echo "TEMPLATE_IOS_FAILED: $TEMPLATE_IOS_FAILED"
          echo "FANTOM_TESTS_FAILED: $FANTOM_TESTS_FAILED"

          if [[ $RNTESTER_ANDROID_FAILED == "true" || $TEMPLATE_ANDROID_FAILED == "true" || $RNTESTER_IOS_FAILED == "true" || $TEMPLATE_IOS_FAILED == "true" || $FANTOM_TESTS_FAILED == "true" ]]; then
            echo "Rerunning failed jobs in the current workflow"
            gh workflow run retry-workflow.yml -F run_id=${{ github.run_id }}
          fi
validate-dotslash-artifacts .github/workflows/validate-dotslash-artifacts.yml
Triggers
workflow_dispatch, release, push, pull_request, schedule
Runs on
ubuntu-latest
Jobs
validate-dotslash-artifacts
Commands
  • git config --local user.email "bot@reactnative.dev" git config --local user.name "React Native Bot"
View raw YAML
name: Validate DotSlash Artifacts

on:
  workflow_dispatch:
  release:
    types: [published]
  push:
    branches:
      - main
    paths:
      - packages/debugger-shell/bin/react-native-devtools
      - "scripts/releases/**"
      - package.json
      - yarn.lock
  pull_request:
    branches:
      - main
    paths:
      - packages/debugger-shell/bin/react-native-devtools
      - "scripts/releases/**"
      - package.json
      - yarn.lock
  # Same time as the nightly build: 2:15 AM UTC
  schedule:
    - cron: "15 2 * * *"

jobs:
  validate-dotslash-artifacts:
    runs-on: ubuntu-latest
    if: github.repository == 'facebook/react-native'
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          fetch-tags: true
      - name: Setup node.js
        uses: ./.github/actions/setup-node
      - name: Install dependencies
        uses: ./.github/actions/yarn-install
      - name: Configure Git
        shell: bash
        run: |
          git config --local user.email "bot@reactnative.dev"
          git config --local user.name "React Native Bot"
      - name: Validate DotSlash artifacts
        uses: actions/github-script@v8
        with:
          script: |
            const {validateDotSlashArtifacts} = require('./scripts/releases/validate-dotslash-artifacts.js');
            await validateDotSlashArtifacts();