Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve version checks to avoid mistakes in the versioning #35296

Closed
wants to merge 1 commit into from
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
11 changes: 9 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1363,7 +1363,14 @@ jobs:
- run:
name: "Set new react-native version and commit changes"
command: |
node ./scripts/prepare-package-for-release.js -v << parameters.version >> -l << parameters.latest >> --dry-run << parameters.dryrun >>
VERSION=<< parameters.version >>

if [[ -z "$VERSION" ]]; then
VERSION=$(grep '"version"' package.json | cut -d '"' -f 4 | head -1)
echo "Using the version from the package.json: $VERSION"
fi

node ./scripts/prepare-package-for-release.js -v "$VERSION" -l << parameters.latest >> --dry-run << parameters.dryrun >>

build_npm_package:
parameters:
Expand Down Expand Up @@ -1643,7 +1650,7 @@ workflows:
jobs:
- prepare_package_for_release:
name: prepare_package_for_release
version: 'v1000.0.1'
version: ''
latest : false
dryrun: true
- prepare_hermes_workspace:
Expand Down
275 changes: 253 additions & 22 deletions scripts/__tests__/version-utils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
* @format
*/

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

let execResult = null;
jest.mock('shelljs', () => ({
Expand Down Expand Up @@ -38,37 +42,86 @@ describe('version-utils', () => {
});

describe('parseVersion', () => {
it('should throw error if invalid match', () => {
it('should throw error if buildType is undefined', () => {
function testInvalidVersion() {
parseVersion('<invalid version>');
parseVersion('v0.10.5');
}
expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot(
`"Unsupported build type: undefined"`,
);
});

it('should throw error if buildType is not `release`, `dry-run` or `nightly`', () => {
function testInvalidVersion() {
parseVersion('v0.10.5', 'invalid_build_type');
}
expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot(
`"Unsupported build type: invalid_build_type"`,
);
});
it('should throw error if invalid match with release', () => {
function testInvalidVersion() {
parseVersion('<invalid version>', 'release');
}
expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot(
`"You must pass a correctly formatted version; couldn't parse <invalid version>"`,
);
});
it('should throw error if invalid match with dry-run', () => {
function testInvalidVersion() {
parseVersion('<invalid version>', 'dry-run');
}
expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot(
`"You must pass a correctly formatted version; couldn't parse <invalid version>"`,
);
});
it('should throw error if invalid match with nightly', () => {
function testInvalidVersion() {
parseVersion('<invalid version>', 'nightly');
}
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');
it('should parse pre-release version with release and `.`', () => {
const {version, major, minor, patch, prerelease} = parseVersion(
'0.66.0-rc.4',
'release',
);
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');
it('should parse pre-release version with release and `-`', () => {
const {version, major, minor, patch, prerelease} = parseVersion(
'0.66.0-rc-4',
'release',
);
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 reject pre-release version with random prerelease pattern', () => {
function testInvalidVersion() {
parseVersion('0.66.0-something_invalid', 'release');
}
expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot(
`"Version 0.66.0-something_invalid is not valid for Release"`,
);
});

it('should parse stable version', () => {
const {version, major, minor, patch, prerelease} = parseVersion('0.66.0');
const {version, major, minor, patch, prerelease} = parseVersion(
'0.66.0',
'release',
);
expect(version).toBe('0.66.0');
expect(major).toBe('0');
expect(minor).toBe('66');
Expand All @@ -77,42 +130,220 @@ describe('version-utils', () => {
});

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');
const {version, major, minor, patch, prerelease} = parseVersion(
'v0.66.0-rc.4',
'release',
);
expect(version).toBe('0.66.0-rc.4');
expect(major).toBe('0');
expect(minor).toBe('66');
expect(patch).toBe('1');
expect(patch).toBe('0');
expect(prerelease).toBe('rc.4');
});

it('should reject pre-release version with patch != 0', () => {
function testInvalidVersion() {
parseVersion('0.66.3-rc.4', 'release');
}
expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot(
`"Version 0.66.3-rc.4 is not valid for Release"`,
);
});

it('should reject pre-release version from tag with random prerelease pattern', () => {
function testInvalidVersion() {
parseVersion('v0.66.0-something_invalid', 'release');
}
expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot(
`"Version 0.66.0-something_invalid is not valid for Release"`,
);
});

it('should parse stable version from tag', () => {
const {version, major, minor, patch, prerelease} =
parseVersion('v0.66.0');
const {version, major, minor, patch, prerelease} = parseVersion(
'v0.66.0',
'release',
);
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');
it('should reject nightly with no prerelease', () => {
// this should fail
function testInvalidFunction() {
parseVersion('0.0.0', 'nightly');
}
expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot(
`"Version 0.0.0 is not valid for nightlies"`,
);
});

it('should reject nightly with prerelease but wrong version numbers', () => {
// this should fail
function testInvalidFunction() {
parseVersion('1.2.3-pre-release', 'nightly');
}
expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot(
`"Version 1.2.3-pre-release is not valid for nightlies"`,
);
});

it('should parse nightly with 0.0.0 and a prerelease part', () => {
// this should fail
const {version, major, minor, patch, prerelease} = parseVersion(
'0.0.0-pre-release',
'nightly',
);

expect(version).toBe('0.0.0-pre-release');
expect(major).toBe('0');
expect(minor).toBe('0');
expect(patch).toBe('0');
expect(prerelease).toBe('pre-release');
});
it('should parse dryrun with release version', () => {
const {version, major, minor, patch, prerelease} = parseVersion(
'0.7.3',
'dry-run',
);
expect(version).toBe('0.7.3');
expect(major).toBe('0');
expect(minor).toBe('7');
expect(patch).toBe('3');
expect(prerelease).toBeUndefined();
});

it('should parse dryrun fake version', () => {
const {version, major, minor, patch, prerelease} =
parseVersion('1000.0.0');
it('should parse dryrun with prerelease . version', () => {
const {version, major, minor, patch, prerelease} = parseVersion(
'0.20.0-rc.0',
'dry-run',
);
expect(version).toBe('0.20.0-rc.0');
expect(major).toBe('0');
expect(minor).toBe('20');
expect(patch).toBe('0');
expect(prerelease).toBe('rc.0');
});

it('should reject dryrun with prerelease . version with patch different from 0', () => {
function testInvalidFunction() {
parseVersion('0.20.3-rc.0', 'dry-run');
}
expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot(
`"Version 0.20.3-rc.0 is not valid for dry-runs"`,
);
});

it('should parse dryrun with prerelease - version', () => {
const {version, major, minor, patch, prerelease} = parseVersion(
'0.20.0-rc-0',
'dry-run',
);
expect(version).toBe('0.20.0-rc-0');
expect(major).toBe('0');
expect(minor).toBe('20');
expect(patch).toBe('0');
expect(prerelease).toBe('rc-0');
});

it('should reject dryrun with prerelease - version with patch different from 0', () => {
function testInvalidFunction() {
parseVersion('0.20.3-rc-0', 'dry-run');
}
expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot(
`"Version 0.20.3-rc-0 is not valid for dry-runs"`,
);
});

it('should parse dryrun with main version', () => {
const {version, major, minor, patch, prerelease} = parseVersion(
'1000.0.0',
'dry-run',
);
expect(version).toBe('1000.0.0');
expect(major).toBe('1000');
expect(minor).toBe('0');
expect(patch).toBe('0');
expect(prerelease).toBeUndefined();
});

it('should fail for dryrun with v1000.0.1 version', () => {
function testInvalidFunction() {
parseVersion('v1000.0.1', 'dry-run');
}
expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot(
`"Version 1000.0.1 is not valid for dry-runs"`,
);
});
it('should parse dryrun with nightly version', () => {
const {version, major, minor, patch, prerelease} = parseVersion(
'0.0.0-something-else',
'dry-run',
);
expect(version).toBe('0.0.0-something-else');
expect(major).toBe('0');
expect(minor).toBe('0');
expect(patch).toBe('0');
expect(prerelease).toBe('something-else');
});

it('should reject dryrun invalid values', () => {
function testInvalidFunction() {
parseVersion('1000.0.4', 'dry-run');
}
expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot(
`"Version 1000.0.4 is not valid for dry-runs"`,
);
});

it('should reject dryrun for invalid prerelease', () => {
function testInvalidFunction() {
parseVersion('0.6.4-something-else', 'dry-run');
}
expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot(
`"Version 0.6.4-something-else is not valid for dry-runs"`,
);
});

it('should reject dryrun for nightlies with invalid prerelease', () => {
function testInvalidFunction() {
parseVersion('0.0.0', 'dry-run');
}
expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot(
`"Version 0.0.0 is not valid for dry-runs"`,
);
});
});

describe('Validate version', () => {
it('Throw error if the buildType is unknown', () => {
function testInvalidFunction() {
validateBuildType('wrong_build');
}
expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot(
`"Unsupported build type: wrong_build"`,
);
});
it('Does not throw if the buildType is release', () => {
function testValidCall() {
validateBuildType('release');
}
expect(testValidCall).not.toThrowError();
});
it('Does not throw if the buildType is nightly', () => {
function testValidCall() {
validateBuildType('nightly');
}
expect(testValidCall).not.toThrowError();
});
it('Does not throw if the buildType is dry-run', () => {
function testValidCall() {
validateBuildType('dry-run');
}
expect(testValidCall).not.toThrowError();
});
});
});
2 changes: 1 addition & 1 deletion scripts/bump-oss-version.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ async function main() {
}

let latest = false;
const {version, prerelease} = parseVersion(releaseVersion);
const {version, prerelease} = parseVersion(releaseVersion, 'release');
kelset marked this conversation as resolved.
Show resolved Hide resolved
if (!prerelease) {
const {setLatest} = await inquirer.prompt({
type: 'confirm',
Expand Down
Loading