Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/actions/maestro-android/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ inputs:
required: false
default: "."
description: The directory from which metro should be started
emulator-arch:
required: false
default: x86
description: The architecture of the emulator to run

runs:
using: composite
Expand Down Expand Up @@ -53,7 +57,7 @@ runs:
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 24
arch: x86
arch: ${{ inputs.emulator-arch }}
ram-size: '8192M'
heap-size: '4096M'
disk-size: '10G'
Expand All @@ -72,13 +76,13 @@ runs:
uses: actions/upload-artifact@v4.3.4
if: always()
with:
name: e2e_android_${{ steps.normalize-app-id.outputs.app-id }}_report_${{ inputs.flavor }}_NewArch
name: e2e_android_${{ steps.normalize-app-id.outputs.app-id }}_report_${{ inputs.flavor }}_${{ inputs.emulator-arch }}_NewArch
path: |
report.xml
screen.mp4
- name: Store Logs
if: steps.run-tests.outcome == 'failure'
uses: actions/upload-artifact@v4.3.4
with:
name: maestro-logs-android-${{ steps.normalize-app-id.outputs.app-id }}-${{ inputs.flavor }}-NewArch
name: maestro-logs-android-${{ steps.normalize-app-id.outputs.app-id }}-${{ inputs.flavor }}-${{ inputs.emulator-arch }}-NewArch
path: /tmp/MaestroLogs
41 changes: 41 additions & 0 deletions .github/actions/prepare-hermes-v1-app/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: prepare-hermes-v1-app
description: Prepares a React Native app with Hermes V1 enabled
inputs:
retry-count:
description: 'Number of times to retry the yarn install on failure'
runs:
using: composite
steps:
- name: Create new app
shell: bash
run: |
cd /tmp
npx @react-native-community/cli init RNApp --skip-install --version nightly
- name: Select latest Hermes V1 version
shell: bash
run: |
node "$GITHUB_WORKSPACE/.github/workflow-scripts/selectLatestHermesV1Version.js"
- name: Apply patch to enable Hermes V1
shell: bash
run: |
cd /tmp/RNApp
git apply --binary --3way --whitespace=nowarn "$GITHUB_WORKSPACE/.github/workflow-scripts/hermes-v1.patch"
echo "✅ Patch applied successfully"
- name: Install app dependencies with retry
uses: nick-fields/retry@v3
with:
timeout_minutes: 10
max_attempts: ${{ inputs.retry-count }}
retry_wait_seconds: 15
shell: bash
command: |
cd /tmp/RNApp
yarn install
on_retry_command: |
echo "Cleaning up for yarn retry..."
cd /tmp/RNApp
rm -rf node_modules yarn.lock || true
yarn cache clean || true
30 changes: 30 additions & 0 deletions .github/workflow-scripts/hermes-v1.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
diff --git a/android/settings.gradle b/android/settings.gradle
index 63b5d4e..6359ec3 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -4,3 +4,11 @@ extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autoli
rootProject.name = 'RNApp'
include ':app'
includeBuild('../node_modules/@react-native/gradle-plugin')
+
+includeBuild('../node_modules/react-native') {
+ dependencySubstitution {
+ substitute(module("com.facebook.react:react-android")).using(project(":packages:react-native:ReactAndroid"))
+ substitute(module("com.facebook.react:react-native")).using(project(":packages:react-native:ReactAndroid"))
+ substitute(project(":packages:react-native:ReactAndroid:hermes-engine")).using(module("com.facebook.hermes:hermes-android:$HERMES_V1_VERSION"))
+ }
+}
diff --git a/package.json b/package.json
index f05d51b..69938af 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,9 @@
"react-test-renderer": "19.2.0",
"typescript": "^5.8.3"
},
+ "resolutions": {
+ "hermes-compiler": "$HERMES_V1_VERSION"
+ },
"engines": {
"node": ">=20"
}
38 changes: 38 additions & 0 deletions .github/workflow-scripts/selectLatestHermesV1Version.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');

const PATCH_FILE_PATH = path.join(__dirname, 'hermes-v1.patch');

