Skip to content

Commit fa83e8d

Browse files
devversionjelbourn
authored andcommitted
build: allow minor releases from master branch (#14564)
1 parent eeda91d commit fa83e8d

File tree

4 files changed

+42
-22
lines changed

4 files changed

+42
-22
lines changed

tools/release/stage-release.ts

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {GitClient} from './git/git-client';
88
import {getGithubBranchCommitsUrl} from './git/github-urls';
99
import {promptForNewVersion} from './prompt/new-version-prompt';
1010
import {parseVersionName, Version} from './version-name/parse-version';
11-
import {getExpectedPublishBranch} from './version-name/publish-branch';
11+
import {getAllowedPublishBranches} from './version-name/publish-branches';
1212

1313
/** Default filename for the changelog. */
1414
const CHANGELOG_FILE_NAME = 'CHANGELOG.md';
@@ -84,20 +84,22 @@ class StageReleaseTask {
8484
console.log();
8585

8686
const newVersion = await promptForNewVersion(this.currentVersion);
87-
const expectedPublishBranch = getExpectedPublishBranch(newVersion);
87+
const newVersionName = newVersion.format();
88+
const stagingBranch = `release-stage/${newVersionName}`;
8889

8990
// After the prompt for the new version, we print a new line because we want the
9091
// new log messages to be more in the foreground.
9192
console.log();
9293

94+
// Ensure there are no uncommitted changes. Checking this before switching to a
95+
// publish branch is sufficient as unstaged changes are not specific to Git branches.
9396
this.verifyNoUncommittedChanges();
94-
this.switchToPublishBranch(expectedPublishBranch);
9597

96-
this.verifyLocalCommitsMatchUpstream(expectedPublishBranch);
97-
await this.verifyPassingGithubStatus(expectedPublishBranch);
98+
// Branch that will be used to stage the release for the new selected version.
99+
const publishBranch = this.switchToPublishBranch(newVersion);
98100

99-
const newVersionName = newVersion.format();
100-
const stagingBranch = `release-stage/${newVersionName}`;
101+
this.verifyLocalCommitsMatchUpstream(publishBranch);
102+
await this.verifyPassingGithubStatus(publishBranch);
101103

102104
if (!this.git.checkoutNewBranch(stagingBranch)) {
103105
console.error(red(`Could not create release staging branch: ${stagingBranch}. Aborting...`));
@@ -146,24 +148,39 @@ class StageReleaseTask {
146148
* Checks if the user is on the expected publish branch. If the user is on a different branch,
147149
* this function automatically tries to checkout the publish branch.
148150
*/
149-
private switchToPublishBranch(expectedPublishBranch: string): boolean {
151+
private switchToPublishBranch(newVersion: Version): string {
152+
const allowedBranches = getAllowedPublishBranches(newVersion);
150153
const currentBranchName = this.git.getCurrentBranch();
151154

152-
// If current branch already matches the expected publish branch, just continue
153-
// by exiting this function.
154-
if (expectedPublishBranch === currentBranchName) {
155-
return;
155+
// If current branch already matches one of the allowed publish branches, just continue
156+
// by exiting this function and returning the currently used publish branch.
157+
if (allowedBranches.includes(currentBranchName)) {
158+
console.log(green(` ✓ Using the "${italic(currentBranchName)}" branch.`));
159+
return currentBranchName;
156160
}
157161

158-
if (!this.git.checkoutBranch(expectedPublishBranch)) {
159-
console.error(red(` ✘ Could not switch to the "${italic(expectedPublishBranch)}" ` +
162+
// In case there are multiple allowed publish branches for this version, we just
163+
// exit and let the user decide which branch they want to release from.
164+
if (allowedBranches.length !== 1) {
165+
console.warn(yellow(' ✘ You are not on an allowed publish branch.'));
166+
console.warn(yellow(` Please switch to one of the following branches: ` +
167+
`${allowedBranches.join(', ')}`));
168+
process.exit(0);
169+
}
170+
171+
// For this version there is only *one* allowed publish branch, so we could
172+
// automatically switch to that branch in case the user isn't on it yet.
173+
const defaultPublishBranch = allowedBranches[0];
174+
175+
if (!this.git.checkoutBranch(defaultPublishBranch)) {
176+
console.error(red(` ✘ Could not switch to the "${italic(defaultPublishBranch)}" ` +
160177
`branch.`));
161178
console.error(red(` Please ensure that the branch exists or manually switch to the ` +
162179
`branch.`));
163180
process.exit(1);
164181
}
165182

166-
console.log(green(` ✓ Switched to the "${italic(expectedPublishBranch)}" branch.`));
183+
console.log(green(` ✓ Switched to the "${italic(defaultPublishBranch)}" branch.`));
167184
}
168185

169186
/** Verifies that the local branch is up to date with the given publish branch. */

tools/release/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"compilerOptions": {
3-
"lib": ["es2015"],
3+
"lib": ["es2016"],
44
"types": ["node"]
55
}
66
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Version} from './parse-version';
2-
import {VersionType} from './publish-branch';
2+
import {VersionType} from './publish-branches';
33

44
/** Type of a new release */
55
export type ReleaseType = VersionType | 'stable-release' | 'bump-prerelease';

tools/release/version-name/publish-branch.ts renamed to tools/release/version-name/publish-branches.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@ import {Version} from './parse-version';
22

33
export type VersionType = 'major' | 'minor' | 'patch';
44

5-
/** Determines the expected branch name for publishing the specified version. */
6-
export function getExpectedPublishBranch(version: Version): string {
5+
/** Determines the allowed branch names for publishing the specified version. */
6+
export function getAllowedPublishBranches(version: Version): string[] {
77
const versionType = getSemverVersionType(version);
88

99
if (versionType === 'major') {
10-
return 'master';
10+
return ['master'];
1111
} else if (versionType === 'minor') {
12-
return `${version.major}.x`;
12+
// It's also possible that the caretaker wants to stage a minor release from a different
13+
// branch than "master". This can happen if major changes have been merged into "master"
14+
// and non-major changes are cherry-picked into a separate branch (e.g. 7.x)
15+
return ['master', `${version.major}.x`];
1316
} else if (versionType === 'patch') {
14-
return `${version.major}.${version.minor}.x`;
17+
return [`${version.major}.${version.minor}.x`];
1518
}
1619
}
1720

0 commit comments

Comments
 (0)