diff --git a/scripts/__tests__/version-utils-test.js b/scripts/__tests__/version-utils-test.js index cc5c8d54d3..b662ebd1f0 100644 --- a/scripts/__tests__/version-utils-test.js +++ b/scripts/__tests__/version-utils-test.js @@ -7,9 +7,37 @@ * @format */ -const {parseVersion} = require('../version-utils'); +const {parseVersion, getNextVersionFromTags} = require('../version-utils'); + +let execResult = null; +jest.mock('shelljs', () => ({ + exec: () => { + return { + stdout: execResult, + }; + }, +})); describe('version-utils', () => { + describe('getNextVersionFromTags', () => { + it('should increment last stable tag', () => { + execResult = + 'v0.66.3\nv0.66.2\nv0.66.1\nv0.66.0-rc.4\nv0.66.0-rc.3\nv0.66.0-rc.2\nv0.66.0-rc.1\nv0.66.0-rc.0'; + expect(getNextVersionFromTags('0.66-stable')).toBe('0.66.4'); + }); + + it('should find last prerelease tag and increment', () => { + execResult = + 'v0.66.0-rc.4\nv0.66.0-rc.3\nv0.66.0-rc.2\nv0.66.0-rc.1\nv0.66.0-rc.0'; + expect(getNextVersionFromTags('0.66-stable')).toBe('0.66.0-rc.5'); + }); + + it('should return rc.0 version if no previous tags', () => { + execResult = '\n'; + expect(getNextVersionFromTags('0.66-stable')).toBe('0.66.0-rc.0'); + }); + }); + describe('parseVersion', () => { it('should throw error if invalid match', () => { function testInvalidVersion() { diff --git a/scripts/version-utils.js b/scripts/version-utils.js index 2be7394398..59d0d9fc69 100644 --- a/scripts/version-utils.js +++ b/scripts/version-utils.js @@ -7,6 +7,8 @@ * @format */ +const {exec} = require('shelljs'); + function parseVersion(versionStr) { const match = versionStr.match(/^v?((\d+)\.(\d+)\.(\d+)(?:-(.+))?)$/); if (!match) { @@ -24,6 +26,49 @@ function parseVersion(versionStr) { }; } +function getLatestVersionTag(branchVersion) { + // Returns list of tags like ["v0.67.2", "v0.67.1", "v0.67.0-rc.3", "v0.67.0-rc.2", ...] in reverse lexical order + const tags = exec(`git tag --list "v${branchVersion}*" --sort=-refname`, { + silent: true, + }) + .stdout.trim() + .split('\n') + .filter(tag => tag.length > 0); + + // If there are no tags, return null + if (tags.length === 0) { + return null; + } + + // Return most recent tag (with the "v" prefix) + return tags[0]; +} + +function getNextVersionFromTags(branch) { + // Assumption that branch names will follow pattern `{major}.{minor}-stable` + // Ex. "0.67-stable" -> "0.67" + const branchVersion = branch.replace('-stable', ''); + + // Get the latest version tag of the release branch + const versionTag = getLatestVersionTag(branchVersion); + + // If there are no tags , we assume this is the first pre-release + if (versionTag == null) { + return `${branchVersion}.0-rc.0`; + } + + const {major, minor, patch, prerelease} = parseVersion(versionTag); + if (prerelease != null) { + // prelease is of the form "rc.X" + const prereleasePatch = parseInt(prerelease.slice(3), 10); + return `${major}.${minor}.${patch}-rc.${prereleasePatch + 1}`; + } + + // If not prerelease, increment the patch version + return `${major}.${minor}.${parseInt(patch, 10) + 1}`; +} + module.exports = { parseVersion, + getNextVersionFromTags, };