Skip to content

Commit

Permalink
[LOCAL] backport from 0.66 the logic to deploy new releases
Browse files Browse the repository at this point in the history
  • Loading branch information
kelset committed Nov 7, 2022
1 parent 2765172 commit 1ed7d57
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 99 deletions.
84 changes: 54 additions & 30 deletions scripts/bump-oss-version.js
Expand Up @@ -19,24 +19,38 @@
const fs = require('fs');
const {cat, echo, exec, exit, sed} = require('shelljs');
const yargs = require('yargs');

let argv = yargs.option('r', {
alias: 'remote',
default: 'origin',
})
.option('n', {
alias: 'nightly',
type: 'boolean',
default: false,
}).argv;
const {parseVersion} = require('./version-utils');

let argv = yargs
.option('r', {
alias: 'remote',
default: 'origin',
})
.option('n', {
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,
Expand All @@ -52,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',
Expand Down Expand Up @@ -144,17 +158,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');
Expand All @@ -181,8 +204,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');
Expand Down
151 changes: 82 additions & 69 deletions scripts/publish-npm.js
Expand Up @@ -10,29 +10,29 @@
'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
* version to publish the package.
*
* 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)
*
Expand All @@ -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));

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',
);
}).stdout.trim();
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;
}

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);
}

// -------- Generating Android Artifacts with JavaDoc
Expand All @@ -141,7 +139,7 @@ let artifacts = ['-javadoc.jar', '-sources.jar', '.aar', '.pom'].map(suffix => {
return `react-native-${releaseVersion}${suffix}`;
});

artifacts.forEach(name => {
artifacts.forEach((name) => {
if (
!test(
'-e',
Expand All @@ -153,12 +151,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}` : '';
Expand All @@ -170,5 +185,3 @@ if (exec(`npm publish ${tagFlag} ${otpFlag}`).code) {
echo(`Published to npm ${releaseVersion}`);
exit(0);
}

/*eslint-enable no-undef */
29 changes: 29 additions & 0 deletions 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,
};

0 comments on commit 1ed7d57

Please sign in to comment.