From 0cd879516eb124664cef22863690093c5a6c9c97 Mon Sep 17 00:00:00 2001 From: Aryeh Beitz Date: Tue, 9 Jan 2018 11:31:54 +0200 Subject: [PATCH] feat: multi param support for monitor --- cli/commands/monitor.js | 171 ++++++++++++++++--------- test/acceptance/cli.acceptance.test.js | 30 ++++- 2 files changed, 136 insertions(+), 65 deletions(-) diff --git a/cli/commands/monitor.js b/cli/commands/monitor.js index a6379cd570..29f6e096d5 100644 --- a/cli/commands/monitor.js +++ b/cli/commands/monitor.js @@ -7,87 +7,130 @@ var snyk = require('../../lib/'); var config = require('../../lib/config'); var url = require('url'); var chalk = require('chalk'); +var spinner = require('../../lib/spinner'); var detect = require('../../lib/detect'); var plugins = require('../../lib/plugins'); var ModuleInfo = require('../../lib/module-info'); -function monitor(path, options) { - if (typeof path === 'object') { - options = path; - path = process.cwd(); +function monitor() { + var args = [].slice.call(arguments, 0); + var options = {}; + var results = []; + if (typeof args[args.length - 1] === 'object') { + options = args.pop(); } - if (!path) { - path = process.cwd(); - } + args = args.filter(Boolean); - if (!options) { - options = {}; + // populate with default path (cwd) if no path given + if (args.length === 0) { + args.unshift(process.cwd()); } if (options.id) { snyk.id = options.id; } - return apiTokenExists('snyk monitor').then(function () { - return fs.exists(path); - }).then(function (exists) { - if (!exists) { - throw new Error('snyk monitor should be pointed at an existing project'); - } - var packageManager = detect.detectPackageManager(path, options); - var targetFile = options.file || detect.detectPackageFile(path); - var meta = { - method: 'cli', - packageManager: packageManager, - 'policy-path': options['policy-path'], - 'project-name': options['project-name'] || config['PROJECT_NAME'], - }; - var plugin = plugins.loadPlugin(packageManager); - var moduleInfo = ModuleInfo(plugin, options.policy); - return moduleInfo.inspect(path, targetFile, options) - .then(snyk.monitor.bind(null, path, meta)) - .then(function (res) { - var endpoint = url.parse(config.API); - var leader = ''; - if (res.org) { - leader = '/org/' + res.org; - } - endpoint.pathname = leader + '/manage'; - var manageUrl = url.format(endpoint); + var lbl = 'Running monitor...'; - endpoint.pathname = leader + '/monitor/' + res.id; + return spinner(lbl).then(function () { + return apiTokenExists('snyk monitor'); + }) + .then(function () { + return args.reduce(function (acc, path) { + return acc.then(function () { + return fs.exists(path).then(function (exists) { + if (!exists) { + throw new Error( + 'snyk monitor should be pointed at an existing project'); + } + var packageManager = detect.detectPackageManager(path, options); + var targetFile = options.file || detect.detectPackageFile(path); + var meta = { + method: 'cli', + packageManager: packageManager, + 'policy-path': options['policy-path'], + 'project-name': options['project-name'] || config['PROJECT_NAME'], + }; + var plugin = plugins.loadPlugin(packageManager); + var moduleInfo = ModuleInfo(plugin, options.policy); + return moduleInfo.inspect(path, targetFile, options) + .then(snyk.monitor.bind(null, path, meta)) + .then(function (res) { + res.path = path; + var endpoint = url.parse(config.API); + var leader = ''; + if (res.org) { + leader = '/org/' + res.org; + } + endpoint.pathname = leader + '/manage'; + var manageUrl = url.format(endpoint); - return formatMonitorOutput( - packageManager, res, - manageUrl, options.json - ); + endpoint.pathname = leader + '/monitor/' + res.id; + var output = formatMonitorOutput( + packageManager, res, + manageUrl, options.json + ); + // push a good result + results.push({ok: true, data: output, path: path}); + }); + }).catch(function (err) { + // push this error so the promise chain continues + results.push({ok: false, data: err, path: path}); + }); }); - }); + }, Promise.resolve()) + .then(function () { + if (options.json) { + var dataToSend = results.map(function (result) { + if (result.ok) { + return JSON.parse(result.data) + } + return {ok: false, error: result.data.message, path: result.path} + }); + // backwards compat - strip array if only one result + dataToSend = dataToSend.length === 1 ? dataToSend[0] : dataToSend; + var json = JSON.stringify(dataToSend, null, 2); - function formatMonitorOutput(packageManager, res, manageUrl, isJson) { - var issues = res.licensesPolicy ? 'issues' : 'vulnerabilities'; - var strOutput = (packageManager === 'yarn' ? - 'A yarn.lock file was detected - continuing as a Yarn project.\n\n' : - '\n\n') + - 'Captured a snapshot of this project\'s dependencies.\n' + - 'Explore this snapshot at ' + res.uri + '\n\n' + - (res.isMonitored ? - 'Notifications about newly disclosed ' + issues + ' related\n' + - 'to these dependencies will be emailed to you.\n\n' : - chalk.bold.red('Project is inactive, so notifications are turned ' + - 'off.\nActivate this project here: ' + manageUrl + '\n\n')) + - (res.trialStarted ? - chalk.yellow('You\'re over the free plan usage limit, \n' + - 'and are now on a free 14-day premium trial.\n' + - 'View plans here: ' + manageUrl + '\n\n') : - ''); + if (results.every(function (res) { return res.ok; })) { + return json + } - return isJson ? - JSON.stringify(_.assign({}, res, { - manageUrl: manageUrl, - packageManager: packageManager, - })) : strOutput; - } + throw new Error(json); + } + + return results.map(function (res) { + if (res.ok) { + return res.data; + } + return 'For path `' + res.path + '`, ' + res.data.message; + }).join('\n'); + }); + }).then(spinner.clear(lbl)); } + +function formatMonitorOutput(packageManager, res, manageUrl, isJson) { + var issues = res.licensesPolicy ? 'issues' : 'vulnerabilities'; + var strOutput = (packageManager === 'yarn' ? + 'A yarn.lock file was detected - continuing as a Yarn project.\n\n' : '') + + '\n\nProject path: ' + res.path + + '\nCaptured a snapshot of this project\'s dependencies.\n' + + 'Explore this snapshot at ' + res.uri + '\n\n' + + (res.isMonitored ? + 'Notifications about newly disclosed ' + issues + ' related\n' + + 'to these dependencies will be emailed to you.' : + chalk.bold.red('Project is inactive, so notifications are turned ' + + 'off.\nActivate this project here: ' + manageUrl + '\n\n')) + + (res.trialStarted ? + chalk.yellow('You\'re over the free plan usage limit, \n' + + 'and are now on a free 14-day premium trial.\n' + + 'View plans here: ' + manageUrl + '\n\n') : + ''); + + return isJson ? + JSON.stringify(_.assign({}, res, { + manageUrl: manageUrl, + packageManager: packageManager, + })) : strOutput; +} \ No newline at end of file diff --git a/test/acceptance/cli.acceptance.test.js b/test/acceptance/cli.acceptance.test.js index b1077058af..cb60dc9124 100644 --- a/test/acceptance/cli.acceptance.test.js +++ b/test/acceptance/cli.acceptance.test.js @@ -935,7 +935,7 @@ test('`monitor --policy-path`', function (t) { test('`monitor non-existing`', function (t) { chdirWorkspaces(); - return cli.monitor('non-existing') + return cli.monitor('non-existing', {json: true}) .then(function () { t.fail('should have failed'); }) @@ -1176,6 +1176,34 @@ function (t) { }); }); +test('`monitor composer-app ruby-app` works on multiple params', function (t) { + chdirWorkspaces(); + return cli.monitor('composer-app', 'ruby-app', { json: true }) + .then(function (results) { + results = JSON.parse(results); + // assert two proper responses + t.equal(results.length, 2, '2 monitor results'); + + // assert results contain monitor urls + t.match(results[0].manageUrl, 'http://localhost:12345/manage', + 'first monitor url is present'); + t.match(results[1].manageUrl, 'http://localhost:12345/manage', + 'second monitor url is present'); + + // assert results contain monitor urls + t.match(results[0].path, 'composer', 'first monitor url is composer'); + t.match(results[1].path, 'ruby-app', 'second monitor url is ruby-app'); + + // assert proper package managers detected + t.match(results[0].packageManager, 'composer', 'composer package manager'); + t.match(results[1].packageManager, 'rubygems', 'rubygems package manager'); + t.end(); + }) + .catch(function (err) { + t.fail(err.message); + }); +}); + test('`wizard` for unsupported package managers', function (t) { chdirWorkspaces();