From d4e1ac4df9d2b214863784e5ddcbb4d15f0b3545 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sat, 16 Jun 2018 05:11:36 +0800 Subject: [PATCH] ncu-ci: add `ncu-ci rate` --- bin/ncu-ci | 124 ++++++++++++++++++++++++++++++++++--------------- docs/ncu-ci.md | 9 ++++ lib/ci.js | 2 + 3 files changed, 97 insertions(+), 38 deletions(-) diff --git a/bin/ncu-ci b/bin/ncu-ci index c45efcf3..354a3d7a 100755 --- a/bin/ncu-ci +++ b/bin/ncu-ci @@ -26,6 +26,18 @@ const yargs = require('yargs'); // eslint-disable-next-line no-unused-vars const argv = yargs + .command({ + command: 'rate ', + desc: 'Calculate the green rate of a CI job in the last 100 runs', + builder: (yargs) => { + yargs + .positional('type', { + describe: 'type of CI', + choices: ['commit', 'pr'] + }); + }, + handler + }) .command({ command: 'walk ', desc: 'Walk the CI and store the failures', @@ -117,6 +129,67 @@ async function getResults(cli, request, job) { return build; } +async function runQueue(queue, cli, request, argv) { + let dataToCopy = ''; + let dataToJson = []; + + for (let job of queue) { + cli.separator(''); + if (job.link) { + cli.log(`Running ${job.link}`); + } else { + cli.log(`Running ${job.type}: ${job.jobid}`); + } + cli.separator(''); + const build = await getResults(cli, request, job); + build.display(); + + if (argv.copy) { + dataToCopy += build.formatAsMarkdown(); + } + + if (argv.json) { + dataToJson = dataToJson.concat(build.formatAsJson()); + } + } + + if (argv.copy) { + clipboardy.writeSync(dataToCopy); + cli.separator(''); + cli.log(`Written markdown to clipboard`); + } + + if (argv.json) { + writeJson(argv.json, dataToJson); + cli.separator(''); + cli.log(`Written JSON to ${argv.json}`); + } +} + +function pad(any, length) { + return (any + '').padEnd(length); +} + +// Produces a row for https://github.com/nodejs/reliability#ci-health-history +function displayHealth(builds, cli) { + const [ + count, success, pending, aborted, failed, unstable + ] = [ + builds.count, builds.success.length, builds.pending.length, + builds.aborted.length, builds.failed.length, builds.unstable.length + ]; + const rate = `${(success / (count - pending - aborted) * 100).toFixed(2)}%`; + // eslint-disable-next-line max-len + cli.log('| UTC Time | RUNNING | SUCCESS | UNSTABLE | ABORTED | FAILURE | Green Rate |'); + // eslint-disable-next-line max-len + cli.log('| ---------------- | ------- | ------- | -------- | ------- | ------- | ---------- |'); + const time = new Date().toISOString().slice(0, 16).replace('T', ' '); + let result = `| ${time} | ${pad(pending, 7)} | ${pad(success, 8)}|`; + result += ` ${pad(unstable, 8)} | ${pad(aborted, 7)} | ${pad(failed, 7)} |`; + result += ` ${pad(rate, 10)} |`; + cli.log(result); +} + async function main(command, argv) { const cli = new CLI(); const credentials = await auth(); @@ -129,13 +202,19 @@ async function main(command, argv) { 'benchmark': BENCHMARK }; - if (command === 'walk') { + if (command === 'rate' || command === 'walk') { const type = commandToType[argv.type]; const builds = await listBuilds(cli, request, type); - for (const build of builds.failed) { - queue.push(build); + if (command === 'walk') { + for (const build of builds.failed) { + queue.push(build); + } + } else { + displayHealth(builds, cli); } - } else if (command === 'url') { + } + + if (command === 'url') { let parsed = parseJobFromURL(argv.url); if (parsed) { queue.push({ @@ -155,46 +234,15 @@ async function main(command, argv) { }); } } - } else { + } else if (commandToType[command]) { queue.push({ type: commandToType[command], jobid: argv.jobid }); } - let dataToCopy = ''; - let dataToJson = []; - - for (let job of queue) { - cli.separator(''); - if (job.link) { - cli.log(`Running ${job.link}`); - } else { - cli.log(`Running ${job.type}: ${job.jobid}`); - } - cli.separator(''); - const build = await getResults(cli, request, job); - build.display(); - - if (argv.copy) { - dataToCopy += build.formatAsMarkdown(); - } - - if (argv.json) { - dataToJson = dataToJson.concat(build.formatAsJson()); - } - } - - if (argv.copy) { - clipboardy.writeSync(dataToCopy); - cli.separator(''); - cli.log(`Written markdown to clipboard`); - } - - if (argv.json) { - writeJson(argv.json, dataToJson); - cli.separator(''); - cli.log(`Written JSON to ${argv.json}`); + if (queue.length > 0) { + await runQueue(queue, cli, request, argv); } } diff --git a/docs/ncu-ci.md b/docs/ncu-ci.md index e6557f00..4c67853c 100644 --- a/docs/ncu-ci.md +++ b/docs/ncu-ci.md @@ -13,6 +13,8 @@ Supported jobs: ncu-ci Commands: + ncu-ci rate Calculate the green rate of a CI job in the last 100 + runs ncu-ci walk Walk the CI and store the failures ncu-ci url Automatically detect CI type and show results ncu-ci pr Show results of a node-test-pull-request CI job @@ -49,6 +51,13 @@ failures into a JSON file ncu-ci walk pr --json database.json ``` +Calculate the green rate of the CI for +[CI Health History](https://github.com/nodejs/reliability#ci-health-history) + +``` +ncu-ci rate pr +``` + ## Caveats The CI failures are parsed using pattern matching and could be incorrect. Feel diff --git a/lib/ci.js b/lib/ci.js index cecb8d1e..d0fdb0f4 100644 --- a/lib/ci.js +++ b/lib/ci.js @@ -550,9 +550,11 @@ async function listBuilds(cli, request, type) { const aborted = filterBuild(builds, ABORTED); const pending = filterBuild(builds, null); const unstable = filterBuild(builds, UNSTABLE); + const success = filterBuild(builds, SUCCESS); cli.stopSpinner('Done'); return { + success, failed, aborted, pending,