Skip to content

Commit fd566e2

Browse files
codebyterepriyank-p
authored andcommitted
chore: split CI builds to new files
1 parent 48c306b commit fd566e2

16 files changed

+914
-811
lines changed

bin/ncu-ci

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,20 @@ const {
1515
}
1616
} = require('../lib/ci/ci_type_parser');
1717

18+
const { listBuilds } = require('../lib/ci/ci_utils');
19+
20+
const { jobCache } = require('../lib/ci/build-types/job');
21+
const { PRBuild } = require('../lib/ci/build-types/pr_build');
22+
const { CommitBuild } = require('../lib/ci/build-types/commit_build');
23+
const { DailyBuild } = require('../lib/ci/build-types/daily_build');
24+
const { FailureAggregator } = require('../lib/ci/failure_aggregator');
25+
const { BenchmarkRun } = require('../lib/ci/build-types/benchmark_run');
26+
const { HealthBuild } = require('../lib/ci/build-types/health_build');
27+
const { CITGMBuild } = require('../lib/ci/build-types/citgm_build');
1828
const {
19-
PRBuild,
20-
BenchmarkRun,
21-
CommitBuild,
22-
CITGMBuild,
23-
DailyBuild,
24-
CITGMComparisonBuild,
25-
HealthBuild,
26-
listBuilds,
27-
FailureAggregator,
28-
jobCache
29-
} = require('../lib/ci/ci_result_parser');
29+
CITGMComparisonBuild
30+
} = require('../lib/ci/build-types/citgm_comparison_build');
31+
3032
const {
3133
RunPRJob
3234
} = require('../lib/ci/run_ci');

lib/ci/build-types/benchmark_run.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
'use strict';
2+
3+
const { Job } = require('./job');
4+
const { fold } = require('../ci_utils');
5+
6+
class BenchmarkRun extends Job {
7+
constructor(cli, request, id) {
8+
const path = `job/benchmark-node-micro-benchmarks/${id}/`;
9+
super(cli, request, path);
10+
11+
this.results = '';
12+
this.significantResults = '';
13+
}
14+
15+
async getResults() {
16+
const { path, cli } = this;
17+
cli.startSpinner(`Querying results of ${path}`);
18+
const text = await this.getConsoleText();
19+
const index = text.indexOf('improvement');
20+
if (index === -1) {
21+
throw new Error('Not finished');
22+
}
23+
const breakIndex = text.lastIndexOf('\n', index);
24+
const results = text.slice(breakIndex + 1)
25+
.replace(/\nSending e-mails[\s\S]+/mg, '');
26+
this.results = results;
27+
cli.stopSpinner('Data downloaded');
28+
this.significantResults = this.getSignificantResults(results);
29+
return results;
30+
}
31+
32+
getSignificantResults(data) {
33+
const lines = data.split('\n');
34+
const significant = lines.filter(line => line.indexOf('*') !== -1);
35+
return significant.slice(0, -3).join('\n');
36+
}
37+
38+
display() {
39+
const { cli, results, significantResults } = this;
40+
cli.log(results);
41+
cli.separator('significant results');
42+
cli.log(significantResults);
43+
}
44+
45+
formatAsMarkdown() {
46+
const { results, significantResults } = this;
47+
const output = (fold('Benchmark results', results) + '\n\n' +
48+
fold('Significant impact', significantResults) + '\n');
49+
return output;
50+
}
51+
52+
formatAsJson() {
53+
const results = this.significantResults.split('\n').slice(1);
54+
const json = [];
55+
for (const line of results) {
56+
const star = line.indexOf('*');
57+
const name = line.slice(0, star).trim();
58+
const [file, ...config] = name.split(' ');
59+
const confidence = line.match(/(\*+)/)[1];
60+
const lastStar = line.lastIndexOf('*');
61+
const [improvement, ...accuracy] =
62+
line.slice(lastStar + 1).split(/\s*%/).map(i => i.trim() + '%');
63+
accuracy.pop(); // remove the last empty item
64+
json.push({
65+
file,
66+
config,
67+
confidence,
68+
improvement,
69+
accuracy
70+
});
71+
}
72+
return json;
73+
}
74+
}
75+
76+
module.exports = { BenchmarkRun };

