From 385f8952f59bf31fd7feb9c11481e76b3b71108b Mon Sep 17 00:00:00 2001 From: Lorenzo Sciandra Date: Sun, 6 Nov 2022 23:32:12 +0000 Subject: [PATCH] [LOCAL] backport from 0.66 the logic to deploy new releases --- scripts/bump-oss-version.js | 65 ++++++++++------ scripts/publish-npm.js | 147 ++++++++++++++++++++---------------- scripts/version-utils.js | 29 +++++++ 3 files changed, 152 insertions(+), 89 deletions(-) create mode 100644 scripts/version-utils.js diff --git a/scripts/bump-oss-version.js b/scripts/bump-oss-version.js index d22eb251671..a5dae56e820 100755 --- a/scripts/bump-oss-version.js +++ b/scripts/bump-oss-version.js @@ -19,6 +19,7 @@ const fs = require('fs'); const {cat, echo, exec, exit, sed} = require('shelljs'); const yargs = require('yargs'); +const {parseVersion} = require('./version-utils'); let argv = yargs .option('r', { @@ -29,17 +30,27 @@ let argv = yargs alias: 'nightly', type: 'boolean', default: false, + }) + .option('v', { + alias: 'to-version', + type: 'string', + }) + .option('l', { + alias: 'latest', + type: 'boolean', + default: false, }).argv; const nightlyBuild = argv.nightly; +const version = argv.toVersion; -let version, branch; -if (nightlyBuild) { - const currentCommit = exec('git rev-parse HEAD', { - silent: true, - }).stdout.trim(); - version = `0.0.0-${currentCommit.slice(0, 9)}`; -} else { +if (!version) { + echo('You must specify a version using -v'); + exit(1); +} + +let branch; +if (!nightlyBuild) { // Check we are in release branch, e.g. 0.33-stable branch = exec('git symbolic-ref --short HEAD', { silent: true, @@ -55,24 +66,24 @@ if (nightlyBuild) { // - check that argument version matches branch // e.g. 0.33.1 or 0.33.0-rc4 - version = argv._[0]; - if (!version || version.indexOf(versionMajor) !== 0) { + if (version.indexOf(versionMajor) !== 0) { echo( - `You must pass a tag like 0.${versionMajor}.[X]-rc[Y] to bump a version`, + `You must specify a version tag like 0.${versionMajor}.[X]-rc[Y] to bump a version`, ); exit(1); } } -// Generate version files to detect mismatches between JS and native. -let match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/); -if (!match) { - echo( - `You must pass a correctly formatted version; couldn't parse ${version}`, - ); +let major, + minor, + patch, + prerelease = -1; +try { + ({major, minor, patch, prerelease} = parseVersion(version)); +} catch (e) { + echo(e.message); exit(1); } -let [, major, minor, patch, prerelease] = match; fs.writeFileSync( 'ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java', @@ -149,17 +160,26 @@ if ( exec(`node scripts/set-rn-template-version.js ${version}`); // Verify that files changed, we just do a git diff and check how many times version is added across files +const filesToValidate = [ + 'package.json', + 'ReactAndroid/gradle.properties', + 'template/package.json', +]; let numberOfChangedLinesWithNewVersion = exec( - `git diff -U0 | grep '^[+]' | grep -c ${version} `, + `git diff -U0 ${filesToValidate.join( + ' ', + )}| grep '^[+]' | grep -c ${version} `, {silent: true}, ).stdout.trim(); // Release builds should commit the version bumps, and create tags. // Nightly builds do not need to do that. if (!nightlyBuild) { - if (+numberOfChangedLinesWithNewVersion !== 3) { + if (+numberOfChangedLinesWithNewVersion !== filesToValidate.length) { echo( - 'Failed to update all the files. package.json and gradle.properties must have versions in them', + `Failed to update all the files: [${filesToValidate.join( + ', ', + )}] must have versions in them`, ); echo('Fix the issue, revert and try again'); exec('git diff'); @@ -186,8 +206,9 @@ if (!nightlyBuild) { let remote = argv.remote; exec(`git push ${remote} v${version}`); - // Tag latest if doing stable release - if (version.indexOf('rc') === -1) { + // Tag latest if doing stable release. + // This will also tag npm release as `latest` + if (prerelease == null && argv.latest) { exec('git tag -d latest'); exec(`git push ${remote} :latest`); exec('git tag latest'); diff --git a/scripts/publish-npm.js b/scripts/publish-npm.js index dc611c803f2..7725491ca67 100644 --- a/scripts/publish-npm.js +++ b/scripts/publish-npm.js @@ -10,7 +10,7 @@ 'use strict'; /** - * This script publishes a new version of react-native to NPM. + * 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. * * To make it easier for developers it uses some logic to identify with which @@ -18,21 +18,21 @@ * * To cut a branch (and release RC): * - Developer: `git checkout -b 0.XY-stable` - * - Developer: `./scripts/bump-oss-version.js v0.XY.0-rc.0` + * - Developer: `./scripts/bump-oss-version.js -v v0.XY.0-rc.0` * - CI: test and deploy to npm (run this script) with version `0.XY.0-rc.0` * with tag "next" * * To update RC release: * - Developer: `git checkout 0.XY-stable` * - Developer: cherry-pick whatever changes needed - * - Developer: `./scripts/bump-oss-version.js v0.XY.0-rc.1` + * - Developer: `./scripts/bump-oss-version.js -v v0.XY.0-rc.1` * - CI: test and deploy to npm (run this script) with version `0.XY.0-rc.1` * with tag "next" * * To publish a release: * - Developer: `git checkout 0.XY-stable` * - Developer: cherry-pick whatever changes needed - * - Developer: `./scripts/bump-oss-version.js v0.XY.0` + * - Developer: `./scripts/bump-oss-version.js -v v0.XY.0` * - CI: test and deploy to npm (run this script) with version `0.XY.0` * and no tag ("latest" is implied by npm) * @@ -49,81 +49,79 @@ * If tag v0.XY.Z is present on the commit then publish to npm with version 0.XY.Z and no tag (npm will consider it latest) */ -/*eslint-disable no-undef */ -require('shelljs/global'); +const {exec, echo, exit, test} = require('shelljs'); const yargs = require('yargs'); +const {parseVersion} = require('./version-utils'); -let argv = yargs.option('n', { - alias: 'nightly', - type: 'boolean', - default: false, -}).argv; - -const nightlyBuild = argv.nightly; const buildTag = process.env.CIRCLE_TAG; const otp = process.env.NPM_CONFIG_OTP; -let branchVersion = 0; -if (nightlyBuild) { - branchVersion = 0; -} else { - if (!buildTag) { - echo('Error: We publish only from git tags'); - exit(1); - } - - let match = buildTag.match(/^v(\d+\.\d+)\.\d+(?:-.+)?$/); - if (!match) { - echo('Error: We publish only from release version git tags'); - exit(1); - } - [, branchVersion] = match; -} -// 0.33 +const argv = yargs + .option('n', { + alias: 'nightly', + type: 'boolean', + default: false, + }) + .option('d', { + alias: 'dry-run', + type: 'boolean', + default: false, + }).argv; +const nightlyBuild = argv.nightly; +const dryRunBuild = argv.dryRun; // 34c034298dc9cad5a4553964a5a324450fda0385 -const currentCommit = exec('git rev-parse HEAD', {silent: true}).stdout.trim(); -// [34c034298dc9cad5a4553964a5a324450fda0385, refs/heads/0.33-stable, refs/tags/latest, refs/tags/v0.33.1, refs/tags/v0.34.1-rc] -const tagsWithVersion = exec(`git ls-remote origin | grep ${currentCommit}`, { +const currentCommit = exec('git rev-parse HEAD', { silent: true, -}) - .stdout.split(/\s/) - // ['refs/tags/v0.33.0', 'refs/tags/v0.33.0-rc', 'refs/tags/v0.33.0-rc1', 'refs/tags/v0.33.0-rc2', 'refs/tags/v0.34.0'] - .filter( - version => - !!version && version.indexOf(`refs/tags/v${branchVersion}`) === 0, - ) - // ['refs/tags/v0.33.0', 'refs/tags/v0.33.0-rc', 'refs/tags/v0.33.0-rc1', 'refs/tags/v0.33.0-rc2'] - .filter(version => version.indexOf(branchVersion) !== -1) - // ['v0.33.0', 'v0.33.0-rc', 'v0.33.0-rc1', 'v0.33.0-rc2'] - .map(version => version.slice('refs/tags/'.length)); +}).stdout.trim(); +const shortCommit = currentCommit.slice(0, 9); -if (!nightlyBuild && tagsWithVersion.length === 0) { - echo( - 'Error: Cannot find version tag in current commit. To deploy to NPM you must add tag v0.XY.Z[-rc] to your commit', - ); +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; +} -if (nightlyBuild) { - releaseVersion = `0.0.0-${currentCommit.slice(0, 9)}`; - - // Bump version number in various files (package.json, gradle.properties etc) +// Bump version number in various files (package.json, gradle.properties etc) +// For stable, pre-release releases, we manually call bump-oss-version on release branch +if (nightlyBuild || dryRunBuild) { if ( - exec(`node scripts/bump-oss-version.js --nightly ${releaseVersion}`).code + exec( + `node scripts/bump-oss-version.js --nightly --to-version ${releaseVersion}`, + ).code ) { echo('Failed to bump version number'); exit(1); } -} else if (tagsWithVersion[0].indexOf('-rc') === -1) { - // if first tag on this commit is non -rc then we are making a stable release - // '0.33.0' - releaseVersion = tagsWithVersion[0].slice(1); -} else { - // otherwise pick last -rc tag alphabetically - // 0.33.0-rc2 - releaseVersion = tagsWithVersion[tagsWithVersion.length - 1].slice(1); } const buildAndroid = (rebuildOnError) => { @@ -175,12 +173,29 @@ artifacts.forEach(name => { } }); -// if version contains -rc, tag as prerelease +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 latestCommit = exec("git rev-list -n 1 'latest'", { + silent: true, +}).stdout.replace('\n', ''); +const isLatest = currentCommit === latestCommit; + +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' - : releaseVersion.indexOf('-rc') === -1 - ? '' - : '--tag next'; + : prerelease != null + ? '--tag next' + : isLatest + ? '--tag latest' + : `--tag ${releaseBranch}`; // use otp from envvars if available const otpFlag = otp ? `--otp ${otp}` : ''; @@ -192,5 +207,3 @@ if (exec(`npm publish ${tagFlag} ${otpFlag}`).code) { echo(`Published to npm ${releaseVersion}`); exit(0); } - -/*eslint-enable no-undef */ diff --git a/scripts/version-utils.js b/scripts/version-utils.js new file mode 100644 index 00000000000..2be7394398a --- /dev/null +++ b/scripts/version-utils.js @@ -0,0 +1,29 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +function parseVersion(versionStr) { + const match = versionStr.match(/^v?((\d+)\.(\d+)\.(\d+)(?:-(.+))?)$/); + if (!match) { + throw new Error( + `You must pass a correctly formatted version; couldn't parse ${versionStr}`, + ); + } + const [, version, major, minor, patch, prerelease] = match; + return { + version, + major, + minor, + patch, + prerelease, + }; +} + +module.exports = { + parseVersion, +};