@@ -5,7 +5,9 @@ const CLI = require('../../lib/cli');
5
5
const cli = new CLI ( process . stderr ) ;
6
6
const Request = require ( '../../lib/request' ) ;
7
7
const req = new Request ( ) ;
8
- const { runPromise, runAsync, runSync } = require ( '../../lib/run' ) ;
8
+ const {
9
+ runPromise, runAsync, runSync, forceRunAsync
10
+ } = require ( '../../lib/run' ) ;
9
11
const Session = require ( '../../lib/landing_session' ) ;
10
12
const dir = process . cwd ( ) ;
11
13
const args = process . argv . slice ( 2 ) ;
@@ -40,8 +42,23 @@ if (result.length) {
40
42
}
41
43
42
44
async function main ( state , args ) {
45
+ let session ;
46
+
47
+ try {
48
+ session = Session . restore ( dir ) ;
49
+ } catch ( err ) { // JSON error?
50
+ if ( state === ABORT ) {
51
+ session = new Session ( dir ) ;
52
+ await abort ( session ) ;
53
+ return ;
54
+ }
55
+ cli . warn (
56
+ 'Failed to detect previous session. ' +
57
+ 'please run `git node land --abort`' ) ;
58
+ return ;
59
+ }
60
+
43
61
if ( state === START ) {
44
- let session = Session . restore ( dir ) ;
45
62
if ( session . hasStarted ( ) ) {
46
63
cli . warn (
47
64
'Previous `git node land` session for ' +
@@ -52,19 +69,14 @@ async function main(state, args) {
52
69
session = new Session ( dir , parseInt ( args [ 0 ] ) ) ;
53
70
await start ( session ) ;
54
71
} else if ( state === APPLY ) {
55
- const session = Session . restore ( dir ) ;
56
72
await apply ( session ) ;
57
73
} else if ( state === AMEND ) {
58
- const session = Session . restore ( dir ) ;
59
74
await amend ( session ) ;
60
75
} else if ( state === FINAL ) {
61
- const session = Session . restore ( dir ) ;
62
76
await final ( session ) ;
63
77
} else if ( state === ABORT ) {
64
- const session = Session . restore ( dir ) ;
65
- session . abort ( ) ;
78
+ await abort ( session ) ;
66
79
} else if ( state === CONTINUE ) {
67
- const session = Session . restore ( dir ) ;
68
80
await continueSession ( session ) ;
69
81
}
70
82
}
@@ -78,35 +90,109 @@ async function start(session) {
78
90
const response = await cli . prompt (
79
91
`This PR ${ status } to land, do you want to continue?` ) ;
80
92
if ( response ) {
81
- session . saveMetadata ( status ) ;
93
+ session . saveMetadata ( result ) ;
82
94
session . startApplying ( ) ;
83
95
return apply ( session ) ;
84
96
} else {
85
- session . abort ( ) ;
86
- cli . log ( 'Landing session aborted' ) ;
97
+ await abort ( session ) ;
87
98
process . exit ( ) ;
88
99
}
89
100
}
90
101
102
+ function getNotYetPushedCommits ( session , verbose ) {
103
+ const upstream = session . upstream ;
104
+ const branch = session . branch ;
105
+ var revs ;
106
+ if ( verbose ) {
107
+ revs = runSync ( 'git' ,
108
+ [ 'log' , '--oneline' , `${ upstream } /${ branch } ...HEAD` ] ) ;
109
+ } else {
110
+ revs = runSync ( 'git' , [ 'rev-list' , `${ upstream } /${ branch } ...HEAD` ] ) ;
111
+ }
112
+
113
+ if ( ! revs . trim ( ) ) {
114
+ return [ ] ;
115
+ }
116
+ return revs . trim ( ) . split ( '\n' ) ;
117
+ }
118
+
119
+ async function tryAbortAm ( session , cli ) {
120
+ if ( session . amInProgress ( ) ) {
121
+ const shouldAbortAm = await cli . prompt (
122
+ 'Abort previous git am sessions?' ) ;
123
+ if ( shouldAbortAm ) {
124
+ await forceRunAsync ( 'git' , [ 'am' , '--abort' ] ) ;
125
+ cli . ok ( 'Aborted previous git am sessions' ) ;
126
+ }
127
+ } else {
128
+ cli . ok ( 'No git am in progress' ) ;
129
+ }
130
+ }
131
+
132
+ async function tryAbortRebase ( session , cli ) {
133
+ if ( session . rebaseInProgress ( ) ) {
134
+ const shouldAbortRebase = await cli . prompt (
135
+ 'Abort previous git rebase sessions?' ) ;
136
+ if ( shouldAbortRebase ) {
137
+ await forceRunAsync ( 'git' , [ 'rebase' , '--abort' ] ) ;
138
+ cli . ok ( 'Aborted previous git rebase sessions' ) ;
139
+ }
140
+ } else {
141
+ cli . ok ( 'No git rebase in progress' ) ;
142
+ }
143
+ }
144
+
145
+ async function tryResetHead ( session , cli ) {
146
+ const branch = `${ session . upstream } /${ session . branch } ` ;
147
+ cli . startSpinner ( `Bringing ${ branch } up to date` ) ;
148
+ await runAsync ( 'git' ,
149
+ [ 'fetch' , session . upstream , session . branch ] ) ;
150
+ cli . stopSpinner ( `${ branch } is now up-to-date` ) ;
151
+ const notYetPushed = getNotYetPushedCommits ( session , true ) ;
152
+ if ( notYetPushed . length ) {
153
+ const branch = `${ session . upstream } /${ session . branch } ` ;
154
+ cli . log ( `Found strayed commits in ${ branch } :\n` +
155
+ ` - ${ notYetPushed . join ( '\n - ' ) } ` ) ;
156
+ const shouldReset = await cli . prompt ( `Reset to ${ branch } ?` ) ;
157
+ if ( shouldReset ) {
158
+ await runAsync ( 'git' , [ 'reset' , '--hard' , branch ] ) ;
159
+ cli . ok ( `Reset to ${ branch } ` ) ;
160
+ }
161
+ }
162
+ }
163
+
164
+ async function tryResetBranch ( session , cli ) {
165
+ await tryAbortAm ( session , cli ) ;
166
+ await tryAbortRebase ( session , cli ) ;
167
+
168
+ const branch = `${ session . upstream } /${ session . branch } ` ;
169
+ const shouldResetHead = await cli . prompt (
170
+ `Do you want to try reset the branch to ${ branch } ?` ) ;
171
+ if ( shouldResetHead ) {
172
+ await tryResetHead ( session , cli ) ;
173
+ }
174
+ }
175
+
176
+ async function abort ( session ) {
177
+ session . abort ( ) ;
178
+ await tryResetBranch ( session , cli ) ;
179
+ cli . log ( `Aborted \`git node land\` session in ${ session . ncuDir } ` ) ;
180
+ }
181
+
91
182
async function apply ( session ) {
92
183
if ( ! session . readyToApply ( ) ) {
93
184
cli . warn ( 'This session can not proceed to apply patches, ' +
94
185
'run `git node land --abort`' ) ;
95
186
return ;
96
187
}
97
188
98
- if ( session . hasAM ( ) ) {
99
- const shouldAbortAm = await cli . prompt ( 'Abort previous git am sessions?' ) ;
100
- if ( shouldAbortAm ) {
101
- await runAsync ( 'git' , [ 'am' , '--abort' ] ) ;
102
- }
103
- }
189
+ await tryResetBranch ( session , cli ) ;
104
190
105
191
const { repo, owner, prid } = session ;
106
192
// TODO: restore previously downloaded patches
107
193
cli . startSpinner ( `Downloading patch for ${ prid } ` ) ;
108
194
const patch = await req . promise ( {
109
- url : `https://github.com/nodejs/ ${ owner } /${ repo } /${ prid } .patch`
195
+ url : `https://github.com/${ owner } /${ repo } /pull /${ prid } .patch`
110
196
} ) ;
111
197
session . savePatch ( patch ) ;
112
198
cli . stopSpinner ( `Downloaded patch to ${ session . patchPath } ` ) ;
@@ -118,14 +204,29 @@ async function apply(session) {
118
204
session . startAmending ( ) ;
119
205
if ( / S u b j e c t : \[ P A T C H \] / . test ( patch ) ) {
120
206
const shouldAmend = await cli . prompt (
121
- 'There is only one patch to apply .\n' +
207
+ 'There is only one commit in this PR .\n' +
122
208
'do you want to amend the commit message?' ) ;
123
209
if ( shouldAmend ) {
124
210
const canFinal = await amend ( session ) ;
125
211
if ( canFinal ) {
126
212
return final ( session ) ;
127
213
}
128
214
}
215
+ } else {
216
+ const re = / S u b j e c t : \[ P A T C H 1 \/ ( \d + ) \] / ;
217
+ const match = patch . match ( re ) ;
218
+ if ( ! match ) {
219
+ cli . warn ( 'Cannot get number of commits in the patch. ' +
220
+ 'It seems to be malformed' ) ;
221
+ return ;
222
+ }
223
+ const upstream = session . upstream ;
224
+ const branch = session . branch ;
225
+ cli . log (
226
+ `There are ${ match [ 1 ] } commits in the PR.\n` +
227
+ `Please run \`git rebase ${ upstream } /${ branch } -i\` ` +
228
+ 'and use `git node land --amend` to amend the commit messages' ) ;
229
+ // TODO: do git rebase automatically?
129
230
}
130
231
}
131
232
@@ -136,16 +237,18 @@ async function amend(session) {
136
237
}
137
238
138
239
const rev = runSync ( 'git' , [ 'rev-parse' , 'HEAD' ] ) ;
139
- const original = runSync ( 'git' , [ 'show' , rev , '-s' , '--format=%B' ] ) ;
140
- const metadata = session . metadata . split ( '\n' ) ;
240
+ const original = runSync ( 'git' , [ 'show' , 'HEAD' , '-s' , '--format=%B' ] ) . trim ( ) ;
241
+ const metadata = session . metadata . trim ( ) . split ( '\n' ) ;
141
242
const amended = original . split ( '\n' ) ;
142
- if ( amended [ amended . length - 1 ] !== '\n ' ) {
143
- amended . push ( '\n ' ) ;
243
+ if ( amended [ amended . length - 1 ] !== '' ) {
244
+ amended . push ( '' ) ;
144
245
}
145
246
146
247
for ( const line of metadata ) {
147
248
if ( original . includes ( line ) ) {
148
- cli . warn ( `Found ${ line } , skipping..` ) ;
249
+ if ( line ) {
250
+ cli . warn ( `Found ${ line } , skipping..` ) ;
251
+ }
149
252
} else {
150
253
amended . push ( line ) ;
151
254
}
@@ -154,15 +257,16 @@ async function amend(session) {
154
257
const message = amended . join ( '\n' ) + '\n' ;
155
258
const messageFile = session . saveMessage ( rev , message ) ;
156
259
cli . separator ( 'New Message' ) ;
157
- cli . log ( message ) ;
260
+ cli . log ( message . trim ( ) ) ;
261
+ cli . separator ( ) ;
158
262
const takeMessage = await cli . prompt ( 'Use this message?' ) ;
159
263
if ( takeMessage ) {
160
264
await runAsync ( 'git' , [ 'commit' , '--amend' , '-F' , messageFile ] ) ;
161
- session . markAsAmended ( rev ) ;
265
+ // session.markAsAmended(rev);
162
266
return true ;
163
267
}
164
268
165
- cli . log ( `Please manually edit ${ messageFile } , then run ` +
269
+ cli . log ( `Please manually edit ${ messageFile } , then run\n ` +
166
270
`\`git commit --amend -F ${ messageFile } \` to finish amending the message` ) ;
167
271
return false ;
168
272
} ;
@@ -172,13 +276,16 @@ async function final(session) {
172
276
cli . warn ( 'Not yet ready to final' ) ;
173
277
return ;
174
278
}
175
-
176
279
const upstream = session . upstream ;
177
280
const branch = session . branch ;
178
- const notYetPushed = runSync ( 'git' ,
179
- [ 'rev-list' , ` ${ upstream } / ${ branch } ...HEAD` ] ) . split ( '\n' ) ;
281
+ const notYetPushed = getNotYetPushedCommits ( session ) ;
282
+ const notYetPushedVerbose = getNotYetPushedCommits ( session , true ) ;
180
283
await runAsync ( 'core-validate-commit' , notYetPushed ) ;
181
- cli . log ( 'This session is ready to be completed.' ) ;
284
+ cli . separator ( ) ;
285
+ cli . log ( 'The following commits are ready to be pushed to ' +
286
+ `${ upstream } /${ branch } ` ) ;
287
+ cli . log ( `- ${ notYetPushedVerbose . join ( '\n- ' ) } ` ) ;
288
+ cli . separator ( ) ;
182
289
cli . log ( `run \`git push ${ upstream } ${ branch } \` to finish landing` ) ;
183
290
const shouldClean = await cli . prompt ( 'Clean up generated temporary files?' ) ;
184
291
if ( shouldClean ) {
0 commit comments