lib/ci/build-types/commit_build.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
'use strict';
2+
3+
const { TestBuild } = require('./test_build');
4+
const { FannedBuild } = require('./fanned_build');
5+
const { LinterBuild } = require('./linter_build');
6+
const { NormalBuild } = require('./normal_build');
7+
const { TestRun } = require('./test_run');
8+
const { flatten } = require('../../utils');
9+
const { statusType } = require('../ci_utils');
10+
const { COMMIT_TREE } = require('../jenkins_constants');
11+
const {
12+
FAILURE_TYPES: {
13+
BUILD_FAILURE,
14+
NCU_FAILURE
15+
},
16+
FAILURE_CONSTRUCTORS: {
17+
[BUILD_FAILURE]: BuildFailure,
18+
[NCU_FAILURE]: NCUFailure
19+
}
20+
} = require('../ci_failure_parser');
21+
22+
class CommitBuild extends TestBuild {
23+
constructor(cli, request, id) {
24+
const path = `job/node-test-commit/${id}/`;
25+
const tree = COMMIT_TREE;
26+
super(cli, request, path, tree);
27+
}
28+
29+
getBuilds({ result, subBuilds }) {
30+
if (result === statusType.SUCCESS) {
31+
const builds = this.builds = {
32+
failed: [], aborted: [], pending: [], unstable: []
33+
};
34+
return { result: statusType.SUCCESS, builds };
35+
}
36+
37+
const failed = subBuilds.filter(build => {
38+
return build.result === statusType.FAILURE;
39+
});
40+
const aborted = subBuilds.filter(build => {
41+
return build.result === statusType.ABORTED;
42+
});
43+
const pending = subBuilds.filter(build => {
44+
return build.result === null;
45+
});
46+
const unstable = subBuilds.filter(build => {
47+
return build.result === statusType.UNSTABLE;
48+
});
49+
50+
// build: { buildNumber, jobName, result, url }
51+
const builds = this.builds = { failed, aborted, pending, unstable };
52+
return { result, builds };
53+
}
54+
55+
// Get the failures and their reasons of this build
56+
async getResults(data) {
57+
const { path, cli, request } = this;
58+
59+
if (!data) {
60+
try {
61+
data = await this.getBuildData();
62+
} catch (err) {
63+
this.failures = [
64+
new NCUFailure({ url: this.apiUrl }, err.message)
65+
];
66+
return this.failures;
67+
}
68+
}
69+
this.setBuildData(data);
70+
// No builds at all
71+
if (data.result === statusType.FAILURE && !data.subBuilds.length) {
72+
const failure = new BuildFailure(this, 'Failed to trigger sub builds');
73+
this.failures = [failure];
74+
return {
75+
result: data.result,
76+
builds: { failed: [], aborted: [], pending: [], unstable: [] },
77+
failures: this.failures
78+
};
79+
}
80+
81+
const { result, builds } = this.getBuilds(data);
82+
83+
if (result !== statusType.FAILURE) {
84+
return { result, builds, failures: [] };
85+
}
86+
87+
if (!builds.failed.length) {
88+
const failures = await this.parseConsoleText();
89+
return { result, builds, failures };
90+
}
91+
92+
cli.startSpinner(`Querying failures of ${path}`);
93+
const promises = builds.failed.map(({ jobName, buildNumber, url }) => {
94+
if (jobName.includes('fanned')) {
95+
const cause = this.getCause(data.actions);
96+
const isResumed = cause && cause._class.includes('ResumeCause');
97+
return new FannedBuild(cli, request, jobName, buildNumber, isResumed)
98+
.getResults();
99+
} else if (jobName.includes('linter')) {
100+
return new LinterBuild(cli, request, jobName, buildNumber).getResults();
101+
} else if (jobName.includes('freestyle')) {
102+
return new TestRun(cli, request, url).getResults();
103+
}
104+
return new NormalBuild(cli, request, jobName, buildNumber).getResults();
105+
});
106+
const rawFailures = await Promise.all(promises);
107+
108+
const failures = this.failures = flatten(rawFailures);
109+
cli.stopSpinner('Data downloaded');
110+
return { result, failures, builds };
111+
}
112+
}
113+
114+
module.exports = { CommitBuild };

