mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
0a3ca80af4
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/34694 TL;DR Relax the assumption of having git to build the RN NPM package. We do have two CI Systems: CircleCI for OpenSource and Sandcastle for Internal. It's crucial that the two CIs are aligned. We currently don't have a way to test the new app template on Sandcastle for Android & iOS. This results in scenarios where internal Diffs gets landed and break the public CI externally. This is preparation work to then be able to build the RN NPM package in Sandcastle (which will be done in a follow-up diff). With this we also introduce the restoring of all the changed files after the publishing script is done. ## Changelog [Internal] [Added] - Made it possible to create publishing NPM packages in Sandcastle. Reviewed By: cortinico, cipolleschi Differential Revision: D39467471 fbshipit-source-id: b0de88a768b8a2fb798dd684fa8f97f4d0acb751
278 lines
7.5 KiB
JavaScript
Executable File
278 lines
7.5 KiB
JavaScript
Executable File
/**
|
|
* 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';
|
|
|
|
/**
|
|
* This script prepares a release version of react-native and may publish to NPM.
|
|
* It is supposed to run in CI environment, not on a developer's machine.
|
|
*
|
|
* For a dry run (commitly), this script will:
|
|
* * Version the commitly of the form `1000.0.0-<commitSha>`
|
|
* * Create Android artifacts
|
|
* * It will not publish to npm
|
|
*
|
|
* For a nightly run, this script will:
|
|
* * Version the nightly release of the form `0.0.0-<dateIdentifier>-<commitSha>`
|
|
* * Create Android artifacts
|
|
* * Publish to npm using `nightly` tag
|
|
*
|
|
* For a release run, this script will:
|
|
* * Version the release by the tag version that triggered CI
|
|
* * Create Android artifacts
|
|
* * Publish to npm
|
|
* * using `latest` tag if commit is currently tagged `latest`
|
|
* * or otherwise `{major}.{minor}-stable`
|
|
*/
|
|
|
|
const {exec, echo, exit, env, test} = require('shelljs');
|
|
const {parseVersion} = require('./version-utils');
|
|
const {
|
|
exitIfNotOnGit,
|
|
getCurrentCommit,
|
|
isTaggedLatest,
|
|
revertFiles,
|
|
saveFiles,
|
|
} = require('./scm-utils');
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
const yargs = require('yargs');
|
|
|
|
const buildTag = process.env.CIRCLE_TAG;
|
|
const otp = process.env.NPM_CONFIG_OTP;
|
|
process.env.TMP_PUBLISH_DIR = fs.mkdtempSync(
|
|
path.join(os.tmpdir(), 'rn-publish-'),
|
|
);
|
|
echo(`The temp folder is ${process.env.TMP_PUBLISH_DIR}`);
|
|
|
|
const argv = yargs
|
|
.option('n', {
|
|
alias: 'nightly',
|
|
type: 'boolean',
|
|
default: false,
|
|
})
|
|
.option('d', {
|
|
alias: 'dry-run',
|
|
type: 'boolean',
|
|
default: false,
|
|
})
|
|
.option('h', {
|
|
alias: 'include-hermes',
|
|
type: 'boolean',
|
|
default: false,
|
|
}).argv;
|
|
const nightlyBuild = argv.nightly;
|
|
const dryRunBuild = argv.dryRun;
|
|
const includeHermes = argv.includeHermes;
|
|
const isCommitly = nightlyBuild || dryRunBuild;
|
|
|
|
const filesToSaveAndRestore = [
|
|
'template/Gemfile',
|
|
'template/_ruby-version',
|
|
'template/package.json',
|
|
'.ruby-version',
|
|
'Gemfile.lock',
|
|
'Gemfile',
|
|
'package.json',
|
|
'ReactAndroid/gradle.properties',
|
|
'Libraries/Core/ReactNativeVersion.js',
|
|
'React/Base/RCTVersion.m',
|
|
'ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java',
|
|
'ReactCommon/cxxreact/ReactNativeVersion.h',
|
|
];
|
|
|
|
saveFiles(...filesToSaveAndRestore);
|
|
|
|
if (includeHermes) {
|
|
const HERMES_INSTALL_LOCATION = 'sdks';
|
|
const HERMES_SOURCE_DEST_PATH = `${HERMES_INSTALL_LOCATION}/hermes`;
|
|
|
|
let hermesReleaseTag;
|
|
let hermesReleaseURI;
|
|
if (isCommitly) {
|
|
// use latest commit / tarball
|
|
hermesReleaseURI = 'https://github.com/facebook/hermes/tarball/main';
|
|
} else {
|
|
// use one configured in disk
|
|
fs.readFile(
|
|
`${HERMES_INSTALL_LOCATION}/.hermesversion`,
|
|
{
|
|
encoding: 'utf8',
|
|
flag: 'r',
|
|
},
|
|
function (err, data) {
|
|
if (err) {
|
|
echo('Failed to read current Hermes release tag.');
|
|
// TODO: We'll need to make sure every release going forward has one of these.
|
|
exit(1);
|
|
} else {
|
|
hermesReleaseTag = data.trim();
|
|
hermesReleaseURI = `https://github.com/facebook/hermes/archive/refs/tags/${hermesReleaseTag}.tar.gz`;
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
const tmpDownloadDir = fs.mkdtempSync(
|
|
path.join(os.tmpdir(), 'hermes-tarball'),
|
|
);
|
|
const tmpExtractDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hermes'));
|
|
|
|
const hermesInstallScript = `
|
|
mkdir -p ${HERMES_SOURCE_DEST_PATH} && \
|
|
wget ${hermesReleaseURI} -O ${tmpDownloadDir}/hermes.tar.gz && \
|
|
tar -xzf ${tmpDownloadDir}/hermes.tar.gz -C ${tmpExtractDir} && \
|
|
HERMES_SOURCE_EXTRACT_PATH=$(ls -d ${tmpExtractDir}/*) && \
|
|
mv $HERMES_SOURCE_EXTRACT_PATH ${HERMES_SOURCE_DEST_PATH}
|
|
`;
|
|
|
|
if (fs.existsSync(`${HERMES_SOURCE_DEST_PATH}`)) {
|
|
if (exec(`rm -rf ./${HERMES_SOURCE_DEST_PATH}`).code) {
|
|
echo('Failed to clean up previous Hermes installation.');
|
|
exit(1);
|
|
}
|
|
}
|
|
if (exec(hermesInstallScript).code) {
|
|
echo('Failed to include Hermes in release.');
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// 34c034298dc9cad5a4553964a5a324450fda0385
|
|
const currentCommit = getCurrentCommit();
|
|
const shortCommit = currentCommit.slice(0, 9);
|
|
|
|
const rawVersion =
|
|
// 0.0.0 triggers issues with cocoapods for codegen when building template project.
|
|
dryRunBuild
|
|
? '1000.0.0'
|
|
: // For nightly we continue to use 0.0.0 for clarity for npm
|
|
nightlyBuild
|
|
? '0.0.0'
|
|
: // For pre-release and stable releases, we use the git tag of the version we're releasing (set in bump-oss-version)
|
|
buildTag;
|
|
|
|
let version,
|
|
major,
|
|
minor,
|
|
prerelease = null;
|
|
try {
|
|
({version, major, minor, prerelease} = parseVersion(rawVersion));
|
|
} catch (e) {
|
|
echo(e.message);
|
|
exit(1);
|
|
}
|
|
|
|
let releaseVersion;
|
|
if (dryRunBuild) {
|
|
releaseVersion = `${version}-${shortCommit}`;
|
|
} else if (nightlyBuild) {
|
|
// 2021-09-28T05:38:40.669Z -> 20210928-0538
|
|
const dateIdentifier = new Date()
|
|
.toISOString()
|
|
.slice(0, -8)
|
|
.replace(/[-:]/g, '')
|
|
.replace(/[T]/g, '-');
|
|
releaseVersion = `${version}-${dateIdentifier}-${shortCommit}`;
|
|
} else {
|
|
releaseVersion = version;
|
|
}
|
|
|
|
// Bump version number in various files (package.json, gradle.properties etc)
|
|
// For stable, pre-release releases, we rely on CircleCI job `prepare_package_for_release` to handle this
|
|
if (isCommitly) {
|
|
if (
|
|
exec(`node scripts/set-rn-version.js --to-version ${releaseVersion}`).code
|
|
) {
|
|
echo(`Failed to set version number to ${releaseVersion}`);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// -------- Generating Android Artifacts
|
|
if (exec('./gradlew :ReactAndroid:installArchives').code) {
|
|
echo('Could not generate artifacts');
|
|
exit(1);
|
|
}
|
|
|
|
// -------- Generating the Hermes Engine Artifacts
|
|
env.REACT_NATIVE_HERMES_SKIP_PREFAB = true;
|
|
if (exec('./gradlew :ReactAndroid:hermes-engine:installArchives').code) {
|
|
echo('Could not generate artifacts');
|
|
exit(1);
|
|
}
|
|
|
|
// undo uncommenting javadoc setting
|
|
revertFiles('ReactAndroid/gradle.properties');
|
|
|
|
echo('Generated artifacts for Maven');
|
|
|
|
let artifacts = [
|
|
'.module',
|
|
'.pom',
|
|
'-debug.aar',
|
|
'-release.aar',
|
|
'-debug-sources.jar',
|
|
'-release-sources.jar',
|
|
].map(suffix => {
|
|
return `react-native-${releaseVersion}${suffix}`;
|
|
});
|
|
|
|
artifacts.forEach(name => {
|
|
if (
|
|
!test(
|
|
'-e',
|
|
`./android/com/facebook/react/react-native/${releaseVersion}/${name}`,
|
|
)
|
|
) {
|
|
echo(
|
|
`Failing as expected file: \n\
|
|
android/com/facebook/react/react-native/${releaseVersion}/${name}\n\
|
|
was not correctly generated.`,
|
|
);
|
|
exit(1);
|
|
}
|
|
});
|
|
|
|
if (dryRunBuild) {
|
|
echo('Skipping `npm publish` because --dry-run is set.');
|
|
exit(0);
|
|
}
|
|
|
|
// Running to see if this commit has been git tagged as `latest`
|
|
const isLatest = exitIfNotOnGit(
|
|
() => isTaggedLatest(currentCommit),
|
|
'Not in git. We do not want to publish anything',
|
|
);
|
|
|
|
const releaseBranch = `${major}.${minor}-stable`;
|
|
|
|
// Set the right tag for nightly and prerelease builds
|
|
// If a release is not git-tagged as `latest` we use `releaseBranch` to prevent
|
|
// npm from overriding the current `latest` version tag, which it will do if no tag is set.
|
|
const tagFlag = nightlyBuild
|
|
? '--tag nightly'
|
|
: prerelease != null
|
|
? '--tag next'
|
|
: isLatest
|
|
? '--tag latest'
|
|
: `--tag ${releaseBranch}`;
|
|
|
|
// use otp from envvars if available
|
|
const otpFlag = otp ? `--otp ${otp}` : '';
|
|
|
|
if (exec(`npm publish ${tagFlag} ${otpFlag}`).code) {
|
|
echo('Failed to publish package to npm');
|
|
exit(1);
|
|
} else {
|
|
echo(`Published to npm ${releaseVersion}`);
|
|
exit(0);
|
|
}
|