Skip to content

Commit f53d2ee

Browse files
Merge master
2 parents 97380a5 + f1b31b6 commit f53d2ee

File tree

18 files changed

+2261
-40
lines changed

18 files changed

+2261
-40
lines changed

bin/commands/runs.js

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ const archiver = require("../helpers/archiver"),
1818
{initTimeComponents, instrumentEventTime, markBlockStart, markBlockEnd, getTimeComponents} = require('../helpers/timeComponents'),
1919
downloadBuildArtifacts = require('../helpers/buildArtifacts').downloadBuildArtifacts,
2020
downloadBuildStacktrace = require('../helpers/downloadBuildStacktrace').downloadBuildStacktrace,
21-
updateNotifier = require('update-notifier'),
2221
pkg = require('../../package.json'),
2322
packageDiff = require('../helpers/package-diff');
2423
const { getStackTraceUrl } = require('../helpers/sync/syncSpecsLogs');
@@ -249,6 +248,9 @@ module.exports = function run(args, rawArgs) {
249248
utils.setProcessHooks(data.build_id, bsConfig, bs_local, args, buildReportData);
250249
let message = `${data.message}! ${Constants.userMessages.BUILD_CREATED} with build id: ${data.build_id}`;
251250
let dashboardLink = `${Constants.userMessages.VISIT_DASHBOARD} ${data.dashboard_url}`;
251+
if (turboScaleSession) {
252+
dashboardLink = `${Constants.userMessages.VISIT_ATS_DASHBOARD} ${data.dashboard_url}`;
253+
}
252254
buildReportData = { 'build_id': data.build_id, 'parallels': userSpecifiedParallels, ...buildReportData }
253255
utils.exportResults(data.build_id, `${config.dashboardUrl}${data.build_id}`);
254256
if ((utils.isUndefined(bsConfig.run_settings.parallels) && utils.isUndefined(args.parallels)) || (!utils.isUndefined(bsConfig.run_settings.parallels) && bsConfig.run_settings.parallels == Constants.cliMessages.RUN.DEFAULT_PARALLEL_MESSAGE)) {
@@ -311,6 +313,8 @@ module.exports = function run(args, rawArgs) {
311313
logger.info(Constants.userMessages.BUILD_FAILED_ERROR)
312314
process.exitCode = Constants.BUILD_FAILED_EXIT_CODE;
313315
});
316+
} else {
317+
utils.handleSyncExit(exitCode, data.dashboard_url);
314318
}
315319
});
316320
} else if (utils.nonEmptyArray(bsConfig.run_settings.downloads && !turboScaleSession)) {
@@ -452,23 +456,27 @@ module.exports = function run(args, rawArgs) {
452456
utils.sendUsageReport(bsJsonData, args, err.message, Constants.messageTypes.ERROR, utils.getErrorCodeFromErr(err), null, rawArgs);
453457
process.exitCode = Constants.ERROR_EXIT_CODE;
454458
}).finally(function(){
455-
const notifier = updateNotifier({
456-
pkg,
457-
updateCheckInterval: 1000 * 60 * 60 * 24 * 7,
458-
});
459+
import('update-notifier').then(({ default: updateNotifier } ) => {
460+
const notifier = updateNotifier({
461+
pkg,
462+
updateCheckInterval: 1000 * 60 * 60 * 24 * 7,
463+
});
459464

460-
// Checks for update on first run.
461-
// Set lastUpdateCheck to 0 to spawn the check update process as notifier sets this to Date.now() for preventing
462-
// the check untill one interval period. It runs once.
463-
if (!notifier.disabled && Date.now() - notifier.config.get('lastUpdateCheck') < 50) {
464-
notifier.config.set('lastUpdateCheck', 0);
465-
notifier.check();
466-
}
465+
// Checks for update on first run.
466+
// Set lastUpdateCheck to 0 to spawn the check update process as notifier sets this to Date.now() for preventing
467+
// the check untill one interval period. It runs once.
468+
if (!notifier.disabled && Date.now() - notifier.config.get('lastUpdateCheck') < 50) {
469+
notifier.config.set('lastUpdateCheck', 0);
470+
notifier.check();
471+
}
467472

468-
// Set the config update as notifier clears this after reading.
469-
if (notifier.update && notifier.update.current !== notifier.update.latest) {
470-
notifier.config.set('update', notifier.update);
471-
notifier.notify({isGlobal: true});
472-
}
473+
// Set the config update as notifier clears this after reading.
474+
if (notifier.update && notifier.update.current !== notifier.update.latest) {
475+
notifier.config.set('update', notifier.update);
476+
notifier.notify({isGlobal: true});
477+
}
478+
}).catch((error) => {
479+
logger.debug('Got error loading update-notifier: ', error);
480+
});
473481
});
474482
}

