mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
[LOCAL] Port CircleCI Artifact downloads to speed up release testing to 0.72 (#38553)
Co-authored-by: Riccardo Cipolleschi <cipolleschi@fb.com> resolved: https://github.com/facebook/react-native/pull/37971
This commit is contained in:
co-authored by
Riccardo Cipolleschi
parent
ff37ddb2e2
commit
79c4ec1a9a
+177
-6
@@ -9,9 +9,23 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const {exec} = require('shelljs');
|
||||
const {exec, cp} = require('shelljs');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const {spawn} = require('node:child_process');
|
||||
const path = require('path');
|
||||
|
||||
const circleCIArtifactsUtils = require('./circle-ci-artifacts-utils.js');
|
||||
|
||||
const {
|
||||
generateAndroidArtifacts,
|
||||
generateiOSArtifacts,
|
||||
} = require('./release-utils');
|
||||
|
||||
const {
|
||||
downloadHermesSourceTarball,
|
||||
expandHermesSourceTarball,
|
||||
} = require('../packages/react-native/scripts/hermes/hermes-utils.js');
|
||||
|
||||
/*
|
||||
* Android related utils - leverages android tooling
|
||||
@@ -35,12 +49,12 @@ const launchEmulator = emulatorName => {
|
||||
// from docs: "When using the detached option to start a long-running process, the process will not stay running in the background after the parent exits unless it is provided with a stdio configuration that is not connected to the parent. If the parent's stdio is inherited, the child will remain attached to the controlling terminal."
|
||||
// here: https://nodejs.org/api/child_process.html#optionsdetached
|
||||
|
||||
const cp = spawn(emulatorCommand, [`@${emulatorName}`], {
|
||||
const child_process = spawn(emulatorCommand, [`@${emulatorName}`], {
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
});
|
||||
|
||||
cp.unref();
|
||||
child_process.unref();
|
||||
};
|
||||
|
||||
function tryLaunchEmulator() {
|
||||
@@ -60,7 +74,20 @@ function tryLaunchEmulator() {
|
||||
};
|
||||
}
|
||||
|
||||
function launchAndroidEmulator() {
|
||||
function hasConnectedDevice() {
|
||||
const physicalDevices = exec('adb devices | grep -v emulator', {silent: true})
|
||||
.stdout.trim()
|
||||
.split('\n')
|
||||
.slice(1);
|
||||
return physicalDevices.length > 0;
|
||||
}
|
||||
|
||||
function maybeLaunchAndroidEmulator() {
|
||||
if (hasConnectedDevice()) {
|
||||
console.info('Already have a device connected. Skip launching emulator.');
|
||||
return;
|
||||
}
|
||||
|
||||
const result = tryLaunchEmulator();
|
||||
if (result.success) {
|
||||
console.info('Successfully launched emulator.');
|
||||
@@ -99,11 +126,155 @@ function isPackagerRunning(
|
||||
// this is a very limited implementation of how this should work
|
||||
function launchPackagerInSeparateWindow(folderPath) {
|
||||
const command = `tell application "Terminal" to do script "cd ${folderPath} && yarn start"`;
|
||||
exec(`osascript -e '${command}'`);
|
||||
exec(`osascript -e '${command}' >/dev/null <<EOF`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if Metro is running and it kills it if that's the case
|
||||
*/
|
||||
function checkPackagerRunning() {
|
||||
if (isPackagerRunning() === 'running') {
|
||||
exec(
|
||||
"lsof -i :8081 | grep LISTEN | /usr/bin/awk '{print $2}' | xargs kill",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// === ARTIFACTS === //
|
||||
|
||||
/**
|
||||
* Setups the CircleCIArtifacts if a token has been passed
|
||||
*
|
||||
* Parameters:
|
||||
* - @circleciToken a valid CircleCI Token.
|
||||
* - @branchName the branch of the name we want to use to fetch the artifacts.
|
||||
*/
|
||||
async function setupCircleCIArtifacts(circleciToken, branchName) {
|
||||
if (!circleciToken) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const baseTmpPath = '/tmp/react-native-tmp';
|
||||
await circleCIArtifactsUtils.initialize(
|
||||
circleciToken,
|
||||
baseTmpPath,
|
||||
branchName,
|
||||
);
|
||||
return circleCIArtifactsUtils;
|
||||
}
|
||||
|
||||
async function downloadArtifactsFromCircleCI(
|
||||
circleCIArtifacts,
|
||||
mavenLocalPath,
|
||||
localNodeTGZPath,
|
||||
) {
|
||||
const mavenLocalURL = await circleCIArtifacts.artifactURLForMavenLocal();
|
||||
const hermesURL = await circleCIArtifacts.artifactURLHermesDebug();
|
||||
|
||||
const hermesPath = path.join(
|
||||
circleCIArtifacts.baseTmpPath(),
|
||||
'hermes-ios-debug.tar.gz',
|
||||
);
|
||||
|
||||
console.info('[Download] Maven Local Artifacts');
|
||||
circleCIArtifacts.downloadArtifact(mavenLocalURL, mavenLocalPath);
|
||||
console.info('[Download] Hermes');
|
||||
circleCIArtifacts.downloadArtifact(hermesURL, hermesPath);
|
||||
|
||||
return hermesPath;
|
||||
}
|
||||
|
||||
function buildArtifactsLocally(
|
||||
releaseVersion,
|
||||
buildType,
|
||||
reactNativePackagePath,
|
||||
) {
|
||||
// this is needed to generate the Android artifacts correctly
|
||||
const exitCode = exec(
|
||||
`node scripts/set-rn-version.js --to-version ${releaseVersion} --build-type ${buildType}`,
|
||||
).code;
|
||||
|
||||
if (exitCode !== 0) {
|
||||
console.error(
|
||||
`Failed to set the RN version. Version ${releaseVersion} is not valid for ${buildType}`,
|
||||
);
|
||||
process.exit(exitCode);
|
||||
}
|
||||
|
||||
// Generate native files for Android
|
||||
generateAndroidArtifacts(releaseVersion);
|
||||
|
||||
// Generate iOS Artifacts
|
||||
const jsiFolder = `${reactNativePackagePath}/ReactCommon/jsi`;
|
||||
const hermesCoreSourceFolder = `${reactNativePackagePath}/sdks/hermes`;
|
||||
|
||||
if (!fs.existsSync(hermesCoreSourceFolder)) {
|
||||
console.info('The Hermes source folder is missing. Downloading...');
|
||||
downloadHermesSourceTarball();
|
||||
expandHermesSourceTarball();
|
||||
}
|
||||
|
||||
// need to move the scripts inside the local hermes cloned folder
|
||||
// cp sdks/hermes-engine/utils/*.sh <your_hermes_checkout>/utils/.
|
||||
cp(
|
||||
`${reactNativePackagePath}/sdks/hermes-engine/utils/*.sh`,
|
||||
`${reactNativePackagePath}/sdks/hermes/utils/.`,
|
||||
);
|
||||
|
||||
// for this scenario, we only need to create the debug build
|
||||
// (env variable PRODUCTION defines that podspec side)
|
||||
const buildTypeiOSArtifacts = 'Debug';
|
||||
|
||||
// the android ones get set into /private/tmp/maven-local
|
||||
const localMavenPath = '/private/tmp/maven-local';
|
||||
|
||||
// Generate native files for iOS
|
||||
const hermesPath = generateiOSArtifacts(
|
||||
jsiFolder,
|
||||
hermesCoreSourceFolder,
|
||||
buildTypeiOSArtifacts,
|
||||
localMavenPath,
|
||||
);
|
||||
|
||||
return hermesPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* It prepares the artifacts required to run a new project created from the template
|
||||
*
|
||||
* Parameters:
|
||||
* - @circleCIArtifacts manager object to manage all the download of CircleCIArtifacts. If null, it will fallback not to use them.
|
||||
* - @mavenLocalPath path to the local maven repo that is needed by Android.
|
||||
* - @localNodeTGZPath path where we want to store the react-native tgz.
|
||||
* - @releaseVersion the version that is about to be released.
|
||||
* - @buildType the type of build we want to execute if we build locally.
|
||||
* - @reactNativePackagePath the path to the react native package within the repo.
|
||||
*
|
||||
* Returns:
|
||||
* - @hermesPath the path to hermes for iOS
|
||||
*/
|
||||
async function prepareArtifacts(
|
||||
circleCIArtifacts,
|
||||
mavenLocalPath,
|
||||
localNodeTGZPath,
|
||||
releaseVersion,
|
||||
buildType,
|
||||
reactNativePackagePath,
|
||||
) {
|
||||
return circleCIArtifacts != null
|
||||
? await downloadArtifactsFromCircleCI(
|
||||
circleCIArtifacts,
|
||||
mavenLocalPath,
|
||||
localNodeTGZPath,
|
||||
)
|
||||
: buildArtifactsLocally(releaseVersion, buildType, reactNativePackagePath);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
launchAndroidEmulator,
|
||||
checkPackagerRunning,
|
||||
maybeLaunchAndroidEmulator,
|
||||
isPackagerRunning,
|
||||
launchPackagerInSeparateWindow,
|
||||
setupCircleCIArtifacts,
|
||||
prepareArtifacts,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user