Skip to content

Commit 13191bd

Browse files
committed
Split out promotion verification steps
1 parent 7fcc66a commit 13191bd

File tree

1 file changed

+40
-20
lines changed

1 file changed

+40
-20
lines changed

lib/promote_release.js

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,42 +25,55 @@ class ReleasePromotion {
2525
}
2626

2727
async promote() {
28-
const { version, prid, cli } = this;
29-
3028
// In the promotion stage, we can pull most relevant data
3129
// from the release commit created in the preparation stage.
3230
await this.parseDataFromReleaseCommit();
3331

32+
const { prid, cli, version } = this;
33+
3434
// Verify that PR is ready to promote.
35-
cli.startSpinner('Verifying PR promotion readiness');
3635
const {
3736
jenkinsReady,
3837
githubCIReady,
3938
isApproved
4039
} = await this.verifyPRAttributes();
40+
41+
cli.startSpinner('Verifying Jenkins CI status');
4142
if (!jenkinsReady) {
42-
cli.stopSpinner(`Jenkins CI is failing for #${prid}`);
43+
cli.stopSpinner(
44+
`Jenkins CI is failing for #${prid}`, cli.SPINNER_STATUS.FAILED);
4345
const proceed = await cli.prompt('Do you want to proceed?');
4446
if (!proceed) {
4547
cli.warn(`Aborting release promotion for version ${version}`);
4648
return;
4749
}
48-
} else if (!githubCIReady) {
49-
cli.stopSpinner(`GitHub CI is failing for #${prid}`);
50+
}
51+
cli.stopSpinner('Jenkins CI is passing');
52+
53+
cli.startSpinner('Verifying GitHub CI status');
54+
if (!githubCIReady) {
55+
cli.stopSpinner(
56+
`GitHub CI is failing for #${prid}`, cli.SPINNER_STATUS.FAILED);
5057
const proceed = await cli.prompt('Do you want to proceed?');
5158
if (!proceed) {
5259
cli.warn(`Aborting release promotion for version ${version}`);
5360
return;
5461
}
55-
} else if (!isApproved) {
56-
cli.stopSpinner(`#${prid} does not have sufficient approvals`);
62+
}
63+
cli.stopSpinner('GitHub CI is passing');
64+
65+
cli.startSpinner('Verifying PR approval status');
66+
if (!isApproved) {
67+
cli.stopSpinner(
68+
`#${prid} does not have sufficient approvals`,
69+
cli.SPINNER_STATUS.FAILED);
5770
const proceed = await cli.prompt('Do you want to proceed?');
5871
if (!proceed) {
5972
cli.warn(`Aborting release promotion for version ${version}`);
6073
return;
6174
}
6275
}
63-
cli.stopSpinner(`The release PR for ${version} is ready to promote!`);
76+
cli.stopSpinner(`#${prid} has necessary approvals`);
6477

6578
// Create and sign the release tag.
6679
const shouldTagAndSignRelease = await cli.prompt(
@@ -74,7 +87,7 @@ class ReleasePromotion {
7487
// Set up for next release.
7588
cli.startSpinner('Setting up for next release');
7689
await this.setupForNextRelease();
77-
cli.startSpinner('Successfully set up for next release');
90+
cli.stopSpinner('Successfully set up for next release');
7891

7992
const shouldMergeProposalBranch = await cli.prompt(
8093
'Merge proposal branch into staging branch?');
@@ -86,7 +99,7 @@ class ReleasePromotion {
8699
// Merge vX.Y.Z-proposal into vX.x.
87100
cli.startSpinner('Merging proposal branch');
88101
await this.mergeProposalBranch();
89-
cli.startSpinner('Merged proposal branch');
102+
cli.stopSpinner('Merged proposal branch');
90103

91104
// Cherry pick release commit to master.
92105
const shouldCherryPick = await cli.prompt(
@@ -95,7 +108,17 @@ class ReleasePromotion {
95108
cli.warn(`Aborting release promotion for version ${version}`);
96109
return;
97110
}
98-
await this.cherryPickToMaster();
111+
this.cherryPickToMaster();
112+
113+
// There will be cherry-pick conflicts the Releaser will
114+
// need to resolve, so confirm they've been resolved before
115+
// proceeding with next steps.
116+
const didResolveConflicts = await cli.prompt(
117+
'Finished resolving cherry-pick conflicts?', { defaultAnswer: true });
118+
if (!didResolveConflicts) {
119+
cli.warn(`Aborting release promotion for version ${version}`);
120+
return;
121+
}
99122

100123
// Push release tag.
101124
const shouldPushTag = await cli.prompt('Push release tag?',
@@ -142,7 +165,7 @@ class ReleasePromotion {
142165
const checker = new PRChecker(cli, data, { prid, owner, repo });
143166
const jenkinsReady = checker.checkJenkinsCI();
144167
const githubCIReady = checker.checkGitHubCI();
145-
const isApproved = checker.checkReviewsAndWait(false /* checkComments */);
168+
const isApproved = checker.checkReviewsAndWait(new Date(), false);
146169

147170
return {
148171
jenkinsReady,
@@ -160,7 +183,7 @@ class ReleasePromotion {
160183
const components = releaseCommitMessage.split(' ');
161184

162185
// Parse out release date.
163-
if (!/\d{4}-\d{2}-\d{2}/.match(components[0])) {
186+
if (!components[0].match(/\d{4}-\d{2}-\d{2}/)) {
164187
cli.error(`Release commit contains invalid date: ${components[0]}`);
165188
return;
166189
}
@@ -283,17 +306,14 @@ class ReleasePromotion {
283306
return runSync('./tools/release.sh', ['-i', keyPath]);
284307
}
285308

286-
async cherryPickToMaster() {
287-
// Since we've committed the Working On commit,
288-
// the release commit will be 1 removed from
289-
// tip-of-tree (e.g HEAD~1).
309+
cherryPickToMaster() {
310+
// Since we've committed the Working On commit, the release
311+
// commit will be 1 removed from tip-of-tree (e.g HEAD~1).
290312
const releaseCommitSha = this.getCommitSha(1);
291313
runSync('git', ['checkout', 'master']);
292314

293315
// There will be conflicts.
294316
runSync('git', ['cherry-pick', releaseCommitSha]);
295-
// TODO(codebytere): gracefully handle conflicts and
296-
// wait for the releaser to resolve.
297317
}
298318
}
299319

0 commit comments

Comments
 (0)