bin/helpers/archiver.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,30 @@ const archiveSpecs = (runSettings, filePath, excludeFiles, md5data) => {
7272
});
7373
}
7474

75+
// Split mac and win configs
76+
let macPackageJSON = {};
77+
let winPackageJSON = {};
78+
Object.assign(macPackageJSON, packageJSON);
79+
Object.assign(winPackageJSON, packageJSON);
80+
81+
if (typeof runSettings.npm_dependencies === 'object') {
82+
let macNpmDependencies = Object.assign({}, runSettings.npm_dependencies, runSettings.mac_npm_dependencies || {});
83+
let winNpmDependencies = Object.assign({}, runSettings.npm_dependencies, runSettings.win_npm_dependencies || {});
84+
85+
Object.assign(macPackageJSON, {
86+
devDependencies: macNpmDependencies,
87+
});
88+
89+
Object.assign(winPackageJSON, {
90+
devDependencies: winNpmDependencies,
91+
});
92+
}
93+
7594
if (Object.keys(packageJSON).length > 0) {
76-
let packageJSONString = JSON.stringify(packageJSON, null, 4);
77-
archive.append(packageJSONString, {name: `${cypressAppendFilesZipLocation}browserstack-package.json`});
95+
const macPackageJSONString = JSON.stringify(macPackageJSON, null, 4);
96+
const winPackageJSONString = JSON.stringify(winPackageJSON, null, 4);
97+
archive.append(macPackageJSONString, {name: `${cypressAppendFilesZipLocation}browserstack-mac-package.json`});
98+
archive.append(winPackageJSONString, {name: `${cypressAppendFilesZipLocation}browserstack-win-package.json`});
7899
}
79100

80101
//Create copy of package.json

bin/helpers/buildArtifacts.js

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const { default: axios } = require('axios');
1212
const HttpsProxyAgent = require('https-proxy-agent');
1313
const FormData = require('form-data');
1414
const decompress = require('decompress');
15+
const unzipper = require("unzipper");
1516

