forked from hindsightsoftware/behave-pro-node
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
158 additions
and
128 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,16 @@ | ||
#!/usr/bin/env node | ||
"use strict"; | ||
var BehavePro = require("./lib/behavepro"); | ||
var _ = require("lodash"); | ||
const BehavePro = require("./lib/behavepro"); | ||
const _ = require("lodash"); | ||
|
||
var defaultSettings = { | ||
const defaultSettings = { | ||
host: "https://behave.pro", | ||
output: "features", | ||
manual: false, | ||
config: "config.json" | ||
}; | ||
|
||
module.exports = function(settings, callback) { | ||
module.exports = function(settings) { | ||
_.defaults(settings, defaultSettings); | ||
BehavePro.fetchFeatures(settings, function() { | ||
if (callback) callback(); | ||
}); | ||
return BehavePro.fetchFeatures(settings) | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,146 +1,171 @@ | ||
#!/usr/bin/env node | ||
// @ts-check | ||
"use strict"; | ||
const request = require("request"); | ||
const fetch = require("node-fetch"); | ||
const unzipper = require("unzipper"); | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
const mkdir = require("mkdirp"); | ||
const _ = require("lodash"); | ||
const chalk = require("chalk"); | ||
const red = chalk.red; | ||
|
||
const fetchFeaturesFromConfig = function(settings, callback) { | ||
fs.exists(process.cwd() + "/" + settings.config, function findConfig(exists) { | ||
if (exists) { | ||
const configuration = require(process.cwd() + "/" + settings.config); | ||
configuration.forEach(function(config) { | ||
_.extend(settings, config); | ||
fetchFeatures(settings, callback); | ||
}); | ||
} else { | ||
const err = new Error( | ||
red("Could not find config at " + process.cwd() + "/" + settings.config) | ||
); | ||
throw err; | ||
} | ||
}); | ||
}; | ||
|
||
const fetchFeatures = function(settings, callback) { | ||
/** | ||
* @typedef {{ | ||
* host?: string, | ||
* id?: string, | ||
* userId?: string, | ||
* apiKey?: string, | ||
* output?:string, | ||
* manual?: boolean, | ||
* config?: string | ||
* }} Settings | ||
*/ | ||
|
||
/** | ||
* | ||
* @param {Settings} settings | ||
*/ | ||
async function fetchFeaturesFromConfig(settings) { | ||
const settingsPath = path.join(process.cwd(), settings.config); | ||
try { | ||
await fs.promises.access( | ||
settingsPath, | ||
fs.constants.F_OK | fs.constants.R_OK | ||
); | ||
|
||
const configuration = require(settingsPath); | ||
const features = configuration.map(function (config) { | ||
_.extend(settings, config); | ||
return fetchFeatures(settings); | ||
}); | ||
return await Promise.all(features); | ||
} catch (error) { | ||
throw new Error( | ||
chalk.red(`Could not find config at: ${chalk.bold(settingsPath)}`) | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* | ||
* @param {Settings} settings | ||
*/ | ||
async function fetchFeatures(settings) { | ||
const projectId = settings.id; | ||
const userId = settings.userId; | ||
const apiKey = settings.apiKey; | ||
|
||
ensureSettingsExist(projectId, userId, apiKey, function() { | ||
console.log( | ||
chalk.cyan("Downloading features from JIRA project " + projectId + "...") | ||
); | ||
const url = [ | ||
settings.host, | ||
"/rest/cucumber/1.0/project/", | ||
projectId, | ||
"/features?manual=", | ||
settings.manual | ||
].join(""); | ||
|
||
request( | ||
{ | ||
url: url, | ||
headers: { | ||
Authorization: | ||
"Basic " + Buffer.from(userId + ":" + apiKey).toString("base64") | ||
}, | ||
encoding: null | ||
}, | ||
function(error, response, body) { | ||
if (error) throw error; | ||
let err = null; | ||
switch (response.statusCode) { | ||
case 500: | ||
err = new Error(red("Server error: check your host url")); | ||
throw err; | ||
case 401: | ||
err = new Error( | ||
red("Unauthorized: ensure userId and apiKey are both valid") | ||
); | ||
throw err; | ||
case 200: | ||
break; | ||
default: | ||
err = new Error( | ||
red(response.statusCode + " http error when downloading") | ||
); | ||
throw err; | ||
} | ||
|
||
const path = settings.output + "/" + projectId; | ||
mkdir(path, function(err) { | ||
if (err) throw err; | ||
writeFeatures(body, path, function() { | ||
countFeatures(path, function(files) { | ||
console.log( | ||
chalk.green( | ||
`Saved ${files.length} ${ | ||
files.length > 1 ? "features" : "feature" | ||
} to ${process.cwd()}/${path}/` | ||
) | ||
); | ||
}); | ||
if (callback) callback(); | ||
}); | ||
}); | ||
} | ||
); | ||
ensureSettingsExist(projectId, userId, apiKey); | ||
|
||
console.log( | ||
chalk.cyan( | ||
`Downloading features from JIRA project ${chalk.bold(projectId)} ...` | ||
) | ||
); | ||
|
||
const url = [ | ||
settings.host, | ||
"/rest/cucumber/1.0/project/", | ||
projectId, | ||
"/features?manual=", | ||
settings.manual, | ||
].join(""); | ||
|
||
const response = await fetch(url, { | ||
headers: { | ||
Authorization: `Basic ${Buffer.from(`${userId}:${apiKey}`).toString( | ||
"base64" | ||
)}`, | ||
}, | ||
}); | ||
}; | ||
|
||
let err = null; | ||
switch (response.status) { | ||
case 500: | ||
err = new Error(chalk.red("Server error: check your host url")); | ||
throw err; | ||
case 401: | ||
err = new Error( | ||
chalk.red("Unauthorized: ensure userId and apiKey are both valid") | ||
); | ||
throw err; | ||
case 200: | ||
break; | ||
default: | ||
err = new Error( | ||
chalk.red(response.status + " http error when downloading") | ||
); | ||
throw err; | ||
} | ||
|
||
const projectPath = path.join(settings.output, `${projectId}`); | ||
await mkdir(projectPath); | ||
const buffer = await response.buffer(); | ||
await writeFeatures(buffer, projectPath); | ||
const filesCount = await countFeatures(projectPath); | ||
|
||
console.log( | ||
chalk.green( | ||
`Saved ${filesCount} ${ | ||
filesCount > 1 ? "features" : "feature" | ||
} to ${path.join(process.cwd(), projectPath)}/` | ||
) | ||
); | ||
} | ||
|
||
module.exports = { | ||
fetchFeatures: fetchFeatures, | ||
fetchFeaturesFromConfig: fetchFeaturesFromConfig | ||
fetchFeaturesFromConfig: fetchFeaturesFromConfig, | ||
}; | ||
|
||
function writeFeatures(body, path, callback) { | ||
fs.writeFile(path + ".zip", body, function(err) { | ||
if (err) throw err; | ||
const stream = fs.createReadStream(path + ".zip").pipe( | ||
/** | ||
* | ||
* @param {Buffer} buffer | ||
* @param {string} featuresPath | ||
*/ | ||
async function writeFeatures(buffer, featuresPath) { | ||
const zipPath = featuresPath + ".zip"; | ||
await fs.promises.writeFile(zipPath, buffer); | ||
|
||
await fs | ||
.createReadStream(zipPath) | ||
.pipe( | ||
unzipper.Extract({ | ||
path: path | ||
path: featuresPath, | ||
}) | ||
); | ||
) | ||
.promise(); | ||
|
||
stream.on("close", function() { | ||
removeZip(path + ".zip"); | ||
callback(); | ||
}); | ||
}); | ||
await await fs.promises.unlink(zipPath); | ||
} | ||
|
||
function ensureSettingsExist(projectId, userId, apiKey, callback) { | ||
/** | ||
* | ||
* @param {string} projectId | ||
* @param {string} userId | ||
* @param {string} apiKey | ||
*/ | ||
function ensureSettingsExist(projectId, userId, apiKey) { | ||
let err = null; | ||
|
||
if (!projectId) { | ||
err = new Error(red("projectId is missing")); | ||
err = new Error(chalk.red("projectId is missing")); | ||
} else if (!userId) { | ||
err = new Error(red("userId is missing")); | ||
err = new Error(chalk.red("userId is missing")); | ||
} else if (!apiKey) { | ||
err = new Error(red("apiKey is missing")); | ||
err = new Error(chalk.red("apiKey is missing")); | ||
} | ||
|
||
if (err) { | ||
throw err; | ||
} | ||
|
||
return 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(); | ||
}); | ||
/** | ||
* | ||
* @param {string} path | ||
*/ | ||
async function countFeatures(path) { | ||
const files = await fs.promises.readdir(path); | ||
return files.length; | ||
} |