function getLatestHermesV1Version() {
const npmString = "npm view hermes-compiler@latest-v1 version";

try {
const result = execSync(npmString, { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
return result;
} catch (error) {
throw new Error(`Failed to get package version for hermes-compiler@latest-v1`);
}
}

function setHermesV1VersionInPatch(version) {
if (!fs.existsSync(PATCH_FILE_PATH)) {
throw new Error(`Patch file not found at path: ${PATCH_FILE_PATH}`);
}

let patchContent = fs.readFileSync(PATCH_FILE_PATH, 'utf8');
const updatedContent = patchContent.replaceAll(
"$HERMES_V1_VERSION",
version
);
fs.writeFileSync(PATCH_FILE_PATH, updatedContent, 'utf8');
}

setHermesV1VersionInPatch(getLatestHermesV1Version());
70 changes: 70 additions & 0 deletions .github/workflows/test-hermes-v1-android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Test Hermes V1 with nightly on Android

on:
workflow_call:
inputs:
retry-count:
description: 'Number of times to retry the build on failure'
required: false
type: number
default: 3

jobs:
test-hermes-v1-android:
name: Test Hermes V1 on Android
runs-on: 4-core-ubuntu
strategy:
matrix:
flavor: [debug, release]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup node.js
uses: actions/setup-node@v4
with:
node-version: '22.14.0'
cache: yarn

- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'zulu'

- name: Prepare the app with Hermes V1
uses: ./.github/actions/prepare-hermes-v1-app
with:
retry-count: ${{ inputs.retry-count }}

- name: Build Android with retry
uses: nick-fields/retry@v3
env:
CMAKE_VERSION: 3.31.5
ORG_GRADLE_PROJECT_reactNativeArchitectures: x86_64
with:
timeout_minutes: 45
max_attempts: ${{ inputs.retry-count }}
retry_wait_seconds: 30
shell: bash
command: |
cd /tmp/RNApp/android
CAPITALIZED_FLAVOR=$(echo "${{ matrix.flavor }}" | awk '{print toupper(substr($0, 1, 1)) substr($0, 2)}')
./gradlew assemble${CAPITALIZED_FLAVOR} -PhermesV1Enabled=true
on_retry_command: |
echo "Cleaning up for Android retry..."
cd /tmp/RNApp/android
./gradlew clean || true
rm -rf build app/build .gradle || true

- name: Run E2E Tests
uses: ./.github/actions/maestro-android
timeout-minutes: 60
with:
app-path: /tmp/RNApp/android/app/build/outputs/apk/${{ matrix.flavor }}/app-${{ matrix.flavor }}.apk
app-id: com.rnapp
maestro-flow: ./scripts/e2e/.maestro/
install-java: 'false'
flavor: ${{ matrix.flavor }}
working-directory: /tmp/RNApp
emulator-arch: x86_64
78 changes: 78 additions & 0 deletions .github/workflows/test-hermes-v1-ios.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Test Hermes V1 with nightly on iOS

on:
workflow_call:
inputs:
retry-count:
description: 'Number of times to retry the build on failure'
required: false
type: number
default: 3

jobs:
test-hermes-v1-ios:
name: Test Hermes V1 on iOS
runs-on: macos-15-large
strategy:
matrix:
flavor: [debug, release]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup node.js
uses: actions/setup-node@v4
with:
node-version: '22.14.0'
cache: yarn

- name: Prepare capitalized flavor
id: prepare-flavor
shell: bash
run: |
CAPITALIZED_FLAVOR=$(echo "${{ matrix.flavor }}" | awk '{print toupper(substr($0, 1, 1)) substr($0, 2)}')
echo "capitalized_flavor=$CAPITALIZED_FLAVOR" >> $GITHUB_OUTPUT

- name: Prepare the app with Hermes V1
uses: ./.github/actions/prepare-hermes-v1-app
with:
retry-count: ${{ inputs.retry-count }}

- name: Setup xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: 16.4.0

- name: Build iOS with retry
uses: nick-fields/retry@v3
with:
timeout_minutes: 45
max_attempts: ${{ inputs.retry-count }}
retry_wait_seconds: 30
shell: bash
command: |
cd /tmp/RNApp/ios
bundle install
RCT_HERMES_V1_ENABLED=1 bundle exec pod install
xcodebuild build \
-workspace "RNApp.xcworkspace" \
-scheme "RNApp" \
-configuration "${{ steps.prepare-flavor.outputs.capitalized_flavor }}" \
-sdk "iphonesimulator" \
-destination "generic/platform=iOS Simulator" \
-derivedDataPath "/tmp/RNApp" \
-quiet
on_retry_command: |
echo "Cleaning up for iOS retry..."
cd /tmp/RNApp/ios
rm -rf Pods Podfile.lock build
rm -rf ~/Library/Developer/Xcode/DerivedData/* || true

- name: Run E2E Tests
uses: ./.github/actions/maestro-ios
with:
app-path: "/tmp/RNApp/Build/Products/${{ steps.prepare-flavor.outputs.capitalized_flavor }}-iphonesimulator/RNApp.app"
app-id: org.reactjs.native.example.RNApp
maestro-flow: ./scripts/e2e/.maestro/
flavor: ${{ steps.prepare-flavor.outputs.capitalized_flavor }}
working-directory: /tmp/RNApp
39 changes: 39 additions & 0 deletions .github/workflows/test-hermes-v1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# This jobs runs every day 2 hours after the nightly job for React Native so we can verify how the nightly is behaving.
name: Check Hermes V1 with the nightly build

on:
workflow_dispatch:
# nightly build @ 4:15 AM UTC
schedule:
- cron: '15 4 * * *'

concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: true

jobs:
check-nightly:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Check nightly
run: |
TODAY=$(date "+%Y%m%d")
echo "Checking nightly for $TODAY"
NIGHTLY="$(npm view react-native | grep $TODAY)"
if [[ -z $NIGHTLY ]]; then
echo 'Nightly job failed.'
exit 1
else
echo 'Nightly Worked, All Good!'
fi

test-hermes-v1-ios:
uses: ./.github/workflows/test-hermes-v1-ios.yml
needs: check-nightly

test-hermes-v1-android:
uses: ./.github/workflows/test-hermes-v1-android.yml
needs: check-nightly
Loading