Skip to content

Commit 7c1dfbe

Browse files
committed
make --dryRun more useful
1 parent d65fd6a commit 7c1dfbe

File tree

2 files changed

+69
-59
lines changed

2 files changed

+69
-59
lines changed

components/git/release.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ const RELEASERS = 'releasers';
1515

1616
const releaseOptions = {
1717
dryRun: {
18-
describe: 'Skip all the steps that involve touching more than the local clone',
18+
describe: 'Do not run steps that involve touching more than the local clone, ' +
19+
'instead print the commands so the user can choose to run them manually',
1920
type: 'boolean'
2021
},
2122
prepare: {

lib/promote_release.js

Lines changed: 67 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,8 @@ export default class ReleasePromotion extends Session {
118118
await this.setupForNextRelease();
119119
cli.stopSpinner('Successfully set up for next release');
120120

121-
const shouldMergeProposalBranch = await cli.prompt(
122-
'Merge proposal branch into staging branch?');
123-
if (!shouldMergeProposalBranch) {
124-
cli.warn(`Aborting release promotion for version ${version}`);
125-
throw new Error('Aborted');
126-
}
127-
128121
// Merge vX.Y.Z-proposal into vX.x.
129-
cli.startSpinner('Merging proposal branch');
130122
await this.mergeProposalBranch();
131-
cli.stopSpinner('Merged proposal branch');
132123

133124
// Cherry pick release commit to master.
134125
const shouldCherryPick = await cli.prompt(
@@ -147,7 +138,7 @@ export default class ReleasePromotion extends Session {
147138
// need to resolve, so confirm they've been resolved before
148139
// proceeding with next steps.
149140
cli.separator();
150-
cli.info('Resovle the conflicts and commit the result');
141+
cli.info('Resolve the conflicts and commit the result');
151142
cli.separator();
152143
const didResolveConflicts = await cli.prompt(
153144
'Finished resolving cherry-pick conflicts?', { defaultAnswer: true });
@@ -170,42 +161,11 @@ export default class ReleasePromotion extends Session {
170161
}
171162
}
172163

173-
// Push to the remote default branch
174-
const shouldPushDefaultBranch = await cli.prompt(`Push to ${this.branch}?`,
175-
{ defaultAnswer: true });
176-
if (!shouldPushDefaultBranch) {
177-
cli.warn(`Aborting release promotion for version ${version}`);
178-
throw new Error('Aborted');
179-
}
180-
if (this.dryRun) {
181-
cli.info(`Skipping pushing to ${this.branch} in dry-run mode`);
182-
} else {
183-
await forceRunAsync('git', ['push', this.upstream, this.branch], { ignoreFailure: false });
184-
}
185-
186-
// Push release tag.
187-
const shouldPushTag = await cli.prompt('Push release tag?',
188-
{ defaultAnswer: true });
189-
if (!shouldPushTag) {
190-
cli.warn(`Aborting release promotion for version ${version}`);
191-
throw new Error('Aborted');
192-
}
193-
await this.pushReleaseTag();
164+
// Push to the remote default branch and release tag.
165+
await this.pushTagAndDefaultBranchToRemote();
194166

195167
// Promote and sign the release builds.
196-
const shouldPromote = await cli.prompt('Promote and sign release builds?',
197-
{ defaultAnswer: true });
198-
if (!shouldPromote) {
199-
cli.warn(`Aborting release promotion for version ${version}`);
200-
throw new Error('Aborted');
201-
}
202-
203-
// TODO: move this to .ncurc
204-
const defaultKeyPath = '~/.ssh/node_id_rsa';
205-
const keyPath = await cli.prompt(
206-
`Please enter the path to your ssh key (Default ${defaultKeyPath}): `,
207-
{ questionType: 'input', defaultAnswer: defaultKeyPath });
208-
await this.promoteAndSignRelease(keyPath);
168+
await this.promoteAndSignRelease();
209169

210170
cli.separator();
211171
cli.ok(`Release promotion for ${version} complete.\n`);
@@ -218,16 +178,16 @@ export default class ReleasePromotion extends Session {
218178
' 5. Tag @nodejs-social-team on #nodejs-release Slack channel.\n');
219179

220180
cli.separator();
221-
cli.info('Use the following command to create the release:');
181+
cli.info('Use the following command to create the GitHub release:');
222182
cli.separator();
223183
cli.info(
224184
'awk \'' +
225185
`/^## ${this.date}, Version ${this.version.replaceAll('.', '\\.')} /,` +
226186
'/^<a id="[0-9]+\\.[0-9]+\\.[0-9]+"><\\x2fa>$/{' +
227187
'print buf; if(firstLine == "") firstLine = $0; else buf = $0' +
228188
`}' doc/changelogs/CHANGELOG_V${
229-
this.versionComponents.major}.md | gh release create ${this.version} --verify-tag --latest=${
230-
!this.isLTS} --title=${JSON.stringify(this.releaseTitle)} --notes-file -`);
189+
this.versionComponents.major}.md | gh release create ${this.version} --verify-tag --latest${
190+
this.isLTS ? '=false' : ''} --title=${JSON.stringify(this.releaseTitle)} --notes-file -`);
231191
}
232192

233193
async verifyPRAttributes() {
@@ -399,42 +359,91 @@ export default class ReleasePromotion extends Session {
399359
], { ignoreFailure: false });
400360
}
401361

402-
mergeProposalBranch() {
362+
async mergeProposalBranch() {
403363
const { cli, dryRun, stagingBranch, versionComponents } = this;
364+
const releaseBranch = `v${versionComponents.major}.x`;
365+
366+
let prompt = 'Merge proposal branch into staging branch?';
404367
if (dryRun) {
405-
cli.info('Skipping merging the proposal branch in dry-run mode');
406-
return;
368+
cli.info('Run the following commands to merge the staging branch:');
369+
cli.info(`git push ${this.upstream} HEAD:refs/heads/${releaseBranch}`);
370+
cli.info(`git push ${this.upstream} HEAD:refs/heads/${stagingBranch}`);
371+
prompt = 'Ready to continue?';
407372
}
408373

409-
const releaseBranch = `v${versionComponents.major}.x`;
374+
const shouldMergeProposalBranch = await cli.prompt(prompt, { defaultAnswer: true });
375+
if (!shouldMergeProposalBranch) {
376+
cli.warn('Aborting release promotion');
377+
throw new Error('Aborted');
378+
} else if (dryRun) {
379+
return;
380+
}
410381

411382
// TODO: find a solution for key passphrase from the terminal
412-
return Promise.all([
383+
cli.startSpinner('Merging proposal branch');
384+
await Promise.all([
413385
forceRunAsync('git', ['push', this.upstream, `HEAD:refs/heads/${releaseBranch}`],
414386
{ ignoreFailure: false }),
415387
forceRunAsync('git', ['push', this.upstream, `HEAD:refs/heads/${stagingBranch}`],
416388
{ ignoreFailure: false })
417389
]);
390+
cli.stopSpinner('Merged proposal branch');
418391
}
419392

420-
pushReleaseTag() {
393+
async pushTagAndDefaultBranchToRemote() {
421394
const { cli, dryRun, version } = this;
395+
const tagVersion = `v${version}`;
396+
397+
let prompt = `Push release tag and ${this.branch} to ${this.upstream}?`;
422398
if (dryRun) {
423-
cli.info('Skipping pushing the tag in dry-run mode');
399+
cli.info('Run the following commands to push to remote:');
400+
cli.info(`git push ${this.upstream} ${this.branch}`);
401+
cli.info(`git push ${this.upstream} ${tagVersion}`);
402+
prompt = 'Ready to continue?';
403+
}
404+
405+
const shouldPushTag = await cli.prompt(prompt, { defaultAnswer: true });
406+
if (!shouldPushTag) {
407+
cli.warn('Aborting release promotion');
408+
throw new Error('Aborted');
409+
} else if (dryRun) {
424410
return;
425411
}
426412

427-
const tagVersion = `v${version}`;
428-
return forceRunAsync('git', ['push', this.upstream, tagVersion], { ignoreFailure: false });
413+
cli.startSpinner('Pushing to remote');
414+
await Promise.all([
415+
forceRunAsync('git', ['push', this.upstream, this.branch], { ignoreFailure: false }),
416+
forceRunAsync('git', ['push', this.upstream, tagVersion], { ignoreFailure: false })
417+
]);
418+
cli.stopSpinner(`Pushed ${tagVersion} and ${this.branch} to remote`);
429419
}
430420

431-
async promoteAndSignRelease(keyPath) {
421+
async promoteAndSignRelease() {
432422
const { cli, dryRun } = this;
423+
let prompt = 'Promote and sign release builds?';
424+
433425
if (dryRun) {
434-
cli.info('Skipping promoting the release in dry-run mode');
426+
cli.info('Run the following command to sign and promote the release:');
427+
cli.info('./tools/release.sh -i <keyPath>');
428+
prompt = 'Ready to continue?';
429+
}
430+
const shouldPromote = await cli.prompt(prompt, { defaultAnswer: true });
431+
if (!shouldPromote) {
432+
cli.warn('Aborting release promotion');
433+
throw new Error('Aborted');
434+
} else if (dryRun) {
435435
return;
436436
}
437+
438+
// TODO: move this to .ncurc
439+
const defaultKeyPath = '~/.ssh/node_id_rsa';
440+
const keyPath = await cli.prompt(
441+
`Please enter the path to your ssh key (Default ${defaultKeyPath}): `,
442+
{ questionType: 'input', defaultAnswer: defaultKeyPath });
443+
444+
cli.startSpinner('Signing and promoting the release');
437445
await forceRunAsync('./tools/release.sh', ['-i', keyPath], { ignoreFailure: false });
446+
cli.stopSpinner('Release has been signed and promoted');
438447
}
439448

440449
async cherryPickToDefaultBranch() {

0 commit comments

Comments
 (0)