Skip to content

Commit a185124

Browse files
committed
Merge branch 'master' of github.com:roshan04/browserstack-cypress-cli
2 parents bc90d98 + 33e772a commit a185124

17 files changed

+643
-240
lines changed

bin/commands/runs.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const archiver = require("../helpers/archiver"),
1818
downloadBuildArtifacts = require('../helpers/buildArtifacts').downloadBuildArtifacts,
1919
updateNotifier = require('update-notifier'),
2020
pkg = require('../../package.json');
21+
2122
module.exports = function run(args, rawArgs) {
2223
let bsConfigPath = utils.getConfigPath(args.cf);
2324
//Delete build_results.txt from log folder if already present.
@@ -200,7 +201,27 @@ module.exports = function run(args, rawArgs) {
200201
build_id: data.build_id,
201202
test_zip_size: test_zip_size,
202203
npm_zip_size: npm_zip_size,
204+
test_suite_zip_upload: md5data.zipUrlPresent ? 0 : 1,
205+
package_zip_upload: md5data.packageUrlPresent ? 0 : 1
206+
};
207+
208+
if (!md5data.zipUrlPresent && zip.tests_upload_time) {
209+
dataToSend.test_suite_zip_size = parseFloat((test_zip_size / 1024).toFixed(2));
210+
dataToSend.test_suite_zip_upload_avg_speed = parseFloat(((test_zip_size * 1000) / (1024 * zip.tests_upload_time)).toFixed(2));
211+
};
212+
213+
if (!md5data.packageUrlPresent && zip.npm_package_upload_time) {
214+
dataToSend.npm_package_zip_size = parseFloat((npm_zip_size / 1024).toFixed(2));
215+
dataToSend.npm_package_zip_upload_avg_speed = parseFloat(((npm_zip_size * 1000) / (1024 * zip.npm_package_upload_time)).toFixed(2));
203216
};
217+
218+
if (zip.tests_upload_time || zip.npm_package_upload_time) {
219+
dataToSend.time_components.zip.zipUploadSplit = {
220+
tests_upload_time: zip.tests_upload_time,
221+
npm_package_upload_time: zip.npm_package_upload_time,
222+
}
223+
}
224+
204225
if (bsConfig && bsConfig.connection_settings) {
205226
if (bsConfig.connection_settings.local_mode) {
206227
dataToSend.local_mode = bsConfig.connection_settings.local_mode;

bin/helpers/archiver.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
'use strict';
2-
const fs = require("fs");
2+
const fs = require("fs"),
3+
path = require("path");
34

45
const archiver = require("archiver"),
56
Constants = require('../helpers/constants'),
67
logger = require("./logger").winstonLogger,
7-
utils = require('../helpers/utils'),
8-
path = require('path');
8+
utils = require('../helpers/utils');
99

1010
const archiveSpecs = (runSettings, filePath, excludeFiles, md5data) => {
1111
return new Promise(function (resolve, reject) {
@@ -14,7 +14,17 @@ const archiveSpecs = (runSettings, filePath, excludeFiles, md5data) => {
1414
}
1515
var output = fs.createWriteStream(filePath);
1616

17-
var cypressFolderPath = path.dirname(runSettings.cypressConfigFilePath);
17+
var cypressFolderPath = '';
18+
let cypressAppendFilesZipLocation = '';
19+
if (runSettings.home_directory) {
20+
cypressFolderPath = runSettings.home_directory;
21+
cypressAppendFilesZipLocation = runSettings.cypressZipStartLocation;
22+
if (cypressAppendFilesZipLocation !== '') {
23+
cypressAppendFilesZipLocation += '/';
24+
}
25+
} else {
26+
cypressFolderPath = path.dirname(runSettings.cypressConfigFilePath);
27+
}
1828

1929
logger.info(`Creating tests.zip with files in ${cypressFolderPath}`);
2030

@@ -61,7 +71,7 @@ const archiveSpecs = (runSettings, filePath, excludeFiles, md5data) => {
6171

6272
if (Object.keys(packageJSON).length > 0) {
6373
let packageJSONString = JSON.stringify(packageJSON, null, 4);
64-
archive.append(packageJSONString, {name: 'browserstack-package.json'});
74+
archive.append(packageJSONString, {name: `${cypressAppendFilesZipLocation}browserstack-package.json`});
6575
}
6676

6777
// do not add cypress.json if arg provided is false
@@ -73,7 +83,7 @@ const archiveSpecs = (runSettings, filePath, excludeFiles, md5data) => {
7383
fs.readFileSync(runSettings.cypressConfigFilePath)
7484
);
7585
let cypressJSONString = JSON.stringify(cypressJSON, null, 4);
76-
archive.append(cypressJSONString, {name: 'cypress.json'});
86+
archive.append(cypressJSONString, {name: `${cypressAppendFilesZipLocation}cypress.json`});
7787
}
7888

7989
archive.finalize();

bin/helpers/buildArtifacts.js

Lines changed: 114 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
const fs = require('fs'),
44
path = require('path');
55

6-
const axios = require('axios'),
7-
unzipper = require('unzipper');
6+
const unzipper = require('unzipper');
87

98
const logger = require('./logger').winstonLogger,
109
utils = require("./utils"),
1110
Constants = require("./constants"),
1211
config = require("./config");
1312

13+
const request = require('request');
14+
1415

1516
let BUILD_ARTIFACTS_TOTAL_COUNT = 0;
1617
let BUILD_ARTIFACTS_FAIL_COUNT = 0;
@@ -95,32 +96,31 @@ const downloadAndUnzip = async (filePath, fileName, url) => {
9596
let tmpFilePath = path.join(filePath, fileName);
9697
const writer = fs.createWriteStream(tmpFilePath);
9798

98-
return axios({
99-
method: 'get',
100-
url: url,
101-
responseType: 'stream',
102-
}).then(response => {
103-
104-
//ensure that the user can call `then()` only when the file has
105-
//been downloaded entirely.
106-
107-
return new Promise(async (resolve, reject) => {
108-
response.data.pipe(writer);
109-
let error = null;
110-
writer.on('error', err => {
111-
error = err;
112-
writer.close();
113-
reject(err);
114-
});
115-
writer.on('close', async () => {
116-
if (!error) {
117-
await unzipFile(filePath, fileName);
118-
fs.unlinkSync(tmpFilePath);
119-
resolve(true);
120-
}
121-
//no need to call the reject here, as it will have been called in the
122-
//'error' stream;
123-
});
99+
return new Promise(async (resolve, reject) => {
100+
request.get(url).on('response', function(response) {
101+
102+
if(response.statusCode != 200) {
103+
reject();
104+
} else {
105+
//ensure that the user can call `then()` only when the file has
106+
//been downloaded entirely.
107+
response.pipe(writer);
108+
let error = null;
109+
writer.on('error', err => {
110+
error = err;
111+
writer.close();
112+
reject(err);
113+
});
114+
writer.on('close', async () => {
115+
if (!error) {
116+
await unzipFile(filePath, fileName);
117+
fs.unlinkSync(tmpFilePath);
118+
resolve(true);
119+
}
120+
//no need to call the reject here, as it will have been called in the
121+
//'error' stream;
122+
});
123+
}
124124
});
125125
});
126126
}
@@ -135,7 +135,7 @@ const unzipFile = async (filePath, fileName) => {
135135
}
136136

137137
const sendUpdatesToBstack = async (bsConfig, buildId, args, options, rawArgs) => {
138-
let url = `${config.buildUrl}${buildId}/build_artifacts/status`;
138+
options.url = `${config.buildUrl}${buildId}/build_artifacts/status`;
139139

140140
let cypressJSON = utils.getCypressJSON(bsConfig);
141141

@@ -156,65 +156,95 @@ const sendUpdatesToBstack = async (bsConfig, buildId, args, options, rawArgs) =>
156156
}
157157
}
158158

159-
try {
160-
await axios.post(url, data, options);
161-
} catch (err) {
162-
utils.sendUsageReport(bsConfig, args, err, Constants.messageTypes.ERROR, 'api_failed_build_artifacts_status_update', null, rawArgs);
163-
}
159+
options.formData = data.toString();
160+
let responseData = null;
161+
return new Promise (async (resolve, reject) => {
162+
request.post(options, function (err, resp, data) {
163+
if(err) {
164+
utils.sendUsageReport(bsConfig, args, err, Constants.messageTypes.ERROR, 'api_failed_build_artifacts_status_update', null, rawArgs);
165+
reject(err);
166+
} else {
167+
try {
168+
responseData = JSON.parse(data);
169+
} catch(e) {
170+
responseData = {};
171+
}
172+
if (resp.statusCode != 200) {
173+
if (responseData && responseData["error"]) {
174+
utils.sendUsageReport(bsConfig, args, responseData["error"], Constants.messageTypes.ERROR, 'api_failed_build_artifacts_status_update', null, rawArgs);
175+
reject(responseData["error"])
176+
}
177+
}
178+
}
179+
resolve()
180+
});
181+
});
164182
}
165183

166184
exports.downloadBuildArtifacts = async (bsConfig, buildId, args, rawArgs) => {
167-
BUILD_ARTIFACTS_FAIL_COUNT = 0;
168-
BUILD_ARTIFACTS_TOTAL_COUNT = 0;
169-
170-
let url = `${config.buildUrl}${buildId}/build_artifacts`;
171-
let options = {
172-
auth: {
173-
username: bsConfig.auth.username,
174-
password: bsConfig.auth.access_key,
175-
},
176-
headers: {
177-
'User-Agent': utils.getUserAgent(),
178-
},
179-
};
180-
181-
let message = null;
182-
let messageType = null;
183-
let errorCode = null;
184-
185-
try {
186-
const res = await axios.get(url, options);
187-
let buildDetails = res.data;
188-
189-
await createDirectories(buildId, buildDetails);
190-
await parseAndDownloadArtifacts(buildId, buildDetails);
191-
192-
if (BUILD_ARTIFACTS_FAIL_COUNT > 0) {
193-
messageType = Constants.messageTypes.ERROR;
194-
message = Constants.userMessages.DOWNLOAD_BUILD_ARTIFACTS_FAILED.replace('<build-id>', buildId).replace('<machine-count>', BUILD_ARTIFACTS_FAIL_COUNT);
195-
logger.error(message);
185+
return new Promise ( async (resolve, reject) => {
186+
BUILD_ARTIFACTS_FAIL_COUNT = 0;
187+
BUILD_ARTIFACTS_TOTAL_COUNT = 0;
188+
189+
let options = {
190+
url: `${config.buildUrl}${buildId}/build_artifacts`,
191+
auth: {
192+
username: bsConfig.auth.username,
193+
password: bsConfig.auth.access_key,
194+
},
195+
headers: {
196+
'User-Agent': utils.getUserAgent(),
197+
},
198+
};
199+
200+
let message = null;
201+
let messageType = null;
202+
let errorCode = null;
203+
let buildDetails = null;
204+
request.get(options, async function (err, resp, body) {
205+
if(err) {
206+
utils.sendUsageReport(bsConfig, args, err, Constants.messageTypes.ERROR, 'api_failed_build_artifacts', null, rawArgs);
196207
process.exitCode = Constants.ERROR_EXIT_CODE;
197208
} else {
198-
messageType = Constants.messageTypes.SUCCESS;
199-
message = Constants.userMessages.DOWNLOAD_BUILD_ARTIFACTS_SUCCESS.replace('<build-id>', buildId).replace('<user-path>', process.cwd());
200-
logger.info(message);
209+
try {
210+
buildDetails = JSON.parse(body);
211+
if(resp.statusCode != 200) {
212+
logger.error('Downloading the build artifacts failed.');
213+
logger.error(`Error: Request failed with status code ${resp.statusCode}`)
214+
utils.sendUsageReport(bsConfig, args, buildDetails, Constants.messageTypes.ERROR, 'api_failed_build_artifacts', null, rawArgs);
215+
process.exitCode = Constants.ERROR_EXIT_CODE;
216+
} else {
217+
await createDirectories(buildId, buildDetails);
218+
await parseAndDownloadArtifacts(buildId, buildDetails);
219+
if (BUILD_ARTIFACTS_FAIL_COUNT > 0) {
220+
messageType = Constants.messageTypes.ERROR;
221+
message = Constants.userMessages.DOWNLOAD_BUILD_ARTIFACTS_FAILED.replace('<build-id>', buildId).replace('<machine-count>', BUILD_ARTIFACTS_FAIL_COUNT);
222+
logger.error(message);
223+
process.exitCode = Constants.ERROR_EXIT_CODE;
224+
} else {
225+
messageType = Constants.messageTypes.SUCCESS;
226+
message = Constants.userMessages.DOWNLOAD_BUILD_ARTIFACTS_SUCCESS.replace('<build-id>', buildId).replace('<user-path>', process.cwd());
227+
logger.info(message);
228+
}
229+
await sendUpdatesToBstack(bsConfig, buildId, args, options, rawArgs)
230+
utils.sendUsageReport(bsConfig, args, message, messageType, null, null, rawArgs);
231+
}
232+
} catch (err) {
233+
messageType = Constants.messageTypes.ERROR;
234+
errorCode = 'api_failed_build_artifacts';
235+
if (BUILD_ARTIFACTS_FAIL_COUNT > 0) {
236+
messageType = Constants.messageTypes.ERROR;
237+
message = Constants.userMessages.DOWNLOAD_BUILD_ARTIFACTS_FAILED.replace('<build-id>', buildId).replace('<machine-count>', BUILD_ARTIFACTS_FAIL_COUNT);
238+
logger.error(message);
239+
} else {
240+
logger.error('Downloading the build artifacts failed.');
241+
}
242+
utils.sendUsageReport(bsConfig, args, err, messageType, errorCode, null, rawArgs);
243+
logger.error(`Error: Request failed with status code ${resp.statusCode}`)
244+
process.exitCode = Constants.ERROR_EXIT_CODE;
245+
}
201246
}
202-
203-
await sendUpdatesToBstack(bsConfig, buildId, args, options, rawArgs);
204-
utils.sendUsageReport(bsConfig, args, message, messageType, null, null, rawArgs);
205-
} catch (err) {
206-
messageType = Constants.messageTypes.ERROR;
207-
errorCode = 'api_failed_build_artifacts';
208-
209-
if (BUILD_ARTIFACTS_FAIL_COUNT > 0) {
210-
messageType = Constants.messageTypes.ERROR;
211-
message = Constants.userMessages.DOWNLOAD_BUILD_ARTIFACTS_FAILED.replace('<build-id>', buildId).replace('<machine-count>', BUILD_ARTIFACTS_FAIL_COUNT);
212-
logger.error(message);
213-
} else {
214-
logger.error('Downloading the build artifacts failed.');
215-
}
216-
217-
utils.sendUsageReport(bsConfig, args, err, messageType, errorCode, null, rawArgs);
218-
process.exitCode = Constants.ERROR_EXIT_CODE;
219-
}
247+
resolve();
248+
});
249+
});
220250
};

bin/helpers/capabilityHelper.js

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
const fs = require('fs'),
2+
path = require('path');
3+
14
const logger = require("./logger").winstonLogger,
25
Constants = require("./constants"),
3-
Utils = require("./utils"),
4-
fs = require('fs');
6+
Utils = require("./utils");
57

68
const caps = (bsConfig, zip) => {
79
return new Promise(function (resolve, reject) {
@@ -129,6 +131,13 @@ const caps = (bsConfig, zip) => {
129131
})
130132
}
131133

134+
const addCypressZipStartLocation = (runSettings) => {
135+
let resolvedHomeDirectoryPath = path.resolve(runSettings.home_directory);
136+
let resolvedCypressConfigFilePath = path.resolve(runSettings.cypressConfigFilePath);
137+
runSettings.cypressZipStartLocation = path.dirname(resolvedCypressConfigFilePath.split(resolvedHomeDirectoryPath)[1]);
138+
runSettings.cypressZipStartLocation = runSettings.cypressZipStartLocation.substring(1);
139+
}
140+
132141
const validate = (bsConfig, args) => {
133142
return new Promise(function (resolve, reject) {
134143
logger.info(Constants.userMessages.VALIDATING_CONFIG);
@@ -185,11 +194,33 @@ const validate = (bsConfig, args) => {
185194
} catch(error){
186195
reject(Constants.validationMessages.INVALID_CYPRESS_JSON)
187196
}
197+
198+
//check if home_directory is present or not in user run_settings
199+
if (!Utils.isUndefined(bsConfig.run_settings.home_directory)) {
200+
// check if home_directory exists or not
201+
if (!fs.existsSync(bsConfig.run_settings.home_directory)) {
202+
reject(Constants.validationMessages.HOME_DIRECTORY_NOT_FOUND);
203+
}
204+
205+
// check if home_directory is a directory or not
206+
if (!fs.statSync(bsConfig.run_settings.home_directory).isDirectory()) {
207+
reject(Constants.validationMessages.HOME_DIRECTORY_NOT_A_DIRECTORY);
208+
}
209+
210+
// check if cypress config file (cypress.json) is a part of home_directory or not
211+
if (!path.resolve(bsConfig.run_settings.cypressConfigFilePath).includes(path.resolve(bsConfig.run_settings.home_directory))) {
212+
reject(Constants.validationMessages.CYPRESS_CONFIG_FILE_NOT_PART_OF_HOME_DIRECTORY);
213+
}
214+
215+
addCypressZipStartLocation(bsConfig.run_settings);
216+
}
217+
188218
resolve(cypressJson);
189219
});
190220
}
191221

192222
module.exports = {
193223
caps,
224+
addCypressZipStartLocation,
194225
validate
195226
}

0 commit comments

Comments
 (0)