Skip to content

Commit

Permalink
Move utilities to testing-utils and circleci to a separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
Riccardo Cipolleschi committed Jun 30, 2023
1 parent f9a0a5c commit 09d0422
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 197 deletions.
182 changes: 182 additions & 0 deletions scripts/circle-ci-artifacts-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
#!/usr/bin/env node
/**
* 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.
*
* @format
*/

'use strict';

const {exec} = require('shelljs');

const util = require('util');
const asyncRequest = require('request');
const request = util.promisify(asyncRequest);

let circleCIHeaders;
let jobs;
let baseTemporaryPath;

async function initialize(circleCIToken, baseTempPath, branchName) {
console.info('Getting CircleCI infoes');
circleCIHeaders = {'Circle-Token': circleCIToken};
baseTemporaryPath = baseTempPath;
exec(`mkdir -p ${baseTemporaryPath}`);
const pipeline = await _getLastCircleCIPipelineID(branchName);
const packageAndReleaseWorkflow = await _getPackageAndReleaseWorkflow(
pipeline.id,
);
_throwIfPendingOrUnsuccessfulWorkflow(packageAndReleaseWorkflow);
const testsWorkflow = await _getTestsWorkflow(pipeline.id);
_throwIfPendingOrUnsuccessfulWorkflow(testsWorkflow);
const jobsPromises = [
_getCircleCIJobs(packageAndReleaseWorkflow.id),
_getCircleCIJobs(testsWorkflow.id),
];

const jobsResults = await Promise.all(jobsPromises);

jobs = jobsResults.flatMap(jobs => jobs);
}

function baseTmpPath() {
return baseTemporaryPath;
}

async function _throwIfPendingOrUnsuccessfulWorkflow(workflow) {
if (workflow.status !== 'success') {
throw new Error(
`The ${workflow.name} workflow status is ${workflow.status}. Please, wait for it to be finished before start testing or fix it`,
);
}
}

async function _getLastCircleCIPipelineID(branchName) {
const options = {
method: 'GET',
url: 'https://circleci.com/api/v2/project/gh/facebook/react-native/pipeline',
qs: {
branch: branchName,
},
headers: circleCIHeaders,
};

const response = await request(options);
if (response.error) {
throw new Error(error);
}

const lastPipeline = JSON.parse(response.body).items[0];
return {id: lastPipeline.id, number: lastPipeline.number};
}

async function _getSpecificWorkflow(pipelineId, workflowName) {
const options = {
method: 'GET',
url: `https://circleci.com/api/v2/pipeline/${pipelineId}/workflow`,
headers: circleCIHeaders,
};
const response = await request(options);
if (response.error) {
throw new Error(error);
}

const body = JSON.parse(response.body);
return body.items.find(workflow => workflow.name === workflowName);
}

async function _getPackageAndReleaseWorkflow(pipelineId) {
return _getSpecificWorkflow(
pipelineId,
'package_and_publish_release_dryrun',
);
}

async function _getTestsWorkflow(pipelineId) {
return _getSpecificWorkflow(pipelineId, 'tests');
}

async function _getCircleCIJobs(workflowId) {
const options = {
method: 'GET',
url: `https://circleci.com/api/v2/workflow/${workflowId}/job`,
headers: circleCIHeaders,
};
const response = await request(options);
if (response.error) {
throw new Error(error);
}

const body = JSON.parse(response.body);
return body.items;
}

async function _getJobsArtifacts(jobNumber) {
const options = {
method: 'GET',
url: `https://circleci.com/api/v2/project/gh/facebook/react-native/${jobNumber}/artifacts`,
headers: circleCIHeaders,
};
const response = await request(options);
if (response.error) {
throw new Error(error);
}

const body = JSON.parse(response.body);
return body.items;
}

async function _findUrlForJob(jobName, artifactPath) {
const job = jobs.find(j => j.name === jobName);
const artifacts = await _getJobsArtifacts(job.job_number);
return artifacts.find(artifact => artifact.path.indexOf(artifactPath) > -1)
.url;
}

