Skip to content

Commit 2b07377

Browse files
devversionandrewseguin
authored andcommitted
build: release-staging script should have option to not bump version (#16147)
Adds a new prompt choice when staging a new release that can be used if the version has been updated before. In that case we don't want to bump the version automatically but rather use the existing version and generate the changelog for it. Closes #16136
1 parent 04a95c7 commit 2b07377

File tree

4 files changed

+55
-35
lines changed

4 files changed

+55
-35
lines changed

tools/release/prompt/new-version-prompt.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {ChoiceType, prompt} from 'inquirer';
1+
import {ChoiceType, prompt, Separator} from 'inquirer';
22
import {createNewVersion, ReleaseType} from '../version-name/create-version';
33
import {parseVersionName, Version} from '../version-name/parse-version';
44
import {determineAllowedPrereleaseLabels} from './prerelease-labels';
@@ -17,6 +17,7 @@ type VersionPromptAnswers = {
1717
export async function promptForNewVersion(currentVersion: Version): Promise<Version> {
1818
const allowedPrereleaseChoices = determineAllowedPrereleaseLabels(currentVersion);
1919
const versionChoices: ChoiceType[] = [];
20+
const currentVersionName = currentVersion.format();
2021

2122
if (currentVersion.prereleaseLabel) {
2223
versionChoices.push(
@@ -39,6 +40,11 @@ export async function promptForNewVersion(currentVersion: Version): Promise<Vers
3940
createVersionChoice(currentVersion, 'patch', 'Patch release'));
4041
}
4142

43+
// We always want to provide the option to use the current version. This is useful
44+
// if the version got bumped manually before.
45+
versionChoices.push(new Separator(),
46+
{name: `Use current version (${currentVersionName})`, value: currentVersionName});
47+
4248
const answers = await prompt<VersionPromptAnswers>([{
4349
type: 'list',
4450
name: 'proposedVersion',
@@ -48,8 +54,10 @@ export async function promptForNewVersion(currentVersion: Version): Promise<Vers
4854
type: 'confirm',
4955
name: 'isPrerelease',
5056
message: 'Should this be a pre-release?',
51-
// Prompt whether this should a pre-release if the current release is not a pre-release
52-
when: !currentVersion.prereleaseLabel,
57+
// We don't want to prompt whether this should be a pre-release if the current version
58+
// is already a pre-release or if the version has been already bumped manually.
59+
when: ({proposedVersion}) =>
60+
!currentVersion.prereleaseLabel && proposedVersion !== currentVersionName,
5361
default: false,
5462
}, {
5563
type: 'list',

tools/release/publish-release.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class PublishReleaseTask extends BaseReleaseTask {
7979
// Branch that will be used to build the output for the release of the current version.
8080
const publishBranch = this.switchToPublishBranch(newVersion);
8181

82-
this._verifyLastCommitVersionBump();
82+
this._verifyLastCommitFromStagingScript();
8383
this.verifyLocalCommitsMatchUpstream(publishBranch);
8484

8585
const upstreamRemote = await this._getProjectUpstreamRemote();
@@ -147,13 +147,13 @@ class PublishReleaseTask extends BaseReleaseTask {
147147
}
148148

149149
/**
150-
* Verifies that the latest commit on the current branch is a version bump from the
151-
* staging script.
150+
* Verifies that the latest commit on the current branch has been created
151+
* through the release staging script.
152152
*/
153-
private _verifyLastCommitVersionBump() {
154-
if (!/chore: bump version/.test(this.git.getCommitTitle('HEAD'))) {
155-
console.error(red(` ✘ The latest commit of the current branch does not seem to be a ` +
156-
`version bump.`));
153+
private _verifyLastCommitFromStagingScript() {
154+
if (!/chore: (bump version|update changelog for)/.test(this.git.getCommitTitle('HEAD'))) {
155+
console.error(red(` ✘ The latest commit of the current branch does not seem to be ` +
156+
` created by the release staging script.`));
157157
console.error(red(` Please stage the release using the staging script.`));
158158
process.exit(1);
159159
}

tools/release/stage-release.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class StageReleaseTask extends BaseReleaseTask {
7676

7777
const newVersion = await promptForNewVersion(this.currentVersion);
7878
const newVersionName = newVersion.format();
79+
const needsVersionBump = !newVersion.equalsTo(this.currentVersion);
7980
const stagingBranch = `release-stage/${newVersionName}`;
8081

8182
// After the prompt for the new version, we print a new line because we want the
@@ -97,11 +98,13 @@ class StageReleaseTask extends BaseReleaseTask {
9798
process.exit(1);
9899
}
99100

100-
this._updatePackageJsonVersion(newVersionName);
101+
if (needsVersionBump) {
102+
this._updatePackageJsonVersion(newVersionName);
101103

102-
console.log(green(` ✓ Updated the version to "${bold(newVersionName)}" inside of the ` +
103-
`${italic('package.json')}`));
104-
console.log();
104+
console.log(green(` ✓ Updated the version to "${bold(newVersionName)}" inside of the ` +
105+
`${italic('package.json')}`));
106+
console.log();
107+
}
105108

106109
await promptAndGenerateChangelog(join(this.projectDir, CHANGELOG_FILE_NAME));
107110

@@ -119,7 +122,14 @@ class StageReleaseTask extends BaseReleaseTask {
119122
}
120123

121124
this.git.stageAllChanges();
122-
this.git.createNewCommit(`chore: bump version to ${newVersionName} w/ changelog`);
125+
126+
// Note: When updating the commit messages here. Please also update the
127+
// release publish script to detect the new commit messages.
128+
if (needsVersionBump) {
129+
this.git.createNewCommit(`chore: bump version to ${newVersionName} w/ changelog`);
130+
} else {
131+
this.git.createNewCommit(`chore: update changelog for ${newVersionName}`);
132+
}
123133

124134
console.info();
125135
console.info(green(` ✓ Created the staging commit for: "${newVersionName}".`));

tools/release/version-name/parse-version.ts

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,49 @@
22
const versionNameRegex = /^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc)\.(\d)+)?$/;
33

44
export class Version {
5-
65
constructor(
7-
/** Major version number */
8-
public major: number,
9-
/** Minor version number */
10-
public minor: number,
11-
/** Patch version number */
12-
public patch: number,
13-
/** Pre-release label for the version (e.g. alpha, beta, rc) */
14-
public prereleaseLabel?: string,
15-
/** Number for the pre-release. There can be multiple pre-releases for a version. */
16-
public prereleaseNumber?: number) {}
6+
/** Major version number */
7+
public major: number,
8+
/** Minor version number */
9+
public minor: number,
10+
/** Patch version number */
11+
public patch: number,
12+
/** Pre-release label for the version (e.g. alpha, beta, rc) */
13+
public prereleaseLabel: string|null,
14+
/** Number for the pre-release. There can be multiple pre-releases for a version. */
15+
public prereleaseNumber: number|null) {}
1716

1817
/** Serializes the version info into a string formatted version name. */
1918
format(): string {
2019
return serializeVersion(this);
2120
}
2221

2322
clone(): Version {
24-
return new Version(this.major, this.minor, this.patch, this.prereleaseLabel,
25-
this.prereleaseNumber);
23+
return new Version(
24+
this.major, this.minor, this.patch, this.prereleaseLabel, this.prereleaseNumber);
25+
}
26+
27+
equalsTo(other: Version): boolean {
28+
return this.major === other.major && this.minor === other.minor && this.patch === other.patch &&
29+
this.prereleaseLabel === other.prereleaseLabel &&
30+
this.prereleaseNumber === other.prereleaseNumber;
2631
}
2732
}
2833

2934
/**
3035
* Parses the specified version and returns an object that represents the individual
3136
* version segments.
3237
*/
33-
export function parseVersionName(version: string): Version | null {
38+
export function parseVersionName(version: string): Version|null {
3439
const matches = version.match(versionNameRegex);
3540

3641
if (!matches) {
3742
return null;
3843
}
3944

4045
return new Version(
41-
Number(matches[1]),
42-
Number(matches[2]),
43-
Number(matches[3]),
44-
matches[4],
45-
Number(matches[5]));
46+
Number(matches[1]), Number(matches[2]), Number(matches[3]), matches[4] || null,
47+
Number(matches[5]) || null);
4648
}
4749

4850
/** Serializes the specified version into a string. */
@@ -51,7 +53,7 @@ export function serializeVersion(newVersion: Version): string {
5153

5254
let versionString = `${major}.${minor}.${patch}`;
5355

54-
if (prereleaseLabel && !isNaN(prereleaseNumber)) {
56+
if (prereleaseLabel && prereleaseNumber !== null) {
5557
versionString += `-${prereleaseLabel}.${prereleaseNumber}`;
5658
}
5759

0 commit comments

Comments
 (0)