Skip to content

Commit

Permalink
feat: multi param support for monitor
Browse files Browse the repository at this point in the history
  • Loading branch information
aryehbeitz committed Jan 11, 2018
1 parent f6e3ae9 commit 0cd8795
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 65 deletions.
171 changes: 107 additions & 64 deletions cli/commands/monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
30 changes: 29 additions & 1 deletion test/acceptance/cli.acceptance.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
})
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 0cd8795

Please sign in to comment.