@@ -25,42 +25,55 @@ class ReleasePromotion {
25
25
}
26
26
27
27
async promote ( ) {
28
- const { version, prid, cli } = this ;
29
-
30
28
// In the promotion stage, we can pull most relevant data
31
29
// from the release commit created in the preparation stage.
32
30
await this . parseDataFromReleaseCommit ( ) ;
33
31
32
+ const { prid, cli, version } = this ;
33
+
34
34
// Verify that PR is ready to promote.
35
- cli . startSpinner ( 'Verifying PR promotion readiness' ) ;
36
35
const {
37
36
jenkinsReady,
38
37
githubCIReady,
39
38
isApproved
40
39
} = await this . verifyPRAttributes ( ) ;
40
+
41
+ cli . startSpinner ( 'Verifying Jenkins CI status' ) ;
41
42
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 ) ;
43
45
const proceed = await cli . prompt ( 'Do you want to proceed?' ) ;
44
46
if ( ! proceed ) {
45
47
cli . warn ( `Aborting release promotion for version ${ version } ` ) ;
46
48
return ;
47
49
}
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 ) ;
50
57
const proceed = await cli . prompt ( 'Do you want to proceed?' ) ;
51
58
if ( ! proceed ) {
52
59
cli . warn ( `Aborting release promotion for version ${ version } ` ) ;
53
60
return ;
54
61
}
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 ) ;
57
70
const proceed = await cli . prompt ( 'Do you want to proceed?' ) ;
58
71
if ( ! proceed ) {
59
72
cli . warn ( `Aborting release promotion for version ${ version } ` ) ;
60
73
return ;
61
74
}
62
75
}
63
- cli . stopSpinner ( `The release PR for ${ version } is ready to promote! ` ) ;
76
+ cli . stopSpinner ( `# ${ prid } has necessary approvals ` ) ;
64
77
65
78
// Create and sign the release tag.
66
79
const shouldTagAndSignRelease = await cli . prompt (
@@ -74,7 +87,7 @@ class ReleasePromotion {
74
87
// Set up for next release.
75
88
cli . startSpinner ( 'Setting up for next release' ) ;
76
89
await this . setupForNextRelease ( ) ;
77
- cli . startSpinner ( 'Successfully set up for next release' ) ;
90
+ cli . stopSpinner ( 'Successfully set up for next release' ) ;
78
91
79
92
const shouldMergeProposalBranch = await cli . prompt (
80
93
'Merge proposal branch into staging branch?' ) ;
@@ -86,7 +99,7 @@ class ReleasePromotion {
86
99
// Merge vX.Y.Z-proposal into vX.x.
87
100
cli . startSpinner ( 'Merging proposal branch' ) ;
88
101
await this . mergeProposalBranch ( ) ;
89
- cli . startSpinner ( 'Merged proposal branch' ) ;
102
+ cli . stopSpinner ( 'Merged proposal branch' ) ;
90
103
91
104
// Cherry pick release commit to master.
92
105
const shouldCherryPick = await cli . prompt (
@@ -95,7 +108,17 @@ class ReleasePromotion {
95
108
cli . warn ( `Aborting release promotion for version ${ version } ` ) ;
96
109
return ;
97
110
}
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
+ }
99
122
100
123
// Push release tag.
101
124
const shouldPushTag = await cli . prompt ( 'Push release tag?' ,
@@ -142,7 +165,7 @@ class ReleasePromotion {
142
165
const checker = new PRChecker ( cli , data , { prid, owner, repo } ) ;
143
166
const jenkinsReady = checker . checkJenkinsCI ( ) ;
144
167
const githubCIReady = checker . checkGitHubCI ( ) ;
145
- const isApproved = checker . checkReviewsAndWait ( false /* checkComments */ ) ;
168
+ const isApproved = checker . checkReviewsAndWait ( new Date ( ) , false ) ;
146
169
147
170
return {
148
171
jenkinsReady,
@@ -160,7 +183,7 @@ class ReleasePromotion {
160
183
const components = releaseCommitMessage . split ( ' ' ) ;
161
184
162
185
// 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 } / ) ) {
164
187
cli . error ( `Release commit contains invalid date: ${ components [ 0 ] } ` ) ;
165
188
return ;
166
189
}
@@ -283,17 +306,14 @@ class ReleasePromotion {
283
306
return runSync ( './tools/release.sh' , [ '-i' , keyPath ] ) ;
284
307
}
285
308
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).
290
312
const releaseCommitSha = this . getCommitSha ( 1 ) ;
291
313
runSync ( 'git' , [ 'checkout' , 'master' ] ) ;
292
314
293
315
// There will be conflicts.
294
316
runSync ( 'git' , [ 'cherry-pick' , releaseCommitSha ] ) ;
295
- // TODO(codebytere): gracefully handle conflicts and
296
- // wait for the releaser to resolve.
297
317
}
298
318
}
299
319
0 commit comments