From b2d3a22b371d93af16ffb348370df1cfa2d3feaa Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Tue, 5 May 2020 18:58:02 +0530 Subject: [PATCH 01/13] Adding required instrumentation --- bin/commands/info.js | 108 ++++++++++++++-------- bin/commands/init.js | 15 ++- bin/commands/runs.js | 99 ++++++++++++-------- bin/commands/stop.js | 104 +++++++++++++-------- bin/helpers/archiver.js | 13 +-- bin/helpers/build.js | 20 ++-- bin/helpers/capabilityHelper.js | 23 +++-- bin/helpers/config.js | 3 + bin/helpers/constants.js | 38 +++++--- bin/helpers/logger.js | 41 +++++++-- bin/helpers/usageReporting.js | 157 ++++++++++++++++++++++++++++++++ bin/helpers/util.js | 71 +++++++++++++++ bin/helpers/zipUpload.js | 13 +-- bin/runner.js | 12 +-- package.json | 3 +- 15 files changed, 538 insertions(+), 182 deletions(-) create mode 100644 bin/helpers/usageReporting.js create mode 100644 bin/helpers/util.js 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", From 2f04bc250a62e0bd1de56a01b856f1c3e4cec0b9 Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Wed, 6 May 2020 17:35:00 +0530 Subject: [PATCH 02/13] Update endpoint and payload --- bin/helpers/config.js | 3 +- bin/helpers/usageReporting.js | 78 +++++++++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/bin/helpers/config.js b/bin/helpers/config.js index 78377fd1..2e454743 100644 --- a/bin/helpers/config.js +++ b/bin/helpers/config.js @@ -11,8 +11,7 @@ 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.usageReportingUrl = `http://127.0.0.1:8000/send_event_cy_internal`; config.fileName = "tests.zip"; module.exports = config; diff --git a/bin/helpers/usageReporting.js b/bin/helpers/usageReporting.js index d5ef441f..a225c192 100644 --- a/bin/helpers/usageReporting.js +++ b/bin/helpers/usageReporting.js @@ -81,10 +81,10 @@ function cli_version_and_path(bsConfig) { // 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 _path = path.join(bsConfig.run_settings.cypress_proj_dir, 'node_modules', 'browserstack-cypress'); let version = get_version(_path); if (!version) { - version = get_version('browserstack-cypress-cli'); + version = get_version('browserstack-cypress'); if (!version) { // return path = null if version is null @@ -95,7 +95,7 @@ function cli_version_and_path(bsConfig) { } return [version, _path]; } else { - let version = get_version('browserstack-cypress-cli'); + let version = get_version('browserstack-cypress'); if (!version) { // return path = null if version is null @@ -105,6 +105,52 @@ function cli_version_and_path(bsConfig) { } } +function ci_environment() { + var env = process.env; + // Jenkins + if ((typeof env.JENKINS_URL === "string" && env.JENKINS_URL.length > 0) || (typeof env.JENKINS_HOME === "string" && env.JENKINS_HOME.length > 0)) { + return "Jenkins"; + } + // CircleCI + if (env.CI === "true" && env.CIRCLECI === "true") { + return "CircleCI"; + } + // Travis CI + if (env.CI === "true" && env.TRAVIS === "true") { + return "Travis CI"; + } + // Codeship + if (env.CI === "true" && env.CI_NAME === "codeship") { + return "Codeship"; + } + // Bitbucket + if (env.BITBUCKET_BRANCH && env.BITBUCKET_COMMIT) { + return "Bitbucket"; + } + // Drone + if (env.CI === "true" && env.DRONE === "true") { + return "Drone"; + } + // Semaphore + if (env.CI === "true" && env.SEMAPHORE === "true") { + return "Semaphore"; + } + // GitLab + if (env.CI === "true" && env.GITLAB_CI === "true") { + return "GitLab"; + } + // Buildkite + if (env.CI === "true" && env.BUILDKITE === "true") { + return "Buildkite"; + } + // Visual Studio Team Services + if (env.TF_BUILD === "True") { + return "Visual Studio Team Services"; + } + // if no matches, return null + return null; +} + function isUsageReportingEnabled() { return process.env.DISABLE_USAGE_REPORTING; } @@ -112,12 +158,14 @@ function isUsageReportingEnabled() { function send(args) { if (!isUsageReportingEnabled()) return; - let [cli_version, cli_path] = cli_version_and_path(args.bsConfig); + let bsConfig = args.bstack_config; + let [cli_version, cli_path] = cli_version_and_path(bsConfig); + + delete args.bstack_config; const payload = { - api_key: config.usageReportingApiKey, + event_type: "cypress_cli_stats", data: { - event_type: 'cypress_cli_instrumentation', os: _os(), os_version: os_version(), bstack_json_found_in_pwd: bstack_json_found_in_pwd(), @@ -125,18 +173,22 @@ function send(args) { 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 - } + local_cypress_version: local_cypress_version(bsConfig), + ci_environment: ci_environment(), + event_timestamp: new Date().toLocaleString(), + ...args, + }, }; const options = { - method: 'POST', + headers: { + "Content-Type": "text/json", + }, + method: "POST", url: config.usageReportingUrl, body: payload, - json: true - } + json: true, + }; fileLogger.info(`Sending ${payload} to ${config.usageReportingUrl}`); request(options, function (error, res, body) { From 03416683ba8459f78949ab5522b2a9540cf734d7 Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Thu, 7 May 2020 12:58:36 +0530 Subject: [PATCH 03/13] resolve undefined error --- bin/helpers/util.js | 2 +- bin/helpers/zipUpload.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/helpers/util.js b/bin/helpers/util.js index d4de7eab..e1684991 100644 --- a/bin/helpers/util.js +++ b/bin/helpers/util.js @@ -52,7 +52,7 @@ exports.getErrorCodeFromErr = (err) => { exports.sendUsageReport = (bsConfig, args, message, message_type, error_code) => { usageReporting.send({ - args: args, + cli_args: args, message: message, message_type: message_type, error_code: error_code, diff --git a/bin/helpers/zipUpload.js b/bin/helpers/zipUpload.js index 1ac82496..e7cd0692 100644 --- a/bin/helpers/zipUpload.js +++ b/bin/helpers/zipUpload.js @@ -20,6 +20,7 @@ const uploadCypressZip = (bsConfig, filePath) => { } } + let responseData = null; request.post(options, function (err, resp, body) { if (err) { reject(err); From 148f056c7f0d4e1138cf0f0ad32ff470f555e905 Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Thu, 7 May 2020 13:22:44 +0530 Subject: [PATCH 04/13] resolve filelogger err and add retries --- bin/helpers/logger.js | 3 --- bin/helpers/usageReporting.js | 24 +++++++++++++++--------- package.json | 5 +++-- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/bin/helpers/logger.js b/bin/helpers/logger.js index 7454b8b7..7563fce3 100644 --- a/bin/helpers/logger.js +++ b/bin/helpers/logger.js @@ -2,9 +2,6 @@ const winston = require('winston'), fs = require("fs"), path = require("path"); -const { format } = winston; -// const { format } = require("logform"); - const logDir = "log"; // directory path for logs if (!fs.existsSync(logDir)) { // Create the directory if it does not exist diff --git a/bin/helpers/usageReporting.js b/bin/helpers/usageReporting.js index a225c192..020b5613 100644 --- a/bin/helpers/usageReporting.js +++ b/bin/helpers/usageReporting.js @@ -1,7 +1,7 @@ 'use strict'; -const cp = require('child_process'), - os = require('os'), - request = require('request'), +const cp = require("child_process"), + os = require("os"), + request = require("requestretry"), fs = require('fs'), path = require('path'); @@ -188,19 +188,25 @@ function send(args) { url: config.usageReportingUrl, body: payload, json: true, + maxAttempts: 10, // (default) try 3 times + retryDelay: 2000, // (default) wait for 2s before trying again + retrySrategy: request.RetryStrategies.HTTPOrNetworkError, // (default) retry on 5xx or network errors }; - fileLogger.info(`Sending ${payload} to ${config.usageReportingUrl}`); + fileLogger.info(`Sending ${JSON.stringify(payload)} to ${config.usageReportingUrl}`); request(options, function (error, res, body) { if (error) { //write err response to file - fileLogger.err(JSON.stringify(error)); + fileLogger.error(JSON.stringify(error)); return; } - // write response and body to file - fileLogger.info( - `statusCode: ${res.statusCode}, body: ${JSON.stringify(body)}` - ); + // write response file + let response = { + attempts: res.attempts, + statusCode: res.statusCode, + body: body + }; + fileLogger.info(`${JSON.stringify(response)}`); }); } diff --git a/package.json b/package.json index f4c7f866..1ce65ef7 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,9 @@ "fs-extra": "^8.1.0", "mkdirp": "^1.0.3", "request": "^2.88.0", - "yargs": "^14.2.2", - "winston": "^2.3.1" + "requestretry": "^4.1.0", + "winston": "^2.3.1", + "yargs": "^14.2.2" }, "repository": { "type": "git", From c1caee0836c3f15f6164fe76c8f6440d54400ccd Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Thu, 7 May 2020 16:49:11 +0530 Subject: [PATCH 05/13] move api_deprecated code, change array to obj in response --- bin/commands/info.js | 36 ++++++++++++++++++++--------------- bin/commands/stop.js | 32 ++++++++++++++++--------------- bin/helpers/build.js | 23 +++++++++++++--------- bin/helpers/usageReporting.js | 32 ++++++++++++++++++++++--------- 4 files changed, 75 insertions(+), 48 deletions(-) diff --git a/bin/commands/info.js b/bin/commands/info.js index 4408f044..868c65ea 100644 --- a/bin/commands/info.js +++ b/bin/commands/info.js @@ -46,21 +46,9 @@ function buildInfo(args) { build = null; } - 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) { + if (resp.statusCode == 299) { messageType = Constants.messageTypes.INFO; - errorCode = 'api_deprecated'; + errorCode = "api_deprecated"; if (build) { message = build.message; @@ -69,9 +57,27 @@ function buildInfo(args) { message = Constants.userMessages.API_DEPRECATED; logger.info(message); } + } else 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 { messageType = Constants.messageTypes.SUCCESS; - message = `Build info for build id: \n ${JSON.stringify(build, null, 2)}`; + message = `Build info for build id: \n ${JSON.stringify( + build, + null, + 2 + )}`; logger.info(message); } } diff --git a/bin/commands/stop.js b/bin/commands/stop.js index b68330c7..c39ed162 100644 --- a/bin/commands/stop.js +++ b/bin/commands/stop.js @@ -46,29 +46,31 @@ function buildStop(args) { build = null } - 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) { + if (resp.statusCode == 299) { messageType = Constants.messageTypes.INFO; - errorCode = 'api_deprecated'; + errorCode = "api_deprecated"; if (build) { - message = build.message + message = build.message; logger.info(message); } else { message = Constants.userMessages.API_DEPRECATED; logger.info(message); } + } else 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 { messageType = Constants.messageTypes.SUCCESS; message = `${JSON.stringify(build, null, 2)}`; diff --git a/bin/helpers/build.js b/bin/helpers/build.js index 80c67cd2..e09b6577 100644 --- a/bin/helpers/build.js +++ b/bin/helpers/build.js @@ -31,21 +31,26 @@ const createBuild = (bsConfig, zip) => { } catch (error) { build = null } - if (resp.statusCode != 201) { + + if (resp.statusCode == 299) { if (build) { - logger.error(`${Constants.userMessages.BUILD_FAILED} Error: ${build.message}`); - } else { - logger.error(Constants.userMessages.BUILD_FAILED); - } - } else if(resp.statusCode == 299){ - if(build) { logger.info(build.message); } else { logger.info(Constants.userMessages.API_DEPRECATED); } + } else if (resp.statusCode != 201) { + if (build) { + logger.error( + `${Constants.userMessages.BUILD_FAILED} Error: ${build.message}` + ); + } else { + logger.error(Constants.userMessages.BUILD_FAILED); + } } else { - logger.info(build.message) - logger.info(`${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/usageReporting.js b/bin/helpers/usageReporting.js index 020b5613..9f42f6a9 100644 --- a/bin/helpers/usageReporting.js +++ b/bin/helpers/usageReporting.js @@ -88,20 +88,34 @@ function cli_version_and_path(bsConfig) { if (!version) { // return path = null if version is null - return [null, null]; + return { + version: null, + path: null + }; } - _path = npm_global_path(); - return [version, _path]; + return { + version: version, + path: npm_global_path(), + }; } - return [version, _path]; + return { + version: version, + path: _path, + }; } else { let version = get_version('browserstack-cypress'); if (!version) { // return path = null if version is null - return [null, null]; + return { + version: null, + path: null, + }; } - return [version, npm_global_path()]; + return { + version: version, + path: npm_global_path(), + }; } } @@ -159,7 +173,7 @@ function send(args) { if (!isUsageReportingEnabled()) return; let bsConfig = args.bstack_config; - let [cli_version, cli_path] = cli_version_and_path(bsConfig); + let cli_details = cli_version_and_path(bsConfig); delete args.bstack_config; @@ -170,8 +184,8 @@ function send(args) { 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, + cli_version: cli_details.version, + cli_path: cli_details.path, npm_version: npm_version(), local_cypress_version: local_cypress_version(bsConfig), ci_environment: ci_environment(), From 3f61f912359675ffcd5c39d20db6d5a74092747d Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Fri, 8 May 2020 00:47:56 +0530 Subject: [PATCH 06/13] fix disable-usage-reporting flag bug --- bin/commands/info.js | 4 ++-- bin/commands/runs.js | 4 ++-- bin/commands/stop.js | 4 ++-- bin/helpers/usageReporting.js | 2 +- bin/helpers/util.js | 8 +++----- bin/templates/configTemplate.js | 3 ++- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/bin/commands/info.js b/bin/commands/info.js index 868c65ea..fdd5ded0 100644 --- a/bin/commands/info.js +++ b/bin/commands/info.js @@ -14,7 +14,7 @@ function buildInfo(args) { let bsConfigPath = process.cwd() + args.cf; util.validateBstackJson(bsConfigPath).then(function (bsConfig) { - util.setUsageReportingFlag(bsConfig, args.cf.disableUsageReporting); + util.setUsageReportingFlag(bsConfig, args.disableUsageReporting); let buildId = args._[1]; @@ -85,7 +85,7 @@ function buildInfo(args) { }) }).catch(function (err) { logger.error(err); - util.setUsageReportingFlag(null, args.cf.disableUsageReporting); + util.setUsageReportingFlag(null, args.disableUsageReporting); util.sendUsageReport(null, args, err.message, Constants.messageTypes.ERROR, util.getErrorCodeFromErr(err)); }) } diff --git a/bin/commands/runs.js b/bin/commands/runs.js index f6ceecb1..74872c99 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -28,7 +28,7 @@ function runCypress(args) { let bsConfigPath = process.cwd() + args.cf; util.validateBstackJson(bsConfigPath).then(function (bsConfig) { - util.setUsageReportingFlag(bsConfig, args.cf.disableUsageReporting); + util.setUsageReportingFlag(bsConfig, args.disableUsageReporting); // Validate browserstack.json values capabilityHelper.validate(bsConfig).then(function (validated) { @@ -77,7 +77,7 @@ function runCypress(args) { }); }).catch(function (err) { logger.error(err); - util.setUsageReportingFlag(null, args.cf.disableUsageReporting); + util.setUsageReportingFlag(null, args.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 c39ed162..5f9a144e 100644 --- a/bin/commands/stop.js +++ b/bin/commands/stop.js @@ -14,7 +14,7 @@ function buildStop(args) { let bsConfigPath = process.cwd() + args.cf; util.validateBstackJson(bsConfigPath).then(function (bsConfig) { - util.setUsageReportingFlag(bsConfig, args.cf.disableUsageReporting); + util.setUsageReportingFlag(bsConfig, args.disableUsageReporting); let buildId = args._[1]; @@ -81,7 +81,7 @@ function buildStop(args) { }) }).catch(function (err) { logger.error(err); - util.setUsageReportingFlag(null, args.cf.disableUsageReporting); + util.setUsageReportingFlag(null, args.disableUsageReporting); util.sendUsageReport(null, args, err.message, Constants.messageTypes.ERROR, util.getErrorCodeFromErr(err)); }) } diff --git a/bin/helpers/usageReporting.js b/bin/helpers/usageReporting.js index 9f42f6a9..9f2a8088 100644 --- a/bin/helpers/usageReporting.js +++ b/bin/helpers/usageReporting.js @@ -170,7 +170,7 @@ function isUsageReportingEnabled() { } function send(args) { - if (!isUsageReportingEnabled()) return; + if (isUsageReportingEnabled() === "true") return; let bsConfig = args.bstack_config; let cli_details = cli_version_and_path(bsConfig); diff --git a/bin/helpers/util.js b/bin/helpers/util.js index e1684991..5c68090a 100644 --- a/bin/helpers/util.js +++ b/bin/helpers/util.js @@ -61,11 +61,9 @@ exports.sendUsageReport = (bsConfig, args, message, message_type, error_code) => } 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; + if (disableUsageReporting === undefined && bsConfig && bsConfig['disable-usage-reporting'] != undefined) { + process.env.DISABLE_USAGE_REPORTING = bsConfig['disable-usage-reporting']; } else { - process.env.DISABLE_USAGE_REPORTING = true; + process.env.DISABLE_USAGE_REPORTING = disableUsageReporting; } } diff --git a/bin/templates/configTemplate.js b/bin/templates/configTemplate.js index ceacf659..29b08721 100644 --- a/bin/templates/configTemplate.js +++ b/bin/templates/configTemplate.js @@ -19,7 +19,8 @@ module.exports = function () { "connection_settings": { "local": false, "localIdentifier": null - } + }, + "disable-usage-reporting": false } var EOL = require('os').EOL var file = [ From 4d3710417ff855b8694115e6d022d5e4eb3f336e Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Fri, 8 May 2020 01:18:12 +0530 Subject: [PATCH 07/13] log -> resolve/reject while build creation --- bin/commands/runs.js | 8 +++++--- bin/helpers/archiver.js | 6 +++--- bin/helpers/build.js | 26 ++++++++++---------------- bin/helpers/constants.js | 2 +- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 74872c99..4b1a90ce 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -41,12 +41,14 @@ function runCypress(args) { zipUploader.zipUpload(bsConfig, config.fileName).then(function (zip) { // Create build - build.createBuild(bsConfig, zip).then(function (data) { + build.createBuild(bsConfig, zip).then(function (message) { + logger.info(message); + util.sendUsageReport(bsConfig, args, message, Constants.messageTypes.SUCCESS, null); 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'); + logger.error(err); + util.sendUsageReport(bsConfig, args, err, Constants.messageTypes.ERROR, 'build_failed'); }); }).catch(function (err) { // Zip Upload failed diff --git a/bin/helpers/archiver.js b/bin/helpers/archiver.js index e786ccac..630506c0 100644 --- a/bin/helpers/archiver.js +++ b/bin/helpers/archiver.js @@ -16,14 +16,14 @@ const archiveSpecs = (runSettings, filePath) => { archive.on('warning', function (err) { if (err.code === 'ENOENT') { - logger.info(err) + logger.info(err); } else { - reject(err) + reject(err); } }); output.on('close', function () { - resolve("Zipping completed") + resolve("Zipping completed"); }); output.on('end', function () { diff --git a/bin/helpers/build.js b/bin/helpers/build.js index e09b6577..80a42a17 100644 --- a/bin/helpers/build.js +++ b/bin/helpers/build.js @@ -1,8 +1,7 @@ 'use strict'; const request = require('request'); -const logger = require("./logger").winstonLogger, - config = require('./config'), +const config = require('./config'), capabilityHelper = require("../helpers/capabilityHelper"), Constants = require('../helpers/constants'); @@ -23,34 +22,29 @@ const createBuild = (bsConfig, zip) => { request.post(options, function (err, resp, body) { if (err) { - reject(err) + reject(err); } else { - let build = null + let build = null; try { - build = JSON.parse(body) + build = JSON.parse(body); } catch (error) { - build = null + build = null; } if (resp.statusCode == 299) { if (build) { - logger.info(build.message); + resolve(build.message); } else { - logger.info(Constants.userMessages.API_DEPRECATED); + reject(Constants.userMessages.API_DEPRECATED); } } else if (resp.statusCode != 201) { if (build) { - logger.error( - `${Constants.userMessages.BUILD_FAILED} Error: ${build.message}` - ); + reject(`${Constants.userMessages.BUILD_FAILED} Error: ${build.message}`); } else { - logger.error(Constants.userMessages.BUILD_FAILED); + reject(Constants.userMessages.BUILD_FAILED); } } else { - logger.info(build.message); - logger.info( - `${Constants.userMessages.BUILD_CREATED} with build id: ${build.build_id}` - ); + resolve(`${build.message}! ${Constants.userMessages.BUILD_CREATED} with build id: ${build.build_id}`); } resolve(build); } diff --git a/bin/helpers/constants.js b/bin/helpers/constants.js index fd458ad1..176f1c08 100644 --- a/bin/helpers/constants.js +++ b/bin/helpers/constants.js @@ -8,7 +8,7 @@ const userMessages = { CONFIG_FILE_CREATED: "BrowserStack Config File created, you can now run browserstack-cypress --config-file run", CONFIG_FILE_EXISTS: "File already exists, delete the browserstack.json file manually. skipping...", ZIP_DELETE_FAILED: "Could not delete local file.", - ZIP_DELETED: "File deleted successfully.", + ZIP_DELETED: "Zip file deleted successfully.", API_DEPRECATED: "This version of API is deprecated, please use latest version of API.", FAILED_TO_ZIP: "Failed to zip files." }; From fc3d9c049bf00dda132f1e6df34fc55fba28eeda Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Fri, 8 May 2020 11:05:26 +0530 Subject: [PATCH 08/13] remove console.log from fileHelpers --- bin/helpers/fileHelpers.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bin/helpers/fileHelpers.js b/bin/helpers/fileHelpers.js index 700521a8..1aadcbf6 100644 --- a/bin/helpers/fileHelpers.js +++ b/bin/helpers/fileHelpers.js @@ -1,7 +1,9 @@ 'use strict'; -var fs = require('fs-extra'); -var path = require('path'); -var mkdirp = require('mkdirp') +const fs = require('fs-extra'), + path = require('path'), + mkdirp = require('mkdirp'); + +const logger = require('./logger').winstonLogger; exports.isEmpty = function(path, cb) { fs.readdir(path, function(err, files) { @@ -33,7 +35,7 @@ exports.isFile = function(path, cb) { exports.mkdir = function(dir, cb) { mkdirp(dir, '0755', function(err) { if (err) throw err; - console.log('Creating directory: ./' + path.relative(process.cwd(), dir)) + logger.info("Creating directory: ./" + path.relative(process.cwd(), dir)); cb && cb() }) } @@ -41,7 +43,7 @@ exports.mkdir = function(dir, cb) { exports.write = function(f, message, cb) { message = message || 'Creating'; fs.writeFile(f.path, f.file, function() { - console.log(message + ' file: ./' + path.relative(process.cwd(), f.path)); + logger.info(message + " file: ./" + path.relative(process.cwd(), f.path)); cb && cb() }); } From 8d9d4d3bf54d521e80fafca1a935e4af583e4f42 Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Tue, 12 May 2020 11:58:18 +0530 Subject: [PATCH 09/13] update options in help messages --- bin/helpers/constants.js | 3 ++ bin/helpers/util.js | 4 +- bin/runner.js | 93 +++++++++++++++++++++------------ bin/templates/configTemplate.js | 2 +- 4 files changed, 66 insertions(+), 36 deletions(-) diff --git a/bin/helpers/constants.js b/bin/helpers/constants.js index 176f1c08..03558069 100644 --- a/bin/helpers/constants.js +++ b/bin/helpers/constants.js @@ -49,6 +49,9 @@ const cliMessages = { INFO: "Run your tests on BrowserStack.", DESC: "Path to BrowserStack config", CONFIG_DEMAND: "config file is required" + }, + COMMON: { + DISABLE_USAGE_REPORTING: "Disable usage reporting" } } diff --git a/bin/helpers/util.js b/bin/helpers/util.js index 5c68090a..21078e6a 100644 --- a/bin/helpers/util.js +++ b/bin/helpers/util.js @@ -61,8 +61,8 @@ exports.sendUsageReport = (bsConfig, args, message, message_type, error_code) => } exports.setUsageReportingFlag = (bsConfig, disableUsageReporting) => { - if (disableUsageReporting === undefined && bsConfig && bsConfig['disable-usage-reporting'] != undefined) { - process.env.DISABLE_USAGE_REPORTING = bsConfig['disable-usage-reporting']; + if (disableUsageReporting === undefined && bsConfig && bsConfig['disable_usage_reporting'] != undefined) { + process.env.DISABLE_USAGE_REPORTING = bsConfig['disable_usage_reporting']; } else { process.env.DISABLE_USAGE_REPORTING = disableUsageReporting; } diff --git a/bin/runner.js b/bin/runner.js index ffe3e0fa..2b65587b 100755 --- a/bin/runner.js +++ b/bin/runner.js @@ -22,16 +22,22 @@ var argv = yargs .demand(1, Constants.cliMessages.VERSION.DEMAND) .command('init', Constants.cliMessages.INIT.INFO, function(yargs) { argv = yargs - .usage('usage: $0 init [options]') - .options('p', { - alias: 'path', - default: false, - description: Constants.cliMessages.INIT.DESC, - type: 'string' + .usage("usage: $0 init [options]") + .options({ + 'p': { + alias: "path", + default: false, + description: Constants.cliMessages.INIT.DESC, + type: "string", + }, + 'disable-usage-reporting': { + default: undefined, + description: Constants.cliMessages.COMMON.DISABLE_USAGE_REPORTING, + type: "boolean" + }, }) - .help('help') - .wrap(null) - .argv + .help("help") + .wrap(null).argv; if (checkCommands(yargs, argv, 1)) { return require('./commands/init')(argv); @@ -41,14 +47,21 @@ var argv = yargs argv = yargs .usage('usage: $0 ') .demand(1, Constants.cliMessages.BUILD.DEMAND) - .options('cf', { - alias: 'config-file', - describe: Constants.cliMessages.BUILD.DESC, - default: '/browserstack.json', - type: 'string', - nargs: 1, - demand: true, - demand: Constants.cliMessages.BUILD.CONFIG_DEMAND + .options({ + 'cf': { + alias: 'config-file', + describe: Constants.cliMessages.BUILD.DESC, + default: '/browserstack.json', + type: 'string', + nargs: 1, + demand: true, + demand: Constants.cliMessages.BUILD.CONFIG_DEMAND + }, + 'disable-usage-reporting': { + default: undefined, + description: Constants.cliMessages.COMMON.DISABLE_USAGE_REPORTING, + type: "boolean" + }, }) .help('help') .wrap(null) @@ -62,14 +75,21 @@ var argv = yargs argv = yargs .usage('usage: $0 ') .demand(1, Constants.cliMessages.BUILD.DEMAND) - .options('cf', { - alias: 'config-file', - describe: Constants.cliMessages.BUILD.DESC, - default: '/browserstack.json', - type: 'string', - nargs: 1, - demand: true, - demand: Constants.cliMessages.BUILD.CONFIG_DEMAND + .options({ + 'cf': { + alias: 'config-file', + describe: Constants.cliMessages.BUILD.DESC, + default: '/browserstack.json', + type: 'string', + nargs: 1, + demand: true, + demand: Constants.cliMessages.BUILD.CONFIG_DEMAND + }, + 'disable-usage-reporting': { + default: undefined, + description: Constants.cliMessages.COMMON.DISABLE_USAGE_REPORTING, + type: "boolean" + }, }) .help('help') .wrap(null) @@ -82,14 +102,21 @@ var argv = yargs .command('run', Constants.cliMessages.RUN.INFO, function(yargs) { argv = yargs .usage('usage: $0 build') - .options('cf', { - alias: 'config-file', - describe: Constants.cliMessages.RUN.DESC, - default: '/browserstack.json', - type: 'string', - nargs: 1, - demand: true, - demand: Constants.cliMessages.RUN.CONFIG_DEMAND + .options({ + 'cf': { + alias: 'config-file', + describe: Constants.cliMessages.RUN.DESC, + default: '/browserstack.json', + type: 'string', + nargs: 1, + demand: true, + demand: Constants.cliMessages.RUN.CONFIG_DEMAND + }, + 'disable-usage-reporting': { + default: undefined, + description: Constants.cliMessages.COMMON.DISABLE_USAGE_REPORTING, + type: "boolean" + }, }) .help('help') .wrap(null) diff --git a/bin/templates/configTemplate.js b/bin/templates/configTemplate.js index 29b08721..974a0707 100644 --- a/bin/templates/configTemplate.js +++ b/bin/templates/configTemplate.js @@ -20,7 +20,7 @@ module.exports = function () { "local": false, "localIdentifier": null }, - "disable-usage-reporting": false + "disable_usage_reporting": false } var EOL = require('os').EOL var file = [ From 67dd517ed2506adb68b5b057410105616d18c28f Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Tue, 12 May 2020 12:50:19 +0530 Subject: [PATCH 10/13] add user-agent while calling api --- bin/commands/info.js | 11 +++++++---- bin/commands/stop.js | 11 +++++++---- bin/helpers/build.js | 6 ++++-- bin/helpers/util.js | 4 ++++ bin/helpers/zipUpload.js | 6 +++++- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/bin/commands/info.js b/bin/commands/info.js index fdd5ded0..069a848a 100644 --- a/bin/commands/info.js +++ b/bin/commands/info.js @@ -20,12 +20,15 @@ function buildInfo(args) { let options = { url: config.buildUrl + buildId, - method: 'GET', + method: "GET", auth: { user: bsConfig.auth.username, - password: bsConfig.auth.access_key - } - } + password: bsConfig.auth.access_key, + }, + headers: { + "User-Agent": util.getUserAgent, + }, + }; request(options, function (err, resp, body) { let message = null; diff --git a/bin/commands/stop.js b/bin/commands/stop.js index 5f9a144e..57088a6d 100644 --- a/bin/commands/stop.js +++ b/bin/commands/stop.js @@ -20,12 +20,15 @@ function buildStop(args) { let options = { url: config.buildStopUrl + buildId, - method: 'POST', + method: "POST", auth: { user: bsConfig.auth.username, - password: bsConfig.auth.access_key - } - } + password: bsConfig.auth.access_key, + }, + headers: { + "User-Agent": util.getUserAgent(), + }, + }; request(options, function (err, resp, body) { let message = null; diff --git a/bin/helpers/build.js b/bin/helpers/build.js index 80a42a17..9deb7dc5 100644 --- a/bin/helpers/build.js +++ b/bin/helpers/build.js @@ -3,7 +3,8 @@ const request = require('request'); const config = require('./config'), capabilityHelper = require("../helpers/capabilityHelper"), - Constants = require('../helpers/constants'); + Constants = require('../helpers/constants'), + util =require('../helpers/util'); const createBuild = (bsConfig, zip) => { return new Promise(function (resolve, reject) { @@ -15,7 +16,8 @@ const createBuild = (bsConfig, zip) => { password: bsConfig.auth.access_key }, headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + "User-Agent": util.getUserAgent(), }, body: data } diff --git a/bin/helpers/util.js b/bin/helpers/util.js index 21078e6a..252d0cb3 100644 --- a/bin/helpers/util.js +++ b/bin/helpers/util.js @@ -67,3 +67,7 @@ exports.setUsageReportingFlag = (bsConfig, disableUsageReporting) => { process.env.DISABLE_USAGE_REPORTING = disableUsageReporting; } } + +exports.getUserAgent = () => { + return `BStack-Cypress-CLI`; +} diff --git a/bin/helpers/zipUpload.js b/bin/helpers/zipUpload.js index e7cd0692..a5d2d6c7 100644 --- a/bin/helpers/zipUpload.js +++ b/bin/helpers/zipUpload.js @@ -3,7 +3,8 @@ const config = require("./config"), request = require("request"), fs = require("fs"), logger = require("./logger").winstonLogger, - Constants = require("./constants"); + Constants = require("./constants"), + util = require("./util"); const uploadCypressZip = (bsConfig, filePath) => { return new Promise(function (resolve, reject) { @@ -17,6 +18,9 @@ const uploadCypressZip = (bsConfig, filePath) => { file: fs.createReadStream(filePath), filetype: 'zip', filename: 'tests' + }, + headers: { + "User-Agent": util.getUserAgent, } } From e646ae76a714b5eb02808c6795ca43cdd24e1fc7 Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Tue, 12 May 2020 14:26:43 +0530 Subject: [PATCH 11/13] update user-agent --- bin/helpers/util.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/helpers/util.js b/bin/helpers/util.js index 252d0cb3..8128f9f2 100644 --- a/bin/helpers/util.js +++ b/bin/helpers/util.js @@ -1,4 +1,6 @@ 'use strict'; +const os = require("os"); + const usageReporting = require('./usageReporting'), logger = require('./logger').winstonLogger, Constants = require('./constants'); @@ -69,5 +71,5 @@ exports.setUsageReportingFlag = (bsConfig, disableUsageReporting) => { } exports.getUserAgent = () => { - return `BStack-Cypress-CLI`; + return `BStack-Cypress-CLI/1.x (${os.arch()}/${os.platform()}/${os.release()})`; } From 8053797155f446a33aafb4f3da93e41858a9eee5 Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Tue, 12 May 2020 17:07:21 +0530 Subject: [PATCH 12/13] fix user-agent bug --- bin/commands/info.js | 2 +- bin/helpers/zipUpload.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/commands/info.js b/bin/commands/info.js index 069a848a..264cdeb8 100644 --- a/bin/commands/info.js +++ b/bin/commands/info.js @@ -26,7 +26,7 @@ function buildInfo(args) { password: bsConfig.auth.access_key, }, headers: { - "User-Agent": util.getUserAgent, + "User-Agent": util.getUserAgent(), }, }; diff --git a/bin/helpers/zipUpload.js b/bin/helpers/zipUpload.js index a5d2d6c7..3c3931d0 100644 --- a/bin/helpers/zipUpload.js +++ b/bin/helpers/zipUpload.js @@ -20,7 +20,7 @@ const uploadCypressZip = (bsConfig, filePath) => { filename: 'tests' }, headers: { - "User-Agent": util.getUserAgent, + "User-Agent": util.getUserAgent(), } } From 46410d9877d3fab4ec77b2136c81eb6c5fde8189 Mon Sep 17 00:00:00 2001 From: nagpalkaran95 Date: Fri, 15 May 2020 13:21:14 +0530 Subject: [PATCH 13/13] bump version in package.json and update endpoint in config --- bin/helpers/config.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/helpers/config.js b/bin/helpers/config.js index 2e454743..21897e46 100644 --- a/bin/helpers/config.js +++ b/bin/helpers/config.js @@ -11,7 +11,7 @@ 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:8000/send_event_cy_internal`; +config.usageReportingUrl = `https://eds.browserstack.com:443/send_event_cy_internal`; config.fileName = "tests.zip"; module.exports = config; diff --git a/package.json b/package.json index 1ce65ef7..91158511 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "browserstack-cypress-cli", - "version": "1.1.0", + "version": "1.1.3", "description": "BrowserStack Cypress CLI for Cypress integration with BrowserStack's remote devices.", "main": "index.js", "scripts": {