Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
refactor: pull some builds into own files
  • Loading branch information
codebytere committed Jul 22, 2020
commit 7d54e4494e18e60bc539376e94b5a27b2f4459e6
12 changes: 10 additions & 2 deletions bin/ncu-ci
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ const argv = yargs
builder: (yargs) => {
yargs
.positional('jobid', {
describe: 'id of the job',
describe: 'id of the first job',
type: 'number'
});
},
Expand Down Expand Up @@ -361,10 +361,18 @@ class JobCommand extends CICommand {
}

async initialize() {
this.queue.push({
const { queue, argv } = this;

queue.push({
type: commandToType[this.command],
<<<<<<< HEAD
jobid: this.argv.jobid,
noBuild: this.argv.nobuild || false
||||||| merged common ancestors
jobid: this.argv.jobid
=======
jobid: argv.jobid
>>>>>>> refactor: pull some builds into own files
});
}
}
Expand Down
160 changes: 160 additions & 0 deletions lib/ci/build-types/citgm_build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
'use strict';

const { TestBuild } = require('./test_build');
const { flatten } = require('../../utils');
const { getNodeName, pad } = require('../ci_utils');

const {
CITGM_MAIN_TREE,
CITGM_REPORT_TREE
} = require('../jenkins_constants');
const {
FAILURE_TYPES: { NCU_FAILURE },
FAILURE_CONSTRUCTORS: {
[NCU_FAILURE]: NCUFailure
}
} = require('./ci_failure_parser');

class CITGMBuild extends TestBuild {
constructor(cli, request, id) {
// There will always be at least one job id.
const path = `job/citgm-smoker/${id}/`;
const tree = CITGM_MAIN_TREE;

super(cli, request, path, tree);

this.id = id;
}

async getResults() {
const { apiUrl, id } = this;

let headerData;
try {
headerData = await this.getBuildData('Summary');
} catch (err) {
this.failures = [
new NCUFailure({ url: this.apiUrl }, err.message)
];
return this.failures;
}
const { result } = headerData;

this.setBuildData(headerData);

// CITGM jobs store results in a different location than
// they do summary data, so we need to update the endpoint
// and issue a second API call in order to fetch result data.
this.tree = CITGM_REPORT_TREE;
this.path = `job/citgm-smoker/${id}/testReport/`;

let resultData;
try {
resultData = await this.getBuildData('Results');
} catch (err) {
this.failures = [
new NCUFailure({ url: apiUrl }, err.message)
];
return this.failures;
}

this.results = this.parseResults(resultData);

// Update id again so that it correctly displays in Summary output.
this.path = `job/citgm-smoker/${id}/`;

return { result };
}

parseResults(data) {
const { childReports, totalCount, skipCount, failCount } = data;
const results = { all: {}, failures: {}, statistics: {} };

const passCount = totalCount - failCount - skipCount;
results.statistics.passed = passCount;
results.statistics.total = totalCount;
results.statistics.skipped = skipCount;
results.statistics.failed = failCount;

childReports.forEach(platform => {
const cases = flatten(platform.result.suites[0].cases);
const url = platform.child.url;
const nodeName = getNodeName(url);

results.all[nodeName] = { url, modules: cases };

const failedModules = cases.filter(c => c.status === 'FAILED');
results.failures[nodeName] = { url, modules: failedModules };
});

return results;
}

displayBuilds() {
const { cli, results } = this;
const { failed, skipped, passed, total } = results.statistics;

cli.separator('Statistics');
console.table({
Failed: failed,
Skipped: skipped,
Passed: passed,
Total: total
});

cli.separator('Failures');
const output = {};
for (const platform in results.failures) {
const modules = results.failures[platform].modules;
const failures = modules.map(f => f.name);

output[platform] = failures;
}

console.table(output);
}

formatAsJson() {
const { jobUrl, results, sourceURL } = this;

const result = {
source: sourceURL,
upstream: jobUrl,
...results.statistics,
...results.failures
};

return JSON.parse(JSON.stringify(result));
}

formatAsMarkdown() {
const { jobUrl, result, results, id } = this;

let output = `# CITGM Data for [${id}](${jobUrl})\n\n`;

const { failed, skipped, passed, total } = results.statistics;

output += `## Statistics for job [${id}](${jobUrl})\n\n`;
output += '| FAILED | SKIPPED | PASSED | TOTAL |\n';
output += '| -------- | --------- | -------- | ------- |\n';
output += `| ${pad(failed, 8)} | ${pad(skipped, 9)} |`;
output += ` ${pad(passed, 8)} | ${pad(total, 7)} |\n\n`;

if (result === 'success') {
output += `Job [${id}](${jobUrl}) is green.`;
return output;
}

output += `## Failures in job [${id}](${jobUrl})\n\n`;
for (const failure in results.failures) {
const data = results.failures[failure];
output += `### [${failure}](${data.url})\n\n`;

const failures = data.modules.map(f => `* ${f.name}`);
output += `${failures.join('\n')}\n\n`;
}
return output;
}
}

module.exports = { CITGMBuild };
116 changes: 116 additions & 0 deletions lib/ci/build-types/job.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
'use strict';

const qs = require('querystring');
const { CI_DOMAIN } = require('../ci_type_parser');
const Cache = require('../../cache');
const CIFailureParser = require('../ci_failure_parser');
const {
FAILURE_TYPES: { NCU_FAILURE },
FAILURE_CONSTRUCTORS: {
[NCU_FAILURE]: NCUFailure
},
CIResult
} = CIFailureParser;

class Job {
constructor(cli, request, path, tree) {
this.cli = cli;
this.request = request;
this.path = path;
this.tree = tree;
}

get jobUrl() {
const { path } = this;
return `https://${CI_DOMAIN}/${path}`;
}

get apiUrl() {
const { tree, jobUrl } = this;
const query = tree ? `?tree=${qs.escape(tree)}` : '';
return `${jobUrl}api/json${query}`;
}

get consoleUrl() {
const { path } = this;
return `https://${CI_DOMAIN}/${path}consoleText`;
}

get consoleUIUrl() {
const { path } = this;
return `https://${CI_DOMAIN}/${path}console`;
}

async getBuildData(type = 'Build') {
const { cli, path } = this;
cli.startSpinner(`Querying data for ${path}`);
const data = await this.getAPIData();
cli.stopSpinner(`${type} data downloaded`);
return data;
}

getCause(actions) {
if (actions && actions.find(item => item.causes)) {
const action = actions.find(item => item.causes);
return action.causes[0];
}
}

async getAPIData() {
const { apiUrl, cli, request, path } = this;
cli.updateSpinner(`Querying API for ${path}`);
return request.json(apiUrl);
}

async getConsoleText() {
const { cli, consoleUrl, request, path } = this;
cli.updateSpinner(`Querying console text for ${path}`);
const data = await request.text(consoleUrl);
return data.replace(/\r/g, '');
}

getCacheKey() {
return this.path
.replace(/job\//, '')
.replace(/\//g, '-')
.replace(/-$/, '');
}

async parseConsoleText() {
let text;
try {
text = await this.getConsoleText();
} catch (err) {
this.failures = [
new NCUFailure({
url: this.consoleUrl, builtOn: this.builtOn
}, err.message)
];
return this.failures;
}

const parser = new CIFailureParser(this, text);
let results = parser.parse();
if (!results) {
results = [
new CIResult({ url: this.jobUrl, builtOn: this.builtOn }, 'Unknown')
];
}

this.failures = results;
return results;
}
}

// TODO(joyeecheung): do not cache pending jobs
const jobCache = new Cache();
jobCache.wrap(Job, {
getConsoleText() {
return { key: this.getCacheKey(), ext: '.txt' };
},
getAPIData() {
return { key: this.getCacheKey(), ext: '.json' };
}
});

module.exports = { Job, jobCache };
Loading