@@ -30,6 +30,7 @@ class LandingSession extends Session {
30
30
this . lint = lint ;
31
31
this . autorebase = autorebase ;
32
32
this . fixupAll = fixupAll ;
33
+ this . expectedCommitShas = [ ] ;
33
34
}
34
35
35
36
get argv ( ) {
@@ -44,6 +45,8 @@ class LandingSession extends Session {
44
45
async start ( metadata ) {
45
46
const { cli } = this ;
46
47
this . startLanding ( ) ;
48
+ this . expectedCommitShas =
49
+ metadata . data . commits . map ( ( { commit } ) => commit . oid ) ;
47
50
const status = metadata . status ? 'should be ready' : 'is not ready' ;
48
51
// NOTE(mmarchini): default answer is yes. If --yes is given, we need to be
49
52
// more careful though, and we change the default to the result of our
@@ -78,34 +81,46 @@ class LandingSession extends Session {
78
81
}
79
82
80
83
async downloadAndPatch ( ) {
81
- const { cli, req , repo, owner, prid } = this ;
84
+ const { cli, repo, owner, prid, expectedCommitShas } = this ;
82
85
83
- // TODO(joyeecheung): restore previously downloaded patches
84
86
cli . startSpinner ( `Downloading patch for ${ prid } ` ) ;
85
- const patch = await req . text (
86
- `https://github.com/${ owner } /${ repo } /pull/${ prid } .patch` ) ;
87
- this . savePatch ( patch ) ;
88
- cli . stopSpinner ( `Downloaded patch to ${ this . patchPath } ` ) ;
87
+ await runAsync ( 'git' , [
88
+ 'fetch' , `https://github.com/${ owner } /${ repo } .git` ,
89
+ `refs/pull/${ prid } /merge` ] ) ;
90
+ // We fetched the commit that would result if we used `git merge`.
91
+ // ^1 and ^2 refer to the PR base and the PR head, respectively.
92
+ const [ base , head ] = await runAsync ( 'git' ,
93
+ [ 'rev-parse' , 'FETCH_HEAD^1' , 'FETCH_HEAD^2' ] ,
94
+ { captureStdout : 'lines' } ) ;
95
+ const commitShas = await runAsync ( 'git' ,
96
+ [ 'rev-list' , `${ base } ..${ head } ` ] ,
97
+ { captureStdout : 'lines' } ) ;
98
+ cli . stopSpinner ( `Fetched commits as ${ shortSha ( base ) } ..${ shortSha ( head ) } ` ) ;
89
99
cli . separator ( ) ;
90
- // TODO: check that patches downloaded match metadata.commits
100
+
101
+ const mismatchedCommits = [
102
+ ...commitShas . filter ( ( sha ) => ! expectedCommitShas . includes ( sha ) )
103
+ . map ( ( sha ) => `Unexpected commit ${ sha } ` ) ,
104
+ ...expectedCommitShas . filter ( ( sha ) => ! commitShas . includes ( sha ) )
105
+ . map ( ( sha ) => `Missing commit ${ sha } ` )
106
+ ] . join ( '\n' ) ;
107
+ if ( mismatchedCommits . length > 0 ) {
108
+ cli . error ( `Mismatched commits:\n${ mismatchedCommits } ` ) ;
109
+ process . exit ( 1 ) ;
110
+ }
111
+
112
+ const commitInfo = { base, head, shas : commitShas } ;
113
+ this . saveCommitInfo ( commitInfo ) ;
114
+
91
115
try {
92
- await forceRunAsync ( 'git' , [ 'am ' , this . patchPath ] , {
116
+ await forceRunAsync ( 'git' , [ 'cherry-pick ' , ` ${ base } .. ${ head } ` ] , {
93
117
ignoreFailure : false
94
118
} ) ;
95
119
} catch ( ex ) {
96
- const should3Way = await cli . prompt (
97
- 'The normal `git am` failed. Do you want to retry with 3-way merge?' ) ;
98
- if ( should3Way ) {
99
- await forceRunAsync ( 'git' , [ 'am' , '--abort' ] ) ;
100
- await runAsync ( 'git' , [
101
- 'am' ,
102
- '-3' ,
103
- this . patchPath
104
- ] ) ;
105
- } else {
106
- cli . error ( 'Failed to apply patches' ) ;
107
- process . exit ( 1 ) ;
108
- }
120
+ await forceRunAsync ( 'git' , [ 'cherry-pick' , '--abort' ] ) ;
121
+
122
+ cli . error ( 'Failed to apply patches' ) ;
123
+ process . exit ( 1 ) ;
109
124
}
110
125
111
126
// Check for and maybe assign any unmarked deprecations in the codebase.
@@ -126,7 +141,7 @@ class LandingSession extends Session {
126
141
}
127
142
128
143
cli . ok ( 'Patches applied' ) ;
129
- return patch ;
144
+ return commitInfo ;
130
145
}
131
146
132
147
getRebaseSuggestion ( subjects ) {
@@ -173,21 +188,13 @@ class LandingSession extends Session {
173
188
}
174
189
}
175
190
176
- async tryCompleteLanding ( patch ) {
191
+ async tryCompleteLanding ( commitInfo ) {
177
192
const { cli } = this ;
193
+ const subjects = await runAsync ( 'git' ,
194
+ [ 'log' , '--pretty=format:%s' , `${ commitInfo . base } ..${ commitInfo . head } ` ] ,
195
+ { captureStdout : 'lines' } ) ;
178
196
179
- const subjects = patch . match ( / S u b j e c t : \[ P A T C H .* ?\] .* / g) ;
180
- if ( ! subjects ) {
181
- cli . warn ( 'Cannot get number of commits in the patch. ' +
182
- 'It seems to be malformed' ) ;
183
- return ;
184
- }
185
-
186
- // XXX(joyeecheung) we cannot guarantee that no one will put a subject
187
- // line in the commit message but that seems unlikely (some deps update
188
- // might do that).
189
- if ( subjects . length === 1 ) {
190
- // assert(subjects[0].startsWith('Subject: [PATCH]'))
197
+ if ( commitInfo . shas . length === 1 ) {
191
198
const shouldAmend = await cli . prompt (
192
199
'There is only one commit in this PR.\n' +
193
200
'do you want to amend the commit message?' ) ;
@@ -247,7 +254,7 @@ class LandingSession extends Session {
247
254
}
248
255
await this . tryResetBranch ( ) ;
249
256
250
- const patch = await this . downloadAndPatch ( ) ;
257
+ const commitInfo = await this . downloadAndPatch ( ) ;
251
258
252
259
const cleanLint = await this . validateLint ( ) ;
253
260
if ( cleanLint === LINT_RESULTS . FAILED ) {
@@ -280,7 +287,7 @@ class LandingSession extends Session {
280
287
281
288
this . startAmending ( ) ;
282
289
283
- await this . tryCompleteLanding ( patch ) ;
290
+ await this . tryCompleteLanding ( commitInfo ) ;
284
291
}
285
292
286
293
async amend ( ) {
@@ -407,13 +414,13 @@ class LandingSession extends Session {
407
414
}
408
415
if ( this . isApplying ( ) ) {
409
416
// We're still resolving conflicts.
410
- if ( this . amInProgress ( ) ) {
411
- cli . log ( 'Looks like you are resolving a `git am ` conflict' ) ;
417
+ if ( this . cherryPickInProgress ( ) ) {
418
+ cli . log ( 'Looks like you are resolving a `git cherry-pick ` conflict' ) ;
412
419
cli . log ( 'Please run `git status` for help' ) ;
413
420
} else {
414
421
// Conflicts has been resolved - amend.
415
422
this . startAmending ( ) ;
416
- return this . tryCompleteLanding ( this . patch ) ;
423
+ return this . tryCompleteLanding ( this . commitInfo ) ;
417
424
}
418
425
return ;
419
426
}
0 commit comments