From c24819b1c2fe70eadbaa784aed419e512dd9f5ea Mon Sep 17 00:00:00 2001 From: gmccreadie Date: Fri, 26 Jun 2015 17:21:27 +0100 Subject: [PATCH] Behave Node Client --- .gitignore | 2 + README.md | 102 ++++++++++++++++++++++++++++++++++++++++- bin/cli.js | 38 ++++++++++++++++ index.js | 19 ++++++++ lib/behavepro.js | 115 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 21 +++++++++ 6 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100755 bin/cli.js create mode 100755 index.js create mode 100644 lib/behavepro.js create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6984a96 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +features +node_modules diff --git a/README.md b/README.md index a208f5c..5614a6b 100644 --- a/README.md +++ b/README.md @@ -1 +1,101 @@ -# behave-pro-node +# Behave Pro NodeJS Client + +``` +$ npm install behavepro -g +``` + +See [API Key setup](introduction.html) to retrieve the required credentials. + +## Using from the command line + +Parameters can either be passed from the command line: + +``` +$ behavepro [--id PROJECT ID] [--userId USER] [--apiKey KEY] +``` + +Available parameters: + +* [**--host HOST**] *Behave Pro host - default: 'http://behave.pro'* +* [**--id PROJECT ID**] *JIRA project id* +* [**--userId USER**] *Behave Pro user id* +* [**--apiKey KEY**] *Behave Pro api key* +* [**--output DIRECTORY**] *Output directory - default: 'features'* +* [**--manual**] *Include scenarios marked as manual* +* [**--config CONFIG**] *JSON config file - relative to current directory* + +If the three required parameters are missing, they will be attempted to be read from a json config file in the current directory: + +``` +$ behavepro +``` + +config.json +``` +[{ + "id": 10000, + "userId": "amlyYToyNDM0ZG.....ZiNzQwNGI=", + "apiKey": "44993b0481838e.....a246c723e8e" +}, { + "id": 10100, + "userId": "amlyYToyNDM0ZG.....ZiNzQwNGI=", + "apiKey": "b038a67e0f15e5.....fae00662c8a" +}] +``` + +Any additional parameters are to be specified from the command line. + +The host can vary between products, see table below. + + + + + + + + + + + + + + + + + + + + + +
ProductHost
Behave Pro Cloud (default)https://behave.pro
Behave Pro ServerAddress of the VM
Behave for JIRAJIRA address
+ + +## Using from within a script + +You can use the client in your own scripts to download features from Behave Pro. + +``` +$ npm install behavepro --save +``` + + +``` +var BehavePro = require('behavepro'); + +BehavePro({ + "id": 10000, + "userId": "amlyYToyNDM0ZG.....ZiNzQwNGI=", + "apiKey": "44993b0481838e.....a246c723e8e" +}, function() { + // done +}); +``` + +Available parameters: + +* **"host": HOST** - *Behave Pro host - default: 'http://behave.pro'* +* **"id": ID** - *JIRA project id* +* **"userId": USERID** - *Behave Pro user id* +* **"apiKey": APIKEY** - *Behave Pro api key* +* **"output": DIRECTORY** - *Output directory - default: 'features'* +* **"manual": true** - *Include scenarios marked as manual* diff --git a/bin/cli.js b/bin/cli.js new file mode 100755 index 0000000..baf1aa0 --- /dev/null +++ b/bin/cli.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node +'use strict' +var BehavePro = require('../lib/behavepro'); +var args = require('minimist')(process.argv.slice(2)); +var packageJson = require('../package.json'); + +if (args.help) { + console.log( + 'Behave Pro NodeJS client v' + packageJson.version + '\n'+ + '$ behavepro [--id PROJECT ID] [--userId USER] [--apiKey KEY]\n\n' + + '[--host HOST] Behave Pro host - default: \'http://behave.pro\'\n' + + '[--id PROJECT ID] JIRA project id\n' + + '[--userId USER] Behave Pro user id\n' + + '[--apiKey KEY] Behave Pro api key\n' + + '[--output DIRECTORY] Output directory - default: \'features\'\n' + + '[--manual] Include scenarios marked as manual\n' + + '[--config CONFIG] JSON config file - relative to current directory\n' + + 'Further docs at http://docs.behave.pro' + ); + return; +} + +var settings = { + host: args.host || 'https://behave.pro', + id: args.key || args.project || args.id, + userId: args.user || args.userId, + apiKey: args.api || args.apiKey || args.password, + output: args.output || args.dir || args.directory || 'features', + manual: args.manual || args.m || false, + config: args.config || 'config.json' +}; + +// if these aren't defined, attempt to read them from config.json +if (settings.id && settings.userId && settings.apiKey) { + BehavePro.fetchFeatures(settings); +} else { + BehavePro.fetchFeaturesFromConfig(settings); +} \ No newline at end of file diff --git a/index.js b/index.js new file mode 100755 index 0000000..c1f9634 --- /dev/null +++ b/index.js @@ -0,0 +1,19 @@ +#!/usr/bin/env node +'use strict' +var BehavePro = require('./lib/behavepro'); +var _ = require('underscore'); + +var defaultSettings = { + host: 'https://behave.pro', + output: 'features', + manual: false, + config: 'config.json' +}; + +module.exports = function(settings, callback) { + _.defaults(settings, defaultSettings); + BehavePro.fetchFeatures(settings, function() { + console.log(settings); + if (callback) callback(); + }); +} \ No newline at end of file diff --git a/lib/behavepro.js b/lib/behavepro.js new file mode 100644 index 0000000..aa173ba --- /dev/null +++ b/lib/behavepro.js @@ -0,0 +1,115 @@ +#!/usr/bin/env node +'use strict' +var request = require('request'); +var unzip = require('unzip2'); +var fs = require('fs'); +var mkdir = require('mkdirp'); +var _ = require('underscore'); + +module.exports.fetchFeaturesFromConfig = function(settings, callback) { + fs.exists(process.cwd() + '/' + settings.config, function(exists) { + if (exists) { + var configuration = require(process.cwd() + '/' + settings.config); + configuration.forEach(function(config) { + _.extend(settings, config); + fetchFeatures(settings, callback); + }); + } else { + var err = new Error('Could not find config at ' + process.cwd() + '/' + settings.config); + throw err; + } + }); +} + +var fetchFeatures = function(settings, callback) { + var url = settings.host + '/rest/cucumber/1.0/project/' + settings.id+ '/features?manual=' + settings.manual; + var path = settings.output + '/' + settings.id; + + ensureSettingsExist(settings.id, settings.userId, settings.apiKey, function() { + console.log('Downloading features from JIRA project ' + settings.id + '...'); + request({ + url: url, + headers: { + Authorization: 'Basic ' + new Buffer(settings.userId + ':' + settings.apiKey).toString('base64') + }, + encoding: null + }, function(error, response, body) { + if (error) throw error; + var err = null; + switch(response.statusCode) { + case 500: + err = new Error('Server error - Are you using the correct host?'); + throw err; + return; + case 401: + err = new Error('Unauthorized - ensure keys are valid'); + throw err; + return; + case 200: + break; + default: + err = new Error(response.statusCode + ' http error when downloading'); + throw err; + return; + } + + mkdir(path, function(err) { + if (err) throw err; + writeFeatures(body, path, function() { + countFeatures(path, function(files) { + console.log('Saved ' + files.length + ' ' + (files.length > 1 ? 'features' : 'feature') + ' to ' + process.cwd() + '/' + path + '/'); + }); + if (callback) callback(); + }); + }); + }); + }); +} + +module.exports.fetchFeatures = fetchFeatures; + +function writeFeatures(body, path, callback) { + fs.writeFile(path + '.zip', body, function(err) { + if (err) throw err; + var stream = fs.createReadStream(path + '.zip').pipe( + unzip.Extract({ + path: path + }) + ); + + stream.on('close', function() { + removeZip(path + '.zip'); + callback(); + }); + }); +} + +function ensureSettingsExist(id, userId, apiKey, callback) { + var err = null; + if (!id) { + err = new Error('Project id missing'); + throw err; + } + if (!userId) { + err = new Error('User id missing'); + throw err; + } + if (!apiKey) { + err = new Error('API key missing'); + throw err; + } + if (callback) callback(); +} + +function countFeatures(path, callback) { + fs.readdir(path, function(err, files) { + callback(files); + }); +} + +function removeZip(file, callback) { + fs.unlink(file, function(err) { + if (err) throw err; + if (callback) callback(); + }); +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..7cd9163 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "behave-pro-js", + "version": "0.0.1", + "description": "Behave Pro JS exporter", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Hindsight Software Ltd", + "license": "MIT", + "dependencies": { + "minimist": "^1.1.1", + "mkdirp": "^0.5.1", + "request": "^2.58.0", + "underscore": "^1.8.3", + "unzip2": "^0.2.5" + }, + "bin": { + "behavepro": "bin/cli.js" + } +}