async function artifactURLHermesDebug() {
return _findUrlForJob(
'build_hermes_macos-Debug',
'hermes-ios-debug.tar.gz',
);
}

async function artifactURLForMavenLocal() {
return _findUrlForJob(
'build_and_publish_npm_package-2',
'maven-local.zip',
);
}

async function artifactURLForHermesRNTesterAPK() {
const emulatorArch = exec('adb shell getprop ro.product.cpu.abi').trim();
return _findUrlForJob(
'test_android',
`rntester-apk/hermes/release/app-hermes-${emulatorArch}-release.apk`,
);
}

async function artifactURLForJSCRNTesterAPK() {
return _findUrlForJob(
'test_android',
'rntester-apk/jsc/release/app-jsc-arm64-v8a-release.apk',
);
}

function downloadArtifact(artifactURL, destination) {
exec(`rm -rf ${destination}`);
exec(`curl ${artifactURL} -Lo ${destination}`);
}


module.exports = {
initialize,
downloadArtifact,
artifactURLForJSCRNTesterAPK,
artifactURLForHermesRNTesterAPK,
artifactURLForMavenLocal,
artifactURLHermesDebug,
baseTmpPath,
};
22 changes: 16 additions & 6 deletions scripts/test-e2e-local.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*/

const {exec, pushd, popd, pwd, cd, cp} = require('shelljs');
const updateTemplatePackage = require('../scripts/update-template-package');
const updateTemplatePackage = require('./update-template-package');
const yargs = require('yargs');
const path = require('path');
const fs = require('fs');
Expand Down Expand Up @@ -84,7 +84,7 @@ async function testRNTesterIOS(circleCIArtifacts, onReleaseBranch) {
if (argv.hermes && circleCIArtifacts != null) {
const hermesURL = await circleCIArtifacts.artifactURLHermesDebug();
const hermesPath = path.join(
circleCIArtifacts.baseTmpPath,
circleCIArtifacts.baseTmpPath(),
'hermes-ios-debug.tar.gz',
);
// download hermes source code from manifold
Expand Down Expand Up @@ -129,7 +129,7 @@ async function testRNTesterAndroid(circleCIArtifacts) {

if (circleCIArtifacts != null) {
const downloadPath = path.join(
circleCIArtifacts.baseTmpPath,
circleCIArtifacts.baseTmpPath(),
'rntester.apk',
);

Expand Down Expand Up @@ -208,11 +208,10 @@ async function testRNTestProject(circleCIArtifacts) {
const repoRoot = pwd();
const reactNativePackagePath = `${repoRoot}/packages/react-native`;
const localNodeTGZPath = `${reactNativePackagePath}/react-native-${releaseVersion}.tgz`;
console.log(`The final path for react native archive is: ${localNodeTGZPath}`);

const mavenLocalPath =
circleCIArtifacts != null
? path.join(circleCIArtifacts.baseTmpPath, 'maven-local.zip')
? path.join(circleCIArtifacts.baseTmpPath(), 'maven-local.zip')
: '/private/tmp/maven-local';
const hermesPath = await prepareArtifacts(
circleCIArtifacts,
Expand All @@ -228,7 +227,18 @@ async function testRNTestProject(circleCIArtifacts) {
});

// create locally the node module
exec('npm pack', {cwd: reactNativePackagePath});
exec('npm pack --pack-destination ', {cwd: reactNativePackagePath});

// node pack does not creates a version of React Native with the right name on main.
// Let's add some defensive programming checks:
if (!fs.existsSync(localNodeTGZPath)) {
const tarfile = fs.readdirSync(reactNativePackagePath)
.find(name => name.startsWith('react-native-') && name.endsWith('.tgz'));
if (!tarfile) {
throw new Error("Couldn't find a zipped version of react-native");
}
exec(`cp ${path.join(reactNativePackagePath, tarfile)} ${localNodeTGZPath}`);
}

pushd('/tmp/');
// // need to avoid the pod install step - we'll do it later
Expand Down
Loading

0 comments on commit 09d0422

Please sign in to comment.