diff --git a/tools/release/prompt/new-version-prompt.ts b/tools/release/prompt/new-version-prompt.ts index 8be1183da85c..2926a3ad5565 100644 --- a/tools/release/prompt/new-version-prompt.ts +++ b/tools/release/prompt/new-version-prompt.ts @@ -1,4 +1,4 @@ -import {ChoiceType, prompt} from 'inquirer'; +import {ChoiceType, prompt, Separator} from 'inquirer'; import {createNewVersion, ReleaseType} from '../version-name/create-version'; import {parseVersionName, Version} from '../version-name/parse-version'; import {determineAllowedPrereleaseLabels} from './prerelease-labels'; @@ -17,6 +17,7 @@ type VersionPromptAnswers = { export async function promptForNewVersion(currentVersion: Version): Promise { const allowedPrereleaseChoices = determineAllowedPrereleaseLabels(currentVersion); const versionChoices: ChoiceType[] = []; + const currentVersionName = currentVersion.format(); if (currentVersion.prereleaseLabel) { versionChoices.push( @@ -39,6 +40,11 @@ export async function promptForNewVersion(currentVersion: Version): Promise([{ type: 'list', name: 'proposedVersion', @@ -48,8 +54,10 @@ export async function promptForNewVersion(currentVersion: Version): Promise + !currentVersion.prereleaseLabel && proposedVersion !== currentVersionName, default: false, }, { type: 'list', diff --git a/tools/release/publish-release.ts b/tools/release/publish-release.ts index 1b5ab3df617f..f9dc4b8dba5d 100644 --- a/tools/release/publish-release.ts +++ b/tools/release/publish-release.ts @@ -79,7 +79,7 @@ class PublishReleaseTask extends BaseReleaseTask { // Branch that will be used to build the output for the release of the current version. const publishBranch = this.switchToPublishBranch(newVersion); - this._verifyLastCommitVersionBump(); + this._verifyLastCommitFromStagingScript(); this.verifyLocalCommitsMatchUpstream(publishBranch); const upstreamRemote = await this._getProjectUpstreamRemote(); @@ -147,13 +147,13 @@ class PublishReleaseTask extends BaseReleaseTask { } /** - * Verifies that the latest commit on the current branch is a version bump from the - * staging script. + * Verifies that the latest commit on the current branch has been created + * through the release staging script. */ - private _verifyLastCommitVersionBump() { - if (!/chore: bump version/.test(this.git.getCommitTitle('HEAD'))) { - console.error(red(` ✘ The latest commit of the current branch does not seem to be a ` + - `version bump.`)); + private _verifyLastCommitFromStagingScript() { + if (!/chore: (bump version|update changelog for)/.test(this.git.getCommitTitle('HEAD'))) { + console.error(red(` ✘ The latest commit of the current branch does not seem to be ` + + ` created by the release staging script.`)); console.error(red(` Please stage the release using the staging script.`)); process.exit(1); } diff --git a/tools/release/stage-release.ts b/tools/release/stage-release.ts index 8f5d92879d2b..2464420fbffd 100644 --- a/tools/release/stage-release.ts +++ b/tools/release/stage-release.ts @@ -76,6 +76,7 @@ class StageReleaseTask extends BaseReleaseTask { const newVersion = await promptForNewVersion(this.currentVersion); const newVersionName = newVersion.format(); + const needsVersionBump = !newVersion.equalsTo(this.currentVersion); const stagingBranch = `release-stage/${newVersionName}`; // After the prompt for the new version, we print a new line because we want the @@ -97,11 +98,13 @@ class StageReleaseTask extends BaseReleaseTask { process.exit(1); } - this._updatePackageJsonVersion(newVersionName); + if (needsVersionBump) { + this._updatePackageJsonVersion(newVersionName); - console.log(green(` ✓ Updated the version to "${bold(newVersionName)}" inside of the ` + - `${italic('package.json')}`)); - console.log(); + console.log(green(` ✓ Updated the version to "${bold(newVersionName)}" inside of the ` + + `${italic('package.json')}`)); + console.log(); + } await promptAndGenerateChangelog(join(this.projectDir, CHANGELOG_FILE_NAME)); @@ -119,7 +122,14 @@ class StageReleaseTask extends BaseReleaseTask { } this.git.stageAllChanges(); - this.git.createNewCommit(`chore: bump version to ${newVersionName} w/ changelog`); + + // Note: When updating the commit messages here. Please also update the + // release publish script to detect the new commit messages. + if (needsVersionBump) { + this.git.createNewCommit(`chore: bump version to ${newVersionName} w/ changelog`); + } else { + this.git.createNewCommit(`chore: update changelog for ${newVersionName}`); + } console.info(); console.info(green(` ✓ Created the staging commit for: "${newVersionName}".`)); diff --git a/tools/release/version-name/parse-version.ts b/tools/release/version-name/parse-version.ts index bc9fba5bf76f..347b1625b06b 100644 --- a/tools/release/version-name/parse-version.ts +++ b/tools/release/version-name/parse-version.ts @@ -2,18 +2,17 @@ const versionNameRegex = /^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc)\.(\d)+)?$/; export class Version { - constructor( - /** Major version number */ - public major: number, - /** Minor version number */ - public minor: number, - /** Patch version number */ - public patch: number, - /** Pre-release label for the version (e.g. alpha, beta, rc) */ - public prereleaseLabel?: string, - /** Number for the pre-release. There can be multiple pre-releases for a version. */ - public prereleaseNumber?: number) {} + /** Major version number */ + public major: number, + /** Minor version number */ + public minor: number, + /** Patch version number */ + public patch: number, + /** Pre-release label for the version (e.g. alpha, beta, rc) */ + public prereleaseLabel: string|null, + /** Number for the pre-release. There can be multiple pre-releases for a version. */ + public prereleaseNumber: number|null) {} /** Serializes the version info into a string formatted version name. */ format(): string { @@ -21,8 +20,14 @@ export class Version { } clone(): Version { - return new Version(this.major, this.minor, this.patch, this.prereleaseLabel, - this.prereleaseNumber); + return new Version( + this.major, this.minor, this.patch, this.prereleaseLabel, this.prereleaseNumber); + } + + equalsTo(other: Version): boolean { + return this.major === other.major && this.minor === other.minor && this.patch === other.patch && + this.prereleaseLabel === other.prereleaseLabel && + this.prereleaseNumber === other.prereleaseNumber; } } @@ -30,7 +35,7 @@ export class Version { * Parses the specified version and returns an object that represents the individual * version segments. */ -export function parseVersionName(version: string): Version | null { +export function parseVersionName(version: string): Version|null { const matches = version.match(versionNameRegex); if (!matches) { @@ -38,11 +43,8 @@ export function parseVersionName(version: string): Version | null { } return new Version( - Number(matches[1]), - Number(matches[2]), - Number(matches[3]), - matches[4], - Number(matches[5])); + Number(matches[1]), Number(matches[2]), Number(matches[3]), matches[4] || null, + Number(matches[5]) || null); } /** Serializes the specified version into a string. */ @@ -51,7 +53,7 @@ export function serializeVersion(newVersion: Version): string { let versionString = `${major}.${minor}.${patch}`; - if (prereleaseLabel && !isNaN(prereleaseNumber)) { + if (prereleaseLabel && prereleaseNumber !== null) { versionString += `-${prereleaseLabel}.${prereleaseNumber}`; }