1617
let BUILD_ARTIFACTS_TOTAL_COUNT = 0;
1718
let BUILD_ARTIFACTS_FAIL_COUNT = 0;
@@ -36,6 +37,9 @@ const parseAndDownloadArtifacts = async (buildId, data, bsConfig, args, rawArgs,
3637
utils.sendUsageReport(bsConfig, args, warningMessage, Constants.messageTypes.ERROR, 'build_artifacts_not_found', buildReportData, rawArgs);
3738
} else {
3839
BUILD_ARTIFACTS_FAIL_COUNT += 1;
40+
const errorMsg = `Error downloading build artifacts for ${sessionId} with error: ${error}`;
41+
logger.debug(errorMsg);
42+
utils.sendUsageReport(bsConfig, args, errorMsg, Constants.messageTypes.ERROR, 'build_artifacts_parse_error', buildReportData, rawArgs);
3943
}
4044
// delete malformed zip if present
4145
let tmpFilePath = path.join(filePath, fileName);
@@ -103,14 +107,16 @@ const downloadAndUnzip = async (filePath, fileName, url) => {
103107
let tmpFilePath = path.join(filePath, fileName);
104108
const writer = fs.createWriteStream(tmpFilePath);
105109

110+
logger.debug(`Downloading build artifact for: ${filePath}`)
106111
return new Promise(async (resolve, reject) => {
107112
try {
108113
const response = await axios.get(url, {responseType: 'stream'});
109114
if(response.status != 200) {
110115
if (response.statusCode === 404) {
111116
reject(Constants.userMessages.DOWNLOAD_BUILD_ARTIFACTS_NOT_FOUND);
112117
}
113-
reject()
118+
const errorMsg = `Non 200 status code, got status code: ${response.statusCode}`;
119+
reject(errorMsg);
114120
} else {
115121
//ensure that the user can call `then()` only when the file has
116122
//been downloaded entirely.
@@ -122,13 +128,15 @@ const downloadAndUnzip = async (filePath, fileName, url) => {
122128
reject(err);
123129
});
124130
writer.on('close', async () => {
125-
if (!error) {
126-
await unzipFile(filePath, fileName);
127-
fs.unlinkSync(tmpFilePath);
128-
resolve(true);
131+
try {
132+
if (!error) {
133+
await unzipFile(filePath, fileName);
134+
fs.unlinkSync(tmpFilePath);
135+
}
136+
} catch (error) {
137+
reject(error);
129138
}
130-
//no need to call the reject here, as it will have been called in the
131-
//'error' stream;
139+
resolve(true);
132140
});
133141
}
134142
} catch (error) {
@@ -139,13 +147,25 @@ const downloadAndUnzip = async (filePath, fileName, url) => {
139147

140148
const unzipFile = async (filePath, fileName) => {
141149
return new Promise( async (resolve, reject) => {
142-
await decompress(path.join(filePath, fileName), filePath)
143-
.then((files) => {
150+
try {
151+
await decompress(path.join(filePath, fileName), filePath);
144152
resolve();
145-
})
146-
.catch((error) => {
147-
reject(error);
148-
});
153+
} catch (error) {
154+
logger.debug(`Error unzipping with decompress, trying with unzipper. Stacktrace: ${error}.`);
155+
try {
156+
fs.createReadStream(path.join(filePath, fileName))
157+
.pipe(unzipper.Extract({ path: filePath }))
158+
.on("close", () => {
159+
resolve();
160+
})
161+
.on("error", (err) => {
162+
reject(err);
163+
});
164+
} catch (unzipperError) {
165+
logger.debug(`Unzipper package error: ${unzipperError}`);
166+
reject(Constants.userMessages.BUILD_ARTIFACTS_UNZIP_FAILURE);
167+
}
168+
}
149169
});
150170
}
151171

bin/helpers/checkUploaded.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22
const { default: axios } = require('axios');
3+
const { combineMacWinNpmDependencies } = require('./helper');
34

45
const crypto = require('crypto'),
56
Constants = require('./constants'),
@@ -59,7 +60,7 @@ const checkPackageMd5 = (runSettings) => {
5960

6061
if (typeof runSettings.npm_dependencies === 'object') {
6162
Object.assign(packageJSON, {
62-
devDependencies: utils.sortJsonKeys(runSettings.npm_dependencies),
63+
devDependencies: utils.sortJsonKeys(combineMacWinNpmDependencies(runSettings)),
6364
});
6465
}
6566

bin/helpers/constants.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const userMessages = {
5757
FAILED_MD5_CHECK:
5858
"Something went wrong - you can retry running browserstack-cypress with ‘--force-upload’ parameter, or contact BrowserStack Support.",
5959
VISIT_DASHBOARD: "Visit the Automate dashboard for real-time test reporting:",
60+
VISIT_ATS_DASHBOARD: "Visit the Automate TurboScale dashboard for real-time test reporting:",
6061
CONFLICTING_INIT_ARGUMENTS:
6162
"Conflicting arguments given. You can use --path only with a file name, and not with a file path.",
6263
NO_PARALLELS:
@@ -123,7 +124,8 @@ const userMessages = {
123124
CYPRESS_PORT_WARNING:
124125
"The requested port number <x> is ignored. The default BrowserStack port will be used for this execution",
125126
CYPRESS_INTERACTIVE_SESSION_CONFLICT_VALUES:
126-
"Conflicting values (True & False) were found for the interactive_debugging capability. Please resolve this issue to proceed further."
127+
"Conflicting values (True & False) were found for the interactive_debugging capability. Please resolve this issue to proceed further.",
128+
BUILD_ARTIFACTS_UNZIP_FAILURE: "Failed to unzip build artifacts.",
127129
};
128130

129131
const validationMessages = {
@@ -342,7 +344,11 @@ const filesToIgnoreWhileUploading = [
342344
"package.json",
343345
"**/package.json",
344346
"browserstack-package.json",
347+
"browserstack-mac-package.json",
348+
"browserstack-win-package.json",
345349
"**/browserstack-package.json",
350+
"**/browserstack-mac-package.json",
351+
"**/browserstack-win-package.json",
346352
"tests.zip",
347353
"**/tests.zip",
348354
"cypress.json",

bin/helpers/helper.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,3 +440,7 @@ exports.truncateString = (field, truncateSizeInBytes) => {
440440

441441
return field;
442442
};
443+
444+
exports.combineMacWinNpmDependencies = (runSettings) => {
445+
return Object.assign({}, runSettings.npm_dependencies, runSettings.win_npm_dependencies || {}, runSettings.mac_npm_dependencies || {})
446+
};

bin/helpers/packageInstaller.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99
{ get_version } = require('./usageReporting'),
1010
process = require('process'),
1111
{ spawn } = require('child_process'),
12+
cliUtils = require("./utils"),
1213
util = require('util');
1314

15+
const { combineMacWinNpmDependencies } = require("./helper");
16+
1417
let nodeProcess;
1518

1619
const setupPackageFolder = (runSettings, directoryPath) => {
@@ -28,9 +31,10 @@ const setupPackageFolder = (runSettings, directoryPath) => {
2831
Object.assign(packageJSON, runSettings.package_config_options);
2932
}
3033

34+
// Combine win and mac specific dependencies if present
3135
if (typeof runSettings.npm_dependencies === 'object') {
3236
Object.assign(packageJSON, {
33-
devDependencies: runSettings.npm_dependencies,
37+
devDependencies: combineMacWinNpmDependencies(runSettings),
3438
});
3539
}
3640

@@ -58,7 +62,7 @@ const setupPackageFolder = (runSettings, directoryPath) => {
5862
})
5963
};
6064

61-
const packageInstall = (packageDir) => {
65+
const packageInstall = (packageDir, bsConfig) => {
6266
return new Promise(function (resolve, reject) {
6367
const nodeProcessCloseCallback = (code) => {
6468
if(code == 0) {
@@ -74,6 +78,16 @@ const packageInstall = (packageDir) => {
7478
reject(`Packages were not installed successfully. Error Description ${util.format('%j', error)}`);
7579
};
7680

81+
// Moving .npmrc to tmpBstackPackages
82+
try {
83+
logger.debug(`Copying .npmrc file to temporary package directory`);
84+
const npmrcRootPath = path.join(cliUtils.isNotUndefined(bsConfig.run_settings.home_directory) ? path.resolve(bsConfig.run_settings.home_directory) : './', '.npmrc');
85+
const npmrcTmpPath = path.join(path.resolve(packageDir), '.npmrc');
86+
fs.copyFileSync(npmrcRootPath, npmrcTmpPath);
87+
} catch (error) {
88+
logger.debug(`Failed copying .npmrc to ${packageDir}: ${error}`)
89+
}
90+
7791
let nodeProcess;
7892
logger.debug(`Fetching npm version and its major version`);
7993
const npm_version = get_version('npm')
@@ -147,7 +161,7 @@ const packageSetupAndInstaller = (bsConfig, packageDir, instrumentBlocks) => {
147161
instrumentBlocks.markBlockEnd("packageInstaller.folderSetup");
148162
instrumentBlocks.markBlockStart("packageInstaller.packageInstall");
149163
logger.debug("Started installing dependencies specified in browserstack.json");
150-
return packageInstall(packageDir);
164+
return packageInstall(packageDir, bsConfig);
151165
}).then((_result) => {
152166
logger.debug("Completed installing dependencies");
153167
instrumentBlocks.markBlockEnd("packageInstaller.packageInstall");

bin/helpers/utils.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,16 @@ exports.setDefaults = (bsConfig, args) => {
220220
bsConfig.run_settings.npm_dependencies = {}
221221
}
222222

223+
// setting win_npm_dependencies to {} if not present
224+
if (bsConfig.run_settings && this.isUndefined(bsConfig.run_settings.win_npm_dependencies)) {
225+
bsConfig.run_settings.win_npm_dependencies = {}
226+
}
227+
228+
// setting mac_npm_dependencies to {} if not present
229+
if (bsConfig.run_settings && this.isUndefined(bsConfig.run_settings.mac_npm_dependencies)) {
230+
bsConfig.run_settings.mac_npm_dependencies = {}
231+
}
232+
223233
// setting connection_settings to {} if not present
224234
if (this.isUndefined(bsConfig.connection_settings)) {
225235
bsConfig.connection_settings = {};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Sending all the remaining queues for synchronous manner
3+
*/
4+
5+
const RequestQueueHandler = require('./requestQueueHandler');
6+
7+
const shutdown = async () => {
8+
const requestHandler = new RequestQueueHandler();
9+
requestHandler.queue = require(process.argv[2].trim());
10+
await requestHandler.shutdown();
11+
}
12+
13+
shutdown();
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const path = require('path');
2+
3+
exports.consoleHolder = Object.assign({},console);
4+
exports.BATCH_SIZE = 1000;
5+
exports.BATCH_INTERVAL = 2000;
6+
exports.API_URL = 'https://collector-observability.browserstack.com';
7+
8+
exports.IPC_EVENTS = {
9+
LOG: 'testObservability:cypressLog',
10+
CONFIG: 'testObservability:cypressConfig',
11+
SCREENSHOT: 'testObservability:cypressScreenshot',
12+
COMMAND: 'testObservability:cypressCommand',
13+
CUCUMBER: 'testObservability:cypressCucumberStep',
14+
PLATFORM_DETAILS: 'testObservability:cypressPlatformDetails'
15+
};
16+
17+
exports.OBSERVABILITY_ENV_VARS = [
18+
"BROWSERSTACK_TEST_OBSERVABILITY",
19+
"BROWSERSTACK_AUTOMATION",
20+
"BS_TESTOPS_BUILD_COMPLETED",
21+
"BS_TESTOPS_JWT",
22+
"BS_TESTOPS_BUILD_HASHED_ID",
23+
"BS_TESTOPS_ALLOW_SCREENSHOTS",
24+
"OBSERVABILITY_LAUNCH_SDK_VERSION",
25+
"BROWSERSTACK_OBSERVABILITY_DEBUG",
26+
"OBS_CRASH_REPORTING_USERNAME",
27+
"OBS_CRASH_REPORTING_ACCESS_KEY",
28+
"OBS_CRASH_REPORTING_BS_CONFIG_PATH",
29+
"OBS_CRASH_REPORTING_CYPRESS_CONFIG_PATH"
30+
];
31+
32+
exports.TEST_OBSERVABILITY_REPORTER = 'browserstack-cypress-cli/bin/testObservability/reporter';
33+
34+
exports.TEST_OBSERVABILITY_REPORTER_LOCAL = path.join(__dirname, '..', 'reporter');
35+
36+
exports.PENDING_QUEUES_FILE = `pending_queues_${process.pid}.json`;

0 commit comments

Comments
 (0)