Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions scripts/__tests__/version-utils-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* 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
*/

const {parseVersion} = require('../version-utils');

describe('version-utils', () => {
describe('parseVersion', () => {
it('should throw error if invalid match', () => {
function testInvalidVersion() {
parseVersion('<invalid version>');
}
expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot(
`"You must pass a correctly formatted version; couldn't parse <invalid version>"`,
);
});

it('should parse pre-release version with .', () => {
const {version, major, minor, patch, prerelease} =
parseVersion('0.66.0-rc.4');
expect(version).toBe('0.66.0-rc.4');
expect(major).toBe('0');
expect(minor).toBe('66');
expect(patch).toBe('0');
expect(prerelease).toBe('rc.4');
});

it('should parse pre-release version with -', () => {
const {version, major, minor, patch, prerelease} =
parseVersion('0.66.0-rc-4');
expect(version).toBe('0.66.0-rc-4');
expect(major).toBe('0');
expect(minor).toBe('66');
expect(patch).toBe('0');
expect(prerelease).toBe('rc-4');
});

it('should parse stable version', () => {
const {version, major, minor, patch, prerelease} = parseVersion('0.66.0');
expect(version).toBe('0.66.0');
expect(major).toBe('0');
expect(minor).toBe('66');
expect(patch).toBe('0');
expect(prerelease).toBeUndefined();
});
it('should parse pre-release version from tag', () => {
const {version, major, minor, patch, prerelease} =
parseVersion('v0.66.1-rc.4');
expect(version).toBe('0.66.1-rc.4');
expect(major).toBe('0');
expect(minor).toBe('66');
expect(patch).toBe('1');
expect(prerelease).toBe('rc.4');
});

it('should parse stable version from tag', () => {
const {version, major, minor, patch, prerelease} =
parseVersion('v0.66.0');
expect(version).toBe('0.66.0');
expect(major).toBe('0');
expect(minor).toBe('66');
expect(patch).toBe('0');
expect(prerelease).toBeUndefined();
});

it('should parse nightly fake version', () => {
const {version, major, minor, patch, prerelease} = parseVersion('0.0.0');
expect(version).toBe('0.0.0');
expect(major).toBe('0');
expect(minor).toBe('0');
expect(patch).toBe('0');
expect(prerelease).toBeUndefined();
});

it('should parse dryrun fake version', () => {
const {version, major, minor, patch, prerelease} =
parseVersion('1000.0.0');
expect(version).toBe('1000.0.0');
expect(major).toBe('1000');
expect(minor).toBe('0');
expect(patch).toBe('0');
expect(prerelease).toBeUndefined();
});
});
});
26 changes: 17 additions & 9 deletions scripts/bump-oss-version.js
Original file line number Diff line number Diff line change
Expand Up @@ -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', {
Expand All @@ -33,6 +34,11 @@ let argv = yargs
.option('v', {
alias: 'to-version',
type: 'string',
})
.option('l', {
alias: 'latest',
type: 'boolean',
default: false,
}).argv;

const nightlyBuild = argv.nightly;
Expand Down Expand Up @@ -68,15 +74,16 @@ if (!nightlyBuild) {
}
}

// 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 @@ -227,8 +234,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
137 changes: 61 additions & 76 deletions scripts/publish-npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -49,11 +49,14 @@
* 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
const buildTag = process.env.CIRCLE_TAG;
const otp = process.env.NPM_CONFIG_OTP;

const argv = yargs
.option('n', {
alias: 'nightly',
type: 'boolean',
Expand All @@ -64,75 +67,54 @@ let argv = yargs
type: 'boolean',
default: false,
}).argv;

const nightlyBuild = argv.nightly;
const dryRunBuild = argv.dryRun;
const buildFromMain = nightlyBuild || dryRunBuild;
const buildTag = process.env.CIRCLE_TAG;
const otp = process.env.NPM_CONFIG_OTP;

let branchVersion = 0;
if (buildFromMain) {
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

// 34c034298dc9cad5a4553964a5a324450fda0385
const currentCommit = exec('git rev-parse HEAD', {silent: true}).stdout.trim();

// Note: We rely on tagsWithVersion to be alphabetically sorted
// [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)
// ['0.33.0', '0.33.0-rc', '0.33.0-rc1', '0.33.0-rc2']
.map(version => version.slice('refs/tags/v'.length));

if (!buildFromMain && 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 (buildFromMain) {
if (nightlyBuild) {
releaseVersion = '0.0.0-';
// 2021-09-28T05:38:40.669Z -> 20210928-0538
releaseVersion += new Date()
.toISOString()
.slice(0, -8)
.replace(/[-:]/g, '')
.replace(/[T]/g, '-');
} else {
// 0.0.0 triggers issues with cocoapods for codegen for building template project.
releaseVersion = '1000.0.0';
}

releaseVersion += `-${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 --to-version ${releaseVersion}`,
Expand All @@ -141,14 +123,6 @@ if (buildFromMain) {
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];
} else {
// otherwise pick last -rc tag, indicates latest rc version due to alpha-sort
// '0.33.0-rc2'
releaseVersion = tagsWithVersion[tagsWithVersion.length - 1];
}

// -------- Generating Android Artifacts with JavaDoc
Expand Down Expand Up @@ -183,12 +157,24 @@ if (dryRunBuild) {
exit(0);
}

// if version contains -rc, tag as prerelease
// 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 @@ -200,4 +186,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
Original file line number Diff line number Diff line change
@@ -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,
};