From 32d92d684c2915ab9989ad76c0cba31b7ef24b1a Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Wed, 11 Jun 2025 03:48:05 -0700 Subject: [PATCH 1/5] rename build-ios to build-ios-dependencies (#51480) Summary: This change renames the build-ios workflow to build-ios-dependencies to prepare for build-ios-core ## Changelog: [Internal] - Rename build-ios to build-ios-dependencies Pull Request resolved: https://github.com/facebook/react-native/pull/51480 Test Plan: GHA Differential Revision: D75133854 Reviewed By: rshest Pulled By: rshest --- .github/workflows/nightly.yml | 2 +- .../{prebuild-ios.yml => prebuild-ios-dependencies.yml} | 2 +- .github/workflows/publish-release.yml | 3 ++- .github/workflows/test-all.yml | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) rename .github/workflows/{prebuild-ios.yml => prebuild-ios-dependencies.yml} (99%) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 53dff769c6be..d913bbbaa228 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -101,7 +101,7 @@ jobs: flavor: ${{ matrix.flavor }} prebuild_apple_dependencies: - uses: ./.github/workflows/prebuild-ios.yml + uses: ./.github/workflows/prebuild-ios-dependencies.yml secrets: inherit build_hermesc_linux: diff --git a/.github/workflows/prebuild-ios.yml b/.github/workflows/prebuild-ios-dependencies.yml similarity index 99% rename from .github/workflows/prebuild-ios.yml rename to .github/workflows/prebuild-ios-dependencies.yml index 56f15777fa8d..3ae438892382 100644 --- a/.github/workflows/prebuild-ios.yml +++ b/.github/workflows/prebuild-ios-dependencies.yml @@ -1,4 +1,4 @@ -name: Prebuild iOS +name: Prebuild iOS Dependencies on: workflow_call: # this directive allow us to call this workflow from other workflows diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 6e0521579226..692a21aafb13 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -96,8 +96,9 @@ jobs: hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }} react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }} flavor: ${{ matrix.flavor }} + prebuild_apple_dependencies: - uses: ./.github/workflows/prebuild-ios.yml + uses: ./.github/workflows/prebuild-ios-dependencies.yml secrets: inherit build_hermesc_linux: diff --git a/.github/workflows/test-all.yml b/.github/workflows/test-all.yml index 99797d317ba8..b533780bb2f5 100644 --- a/.github/workflows/test-all.yml +++ b/.github/workflows/test-all.yml @@ -117,7 +117,7 @@ jobs: flavor: ${{ matrix.flavor }} prebuild_apple_dependencies: - uses: ./.github/workflows/prebuild-ios.yml + uses: ./.github/workflows/prebuild-ios-dependencies.yml secrets: inherit test_ios_rntester_ruby_3_2_0: From c042a2636408130e2ae88612ca5e8016ce6eb56a Mon Sep 17 00:00:00 2001 From: cipolleschi <> Date: Wed, 11 Jun 2025 03:48:05 -0700 Subject: [PATCH 2/5] Use capital letters for Debug and Release Summary: Introduce the BuildFlavor typeand refactor the build scripts to use 'Debug' and 'Release'. For iOS we always use capitalized Debug and Release and it will make it easier to work with CI too. ## Changelog: [Internal] - Differential Revision: D76338034 --- .../scripts/ios-prebuild/build.js | 4 +-- .../react-native/scripts/ios-prebuild/cli.js | 12 ++++---- .../scripts/ios-prebuild/hermes.js | 28 +++++++++++-------- .../ios-prebuild/reactNativeDependencies.js | 28 ++++++++++--------- .../scripts/ios-prebuild/setup.js | 4 ++- .../scripts/ios-prebuild/types.js | 2 ++ .../scripts/ios-prebuild/xcframework.js | 5 +++- 7 files changed, 48 insertions(+), 35 deletions(-) diff --git a/packages/react-native/scripts/ios-prebuild/build.js b/packages/react-native/scripts/ios-prebuild/build.js index e0454e658b4b..48987866da15 100644 --- a/packages/react-native/scripts/ios-prebuild/build.js +++ b/packages/react-native/scripts/ios-prebuild/build.js @@ -9,7 +9,7 @@ */ /*:: -import type {Destination} from './types'; +import type {BuildFlavor, Destination} from './types'; */ const {createLogger} = require('./utils'); @@ -52,7 +52,7 @@ function computeFrameworkPaths( function buildSwiftPackage( rootFolder /*: string */, buildFolder /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, platform /*: Destination */, outputFolder /*: string */, ) { diff --git a/packages/react-native/scripts/ios-prebuild/cli.js b/packages/react-native/scripts/ios-prebuild/cli.js index 55a32033961b..01301c800af7 100644 --- a/packages/react-native/scripts/ios-prebuild/cli.js +++ b/packages/react-native/scripts/ios-prebuild/cli.js @@ -11,7 +11,7 @@ const yargs = require('yargs'); /*:: -import type {Destination, Platform} from './types'; +import type {BuildFlavor, Destination, Platform} from './types'; */ const platforms /*: $ReadOnlyArray */ = [ @@ -77,7 +77,7 @@ async function getCLIConfiguration() /*: Promise, identity: ?string, |}> */ { @@ -103,10 +103,10 @@ async function getCLIConfiguration() /*: Promise platformToDestination[p]); // Validate flavor - const resolvedFlavor = argv.flavor.toLowerCase(); - if (resolvedFlavor !== 'debug' && resolvedFlavor !== 'release') { + const flavor = argv.flavor; + if (flavor !== 'Debug' && flavor !== 'Release') { console.error( - `Invalid flavor specified: ${resolvedFlavor}\nValid flavors are: debug, release`, + `Invalid flavor specified: ${flavor}\nValid flavors are: Debug, Release`, ); return undefined; } @@ -121,7 +121,7 @@ async function getCLIConfiguration() /*: Promise */ { hermesLog(`Preparing Hermes...`); @@ -135,7 +139,7 @@ const HermesEngineSourceTypes = { function checkExistingVersion( versionFilePath /*: string */, version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string */, ) { const resolvedVersion = `${version}-${buildType}`; @@ -177,18 +181,18 @@ function hermesEngineTarballEnvvarDefined() /*: boolean */ { function getTarballUrl( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, ) /*: string */ { const mavenRepoUrl = 'https://repo1.maven.org/maven2'; const namespace = 'com/facebook/react'; - return `${mavenRepoUrl}/${namespace}/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-ios-${buildType}.tar.gz`; + return `${mavenRepoUrl}/${namespace}/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-ios-${buildType.toLowerCase()}.tar.gz`; } function getNightlyTarballUrl( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, ) /*: string */ { - const params = `r=snapshots&g=com.facebook.react&a=react-native-artifacts&c=hermes-ios-${buildType}&e=tar.gz&v=${version}-SNAPSHOT`; + const params = `r=snapshots&g=com.facebook.react&a=react-native-artifacts&c=hermes-ios-${buildType.toLowerCase()}&e=tar.gz&v=${version}-SNAPSHOT`; return `https://oss.sonatype.org/service/local/artifact/maven/redirect?${params}`; } @@ -231,7 +235,7 @@ async function hermesArtifactExists( */ async function hermesSourceType( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, ) /*: Promise */ { if (hermesEngineTarballEnvvarDefined()) { hermesLog('Using local prebuild tarball'); @@ -262,7 +266,7 @@ async function hermesSourceType( async function resolveSourceFromSourceType( sourceType /*: HermesEngineSourceType */, version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string*/, ) /*: Promise */ { switch (sourceType) { @@ -296,7 +300,7 @@ function localPrebuiltTarball() /*: string */ { async function downloadPrebuildTarball( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string*/, ) /*: Promise */ { const url = getTarballUrl(version, buildType); @@ -306,7 +310,7 @@ async function downloadPrebuildTarball( async function downloadPrebuiltNightlyTarball( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string*/, ) /*: Promise */ { const url = await resolveUrlRedirects( @@ -318,7 +322,7 @@ async function downloadPrebuiltNightlyTarball( async function downloadStableHermes( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string */, ) /*: Promise */ { const tarballUrl = getTarballUrl(version, buildType); @@ -331,7 +335,7 @@ async function downloadStableHermes( async function downloadHermesTarball( tarballUrl /*: string */, version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string */, ) /*: Promise */ { const destPath = buildType diff --git a/packages/react-native/scripts/ios-prebuild/reactNativeDependencies.js b/packages/react-native/scripts/ios-prebuild/reactNativeDependencies.js index bcc3d2d3d517..1d32b76245a4 100644 --- a/packages/react-native/scripts/ios-prebuild/reactNativeDependencies.js +++ b/packages/react-native/scripts/ios-prebuild/reactNativeDependencies.js @@ -8,6 +8,8 @@ * @format */ +/*:: import type {BuildFlavor} from './types'; */ + const {createLogger} = require('./utils'); const {execSync} = require('child_process'); const fs = require('fs'); @@ -26,7 +28,7 @@ const dependencyLog = createLogger('ReactNativeDependencies'); */ async function prepareReactNativeDependenciesArtifactsAsync( version /*:string*/, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, ) /*: Promise */ { dependencyLog(`Preparing ReactNativeDependencies...`); @@ -133,7 +135,7 @@ const ReactNativeDependenciesEngineSourceTypes = { function checkExistingVersion( versionFilePath /*: string */, version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string */, ) { const resolvedVersion = `${version}-${buildType}`; @@ -146,7 +148,7 @@ function checkExistingVersion( if (fs.existsSync(versionFilePath)) { const versionFileContent = fs.readFileSync(versionFilePath, 'utf8'); dependencyLog(`Version found on disk: ${versionFileContent}`); - if (versionFileContent.trim().toLowerCase() === resolvedVersion) { + if (versionFileContent.trim() === resolvedVersion) { dependencyLog( `ReactNativeDependencies artifacts already downloaded and up to date: ${artifactsPath}`, ); @@ -175,18 +177,18 @@ function checkExistingVersion( function getTarballUrl( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, ) /*: string */ { const mavenRepoUrl = 'https://repo1.maven.org/maven2'; const namespace = 'com/facebook/react'; - return `${mavenRepoUrl}/${namespace}/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-${buildType}.tar.gz`; + return `${mavenRepoUrl}/${namespace}/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-${buildType.toLowerCase()}.tar.gz`; } function getNightlyTarballUrl( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, ) /*: string */ { - const params = `r=snapshots&g=com.facebook.react&a=react-native-artifacts&c=reactnative-dependencies-${buildType}&e=tar.gz&v=${version}-SNAPSHOT`; + const params = `r=snapshots&g=com.facebook.react&a=react-native-artifacts&c=reactnative-dependencies-${buildType.toLowerCase()}&e=tar.gz&v=${version}-SNAPSHOT`; return `https://oss.sonatype.org/service/local/artifact/maven/redirect?${params}`; } @@ -229,7 +231,7 @@ async function reactNativeDependenciesArtifactExists( */ async function reactNativeDependenciesSourceType( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, ) /*: Promise */ { const tarballUrl = getTarballUrl(version, buildType); if (await reactNativeDependenciesArtifactExists(tarballUrl)) { @@ -255,7 +257,7 @@ async function reactNativeDependenciesSourceType( async function resolveSourceFromSourceType( sourceType /*: ReactNativeDependenciesEngineSourceType */, version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string*/, ) /*: Promise */ { switch (sourceType) { @@ -273,7 +275,7 @@ async function resolveSourceFromSourceType( async function downloadPrebuildTarball( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string*/, ) /*: Promise */ { const url = getTarballUrl(version, buildType); @@ -287,7 +289,7 @@ async function downloadPrebuildTarball( async function downloadPrebuiltNightlyTarball( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string*/, ) /*: Promise */ { const url = await resolveUrlRedirects( @@ -304,7 +306,7 @@ async function downloadPrebuiltNightlyTarball( async function downloadStableReactNativeDependencies( version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string */, ) /*: Promise */ { const tarballUrl = getTarballUrl(version, buildType); @@ -322,7 +324,7 @@ async function downloadStableReactNativeDependencies( async function downloadReactNativeDependenciesTarball( tarballUrl /*: string */, version /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, artifactsPath /*: string */, ) /*: Promise */ { const destPath = buildType diff --git a/packages/react-native/scripts/ios-prebuild/setup.js b/packages/react-native/scripts/ios-prebuild/setup.js index 0419dd1c206e..bd26c3634f44 100644 --- a/packages/react-native/scripts/ios-prebuild/setup.js +++ b/packages/react-native/scripts/ios-prebuild/setup.js @@ -8,6 +8,8 @@ * @format */ +/*:: import type {BuildFlavor} from './types'; */ + const {prepareHermesArtifactsAsync} = require('./hermes'); const { prepareReactNativeDependenciesArtifactsAsync, @@ -21,7 +23,7 @@ async function setup( root /*:string*/, buildFolder /*: string */, currentVersion /*: string */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, ) { const prebuildLog = createLogger('prebuild'); createFolderIfNotExists(buildFolder); diff --git a/packages/react-native/scripts/ios-prebuild/types.js b/packages/react-native/scripts/ios-prebuild/types.js index 1f7430c198e0..c1ac1489c804 100644 --- a/packages/react-native/scripts/ios-prebuild/types.js +++ b/packages/react-native/scripts/ios-prebuild/types.js @@ -18,6 +18,8 @@ export type Destination = 'iOS' | 'iOS Simulator' | 'macOS,variant=Mac Catalyst'; + +export type BuildFlavor = 'Debug' | 'Release'; */ module.exports = {}; diff --git a/packages/react-native/scripts/ios-prebuild/xcframework.js b/packages/react-native/scripts/ios-prebuild/xcframework.js index b86068e00f91..2177f59dc0b9 100644 --- a/packages/react-native/scripts/ios-prebuild/xcframework.js +++ b/packages/react-native/scripts/ios-prebuild/xcframework.js @@ -8,6 +8,8 @@ * @format */ +/*:: import type {BuildFlavor} from './types'; */ + const {createFolderIfNotExists, createLogger} = require('./utils'); const {execSync} = require('child_process'); const fs = require('fs'); @@ -73,7 +75,8 @@ function buildXCFrameworks( rootFolder /*: string */, buildFolder /*: string */, frameworkFolders /*: Array */, - buildType /*: 'debug' | 'release' */, + buildType /*: BuildFlavor */, + identity /*: ?string */, ) { const outputPath = path.join( buildFolder, From ab15e68903734f381f04a70222dbbc80c86fe8f6 Mon Sep 17 00:00:00 2001 From: cipolleschi <> Date: Wed, 11 Jun 2025 03:48:05 -0700 Subject: [PATCH 3/5] Create dSYMs for React Native core (#51918) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/51918 Create dSYMs for React Native core while building ## Changelog: [Internal] - Differential Revision: D76338032 --- .../scripts/ios-prebuild/build.js | 3 +- .../scripts/ios-prebuild/xcframework.js | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/react-native/scripts/ios-prebuild/build.js b/packages/react-native/scripts/ios-prebuild/build.js index 48987866da15..7381771675e8 100644 --- a/packages/react-native/scripts/ios-prebuild/build.js +++ b/packages/react-native/scripts/ios-prebuild/build.js @@ -58,7 +58,8 @@ function buildSwiftPackage( ) { const buildCommand = `xcodebuild -scheme React -destination "generic/platform=${platform}" -derivedDataPath "${outputFolder}" ` + - `-configuration "${buildType}" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES OTHER_SWIFT_FLAGS="-no-verify-emitted-module-interface"`; + `-configuration "${buildType}" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES OTHER_SWIFT_FLAGS="-no-verify-emitted-module-interface" ` + + `DEBUG_INFORMATION_FORMAT="dwarf-with-dsym"`; buildLog(`Building Swift package for ${buildType}`); buildLog(buildCommand); diff --git a/packages/react-native/scripts/ios-prebuild/xcframework.js b/packages/react-native/scripts/ios-prebuild/xcframework.js index 2177f59dc0b9..c2740a1ae2e6 100644 --- a/packages/react-native/scripts/ios-prebuild/xcframework.js +++ b/packages/react-native/scripts/ios-prebuild/xcframework.js @@ -125,6 +125,19 @@ function buildXCFrameworks( // Create the module map file createModuleMapFile(outputPath, umbrellaHeaderFile); + + // Copy Symbols to symbols folder + const symbolPaths = frameworkFolders.map(framework => + path.join(framework, `..`, `..`, `React.framework.dSYM`), + ); + console.log('Copying symbols to symbols folder...'); + const symbolOutput = path.join(outputPath, '..', 'Symbols'); + symbolPaths.forEach(symbol => { + const destination = extractDestinationFromPath(symbol); + const outputFolder = path.join(symbolOutput, destination); + fs.mkdirSync(outputFolder, {recursive: true}); + execSync(`cp -r ${symbol} ${outputFolder}`); + }); } function copyHeaderFiles( @@ -323,6 +336,23 @@ function cleanPlatformFolders(outputPath /*:string*/) { }); } +function extractDestinationFromPath(symbolPath /*: string */) /*: string */ { + if (symbolPath.includes('iphoneos')) { + return 'iphoneos'; + } + + if (symbolPath.includes('iphonesimulator')) { + return 'iphonesimulator'; + } + + if (symbolPath.includes('maccatalyst')) { + return 'catalyst'; + } + + throw new Error( + `Impossible to extract destination from ${symbolPath}. Valid destinations are iphoneos, iphonesimulator and catalyst.`, + ); +} module.exports = { buildXCFrameworks, }; From 110b82970f4e1f2c7e86125dc692c9579bbe6421 Mon Sep 17 00:00:00 2001 From: cipolleschi <> Date: Wed, 11 Jun 2025 03:48:05 -0700 Subject: [PATCH 4/5] Implement signing for React Native core (#51919) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/51919 Implement signing for the React Native core XCFramework The implementation follows the same approach we used for the ReactNativedependencies archive ## Changelog [Internal] - Differential Revision: D76337972 --- packages/react-native/scripts/ios-prebuild.js | 8 +++++++- .../scripts/ios-prebuild/xcframework.js | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/react-native/scripts/ios-prebuild.js b/packages/react-native/scripts/ios-prebuild.js index 0e71fea00d89..1c7319ba7edf 100644 --- a/packages/react-native/scripts/ios-prebuild.js +++ b/packages/react-native/scripts/ios-prebuild.js @@ -71,7 +71,13 @@ async function main() { if (cli.tasks.compose) { const productsFolder = computeProductsFolder(outputFolder); const frameworkPaths = computeFrameworkPaths(productsFolder); - buildXCFrameworks(root, buildFolder, frameworkPaths, buildType); + buildXCFrameworks( + root, + buildFolder, + frameworkPaths, + buildType, + cli.identity, + ); } // Done! diff --git a/packages/react-native/scripts/ios-prebuild/xcframework.js b/packages/react-native/scripts/ios-prebuild/xcframework.js index c2740a1ae2e6..ffecf7a74e22 100644 --- a/packages/react-native/scripts/ios-prebuild/xcframework.js +++ b/packages/react-native/scripts/ios-prebuild/xcframework.js @@ -138,6 +138,10 @@ function buildXCFrameworks( fs.mkdirSync(outputFolder, {recursive: true}); execSync(`cp -r ${symbol} ${outputFolder}`); }); + + if (identity) { + signXCFramework(identity, outputPath); + } } function copyHeaderFiles( @@ -353,6 +357,16 @@ function extractDestinationFromPath(symbolPath /*: string */) /*: string */ { `Impossible to extract destination from ${symbolPath}. Valid destinations are iphoneos, iphonesimulator and catalyst.`, ); } + +function signXCFramework( + identity /*: string */, + xcframeworkPath /*: string */, +) { + console.log('Signing XCFramework...'); + const command = `codesign --timestamp --sign "${identity}" ${xcframeworkPath}`; + execSync(command, {stdio: 'inherit'}); +} + module.exports = { buildXCFrameworks, }; From 757d59475c6d3942befdb75615ff189b4fa5acdb Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Wed, 11 Jun 2025 04:03:35 -0700 Subject: [PATCH 5/5] Prebuild React Native core in CI (#51921) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/51921 Implemented the CI jobs that builds React Native core in CI and uploads the artifacts for the Debug and Release XCFrameworks and dSYMs ## Changelog: [Internal] - Reviewed By: cortinico Differential Revision: D76338031 --- .github/workflows/nightly.yml | 5 + .github/workflows/prebuild-ios-core.yml | 199 ++++++++++++++++++++++++ .github/workflows/publish-release.yml | 5 + .github/workflows/test-all.yml | 5 + 4 files changed, 214 insertions(+) create mode 100644 .github/workflows/prebuild-ios-core.yml diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index d913bbbaa228..e49618adf0e8 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -104,6 +104,11 @@ jobs: 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_hermes_macos] + build_hermesc_linux: runs-on: ubuntu-latest needs: prepare_hermes_workspace diff --git a/.github/workflows/prebuild-ios-core.yml b/.github/workflows/prebuild-ios-core.yml new file mode 100644 index 000000000000..8959aaa4e75a --- /dev/null +++ b/.github/workflows/prebuild-ios-core.yml @@ -0,0 +1,199 @@ +name: Prebuild iOS Dependencies + +on: + workflow_call: # this directive allow us to call this workflow from other workflows + + +jobs: + build-rn-slice: + runs-on: macos-14 + strategy: + fail-fast: false + matrix: + flavor: ['Debug', 'Release'] + slice: [ + 'ios', + 'ios-simulator', + 'mac-catalyst', + ] + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Restore cache if present + id: restore-ios-slice + uses: actions/cache/restore@v4 + with: + path: packages/react-native/third-party/ + key: v2-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }} + - 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 + with: + xcode-version: '16.2.0' + - name: Yarn Install + if: steps.restore-ios-slice.outputs.cache-hit != 'true' + uses: ./.github/actions/yarn-install + - name: Download Hermes + if: steps.restore-ios-slice.outputs.cache-hit != 'true' + uses: actions/download-artifact@v4 + with: + name: hermes-darwin-bin-${{ matrix.flavor }} + path: /tmp/hermes/hermes-runtime-darwin + - name: Extract Hermes + if: steps.restore-ios-slice.outputs.cache-hit != 'true' + shell: bash + run: | + HERMES_TARBALL_ARTIFACTS_DIR=/tmp/hermes/hermes-runtime-darwin + if [ ! -d $HERMES_TARBALL_ARTIFACTS_DIR ]; then + echo "Hermes tarball artifacts dir not present ($HERMES_TARBALL_ARTIFACTS_DIR)." + exit 0 + fi + + TARBALL_FILENAME=$(node ./packages/react-native/scripts/hermes/get-tarball-name.js --buildType "${{ matrix.flavor }}") + TARBALL_PATH=$HERMES_TARBALL_ARTIFACTS_DIR/$TARBALL_FILENAME + + echo "Looking for $TARBALL_FILENAME in $HERMES_TARBALL_ARTIFACTS_DIR" + echo "$TARBALL_PATH" + + if [ ! -f $TARBALL_PATH ]; then + echo "Hermes tarball not present ($TARBALL_PATH). Build Hermes from source." + exit 0 + fi + + echo "Found Hermes tarball at $TARBALL_PATH" + echo "HERMES_ENGINE_TARBALL_PATH=$TARBALL_PATH" >> $GITHUB_ENV + - name: Download ReactNativeDependencies + uses: actions/download-artifact@v4 + 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' 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 artifacts + uses: actions/upload-artifact@v4.3.4 + 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@v4 + if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode + with: + key: v2-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }} + enableCrossOsArchive: true + path: | + packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products + + compose-xcframework: + runs-on: macos-14 + 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@v4 + - name: Restore cache if present + id: restore-ios-xcframework + uses: actions/cache/restore@v4 + with: + path: packages/react-native/.build/output/xcframeworks + key: v2-ios-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }} + - 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 + with: + xcode-version: '16.2.0' + - 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@v4 + with: + pattern: prebuild-ios-core-slice-${{ matrix.flavor }}-* + path: packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products + 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 ../React${{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 ../../React${{ matrix.flavor }}.framework.dSYM.tar.gz . + - name: Upload XCFramework Artifact + uses: actions/upload-artifact@v4 + with: + name: React${{ matrix.flavor }}.xcframework.tar.gz + path: packages/react-native/.build/output/xcframeworks/React${{matrix.flavor}}.xcframework.tar.gz + - name: Upload dSYM Artifact + uses: actions/upload-artifact@v4 + with: + name: React${{ matrix.flavor }}.framework.dSYM.tar.gz + path: packages/react-native/.build/output/xcframeworks/React${{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@v4 + with: + path: | + packages/react-native/.build/output/xcframeworks/React${{matrix.flavor}}.xcframework.tar.gz + packages/react-native/.build/output/xcframeworks/React${{matrix.flavor}}.framework.dSYM.tar.gz + key: v2-ios-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift') }}-${{ hashFiles('packages/react-native/scripts/ios-prebuild/setup.js') }} diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 692a21aafb13..9cdd88bbac5a 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -101,6 +101,11 @@ jobs: 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_hermes_macos] + build_hermesc_linux: runs-on: ubuntu-latest needs: prepare_hermes_workspace diff --git a/.github/workflows/test-all.yml b/.github/workflows/test-all.yml index b533780bb2f5..da0d4ed74d8a 100644 --- a/.github/workflows/test-all.yml +++ b/.github/workflows/test-all.yml @@ -120,6 +120,11 @@ jobs: 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_hermes_macos] + test_ios_rntester_ruby_3_2_0: runs-on: macos-14 needs: