Skip to content

build: allow minor releases from master branch #14564

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

Merged
Merged
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
47 changes: 32 additions & 15 deletions tools/release/stage-release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {GitClient} from './git/git-client';
import {getGithubBranchCommitsUrl} from './git/github-urls';
import {promptForNewVersion} from './prompt/new-version-prompt';
import {parseVersionName, Version} from './version-name/parse-version';
import {getExpectedPublishBranch} from './version-name/publish-branch';
import {getAllowedPublishBranches} from './version-name/publish-branches';

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

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

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

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

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

const newVersionName = newVersion.format();
const stagingBranch = `release-stage/${newVersionName}`;
this.verifyLocalCommitsMatchUpstream(publishBranch);
await this.verifyPassingGithubStatus(publishBranch);

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

// If current branch already matches the expected publish branch, just continue
// by exiting this function.
if (expectedPublishBranch === currentBranchName) {
return;
// If current branch already matches one of the allowed publish branches, just continue
// by exiting this function and returning the currently used publish branch.
if (allowedBranches.includes(currentBranchName)) {
console.log(green(` ✓ Using the "${italic(currentBranchName)}" branch.`));
return currentBranchName;
}

if (!this.git.checkoutBranch(expectedPublishBranch)) {
console.error(red(` ✘ Could not switch to the "${italic(expectedPublishBranch)}" ` +
// In case there are multiple allowed publish branches for this version, we just
// exit and let the user decide which branch they want to release from.
if (allowedBranches.length !== 1) {
console.warn(yellow(' ✘ You are not on an allowed publish branch.'));
console.warn(yellow(` Please switch to one of the following branches: ` +
`${allowedBranches.join(', ')}`));
process.exit(0);
}

// For this version there is only *one* allowed publish branch, so we could
// automatically switch to that branch in case the user isn't on it yet.
const defaultPublishBranch = allowedBranches[0];

if (!this.git.checkoutBranch(defaultPublishBranch)) {
console.error(red(` ✘ Could not switch to the "${italic(defaultPublishBranch)}" ` +
`branch.`));
console.error(red(` Please ensure that the branch exists or manually switch to the ` +
`branch.`));
process.exit(1);
}

console.log(green(` ✓ Switched to the "${italic(expectedPublishBranch)}" branch.`));
console.log(green(` ✓ Switched to the "${italic(defaultPublishBranch)}" branch.`));
}

/** Verifies that the local branch is up to date with the given publish branch. */
Expand Down
2 changes: 1 addition & 1 deletion tools/release/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"lib": ["es2015"],
"lib": ["es2016"],
"types": ["node"]
}
}
2 changes: 1 addition & 1 deletion tools/release/version-name/create-version.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Version} from './parse-version';
import {VersionType} from './publish-branch';
import {VersionType} from './publish-branches';

/** Type of a new release */
export type ReleaseType = VersionType | 'stable-release' | 'bump-prerelease';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import {Version} from './parse-version';

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

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

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

Expand Down