@@ -50,15 +50,24 @@ const PR_TREE =
50
50
const COMMIT_TREE =
51
51
`result,url,number,${ ACTION_TREE } ,${ CHANGE_TREE } ,builtOn,` +
52
52
`subBuilds[${ BUILD_FIELDS } ]` ;
53
+ const CITGM_MAIN_TREE =
54
+ `result,url,number,${ ACTION_TREE } ,${ CHANGE_TREE } ,builtOn` ;
55
+
53
56
// com.tikal.jenkins.plugins.multijob.MultiJobBuild
54
57
const FANNED_TREE =
55
58
`result,url,number,subBuilds[phaseName,${ BUILD_FIELDS } ]` ;
59
+
56
60
// hudson.matrix.MatrixBuild
57
61
const BUILD_TREE = 'result,runs[url,number,result],builtOn' ;
58
62
const LINTER_TREE = 'result,url,number,builtOn' ;
59
63
const CAUSE_TREE = 'upstreamBuild,upstreamProject,shortDescription,_class' ;
60
64
const RUN_TREE = `actions[causes[${ CAUSE_TREE } ]],builtOn` ;
61
65
66
+ // hudson.tasks.test.MatrixTestResult
67
+ const RESULT_TREE = 'result[suites[cases[name,status]]]' ;
68
+ const CITGM_REPORT_TREE =
69
+ `failCount,skipCount,totalCount,childReports[child[url],${ RESULT_TREE } ]` ;
70
+
62
71
function getPath ( url ) {
63
72
return url . replace ( `https://${ CI_DOMAIN } /` , '' ) . replace ( 'api/json' , '' ) ;
64
73
}
@@ -115,11 +124,11 @@ class Job {
115
124
return `https://${ CI_DOMAIN } /${ path } console` ;
116
125
}
117
126
118
- async getBuildData ( ) {
127
+ async getBuildData ( type = 'Build' ) {
119
128
const { cli, path } = this ;
120
129
cli . startSpinner ( `Querying data for ${ path } ` ) ;
121
130
const data = await this . getAPIData ( ) ;
122
- cli . stopSpinner ( 'Build data downloaded' ) ;
131
+ cli . stopSpinner ( ` ${ type } data downloaded` ) ;
123
132
return data ;
124
133
}
125
134
@@ -133,13 +142,13 @@ class Job {
133
142
async getAPIData ( ) {
134
143
const { cli, request, path } = this ;
135
144
const url = this . apiUrl ;
136
- cli . updateSpinner ( `Querying API of ${ path } ` ) ;
145
+ cli . updateSpinner ( `Querying API for ${ path } ` ) ;
137
146
return request . json ( url ) ;
138
147
}
139
148
140
149
async getConsoleText ( ) {
141
150
const { cli, request, path } = this ;
142
- cli . updateSpinner ( `Querying console text of ${ path } ` ) ;
151
+ cli . updateSpinner ( `Querying console text for ${ path } ` ) ;
143
152
const data = await request . text ( this . consoleUrl ) ;
144
153
return data . replace ( / \r / g, '' ) ;
145
154
}
@@ -334,10 +343,13 @@ class TestBuild extends Job {
334
343
}
335
344
336
345
formatAsJson ( ) {
337
- const result = this . failures . map ( item => Object . assign ( {
338
- source : this . sourceURL ,
339
- upstream : this . jobUrl
346
+ const { jobUrl, failures, sourceURL } = this ;
347
+
348
+ const result = failures . map ( item => Object . assign ( {
349
+ source : sourceURL ,
350
+ upstream : jobUrl
340
351
} , item ) ) ;
352
+
341
353
return JSON . parse ( JSON . stringify ( result ) ) ;
342
354
}
343
355
}
@@ -740,6 +752,147 @@ class PRBuild extends TestBuild {
740
752
}
741
753
}
742
754
755
+ class CITGMBuild extends TestBuild {
756
+ constructor ( cli , request , id ) {
757
+ const path = `job/citgm-smoker/${ id } /` ;
758
+ const tree = CITGM_MAIN_TREE ;
759
+
760
+ super ( cli , request , path , tree ) ;
761
+
762
+ this . id = id ;
763
+ }
764
+
765
+ async getResults ( ) {
766
+ const { id } = this ;
767
+
768
+ let headerData ;
769
+ try {
770
+ headerData = await this . getBuildData ( 'Summary' ) ;
771
+ } catch ( err ) {
772
+ this . failures = [
773
+ new NCUFailure ( { url : this . apiUrl } , err . message )
774
+ ] ;
775
+ return this . failures ;
776
+ }
777
+ const { result } = headerData ;
778
+
779
+ this . setBuildData ( headerData ) ;
780
+
781
+ // CITGM jobs store results in a different location than
782
+ // they do summary data, so we need to update the endpoint
783
+ // and issue a second API call in order to fetch result data.
784
+ this . tree = CITGM_REPORT_TREE ;
785
+ this . path = `job/citgm-smoker/${ this . id } /testReport/` ;
786
+
787
+ let resultData ;
788
+ try {
789
+ resultData = await this . getBuildData ( 'Results' ) ;
790
+ } catch ( err ) {
791
+ this . failures = [
792
+ new NCUFailure ( { url : this . apiUrl } , err . message )
793
+ ] ;
794
+ return this . failures ;
795
+ }
796
+
797
+ this . results = this . parseResults ( resultData ) ;
798
+
799
+ // Update id again so that it correctly displays in Summary output.
800
+ this . path = `job/citgm-smoker/${ id } /` ;
801
+
802
+ return { result } ;
803
+ }
804
+
805
+ parseResults ( data ) {
806
+ const { childReports, totalCount, skipCount, failCount } = data ;
807
+ const results = { all : { } , failures : { } , statistics : { } } ;
808
+
809
+ const passCount = totalCount - failCount - skipCount ;
810
+ results . statistics . passed = passCount ;
811
+ results . statistics . total = totalCount ;
812
+ results . statistics . skipped = skipCount ;
813
+ results . statistics . failed = failCount ;
814
+
815
+ childReports . forEach ( platform => {
816
+ const cases = flatten ( platform . result . suites [ 0 ] . cases ) ;
817
+ const url = platform . child . url ;
818
+ const nodeName = getNodeName ( url ) ;
819
+
820
+ results . all [ nodeName ] = { url, modules : cases } ;
821
+
822
+ const failedModules = cases . filter ( c => c . status === 'FAILED' ) ;
823
+ results . failures [ nodeName ] = { url, modules : failedModules } ;
824
+ } ) ;
825
+
826
+ return results ;
827
+ }
828
+
829
+ displayBuilds ( ) {
830
+ const { cli, results } = this ;
831
+ const { failed, skipped, passed, total } = results . statistics ;
832
+
833
+ cli . separator ( 'Statistics' ) ;
834
+ console . table ( {
835
+ Failed : failed ,
836
+ Skipped : skipped ,
837
+ Passed : passed ,
838
+ Total : total
839
+ } ) ;
840
+
841
+ cli . separator ( 'Failures' ) ;
842
+ const output = { } ;
843
+ for ( const platform in results . failures ) {
844
+ const modules = results . failures [ platform ] . modules ;
845
+ const failures = modules . map ( f => f . name ) ;
846
+
847
+ output [ platform ] = failures ;
848
+ }
849
+
850
+ console . table ( output ) ;
851
+ }
852
+
853
+ formatAsJson ( ) {
854
+ const { jobUrl, results, sourceURL } = this ;
855
+
856
+ const result = {
857
+ source : sourceURL ,
858
+ upstream : jobUrl ,
859
+ ...results . statistics ,
860
+ ...results . failures
861
+ } ;
862
+
863
+ return JSON . parse ( JSON . stringify ( result ) ) ;
864
+ }
865
+
866
+ formatAsMarkdown ( ) {
867
+ const { jobUrl, result, results, id } = this ;
868
+
869
+ let output = `# CITGM Data for [${ id } ](${ jobUrl } )\n\n` ;
870
+
871
+ const { failed, skipped, passed, total } = results . statistics ;
872
+
873
+ output += `## Statistics for job [${ id } ](${ jobUrl } )\n\n` ;
874
+ output += '| FAILED | SKIPPED | PASSED | TOTAL |\n' ;
875
+ output += '| -------- | --------- | -------- | ------- |\n' ;
876
+ output += `| ${ pad ( failed , 8 ) } | ${ pad ( skipped , 9 ) } |` ;
877
+ output += ` ${ pad ( passed , 8 ) } | ${ pad ( total , 7 ) } |\n\n` ;
878
+
879
+ if ( result === SUCCESS ) {
880
+ output += `Job [${ id } ](${ jobUrl } ) is green.` ;
881
+ return output ;
882
+ }
883
+
884
+ output += `## Failures in job [${ id } ](${ jobUrl } )\n\n` ;
885
+ for ( const failure in results . failures ) {
886
+ const data = results . failures [ failure ] ;
887
+ output += `### [${ failure } ](${ data . url } )\n\n` ;
888
+
889
+ const failures = data . modules . map ( f => `* ${ f . name } ` ) ;
890
+ output += `${ failures . join ( '\n' ) } \n\n` ;
891
+ }
892
+ return output ;
893
+ }
894
+ }
895
+
743
896
function filterBuild ( builds , type ) {
744
897
return builds
745
898
. filter ( build => build . result === type )
@@ -1034,6 +1187,7 @@ module.exports = {
1034
1187
PRBuild,
1035
1188
BenchmarkRun,
1036
1189
CommitBuild,
1190
+ CITGMBuild,
1037
1191
HealthBuild,
1038
1192
jobCache,
1039
1193
parseJobFromURL,
0 commit comments