Skip to content

feat: add controllable native operations #65

feat: add controllable native operations

feat: add controllable native operations #65

Workflow file for this run

name: CI
on:
pull_request:
types: [opened, synchronize, reopened]
schedule:
- cron: '17 3 * * 1'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
changes:
name: Classify changes
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
android: ${{ steps.changes.outputs.android }}
ios: ${{ steps.changes.outputs.ios }}
quality: ${{ steps.changes.outputs.quality }}
site: ${{ steps.changes.outputs.site }}
web: ${{ steps.changes.outputs.web }}
steps:
- name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
fetch-depth: 0
- name: Classify changed files
id: changes
shell: bash
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
EVENT_NAME: ${{ github.event_name }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
android=false
ios=false
quality=false
site=false
web=false
if [[ "$EVENT_NAME" != "pull_request" ]]; then
android=true
ios=true
quality=true
site=true
web=true
else
while IFS= read -r file; do
case "$file" in
.github/workflows/ci.yml|.github/actions/**|package.json|yarn.lock|.yarnrc.yml|.yarn/releases/**|.nvmrc)
android=true
ios=true
quality=true
site=true
web=true
;;
.github/workflows/registry-canary.yml|scripts/test-registry-consumers.mjs)
quality=true
web=true
;;
src/**|assets/**)
android=true
ios=true
quality=true
web=true
;;
cpp/fuzz/**|scripts/test-native-fuzz.sh|cpp/benchmark/**|scripts/benchmark-native.mjs|.github/workflows/native-benchmark.yml)
quality=true
;;
cpp/**)
android=true
ios=true
quality=true
web=true
;;
android/**|example/android/**|scripts/run-android-runtime-test.sh)
android=true
quality=true
;;
compatibility/android-api/**|scripts/test-rn-android-compatibility.sh)
android=true
quality=true
;;
compatibility/ios-api/**|scripts/test-rn-ios-compatibility.sh)
ios=true
quality=true
;;
ios/**|example/ios/**|*.podspec)
ios=true
quality=true
;;
example/src/**|example/e2e/**)
android=true
ios=true
quality=true
;;
web/**|fixtures/**|scripts/build-web-wasm.sh|scripts/test-web*.mjs|scripts/web-*)
android=true
ios=true
web=true
quality=true
site=true
;;
scripts/prepare-package.mjs|scripts/test-package-consumers.mjs)
quality=true
web=true
;;
benchmarks/**|scripts/benchmark-web.mjs)
quality=true
site=true
web=true
;;
site/**|docs/**|README*.md|CONTRIBUTING.md|scripts/build-site.mjs|scripts/test-site*.mjs|.github/workflows/pages.yml)
site=true
;;
.github/ISSUE_TEMPLATE/**|.github/PULL_REQUEST_TEMPLATE.md|.github/CODEOWNERS|.github/dependabot.yml)
quality=true
;;
*.md)
site=true
;;
*)
# Unknown repository changes run every gate instead of risking a false skip.
android=true
ios=true
quality=true
site=true
web=true
;;
esac
done < <(git diff --name-only "$BASE_SHA" "$HEAD_SHA")
fi
{
echo "android=$android"
echo "ios=$ios"
echo "quality=$quality"
echo "site=$site"
echo "web=$web"
} >> "$GITHUB_OUTPUT"
{
echo '### CI change classification'
echo
echo "| Gate | Run |"
echo "| --- | --- |"
echo "| Android | $android |"
echo "| iOS | $ios |"
echo "| Core quality | $quality |"
echo "| Site | $site |"
echo "| Web | $web |"
} >> "$GITHUB_STEP_SUMMARY"
android-build:
name: Android New Architecture Build
needs: changes
if: needs.changes.outputs.android == 'true'
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- name: Setup Node.js and dependencies
uses: ./.github/actions/setup
- name: Set up JDK
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5
with:
distribution: zulu
java-version: 17
- name: Set up Gradle
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6
with:
cache-provider: basic
cache-read-only: ${{ github.event_name == 'pull_request' }}
- name: Build package
run: yarn prepare
- name: Build Android and run unit tests
working-directory: example/android
run: |
./gradlew test assembleRelease --stacktrace -PnewArchEnabled=true
mv app/build/outputs/apk/release/app-release.apk app-release-${{ github.sha }}-new-arch.apk
- name: Upload Android reports
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: Android-New-Architecture-Build-Reports
path: example/android/**/build/reports
if-no-files-found: ignore
retention-days: 7
- name: Upload APK
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: app-release-${{ github.sha }}-new-arch
path: example/android/app-release-${{ github.sha }}-new-arch.apk
if-no-files-found: error
retention-days: 7
android-api-level-test:
name: Android New Architecture Runtime Test (API ${{ matrix.api-level }})
needs: [changes, android-build]
if: needs.changes.outputs.android == 'true'
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
fail-fast: ${{ github.event_name == 'pull_request' }}
max-parallel: 2
matrix:
api-level: ${{ fromJSON(github.event_name == 'pull_request' && '[24,31]' || '[24,25,29,30,31]') }}
steps:
- name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- name: Setup Node.js and dependencies
uses: ./.github/actions/setup
- name: Set up JDK
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5
with:
distribution: zulu
java-version: 17
- name: Set up Gradle
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6
with:
cache-provider: basic
cache-read-only: true
- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
| sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Build package
run: yarn prepare
- name: Run instrumentation tests
uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2
with:
api-level: ${{ matrix.api-level }}
target: default
arch: x86_64
profile: Nexus 6
script: sh scripts/run-android-runtime-test.sh ${{ matrix.api-level }}
- name: Upload instrumentation reports
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: New-Arch-Runtime-Test-Reports-${{ matrix.api-level }}
path: |
example/android/app/build/reports
example/android/app/build/outputs/androidTest-results
if-no-files-found: ignore
retention-days: 7
android-rn-compatibility:
name: Android RN API Compatibility (${{ matrix.react-native }}, ${{ matrix.architecture }})
needs: changes
if: needs.changes.outputs.android == 'true'
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: true
max-parallel: 2
matrix:
include:
- react-native: '0.73.11'
architecture: old
- react-native: '0.73.11'
architecture: new
- react-native: '0.74.7'
architecture: new
steps:
- name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- name: Set up JDK
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5
with:
distribution: zulu
java-version: 17
- name: Set up Gradle
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6
with:
gradle-version: '8.3'
cache-provider: basic
cache-read-only: ${{ github.event_name == 'pull_request' }}
- name: Compile library against React Native Android APIs
run: sh scripts/test-rn-android-compatibility.sh ${{ matrix.react-native }} ${{ matrix.architecture }}
ios-build-test:
name: iOS New Architecture Runtime Test
needs: changes
if: needs.changes.outputs.ios == 'true'
runs-on: macos-15
timeout-minutes: 45
steps:
- name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- name: Setup Node.js and dependencies
uses: ./.github/actions/setup
- name: Set up Ruby
uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1
with:
ruby-version: '3.3'
bundler-cache: true
working-directory: example
- name: Cache Pods
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
example/ios/Pods
~/Library/Caches/CocoaPods
key: ${{ runner.os }}-pods-rn86-new-arch-${{ hashFiles('example/ios/Podfile.lock', 'example/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-rn86-new-arch-
- name: Install Pods
env:
NO_FLIPPER: '1'
RCT_NEW_ARCH_ENABLED: '1'
run: |
cd example/ios
bundle exec pod install
- name: Select an available iPhone simulator
id: simulator
run: |
simulator_udid="$(xcrun simctl list devices available | awk -F '[()]' '/iPhone/ { print $2; exit }')"
if [[ -z "$simulator_udid" ]]; then
echo 'No available iPhone simulator was found' >&2
exit 1
fi
echo "udid=$simulator_udid" >> "$GITHUB_OUTPUT"
- name: Test
env:
SIMULATOR_UDID: ${{ steps.simulator.outputs.udid }}
run: |
set -o pipefail
cd example/ios
# Xcode expands $(inherited), not the shell.
# shellcheck disable=SC2016
xcodebuild \
-workspace BsDiffPatchExample.xcworkspace \
-scheme BsDiffPatchExample \
-configuration Release \
-sdk iphonesimulator \
-destination "platform=iOS Simulator,id=$SIMULATOR_UDID" \
-resultBundlePath "$RUNNER_TEMP/ios-tests.xcresult" \
EXPECTED_NEW_ARCH=1 \
GCC_PREPROCESSOR_DEFINITIONS='$(inherited) EXPECTED_NEW_ARCH=$(EXPECTED_NEW_ARCH)' \
test | bundle exec xcpretty
- name: Upload iOS test results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: iOS-New-Architecture-Test-Results
path: ${{ runner.temp }}/ios-tests.xcresult
if-no-files-found: ignore
retention-days: 7
ios-rn-compatibility:
name: iOS RN API Compatibility (${{ matrix.react-native }}, ${{ matrix.architecture }})
needs: changes
if: needs.changes.outputs.ios == 'true'
runs-on: ${{ matrix.runner }}
timeout-minutes: 45
strategy:
fail-fast: true
max-parallel: 2
matrix:
include:
- react-native: '0.73.11'
architecture: old
node: '18'
runner: macos-14
- react-native: '0.73.11'
architecture: new
node: '18'
runner: macos-14
- react-native: '0.74.7'
architecture: new
node: '18'
runner: macos-14
steps:
- name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: ${{ matrix.node }}
- name: Set up Ruby
uses: ruby/setup-ruby@003a5c4d8d6321bd302e38f6f0ec593f77f06600 # v1
with:
ruby-version: '3.3'
bundler-cache: true
working-directory: example
- name: Compile Pod against React Native iOS APIs
run: sh scripts/test-rn-ios-compatibility.sh ${{ matrix.react-native }} ${{ matrix.architecture }}
web-test:
name: Web WASM and Browser Test
needs: changes
if: needs.changes.outputs.web == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- name: Setup Node.js and dependencies
uses: ./.github/actions/setup
- name: Build package
run: yarn prepare
- name: Run Web tests
env:
CHROME_PATH: /usr/bin/google-chrome
run: |
yarn test:web
yarn test:web:browser
yarn test:web:metro
yarn test:package
- name: Verify npm package contents
run: npm pack --dry-run --ignore-scripts
quality:
name: Lint, TypeScript, and Jest
needs: changes
if: needs.changes.outputs.quality == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- name: Setup Node.js and dependencies
uses: ./.github/actions/setup
- name: Run core quality gates
run: |
yarn prepare
yarn typecheck
yarn lint
yarn test --runInBand
yarn test:native-operations
FUZZ_RUNS=2000 yarn test:fuzz
site-test:
name: Documentation Site and Playground Test
needs: changes
if: needs.changes.outputs.site == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout the code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- name: Setup Node.js and dependencies
uses: ./.github/actions/setup
- name: Build documentation site
run: yarn site:build
- name: Validate site and Playground
env:
CHROME_PATH: /usr/bin/google-chrome
run: |
yarn site:test
yarn site:test:browser
ci-complete:
name: Complete CI
needs:
[
changes,
quality,
android-build,
android-api-level-test,
android-rn-compatibility,
ios-build-test,
ios-rn-compatibility,
web-test,
site-test,
]
if: always()
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Check all job statuses
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
run: exit 1
- name: Confirm completion
if: ${{ !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }}
run: echo 'All required CI gates completed successfully.'