From f0c4e87e443270f7ccee692ca85f762451ba0ab8 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Wed, 13 Nov 2024 15:21:31 +0100 Subject: [PATCH 1/2] feat(git-node): use a single `git push` command --- lib/promote_release.js | 66 +++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 43 deletions(-) diff --git a/lib/promote_release.js b/lib/promote_release.js index a83f088d..b3551af0 100644 --- a/lib/promote_release.js +++ b/lib/promote_release.js @@ -134,12 +134,9 @@ export default class ReleasePromotion extends Session { // Set up for next release. cli.startSpinner('Setting up for next release'); - await this.setupForNextRelease(); + const workingOnNewReleaseCommit = await this.setupForNextRelease(); cli.stopSpinner('Successfully set up for next release'); - // Merge vX.Y.Z-proposal into vX.x. - await this.mergeProposalBranch(); - // Cherry pick release commit to master. const shouldCherryPick = await cli.prompt( 'Cherry-pick release commit to the default branch?', { defaultAnswer: true }); @@ -186,8 +183,8 @@ export default class ReleasePromotion extends Session { } } - // Push to the remote default branch and release tag. - await this.pushTagAndDefaultBranchToRemote(); + // Push to the remote the release tag, and default, release, and staging branch. + await this.pushToRemote(workingOnNewReleaseCommit); // Promote and sign the release builds. await this.promoteAndSignRelease(); @@ -385,7 +382,7 @@ export default class ReleasePromotion extends Session { // Create 'Working On' commit. await forceRunAsync('git', ['add', filePath], { ignoreFailure: false }); - return forceRunAsync('git', [ + await forceRunAsync('git', [ 'commit', ...this.gpgSign, '-m', @@ -393,48 +390,27 @@ export default class ReleasePromotion extends Session { '-m', `PR-URL: https://github.com/nodejs/node/pull/${prid}` ], { ignoreFailure: false }); + return forceRunAsync('git', ['rev-parse', 'HEAD'], + { ignoreFailure: false, captureStdout: true }); } - async mergeProposalBranch() { - const { cli, dryRun, stagingBranch, versionComponents } = this; + async pushToRemote(workingOnNewReleaseCommit) { + const { cli, dryRun, version, versionComponents, stagingBranch } = this; const releaseBranch = `v${versionComponents.major}.x`; - - let prompt = 'Merge proposal branch into staging branch?'; - if (dryRun) { - cli.info(dryRunMessage); - cli.info('Run the following commands to merge the staging branch:'); - cli.info(`git push ${this.upstream} HEAD:refs/heads/${releaseBranch - } HEAD:refs/heads/${stagingBranch}`); - prompt = 'Ready to continue?'; - } - - const shouldMergeProposalBranch = await cli.prompt(prompt, { defaultAnswer: true }); - if (!shouldMergeProposalBranch) { - cli.warn('Aborting release promotion'); - throw new Error('Aborted'); - } else if (dryRun) { - return; - } - - // TODO: find a solution for key passphrase from the terminal - cli.startSpinner('Merging proposal branch'); - await forceRunAsync('git', ['push', this.upstream, `HEAD:refs/heads/${releaseBranch}`, - `HEAD:refs/heads/${stagingBranch}`], - { ignoreFailure: false }); - cli.stopSpinner('Merged proposal branch'); - } - - async pushTagAndDefaultBranchToRemote() { - const { cli, dryRun, version } = this; const tagVersion = `v${version}`; this.defaultBranch ??= await this.getDefaultBranch(); - let prompt = `Push release tag and ${this.defaultBranch} to ${this.upstream}?`; + let prompt = `Push release tag and commits to ${this.upstream}?`; if (dryRun) { cli.info(dryRunMessage); - cli.info('Run the following commands to push to remote:'); - cli.info(`git push ${this.upstream} ${this.defaultBranch} ${tagVersion}`); + cli.info('Run the following command to push to remote:'); + cli.info(`git push ${this.upstream} ${ + this.defaultBranch} ${ + tagVersion} ${ + workingOnNewReleaseCommit}:refs/heads/${releaseBranch} ${ + workingOnNewReleaseCommit}:refs/heads/${stagingBranch}`); + cli.warn('Once pushed, you must not delete the local tag'); prompt = 'Ready to continue?'; } @@ -447,9 +423,13 @@ export default class ReleasePromotion extends Session { } cli.startSpinner('Pushing to remote'); - await forceRunAsync('git', ['push', this.upstream, this.defaultBranch, tagVersion], - { ignoreFailure: false }); - cli.stopSpinner(`Pushed ${tagVersion} and ${this.defaultBranch} to remote`); + await forceRunAsync('git', ['push', this.upstream, this.defaultBranch, tagVersion, + `${workingOnNewReleaseCommit}:refs/heads/${releaseBranch}`, + `${workingOnNewReleaseCommit}:refs/heads/${stagingBranch}`], + { ignoreFailure: false }); + cli.stopSpinner(`Pushed ${tagVersion}, ${this.defaultBranch}, ${ + releaseBranch}, and ${stagingBranch} to remote`); + cli.warn('Now that it has been pushed, you must not delete the local tag'); } async promoteAndSignRelease() { From 9dffe17e59056466ede2e7a7eb039cb915f2a560 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 16 Nov 2024 14:45:10 +0100 Subject: [PATCH 2/2] fix: add `.trim()` --- lib/promote_release.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/promote_release.js b/lib/promote_release.js index b3551af0..e3f919a3 100644 --- a/lib/promote_release.js +++ b/lib/promote_release.js @@ -390,8 +390,9 @@ export default class ReleasePromotion extends Session { '-m', `PR-URL: https://github.com/nodejs/node/pull/${prid}` ], { ignoreFailure: false }); - return forceRunAsync('git', ['rev-parse', 'HEAD'], + const workingOnNewReleaseCommit = await forceRunAsync('git', ['rev-parse', 'HEAD'], { ignoreFailure: false, captureStdout: true }); + return workingOnNewReleaseCommit.trim(); } async pushToRemote(workingOnNewReleaseCommit) {