Files
react-native/scripts/releases/utils/version-utils.js
T
Alex Hunt 76598de621 Reorganise and document release script entry points (#42774)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/42774

Reorganise release scripts so that command entry points are grouped based on execution context, which also reflects dependencies between scripts.

Also:

- Document the current behaviours of these scripts.
- Relocate utils out of the root contents.
- Replace `exec` call to `set-rn-version` script with function import.

NOTE: `yarn trigger-react-native-release` (documented command in release process) is unchanged, since this is aliased from `package.json`.

```
├── releases
│   ├── templates/
│   ├── utils/
│   ├── remove-new-arch-flags.js
│   ├── set-rn-version.js
│   └── update-template-package.js
├── releases-ci
│   ├── prepare-package-for-release.js
│   └── publish-npm.js
└── releases-local
    └── trigger-react-native-release.js
```

Changelog: [Internal]

Reviewed By: cipolleschi

Differential Revision: D53274341

fbshipit-source-id: eec2befc43e7a47fd821b2e2bcc818ddffbb6cf7
2024-02-01 06:02:17 -08:00

190 lines
4.6 KiB
JavaScript

/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
const VERSION_REGEX = /^v?((\d+)\.(\d+)\.(\d+)(?:-(.+))?)$/;
/*::
export type BuildType = 'dry-run' | 'release' | 'nightly' | 'prealpha';
export type Version = {
version: string,
major: string,
minor: string,
patch: string,
prerelease: ?string,
}
*/
/**
* Parses a version string and performs some checks to verify its validity.
* A valid version is in the format vX.Y.Z[-KKK] where X, Y, Z are numbers and KKK can be something else.
* The `builtType` is used to enforce that the major version can assume only specific
* values.
*
* Some examples of valid versions are:
* - stable: 0.68.1
* - stable prerelease: 0.70.0-rc.0
* - e2e-test: X.Y.Z-20221116-2018
* - nightly: X.Y.Z-20221116-0bc4547fc
* - dryrun: 1000.0.0
* - prealpha: 0.0.0-prealpha-20221116
*/
function parseVersion(
versionStr /*: string */,
buildType /*: BuildType */,
) /*: Version */ {
if (!validateBuildType(buildType)) {
throw new Error(`Unsupported build type: ${buildType}`);
}
const match = extractMatchIfValid(versionStr);
const [, version, major, minor, patch, prerelease] = match;
const versionObject = {
version,
major,
minor,
patch,
prerelease,
};
validateVersion(versionObject, buildType);
return versionObject;
}
function validateBuildType(
buildType /*: string */,
) /*: buildType is BuildType */ {
const validBuildTypes = new Set([
'release',
'dry-run',
'nightly',
'prealpha',
]);
// $FlowFixMe[incompatible-return]
return validBuildTypes.has(buildType);
}
function extractMatchIfValid(versionStr /*: string */) {
const match = versionStr.match(VERSION_REGEX);
if (!match) {
throw new Error(
`You must pass a correctly formatted version; couldn't parse ${versionStr}`,
);
}
return match;
}
function validateVersion(
versionObject /*: Version */,
buildType /*: BuildType */,
) {
const map = {
release: validateRelease,
'dry-run': validateDryRun,
nightly: validateNightly,
prealpha: validatePrealpha,
};
const validationFunction = map[buildType];
validationFunction(versionObject);
}
/**
* Releases are in the form of 0.Y.Z[-RC.0]
*/
function validateRelease(version /*: Version */) {
const validRelease = isStableRelease(version) || isStablePrerelease(version);
if (!validRelease) {
throw new Error(`Version ${version.version} is not valid for Release`);
}
}
function validateDryRun(version /*: Version */) {
if (
!isMain(version) &&
!isNightly(version) &&
!isStableRelease(version) &&
!isStablePrerelease(version)
) {
throw new Error(`Version ${version.version} is not valid for dry-runs`);
}
}
function validateNightly(version /*: Version */) {
// a valid nightly is a prerelease
if (!isNightly(version)) {
throw new Error(`Version ${version.version} is not valid for nightlies`);
}
}
function validatePrealpha(version /*: Version */) {
if (!isValidPrealpha(version)) {
throw new Error(`Version ${version.version} is not valid for prealphas`);
}
}
function isStableRelease(version /*: Version */) /*: boolean */ {
return (
version.major === '0' && version.minor !== '0' && version.prerelease == null
);
}
function isStablePrerelease(version /*: Version */) /*: boolean */ {
return !!(
version.major === '0' &&
version.minor !== '0' &&
version.patch.match(/^\d+$/) &&
(version.prerelease?.startsWith('rc.') ||
version.prerelease?.startsWith('rc-') ||
version.prerelease?.match(/^(\d{8})-(\d{4})$/))
);
}
function isNightly(version /*: Version */) /*: boolean */ {
// Check if older nightly version
if (version.major === '0' && version.minor === '0' && version.patch === '0') {
return true;
}
return version.version.includes('nightly');
}
function isMain(version /*: Version */) /*: boolean */ {
return (
version.major === '1000' && version.minor === '0' && version.patch === '0'
);
}
function isReleaseBranch(branch /*:string */) /*: boolean */ {
return branch.endsWith('-stable');
}
function isValidPrealpha(version /*: Version */) /*: boolean */ {
return !!(
version.major === '0' &&
version.minor === '0' &&
version.patch === '0' &&
version.prerelease != null &&
version.prerelease.match(/^prealpha-(\d{10})$/)
);
}
module.exports = {
validateBuildType,
parseVersion,
isNightly,
isReleaseBranch,
isMain,
isStableRelease,
isStablePrerelease,
};