@@ -8,11 +8,14 @@ const CIFailureParser = require('./ci_failure_parser');
8
8
const {
9
9
FAILURE_TYPES : {
10
10
BUILD_FAILURE ,
11
- NCU_FAILURE
11
+ NCU_FAILURE ,
12
+ GIT_FAILURE ,
13
+ RESUME_FAILURE
12
14
} ,
13
15
FAILURE_CONSTRUCTORS : {
14
16
[ BUILD_FAILURE ] : BuildFailure ,
15
- [ NCU_FAILURE ] : NCUFailure
17
+ [ NCU_FAILURE ] : NCUFailure ,
18
+ [ RESUME_FAILURE ] : ResumeFailure
16
19
} ,
17
20
CIResult,
18
21
FAILURE_TYPES_NAME
@@ -46,11 +49,12 @@ const COMMIT_TREE =
46
49
`subBuilds[${ BUILD_FIELDS } ]` ;
47
50
// com.tikal.jenkins.plugins.multijob.MultiJobBuild
48
51
const FANNED_TREE =
49
- `result,url,number,subBuilds[phaseName,${ BUILD_FIELDS } ],builtOn ` ;
52
+ `result,url,number,subBuilds[phaseName,${ BUILD_FIELDS } ]` ;
50
53
// hudson.matrix.MatrixBuild
51
54
const BUILD_TREE = 'result,runs[url,number,result],builtOn' ;
52
55
const LINTER_TREE = 'result,url,number,builtOn' ;
53
- const RUN_TREE = 'actions[causes[upstreamBuild,upstreamProject]],builtOn' ;
56
+ const CAUSE_TREE = 'upstreamBuild,upstreamProject,shortDescription,_class' ;
57
+ const RUN_TREE = `actions[causes[${ CAUSE_TREE } ]],builtOn` ;
54
58
55
59
function getPath ( url ) {
56
60
return url . replace ( `https://${ CI_DOMAIN } /` , '' ) . replace ( 'api/json' , '' ) ;
@@ -128,6 +132,13 @@ class Job {
128
132
return data ;
129
133
}
130
134
135
+ getCause ( actions ) {
136
+ if ( actions && actions . find ( item => item . causes ) ) {
137
+ const action = actions . find ( item => item . causes ) ;
138
+ return action . causes [ 0 ] ;
139
+ }
140
+ }
141
+
131
142
async getAPIData ( ) {
132
143
const { cli, request, path } = this ;
133
144
const url = this . apiUrl ;
@@ -355,7 +366,9 @@ function getHighlight(f) {
355
366
)
356
367
. replace (
357
368
/ f a t a l : l o o s e o b j e c t \w + \( s t o r e d i n .g i t \/ o b j e c t s \/ .+ \) i s c o r r u p t / ,
358
- 'fatal: loose object ... (stored in .git/objects/...) is corrupt' ) ;
369
+ 'fatal: loose object ... (stored in .git/objects/...) is corrupt' )
370
+ . replace ( / h u d s o n \. p l u g i n s \. g i t \. G i t E x c e p t i o n : / , '' )
371
+ . replace ( / j a v a \. i o \. I O E x c e p t i o n : / , '' ) ;
359
372
}
360
373
361
374
function markdownRow ( ...args ) {
@@ -427,13 +440,15 @@ class FailureAggregator {
427
440
output += `[${ jobName } /${ first . jobid } ](${ first . link } ) to ` ;
428
441
output += `[${ jobName } /${ last . jobid } ](${ last . link } ) ` ;
429
442
output += `that failed more than 2 PRs\n` ;
443
+ output += `(Generated with \`ncu-ci ` ;
444
+ output += `${ process . argv . slice ( 2 ) . join ( ' ' ) } \`)\n` ;
430
445
const todo = [ ] ;
431
446
for ( const type of Object . keys ( aggregates ) ) {
432
447
output += `\n### ${ FAILURE_TYPES_NAME [ type ] } \n\n` ;
433
448
for ( const item of aggregates [ type ] ) {
434
449
const { reason, type, prs, failures, machines } = item ;
435
450
if ( prs . length < 2 ) { continue ; }
436
- todo . push ( reason ) ;
451
+ todo . push ( { count : prs . length , reason } ) ;
437
452
output += markdownRow ( 'Reason' , `<code>${ reason } </code>` ) ;
438
453
output += markdownRow ( '-' , ':-' ) ;
439
454
output += markdownRow ( 'Type' , type ) ;
@@ -449,16 +464,19 @@ class FailureAggregator {
449
464
}
450
465
output += markdownRow ( 'Last CI' , `${ prs [ prs . length - 1 ] . upstream } ` ) ;
451
466
output += '\n' ;
467
+ const example = failures [ 0 ] . reason ;
452
468
output += fold (
453
469
`<a href="${ failures [ 0 ] . url } ">Example</a>` ,
454
- failures [ 0 ] . reason
470
+ ( example . length > 1024 ? example . slice ( 0 , 1024 ) + '...' : example )
455
471
) ;
456
472
output += '\n\n-------\n\n' ;
457
473
}
458
474
}
459
475
460
476
output += '### Progress\n\n' ;
461
- output += todo . map ( i => `- \`${ i } \`` ) . join ( '\n' ) ;
477
+ output += todo . map (
478
+ ( { count, reason} ) => `- \`${ reason } \` (${ count } )` ) . join ( '\n'
479
+ ) ;
462
480
return output + '\n' ;
463
481
}
464
482
@@ -559,7 +577,10 @@ class CommitBuild extends TestBuild {
559
577
cli . startSpinner ( `Querying failures of ${ path } ` ) ;
560
578
const promises = builds . failed . map ( ( { jobName, buildNumber, url} ) => {
561
579
if ( jobName . includes ( 'fanned' ) ) {
562
- return new FannedBuild ( cli , request , jobName , buildNumber ) . getResults ( ) ;
580
+ const cause = this . getCause ( data . actions ) ;
581
+ const isResumed = cause && cause . _class . includes ( 'ResumeCause' ) ;
582
+ return new FannedBuild ( cli , request , jobName , buildNumber , isResumed )
583
+ . getResults ( ) ;
563
584
} else if ( jobName . includes ( 'linter' ) ) {
564
585
return new LinterBuild ( cli , request , jobName , buildNumber ) . getResults ( ) ;
565
586
} else if ( jobName . includes ( 'freestyle' ) ) {
@@ -622,6 +643,7 @@ class PRBuild extends TestBuild {
622
643
const allBuilds = commitBuild . build . subBuilds ;
623
644
// TODO: fetch result, builtOn, timestamp in the commit build's own data
624
645
// ..or maybe they do not worth an additional API call?
646
+ // Note that we have to pass the actions down to detect resume builds.
625
647
const buildData = {
626
648
result, subBuilds : allBuilds , changeSet, actions, timestamp
627
649
} ;
@@ -682,14 +704,15 @@ async function listBuilds(cli, request, type) {
682
704
}
683
705
684
706
class FannedBuild extends Job {
685
- constructor ( cli , request , jobName , id ) {
707
+ constructor ( cli , request , jobName , id , isResumed ) {
686
708
// assert(jobName.includes('fanned'));
687
709
const path = `job/${ jobName } /${ id } /` ;
688
710
const tree = FANNED_TREE ;
689
711
super ( cli , request , path , tree ) ;
690
712
691
713
this . failures = [ ] ;
692
714
this . builtOn = undefined ;
715
+ this . isResumed = isResumed ;
693
716
}
694
717
695
718
// Get the failures and their reasons of this build
@@ -724,17 +747,33 @@ class FannedBuild extends Job {
724
747
! failedPhase . phaseName . toLowerCase ( ) . includes ( 'compilation' ) ) {
725
748
this . failures = [
726
749
new BuildFailure (
727
- { url : failedPhase . url , builtOn : failedPhase . builtOn } ,
728
- `Failed in ${ failedPhase . phaseName } phase`
750
+ { url : failedPhase . url } ,
751
+ `Failed in ${ failedPhase . phaseName } phase (${ failedPhase . jobName } )`
752
+ // TODO: parse console text for the failed phase
729
753
)
730
754
] ;
731
755
return this . failures ;
732
756
}
733
757
734
758
const { jobName, buildNumber } = failedPhase ;
735
759
const build = new NormalBuild ( cli , request , jobName , buildNumber ) ;
736
- const failures = await build . getResults ( ) ;
737
- this . failures = flatten ( failures ) ;
760
+ let failures = await build . getResults ( ) ;
761
+ failures = flatten ( failures ) ;
762
+
763
+ if ( this . isResumed ) {
764
+ // XXX: if it's a resumed build, we replace the build/git failures
765
+ // with resume failures. Probably just a random guess, though
766
+ for ( let i = 0 ; i < failures . length ; ++ i ) {
767
+ const item = failures [ i ] ;
768
+ if ( item . type === BUILD_FAILURE || item . type === GIT_FAILURE ) {
769
+ failures [ i ] = new ResumeFailure (
770
+ item ,
771
+ `Possible resume failure\n${ item . reason } `
772
+ ) ;
773
+ }
774
+ }
775
+ }
776
+ this . failures = failures ;
738
777
return this . failures ;
739
778
}
740
779
}
@@ -853,10 +892,7 @@ class TestRun extends Job {
853
892
] ;
854
893
return this . failures ;
855
894
}
856
- if ( data . actions && data . actions . find ( item => item . causes ) ) {
857
- const actions = data . actions . find ( item => item . causes ) ;
858
- this . cause = actions . causes [ 0 ] ;
859
- }
895
+ this . causes = this . getCause ( data . actions ) || { } ;
860
896
this . builtOn = data . builtOn ;
861
897
}
862
898
0 commit comments