name: build on: push: branches: - trunk pull_request: merge_group: schedule: # Nightly builds against react-native@nightly at 4:00, Monday through Friday - cron: 0 4 * * 1-5 env: GRADLE_HANGS_ON_WINDOWS: 1 # https://github.com/microsoft/react-native-test-app/issues/2206 HOMEBREW_NO_INSTALL_CLEANUP: 1 VisualStudioVersion: "17.0" concurrency: # Ensure single build of a pull request. `trunk` should not be affected. group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: lint-commit: name: "lint commit message" runs-on: ubuntu-24.04 if: ${{ github.event_name == 'pull_request' }} steps: - name: Checkout uses: actions/checkout@v4 with: filter: blob:none fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain - name: Lint commit message run: | npm run lint:commit review: permissions: issues: write # comment on PRs (suggestion-bot) pull-requests: write # create code reviews (suggestion-bot) strategy: matrix: runner: [macos-14, windows-2022] runs-on: ${{ matrix.runner }} if: ${{ github.event_name != 'schedule' }} steps: - name: Checkout uses: actions/checkout@v4 with: filter: blob:none fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain with: platform: node - name: Deduplicate packages run: | yarn dedupe --check - name: Install npm dependencies uses: ./.github/actions/yarn - name: Validate generated files if: ${{ github.event_name == 'pull_request' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | yarn generate:code yarn generate:schema if [[ -n "$GITHUB_TOKEN" ]]; then git diff | yarn suggestion-bot fi git diff --exit-code shell: bash - name: ClangFormat if: ${{ github.event_name == 'pull_request' && runner.os == 'macOS' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # TODO: GITHUB_TOKEN is not set if a PR comes from a forked repo. # Ignore errors until we can create a GitHub PAT from a system # account. scripts/build/clang-format-diff.sh || true - name: CocoaPods if: ${{ runner.os == 'macOS' }} run: | echo "::add-matcher::.github/rubocop.json" yarn lint:rb echo "::remove-matcher owner=rubocop::" echo "::add-matcher::.github/minitest.json" yarn test:rb echo "::remove-matcher owner=minitest::" - name: Validate Gradle wrapper uses: gradle/actions/wrapper-validation@v4 - name: Populate Gradle cache if: ${{ runner.os != 'Windows' || env.GRADLE_HANGS_ON_WINDOWS != '1' }} uses: ./.github/actions/gradle with: arguments: clean project-root: example - name: JavaScript env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # TODO: GITHUB_TOKEN is not set if a PR comes from a forked repo. # Ignore errors until we can create a GitHub PAT from a system # account. if [[ ${{ runner.os }} == macOS ]]; then yarn format:js if [[ -n "$GITHUB_TOKEN" ]]; then git diff | yarn suggestion-bot else git diff fi git diff --exit-code echo "::add-matcher::.github/eslint-stylish.json" yarn lint:js echo "::remove-matcher owner=eslint-stylish::" fi yarn tsc yarn test:js shell: bash - name: ktlint if: ${{ github.event_name == 'pull_request' && runner.os == 'macOS' }} run: | brew install ktlint echo "::add-matcher::.github/ktlint.json" yarn lint:kt echo "::remove-matcher owner=ktlint::" - name: SwiftFormat if: ${{ github.event_name == 'pull_request' && runner.os == 'macOS' }} run: | echo "::add-matcher::.github/swiftformat.json" yarn format:swift --lint echo "::remove-matcher owner=swiftformat::" - name: SwiftLint if: ${{ runner.os == 'macOS' }} run: | brew install swiftlint echo "::add-matcher::.github/swiftlint.json" swiftlint echo "::remove-matcher owner=swiftlint::" - name: Smoke test `npx --package react-native-test-app@latest init` run: | node ./react-native-test-app/scripts/init.mjs --destination app --name App -p android -p ios -p macos -p windows working-directory: .. - name: Smoke test `setup-react-native` action uses: ./.github/actions/setup-react-native with: version: nightly timeout-minutes: 60 ios: name: "iOS" runs-on: macos-14 steps: - name: Checkout uses: actions/checkout@v4 with: filter: blob:none fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain with: platform: ios project-root: example cache-key-prefix: example - name: Set up react-native@nightly if: ${{ github.event_name == 'schedule' }} uses: ./.github/actions/setup-react-native with: version: nightly - name: Install npm dependencies uses: ./.github/actions/yarn with: immutable: ${{ github.event_name != 'schedule' }} - name: Bundle JavaScript run: | yarn build:ios || yarn build:ios working-directory: example - name: Determine whether the iOS app needs to be built id: affected uses: ./.github/actions/affected - name: Install Pods if: ${{ steps.affected.outputs.ios != '' }} uses: ./.github/actions/cocoapods with: project-directory: ios working-directory: example - name: Build if: ${{ steps.affected.outputs.ios != '' }} run: | ../scripts/build/xcodebuild.sh ios/Example.xcworkspace build-for-testing working-directory: example - name: Test `react-native config` if: ${{ steps.affected.outputs.ios != '' }} run: | node --test test/config.test.mjs working-directory: example - name: Test if: ${{ steps.affected.outputs.ios != '' }} run: | ../scripts/build/xcodebuild.sh ios/Example.xcworkspace test-without-building working-directory: example timeout-minutes: 60 ios-template: name: "iOS [template]" strategy: matrix: template: [all, ios] runs-on: macos-14 if: ${{ github.event_name != 'schedule' }} steps: - name: Checkout uses: actions/checkout@v4 with: filter: blob:none fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain with: platform: ios project-root: example cache-key-prefix: template-${{ matrix.template }} - name: Initialize test app uses: ./.github/actions/init-test-app with: platform: ${{ matrix.template }} - name: Bundle JavaScript run: | yarn build:ios || yarn build:ios working-directory: template-example - name: Determine whether the iOS app needs to be built id: affected uses: ./.github/actions/affected - name: Determine project directory id: configure if: ${{ steps.affected.outputs.ios != '' }} run: | if [[ ${{ matrix.template }} == ios ]]; then echo 'project-directory=.' >> $GITHUB_OUTPUT else echo 'project-directory=ios' >> $GITHUB_OUTPUT fi - name: Install Pods if: ${{ steps.affected.outputs.ios != '' }} run: | pod install --project-directory=${{ steps.configure.outputs.project-directory }} working-directory: template-example - name: Build if: ${{ steps.affected.outputs.ios != '' }} run: | ../scripts/build/xcodebuild.sh ${{ steps.configure.outputs.project-directory }}/TemplateExample.xcworkspace build working-directory: template-example - name: react-native run-ios if: ${{ steps.affected.outputs.ios != '' }} run: | ../scripts/testing/react-native.mjs run-ios working-directory: template-example timeout-minutes: 60 android: name: "Android" strategy: matrix: runner: [ubuntu-24.04] # TODO: Re-add Windows: https://github.com/microsoft/react-native-test-app/issues/2206 runs-on: ${{ matrix.runner }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain with: platform: android - name: Set up react-native@nightly if: ${{ github.event_name == 'schedule' }} uses: ./.github/actions/setup-react-native with: version: nightly - name: Install npm dependencies uses: ./.github/actions/yarn with: immutable: ${{ github.event_name != 'schedule' }} - name: Test `react-native config` run: | node --test test/config.test.mjs working-directory: example - name: Bundle JavaScript # Metro on nightlies currently fails with "SHA-1 for file index.js is # not computed" so we'll skip this step for now. if: ${{ github.event_name != 'schedule' || runner.os != 'Windows' }} run: | yarn build:android || yarn build:android shell: bash working-directory: example - name: Determine whether the Android app needs to be built id: affected # Nightlies currently fail on Windows because of wrong path separators. if: ${{ github.event_name != 'schedule' || runner.os != 'Windows' }} uses: ./.github/actions/affected - name: Build if: ${{ steps.affected.outputs.android != '' }} uses: ./.github/actions/gradle with: project-root: example timeout-minutes: 60 android-template: name: "Android [template]" strategy: matrix: template: [all, android] runner: [ubuntu-24.04] # TODO: Re-add Windows: https://github.com/microsoft/react-native-test-app/issues/2206 runs-on: ${{ matrix.runner }} if: ${{ github.event_name != 'schedule' }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain with: platform: android - name: Initialize test app uses: ./.github/actions/init-test-app with: platform: ${{ matrix.template }} - name: Bundle JavaScript run: | yarn build:android || yarn build:android shell: bash working-directory: template-example - name: Determine whether the Android app needs to be built id: affected uses: ./.github/actions/affected - name: Build if: ${{ steps.affected.outputs.android != '' }} uses: ./.github/actions/gradle with: project-root: template-example - name: react-native run-android if: ${{ steps.affected.outputs.android != '' }} run: | ../scripts/testing/react-native.mjs run-android working-directory: template-example timeout-minutes: 60 macos: name: "macOS" runs-on: macos-14 if: ${{ github.event_name != 'schedule' }} steps: - name: Checkout uses: actions/checkout@v4 with: filter: blob:none fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain with: platform: macos project-root: example cache-key-prefix: example - name: Set up react-native@canary if: ${{ github.event_name == 'schedule' }} uses: ./.github/actions/setup-react-native with: version: canary-macos - name: Install npm dependencies uses: ./.github/actions/yarn with: immutable: ${{ github.event_name != 'schedule' }} - name: Bundle JavaScript run: | yarn build:macos || yarn build:macos working-directory: example - name: Determine whether the macOS app needs to be built id: affected uses: ./.github/actions/affected - name: Install Pods if: ${{ steps.affected.outputs.macos != '' }} uses: ./.github/actions/cocoapods with: project-directory: macos working-directory: example - name: Build x86 if: ${{ steps.affected.outputs.macos != '' }} run: | ../scripts/build/xcodebuild.sh macos/Example.xcworkspace build-for-testing working-directory: example - name: Test `react-native config` if: ${{ steps.affected.outputs.macos != '' }} run: | node --test test/config.test.mjs working-directory: example - name: Test # Temporarily disabled due to random failures if: false # ${{ steps.affected.outputs.macos != '' && github.event_name != 'schedule' }} run: | ../scripts/build/xcodebuild.sh macos/Example.xcworkspace test-without-building working-directory: example - name: Prepare for arm64 build if: ${{ steps.affected.outputs.macos != '' }} run: | rm -fr macos/build working-directory: example - name: Install Pods if: ${{ steps.affected.outputs.macos != '' }} uses: ./.github/actions/cocoapods with: project-directory: macos working-directory: example - name: Build arm64 if: ${{ steps.affected.outputs.macos != '' }} run: | ../scripts/build/xcodebuild.sh macos/Example.xcworkspace build ARCHS=arm64 working-directory: example timeout-minutes: 60 macos-template: name: "macOS [template]" strategy: matrix: template: [all, macos] runs-on: macos-14 if: ${{ github.event_name != 'schedule' }} steps: - name: Checkout uses: actions/checkout@v4 with: filter: blob:none fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain with: platform: macos project-root: example cache-key-prefix: template-${{ matrix.template }} - name: Initialize test app uses: ./.github/actions/init-test-app with: platform: ${{ matrix.template }} - name: Bundle JavaScript run: | yarn build:macos || yarn build:macos working-directory: template-example - name: Determine whether the macOS app needs to be built id: affected uses: ./.github/actions/affected - name: Determine project directory id: configure if: ${{ steps.affected.outputs.macos != '' }} run: | if [[ ${{ matrix.template }} == macos ]]; then echo 'project-directory=.' >> $GITHUB_OUTPUT else echo 'project-directory=macos' >> $GITHUB_OUTPUT fi - name: Install Pods if: ${{ steps.affected.outputs.macos != '' }} run: | pod install --project-directory=${{ steps.configure.outputs.project-directory }} working-directory: template-example - name: Build if: ${{ steps.affected.outputs.macos != '' }} run: | ../scripts/build/xcodebuild.sh ${{ steps.configure.outputs.project-directory }}/TemplateExample.xcworkspace build working-directory: template-example timeout-minutes: 60 visionos: name: "visionOS" runs-on: macos-14 if: ${{ github.event_name != 'schedule' }} steps: - name: Checkout uses: actions/checkout@v4 with: filter: blob:none fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain with: platform: visionos project-root: example cache-key-prefix: example xcode-developer-dir: /Applications/Xcode_15.2.app - name: Set up react-native@nightly if: ${{ github.event_name == 'schedule' }} uses: ./.github/actions/setup-react-native with: version: nightly - name: Install npm dependencies uses: ./.github/actions/yarn with: immutable: ${{ github.event_name != 'schedule' }} - name: Bundle JavaScript run: | yarn build:visionos || yarn build:visionos working-directory: example - name: Determine whether the visionOS app needs to be built id: affected uses: ./.github/actions/affected - name: Install Pods if: ${{ steps.affected.outputs.visionos != '' }} uses: ./.github/actions/cocoapods with: project-directory: visionos working-directory: example - name: Build if: ${{ steps.affected.outputs.visionos != '' }} run: | ../scripts/build/xcodebuild.sh visionos/Example.xcworkspace build-for-testing working-directory: example - name: Test `react-native config` if: ${{ steps.affected.outputs.visionos != '' }} run: | node --test test/config.test.mjs working-directory: example timeout-minutes: 60 visionos-template: name: "visionOS [template]" strategy: matrix: template: [all, visionos] runs-on: macos-14 if: ${{ github.event_name != 'schedule' }} steps: - name: Checkout uses: actions/checkout@v4 with: filter: blob:none fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain with: platform: visionos project-root: example cache-key-prefix: template-${{ matrix.template }} xcode-developer-dir: /Applications/Xcode_15.2.app - name: Initialize test app uses: ./.github/actions/init-test-app with: platform: ${{ matrix.template }} - name: Bundle JavaScript run: | yarn build:visionos || yarn build:visionos working-directory: template-example - name: Determine whether the visionOS app needs to be built id: affected uses: ./.github/actions/affected - name: Determine project directory id: configure if: ${{ steps.affected.outputs.visionos != '' }} run: | if [[ ${{ matrix.template }} == visionos ]]; then echo 'project-directory=.' >> $GITHUB_OUTPUT else echo 'project-directory=visionos' >> $GITHUB_OUTPUT fi - name: Install Pods if: ${{ steps.affected.outputs.visionos != '' }} run: | pod install --project-directory=${{ steps.configure.outputs.project-directory }} working-directory: template-example - name: Build if: ${{ steps.affected.outputs.visionos != '' }} run: | ../scripts/build/xcodebuild.sh ${{ steps.configure.outputs.project-directory }}/TemplateExample.xcworkspace build working-directory: template-example timeout-minutes: 60 windows: name: "Windows" runs-on: windows-2022 strategy: matrix: platform: [ARM64, x64] configuration: [Debug, Release] steps: - name: Checkout uses: actions/checkout@v4 with: filter: blob:none fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain with: platform: windows - name: Set up react-native@canary if: ${{ github.event_name == 'schedule' }} uses: ./.github/actions/setup-react-native with: version: canary-windows - name: Install npm dependencies uses: ./.github/actions/yarn with: immutable: ${{ github.event_name != 'schedule' }} - name: Bundle JavaScript run: | yarn build:windows - name: Generate Visual Studio solution run: | yarn install-windows-test-app --use-nuget working-directory: example - name: Test `react-native config` run: | node --test test/config.test.mjs working-directory: example - name: Determine whether the Windows app needs to be built id: affected uses: ./.github/actions/affected - name: Build if: ${{ steps.affected.outputs.windows != '' }} run: | if ("${{ matrix.configuration }}" -eq "Release") { yarn ci:windows --release --arch ${{ matrix.platform }} } else { yarn ci:windows --arch ${{ matrix.platform }} } working-directory: example/windows - name: Test if: ${{ steps.affected.outputs.windows != '' && matrix.platform == 'x64' }} run: | ../../../scripts/build/MSBuild.ps1 -Configuration ${{ matrix.configuration }} -Platform ${{ matrix.platform }} -Target Build ReactAppTests.vcxproj ../../../scripts/build/VSTest.ps1 ${{ matrix.platform }}\${{ matrix.configuration }}\ReactAppTests.dll working-directory: example/windows/ReactAppTests timeout-minutes: 60 windows-template: name: "Windows [template]" runs-on: windows-2022 if: ${{ github.event_name != 'schedule' }} strategy: matrix: template: [all, windows] steps: - name: Checkout uses: actions/checkout@v4 with: filter: blob:none fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain with: platform: windows - name: Initialize test app uses: ./.github/actions/init-test-app with: platform: ${{ matrix.template }} - name: Bundle JavaScript run: | yarn build:windows - name: Generate Visual Studio solution run: | if ("${{ matrix.template }}" -eq "all") { yarn install-windows-test-app --use-nuget } else { yarn install-windows-test-app --project-directory=. --use-nuget } working-directory: template-example - name: Determine whether the Windows app needs to be built id: affected uses: ./.github/actions/affected - name: Build if: ${{ steps.affected.outputs.windows != '' }} run: | yarn windows --logging --no-packager --no-launch --no-deploy working-directory: template-example timeout-minutes: 60 release: permissions: contents: write # create releases (semantic-release) id-token: write # enable use of OIDC for npm provenance (semantic-release) needs: - review - ios - ios-template - android - android-template - macos - macos-template - windows - windows-template runs-on: ubuntu-24.04 if: ${{ github.event_name != 'schedule' }} steps: - name: Checkout uses: actions/checkout@v4 with: filter: blob:none fetch-depth: 0 - name: Set up toolchain uses: ./.github/actions/setup-toolchain - name: Install npm dependencies uses: ./.github/actions/yarn - name: Verify tarball content run: | yarn test test/pack.test.ts - name: Release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: | yarn semantic-release autobot: name: "Autobot" permissions: contents: read pull-requests: write if: ${{ github.event_name == 'pull_request' }} runs-on: ubuntu-24.04 steps: - name: Label uses: actions/labeler@v5.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} sync-labels: true continue-on-error: true