@@ -11,7 +11,7 @@ const {
11
11
} = require ( '../lib/ci/ci_type_parser' ) ;
12
12
13
13
const {
14
- PRBuild, BenchmarkRun, CommitBuild,
14
+ PRBuild, BenchmarkRun, CommitBuild, HealthBuild ,
15
15
listBuilds, FailureAggregator, jobCache
16
16
} = require ( '../lib/ci/ci_result_parser' ) ;
17
17
const clipboardy = require ( 'clipboardy' ) ;
@@ -126,169 +126,234 @@ const argv = yargs
126
126
. help ( )
127
127
. argv ;
128
128
129
- async function getResults ( cli , request , job ) {
130
- let build ;
131
- const { type, jobid } = job ;
132
- if ( type === PR ) {
133
- build = new PRBuild ( cli , request , jobid ) ;
134
- await build . getResults ( ) ;
135
- } else if ( type === COMMIT ) {
136
- build = new CommitBuild ( cli , request , jobid ) ;
137
- await build . getResults ( ) ;
138
- } else if ( type === BENCHMARK ) {
139
- build = new BenchmarkRun ( cli , request , jobid ) ;
140
- await build . getResults ( ) ;
141
- } else {
142
- yargs . showHelp ( ) ;
143
- return ;
144
- }
145
- return build ;
146
- }
129
+ const commandToType = {
130
+ 'commit' : COMMIT ,
131
+ 'pr' : PR ,
132
+ 'benchmark' : BENCHMARK
133
+ } ;
147
134
148
- async function runQueue ( queue , cli , request , argv ) {
149
- let json = [ ] ;
150
- let markdown = '' ;
135
+ class CICommand {
136
+ constructor ( cli , request , argv ) {
137
+ this . cli = cli ;
138
+ this . request = request ;
139
+ this . argv = argv ;
140
+ this . queue = [ ] ;
141
+ this . json = [ ] ;
142
+ this . markdown = '' ;
143
+ }
151
144
152
- for ( let i = 0 ; i < queue . length ; ++ i ) {
153
- const job = queue [ i ] ;
154
- cli . separator ( '' ) ;
155
- const progress = `[${ i + 1 } /${ queue . length } ]` ;
156
- if ( job . link ) {
157
- cli . log ( `${ progress } Running ${ job . link } ` ) ;
158
- } else {
159
- cli . log ( `${ progress } Running ${ job . type } : ${ job . jobid } ` ) ;
145
+ async drain ( ) {
146
+ if ( this . queue . length === 0 ) {
147
+ return ;
160
148
}
161
- cli . separator ( '' ) ;
162
- const build = await getResults ( cli , request , job ) ;
163
- build . display ( ) ;
164
149
165
- json = json . concat ( build . formatAsJson ( ) ) ;
166
- if ( ( argv . copy || argv . markdown ) && ! argv . stats ) {
167
- markdown += build . formatAsMarkdown ( ) ;
150
+ const { cli, queue, argv, request } = this ;
151
+
152
+ for ( let i = 0 ; i < queue . length ; ++ i ) {
153
+ const job = queue [ i ] ;
154
+ cli . separator ( '' ) ;
155
+ const progress = `[${ i + 1 } /${ queue . length } ]` ;
156
+ if ( job . link ) {
157
+ cli . log ( `${ progress } Running ${ job . link } ` ) ;
158
+ } else if ( job . jobid ) {
159
+ cli . log ( `${ progress } Running ${ job . type } : ${ job . jobid } ` ) ;
160
+ } else {
161
+ cli . log ( `${ progress } Running ${ job . type } ` ) ;
162
+ }
163
+ cli . separator ( '' ) ;
164
+
165
+ let build ;
166
+ switch ( job . type ) {
167
+ case 'health' :
168
+ build = new HealthBuild ( cli , request , job . ciType , job . builds ) ;
169
+ break ;
170
+ case PR :
171
+ build = new PRBuild ( cli , request , job . jobid ) ;
172
+ break ;
173
+ case COMMIT :
174
+ build = new CommitBuild ( cli , request , job . jobid ) ;
175
+ break ;
176
+ case BENCHMARK :
177
+ build = new BenchmarkRun ( cli , request , job . jobid ) ;
178
+ break ;
179
+ default :
180
+ throw new Error ( `Unknown job type ${ job . type } ` ) ;
181
+ }
182
+
183
+ await build . getResults ( ) ;
184
+ build . display ( ) ;
185
+
186
+ const json = build . formatAsJson ( ) ;
187
+ if ( json !== undefined ) {
188
+ this . json = this . json . concat ( json ) ;
189
+ }
190
+ if ( ( argv . copy || argv . markdown ) && ! argv . stats ) {
191
+ this . markdown += build . formatAsMarkdown ( ) ;
192
+ }
168
193
}
169
194
}
170
195
171
- return {
172
- json ,
173
- markdown
174
- } ;
175
- }
196
+ async aggregate ( ) { // noop
197
+ }
198
+
199
+ async serialize ( ) {
200
+ const { argv , cli } = this ;
176
201
177
- function pad ( any , length ) {
178
- return ( any + '' ) . padEnd ( length ) ;
202
+ if ( argv . copy ) {
203
+ if ( this . markdown ) {
204
+ clipboardy . writeSync ( this . markdown ) ;
205
+ cli . separator ( '' ) ;
206
+ cli . log ( `Written markdown to clipboard` ) ;
207
+ } else {
208
+ cli . error ( 'No markdown generated' ) ;
209
+ }
210
+ }
211
+
212
+ if ( argv . markdown ) {
213
+ if ( this . markdown ) {
214
+ writeFile ( argv . markdown , this . markdown ) ;
215
+ cli . separator ( '' ) ;
216
+ cli . log ( `Written markdown to ${ argv . markdown } ` ) ;
217
+ } else {
218
+ cli . error ( 'No markdown generated' ) ;
219
+ }
220
+ }
221
+
222
+ if ( argv . json ) {
223
+ if ( this . json . length ) {
224
+ writeJson ( argv . json , this . json ) ;
225
+ cli . separator ( '' ) ;
226
+ cli . log ( `Written JSON to ${ argv . json } ` ) ;
227
+ } else {
228
+ cli . error ( 'No JSON generated' ) ;
229
+ }
230
+ }
231
+ }
179
232
}
180
233
181
- // Produces a row for https://github.com/nodejs/reliability#ci-health-history
182
- function displayHealth ( builds , cli ) {
183
- const [
184
- count , success , pending , aborted , failed , unstable
185
- ] = [
186
- builds . count , builds . success . length , builds . pending . length ,
187
- builds . aborted . length , builds . failed . length , builds . unstable . length
188
- ] ;
189
- const rate = `${ ( success / ( count - pending - aborted ) * 100 ) . toFixed ( 2 ) } %` ;
190
- // eslint-disable-next-line max-len
191
- cli . log ( '| UTC Time | RUNNING | SUCCESS | UNSTABLE | ABORTED | FAILURE | Green Rate |' ) ;
192
- // eslint-disable-next-line max-len
193
- cli . log ( '| ---------------- | ------- | ------- | -------- | ------- | ------- | ---------- |' ) ;
194
- const time = new Date ( ) . toISOString ( ) . slice ( 0 , 16 ) . replace ( 'T' , ' ' ) ;
195
- let result = `| ${ time } | ${ pad ( pending , 7 ) } | ${ pad ( success , 8 ) } |` ;
196
- result += ` ${ pad ( unstable , 8 ) } | ${ pad ( aborted , 7 ) } | ${ pad ( failed , 7 ) } |` ;
197
- result += ` ${ pad ( rate , 10 ) } |` ;
198
- cli . log ( result ) ;
234
+ class RateCommand extends CICommand {
235
+ async initialize ( ) {
236
+ this . queue . push ( {
237
+ type : 'health' ,
238
+ ciType : commandToType [ this . argv . type ]
239
+ } ) ;
240
+ }
199
241
}
200
242
201
- async function main ( command , argv ) {
202
- const cli = new CLI ( ) ;
203
- const credentials = await auth ( {
204
- github : true ,
205
- jenkins : true
206
- } ) ;
207
- const request = new Request ( credentials ) ;
208
- const queue = [ ] ;
243
+ class WalkCommand extends CICommand {
244
+ constructor ( cli , request , argv ) {
245
+ super ( cli , request , argv ) ;
246
+ if ( argv . cache ) {
247
+ jobCache . enable ( ) ;
248
+ }
249
+ }
209
250
210
- const commandToType = {
211
- 'commit' : COMMIT ,
212
- 'pr' : PR ,
213
- 'benchmark' : BENCHMARK
214
- } ;
251
+ async initialize ( ) {
252
+ const ciType = commandToType [ this . argv . type ] ;
253
+ const builds = await listBuilds ( this . cli , this . request , ciType ) ;
254
+ this . queue . push ( { type : 'health' , ciType, builds } ) ;
255
+ for ( const build of builds . failed . slice ( 0 , this . argv . limit ) ) {
256
+ this . queue . push ( build ) ;
257
+ }
258
+ }
215
259
216
- if ( command === 'rate' || command === 'walk' ) {
217
- const type = commandToType [ argv . type ] ;
218
- const builds = await listBuilds ( cli , request , type ) ;
219
- if ( command === 'walk' ) {
220
- if ( argv . cache ) {
221
- jobCache . enable ( ) ;
222
- }
223
- for ( const build of builds . failed . slice ( 0 , argv . limit ) ) {
224
- queue . push ( build ) ;
225
- }
226
- } else {
227
- displayHealth ( builds , cli ) ;
260
+ async aggregate ( ) {
261
+ const { argv, cli } = this ;
262
+ const aggregator = new FailureAggregator ( cli , this . json ) ;
263
+ this . json = aggregator . aggregate ( ) ;
264
+ cli . log ( '' ) ;
265
+ cli . separator ( 'Stats' ) ;
266
+ cli . log ( '' ) ;
267
+ aggregator . display ( ) ;
268
+
269
+ if ( argv . markdown || argv . copy ) {
270
+ this . markdown = aggregator . formatAsMarkdown ( ) ;
228
271
}
229
272
}
273
+ }
274
+
275
+ class JobCommand extends CICommand {
276
+ constructor ( cli , request , argv , command ) {
277
+ super ( cli , request , argv ) ;
278
+ this . command = command ;
279
+ }
280
+
281
+ async initialize ( ) {
282
+ this . queue . push ( {
283
+ type : commandToType [ this . command ] ,
284
+ jobid : this . argv . jobid
285
+ } ) ;
286
+ }
287
+ }
230
288
231
- if ( command === 'url' ) {
289
+ class URLCommand extends CICommand {
290
+ async initialize ( ) {
291
+ const { argv, cli, request, queue } = this ;
232
292
let parsed = parseJobFromURL ( argv . url ) ;
233
293
if ( parsed ) {
234
294
queue . push ( {
235
295
type : parsed . type ,
236
296
jobid : parsed . jobid
237
297
} ) ;
238
- } else {
239
- const parser = await JobParser . fromPR ( argv . url , cli , request ) ;
240
- if ( ! parser ) { // Not a valid PR URL
241
- return yargs . showHelp ( ) ;
242
- }
243
- const ciMap = parser . parse ( ) ;
244
- for ( const [ type , ci ] of ciMap ) {
245
- queue . push ( {
246
- type : type ,
247
- jobid : ci . jobid
248
- } ) ;
249
- }
298
+ return ;
250
299
}
251
- } else if ( commandToType [ command ] ) {
252
- queue . push ( {
253
- type : commandToType [ command ] ,
254
- jobid : argv . jobid
255
- } ) ;
256
- }
257
300
258
- if ( queue . length > 0 ) {
259
- const data = await runQueue ( queue , cli , request , argv ) ;
301
+ // Parse CI links from PR.
302
+ const parser = await JobParser . fromPR ( argv . url , cli , request ) ;
303
+ if ( ! parser ) { // Not a valid PR URL
304
+ cli . error ( `${ argv . url } is not a valid PR URL` ) ;
305
+ return ;
306
+ }
307
+ const ciMap = parser . parse ( ) ;
308
+ if ( ciMap . size === 0 ) {
309
+ cli . info ( `No CI run detected from ${ argv . url } ` ) ;
310
+ }
311
+ for ( const [ type , ci ] of ciMap ) {
312
+ queue . push ( {
313
+ type : type ,
314
+ jobid : ci . jobid
315
+ } ) ;
316
+ }
317
+ }
318
+ }
260
319
261
- if ( command === 'walk' && argv . stats ) {
262
- const aggregator = new FailureAggregator ( cli , data . json ) ;
263
- data . json = aggregator . aggregate ( ) ;
264
- cli . log ( '' ) ;
265
- cli . separator ( 'Stats' ) ;
266
- cli . log ( '' ) ;
267
- aggregator . display ( ) ;
320
+ async function main ( command , argv ) {
321
+ const cli = new CLI ( ) ;
322
+ const credentials = await auth ( {
323
+ github : true ,
324
+ jenkins : true
325
+ } ) ;
326
+ const request = new Request ( credentials ) ;
268
327
269
- if ( argv . markdown || argv . copy ) {
270
- data . markdown = aggregator . formatAsMarkdown ( ) ;
271
- }
328
+ let commandHandler ;
329
+ // Prepare queue.
330
+ switch ( command ) {
331
+ case 'rate' : {
332
+ commandHandler = new RateCommand ( cli , request , argv ) ;
333
+ break ;
272
334
}
273
-
274
- if ( argv . copy ) {
275
- clipboardy . writeSync ( data . markdown ) ;
276
- cli . separator ( '' ) ;
277
- cli . log ( `Written markdown to clipboard` ) ;
335
+ case 'walk' : {
336
+ commandHandler = new WalkCommand ( cli , request , argv ) ;
337
+ break ;
278
338
}
279
-
280
- if ( argv . markdown ) {
281
- writeFile ( argv . markdown , data . markdown ) ;
282
- cli . separator ( '' ) ;
283
- cli . log ( `Written markdown to ${ argv . markdown } ` ) ;
339
+ case 'url' : {
340
+ commandHandler = new URLCommand ( cli , request , argv ) ;
341
+ break ;
284
342
}
285
-
286
- if ( argv . json ) {
287
- writeJson ( argv . json , data . json ) ;
288
- cli . separator ( '' ) ;
289
- cli . log ( `Written JSON to ${ argv . json } ` ) ;
343
+ case 'pr' :
344
+ case 'commit' :
345
+ case 'benchmark' : {
346
+ commandHandler = new JobCommand ( cli , request , argv , command ) ;
347
+ break ;
290
348
}
349
+ default :
350
+ return yargs . showHelp ( ) ;
291
351
}
352
+
353
+ await commandHandler . initialize ( ) ;
354
+ await commandHandler . drain ( ) ;
355
+ await commandHandler . aggregate ( ) ;
356
+ await commandHandler . serialize ( ) ;
292
357
}
293
358
294
359
function handler ( argv ) {
0 commit comments