diff --git a/bin/commands/info.js b/bin/commands/info.js index 31876fb8..4408f044 100644 --- a/bin/commands/info.js +++ b/bin/commands/info.js @@ -1,8 +1,10 @@ 'use strict'; -var config = require('../helpers/config'); -var request = require('request') -var logger = require("../helpers/logger"); -var Constant = require("../helpers/constants") +const request = require('request'); + +const config = require("../helpers/config"), + logger = require("../helpers/logger").winstonLogger, + Constants = require("../helpers/constants"), + util = require("../helpers/util"); module.exports = function info(args) { return buildInfo(args) @@ -10,46 +12,74 @@ module.exports = function info(args) { function buildInfo(args) { let bsConfigPath = process.cwd() + args.cf; - logger.log(`Reading config from ${args.cf}`); - var bsConfig = require(bsConfigPath); - let buildId = args._[1] + util.validateBstackJson(bsConfigPath).then(function (bsConfig) { + util.setUsageReportingFlag(bsConfig, args.cf.disableUsageReporting); - let options = { - url: config.buildUrl + buildId, - method: 'GET', - auth: { - user: bsConfig.auth.username, - password: bsConfig.auth.access_key - } - } - - request(options, function (err, resp, body) { - if (err) { - logger.log(Constant.userMessages.BUILD_INFO_FAILED); - } else { - let build = null - try { - build = JSON.parse(body) - } catch (error) { - build = null + let buildId = args._[1]; + + let options = { + url: config.buildUrl + buildId, + method: 'GET', + auth: { + user: bsConfig.auth.username, + password: bsConfig.auth.access_key } - - if (resp.statusCode != 200) { - if (build) { - logger.error(`${Constant.userMessages.BUILD_INFO_FAILED} with error: \n${JSON.stringify(build, null, 2)}`); - } else { - logger.error(Constant.userMessages.BUILD_INFO_FAILED); + } + + request(options, function (err, resp, body) { + let message = null; + let messageType = null; + let errorCode = null; + + if (err) { + message = Constants.userMessages.BUILD_INFO_FAILED; + messageType = Constants.messageTypes.ERROR; + errorCode = 'api_failed_build_info'; + + logger.info(message); + } else { + let build = null; + try { + build = JSON.parse(body); + } catch (error) { + build = null; } - } else if(resp.statusCode == 299) { - if(build) { - logger.log(build.message); + + if (resp.statusCode != 200) { + messageType = Constants.messageTypes.ERROR; + errorCode = 'api_failed_build_info'; + + if (build) { + message = `${Constants.userMessages.BUILD_INFO_FAILED} with error: \n${JSON.stringify(build, null, 2)}`; + logger.error(message); + if (build.message === 'Unauthorized') errorCode = 'api_auth_failed'; + } else { + message = Constants.userMessages.BUILD_INFO_FAILED; + logger.error(message); + } + } else if (resp.statusCode == 299) { + messageType = Constants.messageTypes.INFO; + errorCode = 'api_deprecated'; + + if (build) { + message = build.message; + logger.info(message); + } else { + message = Constants.userMessages.API_DEPRECATED; + logger.info(message); + } } else { - logger.log(Constants.userMessages.API_DEPRECATED); + messageType = Constants.messageTypes.SUCCESS; + message = `Build info for build id: \n ${JSON.stringify(build, null, 2)}`; + logger.info(message); } - } else { - logger.log(`Build info for build id: \n ${JSON.stringify(build, null, 2)}`) } - } - }) + util.sendUsageReport(bsConfig, args, message, messageType, errorCode); + }) + }).catch(function (err) { + logger.error(err); + util.setUsageReportingFlag(null, args.cf.disableUsageReporting); + util.sendUsageReport(null, args, err.message, Constants.messageTypes.ERROR, util.getErrorCodeFromErr(err)); + }) } diff --git a/bin/commands/init.js b/bin/commands/init.js index d75c69ef..5cedfd55 100644 --- a/bin/commands/init.js +++ b/bin/commands/init.js @@ -1,7 +1,8 @@ 'use strict'; -var fileHelpers = require('../helpers/fileHelpers'); -const Constants = require('../helpers/constants'); -var logger = require("../helpers/logger"); +const fileHelpers = require("../helpers/fileHelpers"), + Constants = require("../helpers/constants"), + logger = require("../helpers/logger").winstonLogger, + util = require("../helpers/util"); module.exports = function init(args) { return createBrowserStackConfig(args) @@ -21,12 +22,16 @@ function createBrowserStackConfig(args) { }; function allDone() { - logger.log(Constants.userMessages.CONFIG_FILE_CREATED); + let message = Constants.userMessages.CONFIG_FILE_CREATED + logger.info(message); + util.sendUsageReport(null, args, message, Constants.messageTypes.SUCCESS, null); } return fileHelpers.fileExists(config.path, function(exists){ if (exists) { - logger.error(Constants.userMessages.CONFIG_FILE_EXISTS); + let message = Constants.userMessages.CONFIG_FILE_EXISTS; + logger.error(message); + util.sendUsageReport(null, args, message, Constants.messageTypes.ERROR, 'bstack_json_already_exists'); } else { fileHelpers.write(config, null, allDone); } diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 37a45641..f6ceecb1 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -1,12 +1,14 @@ 'use strict'; -var archiver = require("../helpers/archiver"); -var zipUploader = require("../helpers/zipUpload"); -var build = require("../helpers/build"); -var logger = require("../helpers/logger"); -var config = require('../helpers/config'); -var capabilityHelper = require("../helpers/capabilityHelper"); -var fs = require('fs'); -const Constants = require('../helpers/constants'); +const fs = require('fs'); + +const archiver = require("../helpers/archiver"), + zipUploader = require("../helpers/zipUpload"), + build = require("../helpers/build"), + logger = require("../helpers/logger").winstonLogger, + config = require("../helpers/config"), + capabilityHelper = require("../helpers/capabilityHelper"), + Constants = require("../helpers/constants"), + util = require("../helpers/util"); module.exports = function run(args) { return runCypress(args); @@ -15,48 +17,67 @@ module.exports = function run(args) { function deleteZip() { fs.unlink(config.fileName, function (err) { if(err) { - logger.log(Constants.userMessages.ZIP_DELETE_FAILED); + logger.info(Constants.userMessages.ZIP_DELETE_FAILED); } else { - logger.log(Constants.userMessages.ZIP_DELETED); - } + logger.info(Constants.userMessages.ZIP_DELETED); + } }); } function runCypress(args) { let bsConfigPath = process.cwd() + args.cf; - logger.log(`Reading config from ${args.cf}`); - var bsConfig = require(bsConfigPath); - - // Validate browserstack.json - capabilityHelper.validate(bsConfig).then(function (validated) { - logger.log(validated); - // Archive the spec files - archiver.archive(bsConfig.run_settings, config.fileName).then(function (data) { - // Uploaded zip file - zipUploader.zipUpload(bsConfig, config.fileName).then(function (zip) { - // Create build - build.createBuild(bsConfig, zip).then(function (data) { - return; + + util.validateBstackJson(bsConfigPath).then(function (bsConfig) { + util.setUsageReportingFlag(bsConfig, args.cf.disableUsageReporting); + + // Validate browserstack.json values + capabilityHelper.validate(bsConfig).then(function (validated) { + logger.info(validated); + + // Archive the spec files + archiver.archive(bsConfig.run_settings, config.fileName).then(function (data) { + + // Uploaded zip file + zipUploader.zipUpload(bsConfig, config.fileName).then(function (zip) { + + // Create build + build.createBuild(bsConfig, zip).then(function (data) { + return; + }).catch(function (err) { + // Build creation failed + logger.error(Constants.userMessages.BUILD_FAILED) + util.sendUsageReport(bsConfig, args, Constants.userMessages.BUILD_FAILED, Constants.messageTypes.ERROR, 'build_failed'); + }); }).catch(function (err) { - // Build creation failed - logger.error(Constants.userMessages.BUILD_FAILED) + // Zip Upload failed + logger.error(err) + logger.error(Constants.userMessages.ZIP_UPLOAD_FAILED) + util.sendUsageReport(bsConfig, args, `${err}\n${Constants.userMessages.ZIP_UPLOAD_FAILED}`, Constants.messageTypes.ERROR, 'zip_upload_failed'); + }).finally(function () { + deleteZip(); }); }).catch(function (err) { - // Zip Upload failed - logger.error(err) - logger.error(Constants.userMessages.ZIP_UPLOAD_FAILED) - }).finally(function () { - deleteZip(); + // Zipping failed + logger.error(err); + logger.error(Constants.userMessages.FAILED_TO_ZIP); + util.sendUsageReport(bsConfig, args, `${err}\n${Constants.userMessages.FAILED_TO_ZIP}`, Constants.messageTypes.ERROR, 'zip_creation_failed'); + try { + deleteZip(); + } catch (err) { + util.sendUsageReport(bsConfig, args, Constants.userMessages.ZIP_DELETE_FAILED, Constants.messageTypes.ERROR, 'zip_deletion_failed'); + } }); }).catch(function (err) { - // Zipping failed - logger.error(err) - logger.error(Constants.userMessages.FAILED_TO_ZIP) - deleteZip(); + // browerstack.json is not valid + logger.error(err); + logger.error(Constants.validationMessages.NOT_VALID); + + let error_code = util.getErrorCodeFromMsg(err); + util.sendUsageReport(bsConfig, args, `${err}\n${Constants.validationMessages.NOT_VALID}`, Constants.messageTypes.ERROR, error_code); }); }).catch(function (err) { - // browerstack.json is not valid - logger.error(err) - logger.error(Constants.validationMessages.NOT_VALID) - }); + logger.error(err); + util.setUsageReportingFlag(null, args.cf.disableUsageReporting); + util.sendUsageReport(null, args, err.message, Constants.messageTypes.ERROR, util.getErrorCodeFromErr(err)); + }) } diff --git a/bin/commands/stop.js b/bin/commands/stop.js index cb82b74b..b68330c7 100644 --- a/bin/commands/stop.js +++ b/bin/commands/stop.js @@ -1,8 +1,10 @@ 'use strict'; -var config = require('../helpers/config'); -var request = require('request') -var logger = require("../helpers/logger"); -var Constant = require("../helpers/constants") +const request = require('request'); + +const config = require("../helpers/config"), + logger = require("../helpers/logger").winstonLogger, + Constants = require("../helpers/constants"), + util = require("../helpers/util"); module.exports = function stop(args) { return buildStop(args) @@ -10,46 +12,74 @@ module.exports = function stop(args) { function buildStop(args) { let bsConfigPath = process.cwd() + args.cf; - logger.log(`Reading config from ${args.cf}`); - var bsConfig = require(bsConfigPath); - let buildId = args._[1] + util.validateBstackJson(bsConfigPath).then(function (bsConfig) { + util.setUsageReportingFlag(bsConfig, args.cf.disableUsageReporting); - let options = { - url: config.buildStopUrl + buildId, - method: 'POST', - auth: { - user: bsConfig.auth.username, - password: bsConfig.auth.access_key - } - } - - request(options, function (err, resp, body) { - if (err) { - logger.log(Constant.userMessages.BUILD_STOP_FAILED); - } else { - let build = null - try { - build = JSON.parse(body) - } catch (error) { - build = null + let buildId = args._[1]; + + let options = { + url: config.buildStopUrl + buildId, + method: 'POST', + auth: { + user: bsConfig.auth.username, + password: bsConfig.auth.access_key } + } - if (resp.statusCode != 200) { - if (build) { - logger.error(`${Constant.userMessages.BUILD_STOP_FAILED} with error: \n${JSON.stringify(build, null, 2)}`); - } else { - logger.error(Constant.userMessages.BUILD_STOP_FAILED); + request(options, function (err, resp, body) { + let message = null; + let messageType = null; + let errorCode = null; + + if (err) { + message = Constants.userMessages.BUILD_STOP_FAILED; + messageType = Constants.messageTypes.ERROR; + errorCode = 'api_failed_build_stop'; + + logger.info(message); + } else { + let build = null + try { + build = JSON.parse(body) + } catch (error) { + build = null } - } else if (resp.statusCode == 299) { - if (build) { - logger.log(build.message); + + if (resp.statusCode != 200) { + messageType = Constants.messageTypes.ERROR; + errorCode = 'api_failed_build_stop'; + + if (build) { + message = `${Constants.userMessages.BUILD_STOP_FAILED} with error: \n${JSON.stringify(build, null, 2)}`; + logger.error(message); + if (build.message === 'Unauthorized') errorCode = 'api_auth_failed'; + } else { + message = Constants.userMessages.BUILD_STOP_FAILED; + logger.error(message); + } + } else if (resp.statusCode == 299) { + messageType = Constants.messageTypes.INFO; + errorCode = 'api_deprecated'; + + if (build) { + message = build.message + logger.info(message); + } else { + message = Constants.userMessages.API_DEPRECATED; + logger.info(message); + } } else { - logger.log(Constants.userMessages.API_DEPRECATED); + messageType = Constants.messageTypes.SUCCESS; + message = `${JSON.stringify(build, null, 2)}`; + logger.info(message); } - } else { - logger.log(`${JSON.stringify(build, null, 2)}`) } - } + util.sendUsageReport(bsConfig, args, message, messageType, errorCode); + }) + }).catch(function (err) { + logger.error(err); + util.setUsageReportingFlag(null, args.cf.disableUsageReporting); + util.sendUsageReport(null, args, err.message, Constants.messageTypes.ERROR, util.getErrorCodeFromErr(err)); }) } diff --git a/bin/helpers/archiver.js b/bin/helpers/archiver.js index 3f9fea9c..e786ccac 100644 --- a/bin/helpers/archiver.js +++ b/bin/helpers/archiver.js @@ -1,7 +1,8 @@ +'use strict'; +const fs = require("fs"); -const fs = require('fs'), - archiver = require('archiver'), - logger = require("./logger"); +const archiver = require("archiver"), + logger = require("./logger").winstonLogger; const archiveSpecs = (runSettings, filePath) => { return new Promise(function (resolve, reject) { @@ -15,7 +16,7 @@ const archiveSpecs = (runSettings, filePath) => { archive.on('warning', function (err) { if (err.code === 'ENOENT') { - logger.log(err) + logger.info(err) } else { reject(err) } @@ -26,11 +27,11 @@ const archiveSpecs = (runSettings, filePath) => { }); output.on('end', function () { - logger.log('Data has been drained'); + logger.info('Data has been drained'); }); archive.on('error', function (err) { - reject(err) + reject(err); }); archive.pipe(output); diff --git a/bin/helpers/build.js b/bin/helpers/build.js index bc504a0d..80c67cd2 100644 --- a/bin/helpers/build.js +++ b/bin/helpers/build.js @@ -1,8 +1,10 @@ -var request = require('request') -var logger = require("./logger") -var config = require('./config'); -var capabilityHelper = require("../helpers/capabilityHelper"); -const Constants = require('../helpers/constants'); +'use strict'; +const request = require('request'); + +const logger = require("./logger").winstonLogger, + config = require('./config'), + capabilityHelper = require("../helpers/capabilityHelper"), + Constants = require('../helpers/constants'); const createBuild = (bsConfig, zip) => { return new Promise(function (resolve, reject) { @@ -37,13 +39,13 @@ const createBuild = (bsConfig, zip) => { } } else if(resp.statusCode == 299){ if(build) { - logger.log(build.message); + logger.info(build.message); } else { - logger.log(Constants.userMessages.API_DEPRECATED); + logger.info(Constants.userMessages.API_DEPRECATED); } } else { - logger.log(build.message) - logger.log(`${Constants.userMessages.BUILD_CREATED} with build id: ${build.build_id}`); + logger.info(build.message) + logger.info(`${Constants.userMessages.BUILD_CREATED} with build id: ${build.build_id}`); } resolve(build); } diff --git a/bin/helpers/capabilityHelper.js b/bin/helpers/capabilityHelper.js index d77440c3..7a1b2a51 100644 --- a/bin/helpers/capabilityHelper.js +++ b/bin/helpers/capabilityHelper.js @@ -1,6 +1,5 @@ -const logger = require("./logger"), - Constants = require('./constants'), - glob = require("glob"); +const logger = require("./logger").winstonLogger, + Constants = require("./constants"); const caps = (bsConfig, zip) => { return new Promise(function (resolve, reject) { @@ -21,45 +20,45 @@ const caps = (bsConfig, zip) => { }); obj.devices = osBrowserArray if (obj.devices.length == 0) reject(Constants.validationMessages.EMPTY_BROWSER_LIST); - logger.log(`Browser list: ${osBrowserArray.toString()}`); + logger.info(`Browser list: ${osBrowserArray.toString()}`); // Test suite obj.test_suite = zip.zip_url.split("://")[1] if (!obj.test_suite || 0 === obj.test_suite.length) reject("Test suite is empty"); - logger.log(`Test suite: bs://${obj.test_suite}`); + logger.info(`Test suite: bs://${obj.test_suite}`); // Local obj.local = false; if (bsConfig.connection_settings.local === true) obj.local = true; - logger.log(`Local is set to: ${obj.local}`); + logger.info(`Local is set to: ${obj.local}`); // Local Identifier obj.localIdentifier = null; if (obj.local === true && bsConfig.connection_settings.localIdentifier) { obj.localIdentifier = bsConfig.connection_settings.localIdentifier; - logger.log(`Local Identifier is set to: ${obj.localIdentifier}`); + logger.info(`Local Identifier is set to: ${obj.localIdentifier}`); } // Project name obj.project = bsConfig.run_settings.project - if (!obj.project) logger.log(`Project name is: ${obj.project}`); + if (!obj.project) logger.info(`Project name is: ${obj.project}`); // Base url obj.base_url = bsConfig.run_settings.baseUrl - if (obj.base_url) logger.log(`Base url is : ${obj.base_url}`); + if (obj.base_url) logger.info(`Base url is : ${obj.base_url}`); // Build name obj.customBuildName = bsConfig.run_settings.customBuildName - if (obj.customBuildName) logger.log(`Build name is: ${obj.customBuildName}`); + if (obj.customBuildName) logger.info(`Build name is: ${obj.customBuildName}`); //callback url obj.callbackURL = bsConfig.run_settings.callback_url - if (obj.callbackURL) logger.log(`callback url is : ${obj.callbackURL}`); + if (obj.callbackURL) logger.info(`callback url is : ${obj.callbackURL}`); //projectNotifyURL obj.projectNotifyURL = bsConfig.run_settings.project_notify_URL - if (obj.projectNotifyURL) logger.log(`Project notify URL is: ${obj.projectNotifyURL}`); + if (obj.projectNotifyURL) logger.info(`Project notify URL is: ${obj.projectNotifyURL}`); var data = JSON.stringify(obj); resolve(data); diff --git a/bin/helpers/config.js b/bin/helpers/config.js index 75eb084b..78377fd1 100644 --- a/bin/helpers/config.js +++ b/bin/helpers/config.js @@ -11,5 +11,8 @@ config.rails_host = hosts[config.env].rails_host; config.cypress_v1 = `${config.rails_host}/automate/cypress/v1`; config.buildUrl = `${config.cypress_v1}/builds/`; config.buildStopUrl = `${config.cypress_v1}/builds/stop/`; +config.usageReportingUrl = `http://127.0.0.1:3000/send_event_cy/`; +config.usageReportingApiKey = 'abcd'; config.fileName = "tests.zip"; + module.exports = config; diff --git a/bin/helpers/constants.js b/bin/helpers/constants.js index 6bf362a1..fd458ad1 100644 --- a/bin/helpers/constants.js +++ b/bin/helpers/constants.js @@ -14,16 +14,18 @@ const userMessages = { }; const validationMessages = { - INCORRECT_AUTH_PARAMS: "Incorrect auth params.", - EMPTY_BROWSER_LIST: "Browser list is empty", - EMPTY_TEST_SUITE: "Test suite is empty", - EMPTY_BROWSERSTACK_JSON: "Empty browserstack.json", - EMPTY_RUN_SETTINGS: "Empty run settings", - EMPTY_SPEC_FILES: "No spec files specified in run_settings", - VALIDATED: "browserstack.json file is validated", - NOT_VALID: "browerstack.json is not valid", - INVALID_EXTENSION: "Invalid files, please remove these files and try again." + INCORRECT_AUTH_PARAMS: "Incorrect auth params.", + EMPTY_BROWSER_LIST: "Browser list is empty", + EMPTY_TEST_SUITE: "Test suite is empty", + EMPTY_BROWSERSTACK_JSON: "Empty browserstack.json", + EMPTY_RUN_SETTINGS: "Empty run settings", + EMPTY_SPEC_FILES: "No spec files specified in run_settings", + VALIDATED: "browserstack.json file is validated", + NOT_VALID: "browerstack.json is not valid", + NOT_VALID_JSON: "browerstack.json is not a valid json", + INVALID_EXTENSION: "Invalid files, please remove these files and try again.", }; + const cliMessages = { VERSION: { INFO: "shows version information", @@ -50,8 +52,18 @@ const cliMessages = { } } +const messageTypes = { + SUCCESS: "success", + ERROR: "error", + INFO: "info", + WARNING: "warning", + UNKNOWN: "unknown", + NULL: null +} + module.exports = Object.freeze({ - userMessages, - cliMessages, - validationMessages -}) + userMessages, + cliMessages, + validationMessages, + messageTypes, +}); diff --git a/bin/helpers/logger.js b/bin/helpers/logger.js index 57b83266..7454b8b7 100644 --- a/bin/helpers/logger.js +++ b/bin/helpers/logger.js @@ -1,12 +1,35 @@ -function log(message) { - var timestamp = '[' + new Date().toLocaleString() + '] '; - console.log(timestamp + " " + message); -} +const winston = require('winston'), + fs = require("fs"), + path = require("path"); + +const { format } = winston; +// const { format } = require("logform"); -function error(message) { - var timestamp = '[' + new Date().toLocaleString() + '] '; - console.log(timestamp + " [ERROR] " + message); +const logDir = "log"; // directory path for logs +if (!fs.existsSync(logDir)) { + // Create the directory if it does not exist + fs.mkdirSync(logDir); } -exports.log = log -exports.error = error +const winstonLoggerParams = { + transports: [ + new winston.transports.Console({ + colorize: true, + timestamp: function () { + return `[${new Date().toLocaleString()}]`; + }, + prettyPrint: true, + }), + ], +}; + +const winstonFileLoggerParams = { + transports: [ + new winston.transports.File({ + filename: path.join(logDir, "/usage.log"), + }), + ], +}; + +exports.winstonLogger = new winston.Logger(winstonLoggerParams); +exports.fileLogger = new winston.Logger(winstonFileLoggerParams); diff --git a/bin/helpers/usageReporting.js b/bin/helpers/usageReporting.js new file mode 100644 index 00000000..d5ef441f --- /dev/null +++ b/bin/helpers/usageReporting.js @@ -0,0 +1,157 @@ +'use strict'; +const cp = require('child_process'), + os = require('os'), + request = require('request'), + fs = require('fs'), + path = require('path'); + +const config = require('./config'), + fileLogger = require('./logger').fileLogger; + +function get_version(package_name) { + try { + let options = { stdio: 'pipe' }; + return cp.execSync(`${package_name} --version`, options).toString().trim(); + } catch (err) { + return null; + } +} + +function npm_version() { + return get_version('npm'); +} + +function _os() { + return os.platform(); +} + +function os_version() { + return os.release(); +} + +function local_cypress_version(bsConfig) { + // 1. check version of Cypress installed in local project + // 2. check version of Cypress installed globally if not present in project + + if (bsConfig) { + let version = get_version(path.join(bsConfig.run_settings.cypress_proj_dir, 'node_modules', '.bin', 'cypress')); + if (!version) { + version = get_version('cypress'); + } + return version; + } else { + return get_version('cypress'); + } +} + +function bstack_json_found_in_pwd() { + try { + if (fs.existsSync(path.join(process.cwd(), 'browserstack.json'))) { + //file exists + return true; + } + else { + return false; + } + } catch (err) { + return null; + } +} + +function cypress_json_found_in_pwd() { + try { + if (fs.existsSync(path.join(process.cwd(), 'cypress.json'))) { + //file exists + return true; + } + else { + return false; + } + } catch (err) { + return null; + } +} + +function npm_global_path() { + return cp.execSync('npm root -g', { stdio: 'pipe' }).toString().trim(); +} + +function cli_version_and_path(bsConfig) { + // 1. check version of Cypress installed in local project + // 2. check version of Cypress installed globally if not present in project + + if (bsConfig) { + let _path = path.join(bsConfig.run_settings.cypress_proj_dir, 'node_modules', 'browserstack-cypress-cli'); + let version = get_version(_path); + if (!version) { + version = get_version('browserstack-cypress-cli'); + + if (!version) { + // return path = null if version is null + return [null, null]; + } + _path = npm_global_path(); + return [version, _path]; + } + return [version, _path]; + } else { + let version = get_version('browserstack-cypress-cli'); + + if (!version) { + // return path = null if version is null + return [null, null]; + } + return [version, npm_global_path()]; + } +} + +function isUsageReportingEnabled() { + return process.env.DISABLE_USAGE_REPORTING; +} + +function send(args) { + if (!isUsageReportingEnabled()) return; + + let [cli_version, cli_path] = cli_version_and_path(args.bsConfig); + + const payload = { + api_key: config.usageReportingApiKey, + data: { + event_type: 'cypress_cli_instrumentation', + os: _os(), + os_version: os_version(), + bstack_json_found_in_pwd: bstack_json_found_in_pwd(), + cypress_json_found_in_pwd: cypress_json_found_in_pwd(), + cli_version: cli_version, + cli_path: cli_path, + npm_version: npm_version(), + local_cypress_version: local_cypress_version(args.bstack_config), + timestamp: new Date().getTime(), + ...args + } + }; + + const options = { + method: 'POST', + url: config.usageReportingUrl, + body: payload, + json: true + } + + fileLogger.info(`Sending ${payload} to ${config.usageReportingUrl}`); + request(options, function (error, res, body) { + if (error) { + //write err response to file + fileLogger.err(JSON.stringify(error)); + return; + } + // write response and body to file + fileLogger.info( + `statusCode: ${res.statusCode}, body: ${JSON.stringify(body)}` + ); + }); +} + +module.exports = { + send +} diff --git a/bin/helpers/util.js b/bin/helpers/util.js new file mode 100644 index 00000000..d4de7eab --- /dev/null +++ b/bin/helpers/util.js @@ -0,0 +1,71 @@ +'use strict'; +const usageReporting = require('./usageReporting'), + logger = require('./logger').winstonLogger, + Constants = require('./constants'); + +exports.validateBstackJson = (bsConfigPath) => { + return new Promise(function(resolve, reject){ + try { + logger.info(`Reading config from ${bsConfigPath}`); + let bsConfig = require(bsConfigPath); + resolve(bsConfig); + } + catch (e) { + reject(e); + } + }); +} + +exports.getErrorCodeFromMsg = (errMsg) => { + let errorCode = null; + switch (errMsg) { + case Constants.validationMessages.EMPTY_BROWSERSTACK_JSON: + errorCode = "bstack_json_invalid_empty"; + break; + case Constants.validationMessages.INCORRECT_AUTH_PARAMS: + errorCode = "bstack_json_invalid_missing_keys"; + break; + case Constants.validationMessages.EMPTY_BROWSER_LIST: + errorCode = "bstack_json_invalid_no_browsers"; + break; + case Constants.validationMessages.EMPTY_RUN_SETTINGS: + errorCode = "bstack_json_invalid_no_run_settings"; + break; + case Constants.validationMessages.EMPTY_SPEC_FILES: + errorCode = "bstack_json_invalid_values"; + break; + } + return errorCode; +} + +exports.getErrorCodeFromErr = (err) => { + let errorCode = null; + if (err.code === 'SyntaxError') { + errorCode = 'bstack_json_parse_error'; + } else if (err.code === 'EACCES') { + errorCode = 'bstack_json_no_permission'; + } else { + errorCode = 'bstack_json_invalid_unknown'; + } + return errorCode +} + +exports.sendUsageReport = (bsConfig, args, message, message_type, error_code) => { + usageReporting.send({ + args: args, + message: message, + message_type: message_type, + error_code: error_code, + bstack_config: bsConfig + }); +} + +exports.setUsageReportingFlag = (bsConfig, disableUsageReporting) => { + if (disableUsageReporting === undefined && bsConfig && bsConfig.disable_usage_reporting != undefined) { + process.env.DISABLE_USAGE_REPORTING = bsConfig.disable_usage_reporting; + } else if (!disableUsageReporting) { + process.env.DISABLE_USAGE_REPORTING = false; + } else { + process.env.DISABLE_USAGE_REPORTING = true; + } +} diff --git a/bin/helpers/zipUpload.js b/bin/helpers/zipUpload.js index 89f7c1b8..1ac82496 100644 --- a/bin/helpers/zipUpload.js +++ b/bin/helpers/zipUpload.js @@ -1,8 +1,9 @@ -var config = require('./config'); -var request = require('request') -var fs = require('fs'); -var logger = require("./logger") -const Constants = require("./constants") +'use strict'; +const config = require("./config"), + request = require("request"), + fs = require("fs"), + logger = require("./logger").winstonLogger, + Constants = require("./constants"); const uploadCypressZip = (bsConfig, filePath) => { return new Promise(function (resolve, reject) { @@ -35,7 +36,7 @@ const uploadCypressZip = (bsConfig, filePath) => { reject(Constants.userMessages.ZIP_UPLOADER_NOT_REACHABLE); } } else { - logger.log(`Zip uploaded with url: ${responseData.zip_url}`); + logger.info(`Zip uploaded with url: ${responseData.zip_url}`); resolve(responseData); } } diff --git a/bin/runner.js b/bin/runner.js index 2985dbfc..ffe3e0fa 100755 --- a/bin/runner.js +++ b/bin/runner.js @@ -1,8 +1,8 @@ #!/usr/bin/env node - -const yargs = require('yargs') -var logger = require("./helpers/logger"); -const Constants = require('./helpers/constants'); +'use strict'; +const yargs = require('yargs'), + logger = require("./helpers/logger").winstonLogger, + Constants = require('./helpers/constants'); function checkCommands(yargs, argv, numRequired) { if (argv._.length < numRequired) { @@ -54,7 +54,7 @@ var argv = yargs .wrap(null) .argv if (checkCommands(yargs, argv, 1)) { - logger.log(Constants.cliMessages.BUILD.INFO_MESSAGE + argv._[1]); + logger.info(Constants.cliMessages.BUILD.INFO_MESSAGE + argv._[1]); return require('./commands/info')(argv); } }) @@ -75,7 +75,7 @@ var argv = yargs .wrap(null) .argv if (checkCommands(yargs, argv, 1)) { - logger.log(Constants.cliMessages.BUILD.STOP_MESSAGE + argv._[1]); + logger.info(Constants.cliMessages.BUILD.STOP_MESSAGE + argv._[1]); return require('./commands/stop')(argv); } }) diff --git a/package.json b/package.json index 29363418..f4c7f866 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "fs-extra": "^8.1.0", "mkdirp": "^1.0.3", "request": "^2.88.0", - "yargs": "^14.2.2" + "yargs": "^14.2.2", + "winston": "^2.3.1" }, "repository": { "type": "git",