lib/ci/build-types/daily_build.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
3+
const { TestBuild } = require('./test_build');
4+
const { PR_TREE } = require('../jenkins_constants');
5+
6+
class DailyBuild extends TestBuild {
7+
constructor(cli, request, id) {
8+
const path = `job/node-daily-master/${id}/`;
9+
const tree = PR_TREE;
10+
super(cli, request, path, tree);
11+
12+
this.commitBuild = null;
13+
}
14+
15+
formatAsMarkdown() {
16+
if (!this.commitBuild) {
17+
let result = 'Failed to trigger node-daily-master';
18+
if (this.builtOn) {
19+
result += ` on ${this.builtOn}`;
20+
}
21+
result += `\n\nURL: ${this.jobUrl}`;
22+
return result;
23+
}
24+
return super.formatAsMarkdown();
25+
}
26+
}
27+
28+
module.exports = { DailyBuild };

lib/ci/build-types/fanned_build.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
'use strict';
2+
3+
const { Job } = require('./job');
4+
const { NormalBuild } = require('./normal_build');
5+
const { statusType } = require('../ci_utils');
6+
const { flatten } = require('../../utils');
7+
const { FANNED_TREE } = require('../jenkins_constants');
8+
const {
9+
FAILURE_TYPES: {
10+
BUILD_FAILURE,
11+
NCU_FAILURE,
12+
GIT_FAILURE,
13+
RESUME_FAILURE
14+
},
15+
FAILURE_CONSTRUCTORS: {
16+
[BUILD_FAILURE]: BuildFailure,
17+
[NCU_FAILURE]: NCUFailure,
18+
[RESUME_FAILURE]: ResumeFailure
19+
}
20+
} = require('../ci_failure_parser');
21+
22+
class FannedBuild extends Job {
23+
constructor(cli, request, jobName, id, isResumed) {
24+
// assert(jobName.includes('fanned'));
25+
const path = `job/${jobName}/${id}/`;
26+
const tree = FANNED_TREE;
27+
super(cli, request, path, tree);
28+
29+
this.failures = [];
30+
this.builtOn = undefined;
31+
this.isResumed = isResumed;
32+
}
33+
34+
// Get the failures and their reasons of this build
35+
async getResults() {
36+
const { cli, request } = this;
37+
38+
let data;
39+
try {
40+
data = await this.getAPIData();
41+
} catch (err) {
42+
this.failures = [
43+
new NCUFailure({ url: this.apiUrl }, err.message)
44+
];
45+
return this.failures;
46+
}
47+
this.builtOn = data.builtOn;
48+
49+
if (!data.subBuilds.length) {
50+
this.failures = [
51+
new BuildFailure(this, 'Failed to trigger fanned build')
52+
];
53+
return this.failures;
54+
}
55+
56+
const failedPhase = data.subBuilds.find(build => {
57+
return build.result === statusType.FAILURE;
58+
});
59+
60+
if (!failedPhase) {
61+
return this.parseConsoleText();
62+
}
63+
64+
const { jobName, buildNumber } = failedPhase;
65+
const build = new NormalBuild(cli, request, jobName, buildNumber);
66+
let failures = await build.getResults();
67+
if (failures !== undefined) {
68+
failures = flatten(failures);
69+
}
70+
71+
if (this.isResumed) {
72+
// XXX: if it's a resumed build, we replace the build/git failures
73+
// with resume failures. Probably just a random guess, though
74+
for (let i = 0; i < failures.length; ++i) {
75+
const item = failures[i];
76+
if (item.type === BUILD_FAILURE || item.type === GIT_FAILURE) {
77+
failures[i] = new ResumeFailure(
78+
item,
79+
`Possible resume failure\n${item.reason}`
80+
);
81+
}
82+
}
83+
}
84+
this.failures = failures;
85+
return this.failures;
86+
}
87+
}
88+
89+
module.exports = { FannedBuild };

0 commit comments

Comments
 (0)