1/** 2 * Copyright (c) Meta Platforms, Inc. and affiliates. 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 * 7 * @format 8 */ 9 10'use strict'; 11 12/** 13 * This script prepares a release version of react-native and may publish to NPM. 14 * It is supposed to run in CI environment, not on a developer's machine. 15 * 16 * For a dry run (commitly), this script will: 17 * * Version the commitly of the form `1000.0.0-<commitSha>` 18 * * Create Android artifacts 19 * * It will not publish to npm 20 * 21 * For a nightly run, this script will: 22 * * Version the nightly release of the form `0.0.0-<dateIdentifier>-<commitSha>` 23 * * Create Android artifacts 24 * * Publish to npm using `nightly` tag 25 * 26 * For a release run, this script will: 27 * * Version the release by the tag version that triggered CI 28 * * Create Android artifacts 29 * * Publish to npm 30 * * using `latest` tag if commit is currently tagged `latest` 31 * * or otherwise `{major}.{minor}-stable` 32 */ 33 34const {exec, echo, exit} = require('shelljs'); 35const {parseVersion} = require('./version-utils'); 36const { 37 exitIfNotOnGit, 38 getCurrentCommit, 39 isTaggedLatest, 40} = require('./scm-utils'); 41const { 42 generateAndroidArtifacts, 43 publishAndroidArtifactsToMaven, 44 saveFilesToRestore, 45} = require('./release-utils'); 46const fs = require('fs'); 47const os = require('os'); 48const path = require('path'); 49const yargs = require('yargs'); 50 51const buildTag = process.env.CIRCLE_TAG; 52const otp = process.env.NPM_CONFIG_OTP; 53const tmpPublishingFolder = fs.mkdtempSync( 54 path.join(os.tmpdir(), 'rn-publish-'), 55); 56 57const argv = yargs 58 .option('n', { 59 alias: 'nightly', 60 type: 'boolean', 61 default: false, 62 }) 63 .option('d', { 64 alias: 'dry-run', 65 type: 'boolean', 66 default: false, 67 }) 68 .option('r', { 69 alias: 'release', 70 type: 'boolean', 71 default: false, 72 }) 73 .strict().argv; 74const nightlyBuild = argv.nightly; 75const dryRunBuild = argv.dryRun; 76const releaseBuild = argv.release; 77const isCommitly = nightlyBuild || dryRunBuild; 78 79const buildType = releaseBuild 80 ? 'release' 81 : nightlyBuild 82 ? 'nightly' 83 : 'dry-run'; 84 85if (!argv.help) { 86 echo(`The temp publishing folder is ${tmpPublishingFolder}`); 87} 88 89saveFilesToRestore(tmpPublishingFolder); 90 91// 34c034298dc9cad5a4553964a5a324450fda0385 92const currentCommit = getCurrentCommit(); 93const shortCommit = currentCommit.slice(0, 9); 94 95const rawVersion = 96 // 0.0.0 triggers issues with cocoapods for codegen when building template project. 97 dryRunBuild 98 ? '1000.0.0' 99 : // For nightly we continue to use 0.0.0 for clarity for npm 100 nightlyBuild 101 ? '0.0.0' 102 : // For pre-release and stable releases, we use the git tag of the version we're releasing (set in bump-oss-version) 103 buildTag; 104 105let version, 106 major, 107 minor, 108 prerelease = null; 109try { 110 ({version, major, minor, prerelease} = parseVersion(rawVersion, buildType)); 111} catch (e) { 112 echo(e.message); 113 exit(1); 114} 115 116let releaseVersion; 117if (dryRunBuild) { 118 releaseVersion = `${version}-${shortCommit}`; 119} else if (nightlyBuild) { 120 // 2021-09-28T05:38:40.669Z -> 20210928-0538 121 const dateIdentifier = new Date() 122 .toISOString() 123 .slice(0, -8) 124 .replace(/[-:]/g, '') 125 .replace(/[T]/g, '-'); 126 releaseVersion = `${version}-${dateIdentifier}-${shortCommit}`; 127} else { 128 releaseVersion = version; 129} 130 131// Bump version number in various files (package.json, gradle.properties etc) 132// For stable, pre-release releases, we rely on CircleCI job `prepare_package_for_release` to handle this 133if (isCommitly) { 134 if ( 135 exec( 136 `node scripts/set-rn-version.js --to-version ${releaseVersion} --build-type ${buildType}`, 137 ).code 138 ) { 139 echo(`Failed to set version number to ${releaseVersion}`); 140 exit(1); 141 } 142} 143 144generateAndroidArtifacts(releaseVersion, tmpPublishingFolder); 145 146// Write version number to the build folder 147const releaseVersionFile = path.join('build', '.version'); 148fs.writeFileSync(releaseVersionFile, releaseVersion); 149 150if (dryRunBuild) { 151 echo('Skipping `npm publish` because --dry-run is set.'); 152 exit(0); 153} 154 155// Running to see if this commit has been git tagged as `latest` 156const isLatest = exitIfNotOnGit( 157 () => isTaggedLatest(currentCommit), 158 'Not in git. We do not want to publish anything', 159); 160 161// We first publish on Maven Central all the necessary artifacts. 162// NPM publishing is done just after. 163publishAndroidArtifactsToMaven(releaseVersion, nightlyBuild); 164 165const releaseBranch = `${major}.${minor}-stable`; 166 167// Set the right tag for nightly and prerelease builds 168// If a release is not git-tagged as `latest` we use `releaseBranch` to prevent 169// npm from overriding the current `latest` version tag, which it will do if no tag is set. 170const tagFlag = nightlyBuild 171 ? '--tag nightly' 172 : prerelease != null 173 ? '--tag next' 174 : isLatest 175 ? '--tag latest' 176 : `--tag ${releaseBranch}`; 177 178// use otp from envvars if available 179const otpFlag = otp ? `--otp ${otp}` : ''; 180 181if (exec(`npm publish ${tagFlag} ${otpFlag}`).code) { 182 echo('Failed to publish package to npm'); 183 exit(1); 184} else { 185 echo(`Published to npm ${releaseVersion}`); 186 exit(0); 187} 188