Skip to content

Commit 336dc7f

Browse files
authored
feat: allow citgm job comparison (#455)
1 parent d4b189b commit 336dc7f

22 files changed

+17881
-522
lines changed

bin/ncu-ci

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const {
2121
CommitBuild,
2222
CITGMBuild,
2323
DailyBuild,
24+
CITGMComparisonBuild,
2425
HealthBuild,
2526
listBuilds,
2627
FailureAggregator,
@@ -113,7 +114,7 @@ const argv = yargs
113114
builder: (yargs) => {
114115
yargs
115116
.positional('jobid', {
116-
describe: 'id of the job',
117+
describe: 'id of the first job',
117118
type: 'number'
118119
});
119120
},
@@ -132,13 +133,17 @@ const argv = yargs
132133
handler
133134
})
134135
.command({
135-
command: 'citgm <jobid>',
136+
command: 'citgm <jobid> [jobid2]',
136137
desc: 'Show results of a citgm-smoker CI job',
137138
builder: (yargs) => {
138139
yargs
139140
.positional('jobid', {
140141
describe: 'id of the job',
141142
type: 'number'
143+
})
144+
.positional('jobid2', {
145+
describe: 'id of the second job, if doing a comparison',
146+
type: 'number'
142147
});
143148
},
144149
handler
@@ -166,12 +171,14 @@ const argv = yargs
166171
})
167172
.demandCommand(1, 'must provide a valid command')
168173
.option('copy', {
174+
describe: 'Write the results as markdown to clipboard',
169175
default: false,
170-
describe: 'Write the results as markdown to clipboard'
176+
type: 'boolean'
171177
})
172178
.option('nobuild', {
173-
describe: 'If running cigtm, whether or not the CITGM job is citgm-nobuild',
174-
type: 'boolean'
179+
describe: 'If running cigtm, whether or not jobid is citgm-nobuild.',
180+
type: 'boolean',
181+
default: false
175182
})
176183
.option('json <path>', {
177184
type: 'string',
@@ -241,7 +248,11 @@ class CICommand {
241248
break;
242249
case CITGM:
243250
case CITGM_NOBUILD:
244-
build = new CITGMBuild(cli, request, job);
251+
if (job.jobid2) {
252+
build = new CITGMComparisonBuild(cli, request, job);
253+
} else {
254+
build = new CITGMBuild(cli, request, job);
255+
}
245256
break;
246257
case BENCHMARK:
247258
build = new BenchmarkRun(cli, request, job.jobid);
@@ -361,10 +372,13 @@ class JobCommand extends CICommand {
361372
}
362373

363374
async initialize() {
364-
this.queue.push({
375+
const { queue, argv } = this;
376+
377+
queue.push({
365378
type: commandToType[this.command],
366-
jobid: this.argv.jobid,
367-
noBuild: this.argv.nobuild || false
379+
jobid: argv.jobid,
380+
jobid2: argv.jobid2,
381+
noBuild: this.argv.nobuild
368382
});
369383
}
370384
}

docs/ncu-ci.md

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ Commands:
2626
2727
Options:
2828
--version Show version number [boolean]
29-
--copy Write the results as markdown to clipboard [default: false]
30-
--nobuild If running cigtm, whether or not the CITGM job is
31-
citgm-nobuild [boolean]
29+
--copy Write the results as markdown to clipboard
30+
[boolean] [default: false]
31+
--nobuild If running cigtm, whether or not jobid is citgm-nobuild.
32+
[boolean] [default: false]
3233
--json <path> Write the results as json to <path> [string]
3334
--markdown <path> Write the results as markdown to <path> [string]
3435
--help Show help [boolean]
@@ -230,13 +231,13 @@ Notifying upstream projects of job completion
230231
Finished: SUCCESS
231232
```
232233
233-
### `ncu-ci citgm <jobid>`
234+
### `ncu-ci citgm <jobid> [jobid2]`
234235
235-
`ncu-ci citgm <jobid>` shows the results of a given citgm-smoker job. See `ncu-ci citgm --help` for more.
236+
`ncu-ci citgm <jobid> [jobid2]` shows the results of a given citgm-smoker job, with the option to compare per-platform results of two jobs. You See `ncu-ci citgm --help` for more.
236237
237238
Example:
238239
```
239-
node on git:master ❯ ncu-ci citgm 2400 10:25AM
240+
node on git:master ❯ ncu-ci citgm 2400
240241
--------------------------------------------------------------------------------
241242
[1/1] Running CITGM: 2400
242243
--------------------------------------------------------------------------------
@@ -264,12 +265,58 @@ Author Shelley Vohr <shelley.vohr@gmail.com>
264265
└────────────────────────┴───────────────────────┴───────────────────────┴─────────────────────────┴─────────────────────┴─────────────────┴────────────────────┘
265266
```
266267
268+
Comparison Example:
269+
```sh
270+
node-core-utils on git:allow-citgm-comparison ❯ ncu-ci citgm 2392 2390
271+
--------------------------------------------------------------------------------
272+
[1/1] Running CITGM: 2392
273+
--------------------------------------------------------------------------------
274+
✔ Summary data downloaded
275+
✔ Results data downloaded
276+
✔ Summary data downloaded
277+
✔ Results data downloaded
278+
----------------------------------- Summary ------------------------------------
279+
Result FAILURE
280+
URL https://ci.nodejs.org/job/citgm-smoker/2392/
281+
Source https://api.github.com/repos/nodejs/node/git/refs/heads/v12.x
282+
Commit [feed95cd4c2c] Working on v12.18.1
283+
Date 2020-06-02 20:27:47 +0200
284+
Author Michaël Zasso <targos@protonmail.com>
285+
----------------------------------- Summary ------------------------------------
286+
Result FAILURE
287+
URL https://ci.nodejs.org/job/citgm-smoker/2390/
288+
Source https://github.com/nodejs/node/pull/33811/
289+
Commit [9a60117875dd] 2020-06-16, Version 12.18.1 'Erbium' (LTS)
290+
Date 2020-06-09 20:23:09 -0700
291+
Author Shelley Vohr <shelley.vohr@gmail.com>
292+
----------------------------------- Results ------------------------------------
293+
294+
295+
296+
FAILURE: 5 failures in 2390 not present in 2392
297+
298+
299+
┌────────────────────────┬───────────────────────────┬────────────────────────────┐
300+
│ (index) │ 0 │ 1 │
301+
├────────────────────────┼───────────────────────────┼────────────────────────────┤
302+
│ centos7-ppcle │ 'multer-v1.4.2' │ │
303+
│ fedora-latest-x64 │ 'spawn-wrap-v2.0.0' │ │
304+
│ fedora-last-latest-x64 │ │ │
305+
│ debian9-64 │ 'express-session-v1.17.1''yeoman-generator-v4.10.1'
306+
│ osx1014 │ │ │
307+
│ rhel7-s390x │ 'torrent-stream-v1.2.0' │ │
308+
│ aix71-ppc64 │ │ │
309+
│ ubuntu1604-64 │ │ │
310+
│ ubuntu1804-64 │ │ │
311+
└────────────────────────┴───────────────────────────┴────────────────────────────┘
312+
```
313+
267314
### `ncu-ci daily`
268315
269316
`ncu-ci daily` show recent results of `node-daily-master`. You can also aggregate the results by passing `--cache`, or limit the maximum number of CIs jobs to get data from with `--limit=N`. See `ncu-ci daily --help` for more.
270317
271318
```sh
272-
node on git:master ❯ ncu-ci daily 12:14PM
319+
node on git:master ❯ ncu-ci daily
273320
✔ Done--------------------------------------------------------------------------------
274321
[1/16] Running health
275322
--------------------------------------------------------------------------------

lib/ci/build-types/citgm_build.js

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
'use strict';
2+
3+
const { TestBuild } = require('./test_build');
4+
const { flatten } = require('../../utils');
5+
const { getNodeName, pad } = require('../ci_utils');
6+
7+
const {
8+
CITGM_MAIN_TREE,
9+
CITGM_REPORT_TREE
10+
} = require('../jenkins_constants');
11+
const {
12+
FAILURE_TYPES: { NCU_FAILURE },
13+
FAILURE_CONSTRUCTORS: {
14+
[NCU_FAILURE]: NCUFailure
15+
}
16+
} = require('../ci_failure_parser');
17+
18+
class CITGMBuild extends TestBuild {
19+
constructor(cli, request, job) {
20+
const { jobid, noBuild } = job;
21+
const path = noBuild
22+
? `job/citgm-smoker-nobuild/${jobid}/`
23+
: `job/citgm-smoker/${jobid}/`;
24+
25+
const tree = CITGM_MAIN_TREE;
26+
27+
super(cli, request, path, tree);
28+
29+
this.id = jobid;
30+
this.noBuild = noBuild;
31+
}
32+
33+
async getResults() {
34+
const { apiUrl } = this;
35+
36+
let headerData;
37+
try {
38+
headerData = await this.getBuildData('Summary');
39+
} catch (err) {
40+
this.failures = [
41+
new NCUFailure({ url: this.apiUrl }, err.message)
42+
];
43+
return this.failures;
44+
}
45+
const { result } = headerData;
46+
47+
this.setBuildData(headerData);
48+
49+
// CITGM jobs store results in a different location than
50+
// they do summary data, so we need to update the endpoint
51+
// and issue a second API call in order to fetch result data.
52+
this.tree = CITGM_REPORT_TREE;
53+
this.updatePath(true);
54+
let resultData;
55+
try {
56+
resultData = await this.getBuildData('Results');
57+
} catch (err) {
58+
this.failures = [
59+
new NCUFailure({ url: apiUrl }, err.message)
60+
];
61+
return this.failures;
62+
}
63+
64+
this.results = this.parseResults(resultData);
65+
66+
// Update id again so that it correctly displays in Summary output.
67+
this.updatePath(false);
68+
69+
return { result };
70+
}
71+
72+
parseResults(data) {
73+
const { childReports, totalCount, skipCount, failCount } = data;
74+
const results = { all: {}, failures: {}, statistics: {} };
75+
const failureStatuses = ['FAILED', 'REGRESSION'];
76+
77+
const passCount = totalCount - failCount - skipCount;
78+
results.statistics.passed = passCount;
79+
results.statistics.total = totalCount;
80+
results.statistics.skipped = skipCount;
81+
results.statistics.failed = failCount;
82+
83+
childReports.forEach(platform => {
84+
const cases = flatten(platform.result.suites[0].cases);
85+
const url = platform.child.url;
86+
const nodeName = getNodeName(url);
87+
88+
results.all[nodeName] = { url, modules: cases };
89+
90+
const failedModules = cases.filter(c => {
91+
return failureStatuses.includes(c.status);
92+
});
93+
94+
results.failures[nodeName] = { url, modules: failedModules };
95+
});
96+
97+
return results;
98+
}
99+
100+
updatePath(testReport) {
101+
const { id, noBuild } = this;
102+
if (testReport) {
103+
this.path = noBuild
104+
? `job/citgm-smoker-nobuild/${id}/testReport/`
105+
: `job/citgm-smoker/${id}/testReport/`;
106+
} else {
107+
this.path = noBuild
108+
? `job/citgm-smoker-nobuild/${id}/`
109+
: `job/citgm-smoker/${id}/`;
110+
}
111+
}
112+
113+
displayBuilds() {
114+
const { cli, results } = this;
115+
const { failed, skipped, passed, total } = results.statistics;
116+
117+
cli.separator('Statistics');
118+
console.table({
119+
Failed: failed,
120+
Skipped: skipped,
121+
Passed: passed,
122+
Total: total
123+
});
124+
125+
cli.separator('Failures');
126+
const output = {};
127+
for (const platform in results.failures) {
128+
const modules = results.failures[platform].modules;
129+
const failures = modules.map(f => f.name);
130+
131+
output[platform] = failures;
132+
}
133+
134+
console.table(output);
135+
}
136+
137+
formatAsJson() {
138+
const { jobUrl, results, sourceURL } = this;
139+
140+
const result = {
141+
source: sourceURL,
142+
upstream: jobUrl,
143+
...results.statistics,
144+
...results.failures
145+
};
146+
147+
return JSON.parse(JSON.stringify(result));
148+
}
149+
150+
formatAsMarkdown() {
151+
const { jobUrl, result, results, id } = this;
152+
153+
let output = `# CITGM Data for [${id}](${jobUrl})\n\n`;
154+
155+
const { failed, skipped, passed, total } = results.statistics;
156+
157+
output += `## Statistics for job [${id}](${jobUrl})\n\n`;
158+
output += '| FAILED | SKIPPED | PASSED | TOTAL |\n';
159+
output += '| -------- | --------- | -------- | ------- |\n';
160+
output += `| ${pad(failed, 8)} | ${pad(skipped, 9)} |`;
161+
output += ` ${pad(passed, 8)} | ${pad(total, 7)} |\n\n`;
162+
163+
if (result === 'success') {
164+
output += `Job [${id}](${jobUrl}) is green.`;
165+
return output;
166+
}
167+
168+
output += `## Failures in job [${id}](${jobUrl})\n\n`;
169+
for (const failure in results.failures) {
170+
const data = results.failures[failure];
171+
output += `### [${failure}](${data.url})\n\n`;
172+
173+
const failures = data.modules.map(f => `* ${f.name}`);
174+
const items = failures.length > 0 ? `${failures.join('\n')}` : 'None.';
175+
output += `${items}\n\n`;
176+
}
177+
178+
return output;
179+
}
180+
}
181+
182+
module.exports = { CITGMBuild };

0 commit comments

Comments
 (0)