From e324d0317fd667516f7f5351419eb0d7ad92336b Mon Sep 17 00:00:00 2001 From: sparshithNR Date: Mon, 8 Mar 2021 08:42:27 -0800 Subject: [PATCH] Allow csv output format --- bin/supported | 7 +++++ lib/help.js | 1 + lib/output/cli-output.js | 60 ++++++++++++++------------------------ lib/output/csv-output.js | 63 ++++++++++++++++++++++++++++++++++++++++ package.json | 2 ++ tests/cli-test.js | 15 ++++++++++ tests/csv-output-test.js | 56 +++++++++++++++++++++++++++++++++++ yarn.lock | 24 +++++++++++++++ 8 files changed, 190 insertions(+), 38 deletions(-) create mode 100644 lib/output/csv-output.js create mode 100644 tests/csv-output-test.js diff --git a/bin/supported b/bin/supported index b214d42..34279f7 100755 --- a/bin/supported +++ b/bin/supported @@ -1,7 +1,9 @@ #!/usr/bin/env node 'use strict'; const ora = require('ora'); +const { writeFileSync } = require('fs'); const { displayResult } = require('../lib/output/cli-output'); +const { writeToCsv } = require('../lib/output/csv-output'); (async function main(cli) { if (cli.input.length === 0) { @@ -31,6 +33,11 @@ const { displayResult } = require('../lib/output/cli-output'); 2, ), ); + } else if(cli.flags.csv && result) { + let fileName = `${result.projectName}-support-audit.csv`; + let filePath = `${projectPath}/${fileName}`; + writeFileSync(filePath, writeToCsv(result), 'utf-8' ); + console.log(`Report created at ${filePath}`); } else { displayResult(result, cli.flags); } diff --git a/lib/help.js b/lib/help.js index 51b6fe8..06dcb66 100644 --- a/lib/help.js +++ b/lib/help.js @@ -15,6 +15,7 @@ module.exports = chalk` {cyan --unsupported, -u} outputs detailed report of unsupport packages only {cyan --expiring, -e} outputs detailed report of expiring packages only {cyan --supported, -s} outputs detailed report of support packages only + {cyan --csv} outputs csv file in the project path {bold Examples} {gray $} {cyan supported ./path/to/project/} `; diff --git a/lib/output/cli-output.js b/lib/output/cli-output.js index d5b54b5..e122b27 100644 --- a/lib/output/cli-output.js +++ b/lib/output/cli-output.js @@ -291,24 +291,23 @@ function getHead( /** * - * @param {object} reportContent : processed details from the displayContent - * @returns {string} formatted output for the support check run + * @param {object} supportResult : support check result + * */ -function makeConsoleReport(reportContent) { - const { - body, - isInSupportWindow, - currentPolicy, +function makeConsoleReport(supportResult, flags, supportMessage) { + const isInSupportWindow = supportResult.isInSupportWindow; + const currentPolicy = supportMessage ? supportMessage : DEFAULT_SUPPORT_MESSAGE(); + let { expiresSoon, unsupportedPackages, - supportedPackages, nodePackage, emberPackage, - } = reportContent; + supportedPackages, + } = getCategorisedList(supportResult.supportChecks); - let title = getTitle(isInSupportWindow, expiresSoon, nodePackage, emberPackage); + const title = getTitle(isInSupportWindow, expiresSoon, nodePackage, emberPackage); - let head = getHead( + const head = getHead( isInSupportWindow, unsupportedPackages, supportedPackages, @@ -318,9 +317,13 @@ function makeConsoleReport(reportContent) { currentPolicy, ); - return `${title}${head} -${body} -`; + const body = getBodyContent(supportResult.supportChecks, flags); + + return { + title, + head, + body, + }; } /** @@ -413,36 +416,17 @@ function getCategorisedList(pkgList) { * */ function displayResult(supportResult, flags, supportMessage) { - const title = supportResult.projectName; - const isInSupportWindow = supportResult.isInSupportWindow; - const currentPolicy = supportMessage ? supportMessage : DEFAULT_SUPPORT_MESSAGE(); - let { - expiresSoon, - unsupportedPackages, - nodePackage, - emberPackage, - supportedPackages, - } = getCategorisedList(supportResult.supportChecks); + const { title, head, body } = makeConsoleReport(supportResult, flags, supportMessage); - console.log( - makeConsoleReport({ - title, - isInSupportWindow, - body: getBodyContent(supportResult.supportChecks, flags), - currentPolicy, - expiresSoon, - unsupportedPackages, - supportedPackages, - nodePackage, - emberPackage, - }), - ); + console.log(`${title}${head} + ${body}`); } module.exports = { displayResult, - getBodyContent, getCategorisedList, + getBodyContent, getHead, getTitle, + makeConsoleReport, }; diff --git a/lib/output/csv-output.js b/lib/output/csv-output.js new file mode 100644 index 0000000..1da24ba --- /dev/null +++ b/lib/output/csv-output.js @@ -0,0 +1,63 @@ +'use strict'; + +const { Parser } = require('json2csv'); +const stripAnsi = require('strip-ansi'); +const { makeConsoleReport } = require('./cli-output'); +const { MILLSINQUARTER } = require('../util'); +const { getQtrLocale } = require('./messages'); + +module.exports = { + writeToCsv, +}; +function writeToCsv(result, policyDetails) { + const fields = [ + { + label: 'Name', + value: 'name', + }, + { + label: 'Supported', + value: 'isSupported', + }, + { + label: 'Status', + value: row => { + if (!row.isSupported) { + return `${row.type} version violated`; + } else if (row.isSupported && row.duration) { + return `${row.type ? row.type : ''} version expiring soon`; + } else { + return `up-to-date`; + } + }, + }, + { + label: 'Unsupported Since/In', + value: row => { + if (row.duration) { + const qtrs = Math.ceil(row.duration / MILLSINQUARTER); + return `${qtrs} ${getQtrLocale(qtrs)}`; + } else { + return `-`; + } + }, + }, + { + label: 'Resolved Version', + value: 'resolvedVersion', + }, + { + label: 'Latest Version', + value: 'latestVersion', + }, + ]; + + const json2csvParser = new Parser({ fields }); + const csv = json2csvParser.parse(result.supportChecks); + const { title, head } = makeConsoleReport(result, {}, policyDetails); + const fileContent = `${stripAnsi(title)}${stripAnsi(head)} + + ${csv} + `; + return fileContent; +} diff --git a/package.json b/package.json index 2da9295..924f96c 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "debug": "^4.3.1", "execa": "^5.0.0", "ini": "^1.3.7", + "json2csv": "^5.0.6", "meow": "^8.0.0", "minipass-fetch": "^1.3.2", "moment": "^2.29.1", @@ -56,6 +57,7 @@ "parse-package-name": "^0.1.0", "promise.allsettled": "^1.0.4", "semver": "^7.3.4", + "strip-ansi": "^6.0.0", "terminal-link": "^2.1.1" }, "files": [ diff --git a/tests/cli-test.js b/tests/cli-test.js index 84c8524..f672673 100644 --- a/tests/cli-test.js +++ b/tests/cli-test.js @@ -3,6 +3,7 @@ const { expect } = require('chai'); const execa = require('execa'); const { getBinPath } = require('get-bin-path'); +const fs = require('fs'); const registries = require('./registries'); async function runSupportedCmd(inputArgs) { @@ -145,6 +146,20 @@ describe('CLI', function () { ); }); }); + describe('--csv', function () { + afterEach(function () { + let filePath = `${__dirname}/fixtures/unsupported-project/unsupported-project-support-audit.csv`; + if (fs.existsSync(filePath)) fs.unlinkSync(filePath); + }); + it('works against a unsupported project', async function () { + const child = await runSupportedCmd([`${__dirname}/fixtures/unsupported-project`, '--csv']); + expect(child.exitCode).to.eql(1); + expect(child.stderr).to.eql('- working'); + expect(child.stdout).to.includes( + `Report created at ${__dirname}/fixtures/unsupported-project`, + ); + }); + }); describe('--json', function () { it('works against a fully supported project', async function () { const child = await runSupportedCmd([`${__dirname}/fixtures/supported-project`, '--json']); diff --git a/tests/csv-output-test.js b/tests/csv-output-test.js new file mode 100644 index 0000000..45c0591 --- /dev/null +++ b/tests/csv-output-test.js @@ -0,0 +1,56 @@ +'use strict'; + +const { expect } = require('chai'); +const { writeToCsv } = require('../lib/output/csv-output'); + +describe('csv', function () { + it('supported project', function () { + let supportResult = { + projectName: 'example', + isInSupportWindow: true, + supportChecks: [ + { + isSupported: true, + latestVersion: '4.8.5', + name: 'rsvp', + resolvedVersion: '4.8.5', + }, + { + isSupported: true, + name: 'node', + resolvedVersion: '15.3.0', + latestVersion: '>=14.*', + message: '', + }, + ], + }; + let result = writeToCsv(supportResult); + expect(result).to.includes(`✓ Congrats! + Your project is using only supported versions of libraries. No action is required.`); + }); + it('unsupported project', function () { + let supportResult = { + projectName: 'example', + isInSupportWindow: false, + supportChecks: [ + { + isSupported: false, + latestVersion: '4.8.5', + name: 'rsvp', + resolvedVersion: '4.5.5', + }, + { + isSupported: true, + name: 'node', + resolvedVersion: '15.3.0', + latestVersion: '>=14.*', + message: '', + }, + ], + }; + let result = writeToCsv(supportResult); + expect(result).to.includes(`Support Policy Problem Detected! + Please upgrade your dependencies! + Your project is not within the support policy window because of outdated dependencies.`); + }); +}); diff --git a/yarn.lock b/yarn.lock index 0ab2be2..91acd9c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -455,6 +455,11 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +commander@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1471,6 +1476,15 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +json2csv@^5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/json2csv/-/json2csv-5.0.6.tgz#590e0e1b9579e59baa53bda0c0d840f4d8009687" + integrity sha512-0/4Lv6IenJV0qj2oBdgPIAmFiKKnh8qh7bmLFJ+/ZZHLjSeiL3fKKGX3UryvKPbxFbhV+JcYo9KUC19GJ/Z/4A== + dependencies: + commander "^6.1.0" + jsonparse "^1.3.1" + lodash.get "^4.4.2" + jsonparse@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -1592,6 +1606,16 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +lodash.toarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" + integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE= + lodash@^4.17.14, lodash@^4.17.19: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"