Skip to content
Merged
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
31 changes: 26 additions & 5 deletions lib/promote_release.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ export default class ReleasePromotion extends Session {
const workingOnNewReleaseCommit = await this.setupForNextRelease();
cli.stopSpinner('Successfully set up for next release');

const shouldRebaseStagingBranch = await cli.prompt(
'Rebase staging branch on top of the release commit?', { defaultAnswer: true });
const tipOfStagingBranch = shouldRebaseStagingBranch
? await this.rebaseStagingBranch(workingOnNewReleaseCommit)
: workingOnNewReleaseCommit;

// Cherry pick release commit to master.
const shouldCherryPick = await cli.prompt(
'Cherry-pick release commit to the default branch?', { defaultAnswer: true });
Expand Down Expand Up @@ -200,7 +206,7 @@ export default class ReleasePromotion extends Session {
}

// Push to the remote the release tag, and default, release, and staging branch.
await this.pushToRemote(workingOnNewReleaseCommit);
await this.pushToRemote(workingOnNewReleaseCommit, tipOfStagingBranch);

// Promote and sign the release builds.
await this.promoteAndSignRelease();
Expand Down Expand Up @@ -440,7 +446,7 @@ export default class ReleasePromotion extends Session {
return workingOnNewReleaseCommit.trim();
}

async pushToRemote(workingOnNewReleaseCommit) {
async pushToRemote(workingOnNewReleaseCommit, tipOfStagingBranch) {
const { cli, dryRun, version, versionComponents, stagingBranch } = this;
const releaseBranch = `v${versionComponents.major}.x`;
const tagVersion = `v${version}`;
Expand All @@ -454,8 +460,8 @@ export default class ReleasePromotion extends Session {
cli.info(`git push ${this.upstream} ${
this.defaultBranch} ${
tagVersion} ${
workingOnNewReleaseCommit}:refs/heads/${releaseBranch} ${
workingOnNewReleaseCommit}:refs/heads/${stagingBranch}`);
workingOnNewReleaseCommit}:refs/heads/${releaseBranch} +${
tipOfStagingBranch}:refs/heads/${stagingBranch}`);
cli.warn('Once pushed, you must not delete the local tag');
prompt = 'Ready to continue?';
}
Expand All @@ -471,7 +477,7 @@ export default class ReleasePromotion extends Session {
cli.startSpinner('Pushing to remote');
await forceRunAsync('git', ['push', this.upstream, this.defaultBranch, tagVersion,
`${workingOnNewReleaseCommit}:refs/heads/${releaseBranch}`,
`${workingOnNewReleaseCommit}:refs/heads/${stagingBranch}`],
`+${tipOfStagingBranch}:refs/heads/${stagingBranch}`],
{ ignoreFailure: false });
cli.stopSpinner(`Pushed ${tagVersion}, ${this.defaultBranch}, ${
releaseBranch}, and ${stagingBranch} to remote`);
Expand Down Expand Up @@ -507,6 +513,21 @@ export default class ReleasePromotion extends Session {
cli.stopSpinner('Release has been signed and promoted');
}

async rebaseStagingBranch(workingOnNewReleaseCommit) {
const { cli, stagingBranch, upstream } = this;
cli.startSpinner('Fetch staging branch');
await forceRunAsync('git', ['fetch', upstream, stagingBranch], { ignoreFailure: false });
cli.updateSpinner('Reset and rebase');
await forceRunAsync('git', ['reset', 'FETCH_HEAD', '--hard'], { ignoreFailure: false });
await forceRunAsync('git',
['rebase', workingOnNewReleaseCommit, ...this.gpgSign], { ignoreFailure: false });
const tipOfStagingBranch = await forceRunAsync('git', ['rev-parse', 'HEAD'],
{ ignoreFailure: false, captureStdout: true });
cli.stopSpinner('Rebased successfully');

return tipOfStagingBranch.trim();
}

async cherryPickToDefaultBranch() {
this.defaultBranch ??= await this.getDefaultBranch();
const releaseCommitSha = this.releaseCommitSha;
Expand Down
Loading