Skip to content

Commit fd3ae66

Browse files
Merge pull request #196 from browserstack/lib_changes
Remove dependency on axios and add progress bar
2 parents d749c3a + 2f71cd4 commit fd3ae66

File tree

10 files changed

+381
-222
lines changed

10 files changed

+381
-222
lines changed

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/constants.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ const userMessages = {
4343
UPLOADING_TESTS_SUCCESS: "Uploaded tests successfully",
4444
UPLOADING_NPM_PACKAGES: "Uploading required node_modules to BrowserStack",
4545
UPLOADING_NPM_PACKAGES_SUCCESS: "Uploaded node_modules successfully",
46+
SKIP_UPLOADING_TESTS: "Skipping zip upload since BrowserStack already has your test suite that has not changed since the last run.",
47+
SKIP_UPLOADING_NPM_PACKAGES: "Skipping the upload of node_modules since BrowserStack has already cached your npm dependencies that have not changed since the last run.",
4648
LOCAL_TRUE: "you will now be able to test localhost / private URLs",
4749
LOCAL_FALSE: "you won't be able to test localhost / private URLs",
4850
EXIT_SYNC_CLI_MESSAGE: "Exiting the CLI, but your build is still running. You can use the --sync option to keep getting test updates. You can also use the build-info <build-id> command now.",

bin/helpers/reporterHTML.js

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ const fs = require('fs'),
44
logger = require('./logger').winstonLogger,
55
utils = require("./utils"),
66
Constants = require('./constants'),
7-
config = require("./config"),
8-
axios = require("axios");
7+
config = require("./config");
98

109
let templatesDir = path.join(__dirname, '../', 'templates');
1110

@@ -235,24 +234,74 @@ async function cypressReportData(report_data) {
235234
return report_data;
236235
}
237236

237+
function getConfigJsonResponse(combination) {
238+
return new Promise(async (resolve, reject) => {
239+
configJsonResponse = null;
240+
configJsonError = false
241+
request.get(combination.tests.config_json , function(err, resp, body) {
242+
if(err) {
243+
configJsonError = true;
244+
reject([configJsonResponse, configJsonError]);
245+
} else {
246+
if(resp.statusCode != 200) {
247+
configJsonError = true;
248+
reject([configJsonResponse, configJsonError]);
249+
} else {
250+
try {
251+
configJsonResponse = JSON.parse(body);
252+
} catch (err) {
253+
configJsonError = true
254+
reject([configJsonResponse, configJsonError]);
255+
}
256+
}
257+
}
258+
resolve([configJsonResponse, configJsonError]);
259+
});
260+
});
261+
}
262+
263+
function getResultsJsonResponse(combination) {
264+
return new Promise(async (resolve, reject) => {
265+
resultsJsonResponse = null
266+
resultsJsonError = false;
267+
request.get(combination.tests.result_json , function(err, resp, body) {
268+
if(err) {
269+
resultsJsonError = true;
270+
reject([resultsJsonResponse, resultsJsonError]);
271+
} else {
272+
if(resp.statusCode != 200) {
273+
resultsJsonError = true;
274+
reject([resultsJsonResponse, resultsJsonError]);
275+
} else {
276+
try {
277+
resultsJsonResponse = JSON.parse(body);
278+
} catch (err) {
279+
resultsJsonError = true
280+
reject([resultsJsonResponse, resultsJsonError]);
281+
}
282+
}
283+
}
284+
resolve([resultsJsonResponse, resultsJsonError]);
285+
});
286+
});
287+
}
288+
238289
function generateCypressCombinationSpecReportDataWithConfigJson(combination){
239290
return new Promise(async (resolve, reject) => {
240291
try {
241292
let configJsonError, resultsJsonError;
242-
let [configJsonResponse, resultsJsonResponse] = await axios.all([
243-
axios.get(combination.tests.config_json).catch(function (error) {
244-
configJsonError = true;
245-
}),
246-
axios.get(combination.tests.result_json).catch(function(error){
247-
resultsJsonError = true;
248-
})
249-
]);
293+
let configJson, resultsJson;
294+
295+
await Promise.all([getConfigJsonResponse(combination), getResultsJsonResponse(combination)]).then(function (successResult) {
296+
[[configJson, configJsonError], [resultsJson, resultsJsonError]] = successResult;
297+
}).catch(function (failureResult) {
298+
[[configJson, configJsonError], [resultsJson, resultsJsonError]] = failureResult;
299+
});
300+
250301
if(resultsJsonError || configJsonError){
251302
resolve();
252303
}
253304
let tests = {};
254-
let configJson = configJsonResponse.data;
255-
let resultsJson = resultsJsonResponse.data;
256305
if(utils.isUndefined(configJson.tests) || utils.isUndefined(resultsJson.tests)){
257306
resolve();
258307
}
@@ -287,14 +336,15 @@ function generateCypressCombinationSpecReportDataWithConfigJson(combination){
287336
function generateCypressCombinationSpecReportDataWithoutConfigJson(combination){
288337
return new Promise(async (resolve, reject) => {
289338
try {
290-
let resultsJsonError;
291-
let resultsJsonResponse = await axios.get(combination.tests.result_json).catch(function(error){
292-
resultsJsonError = true;
293-
});
339+
let resultsJson ,resultsJsonError;
340+
await getResultsJsonResponse(combination).then(function (successResult) {
341+
[resultsJson, resultsJsonError] = successResult
342+
}).catch( function (failureResult) {
343+
[resultsJson, resultsJsonError] = failureResult
344+
})
294345
if(resultsJsonError || utils.isUndefined(resultsJsonResponse)){
295346
resolve();
296347
}
297-
let resultsJson = resultsJsonResponse.data;
298348
let sessionTests = [];
299349
if(utils.isUndefined(resultsJson.tests)){
300350
resolve();

0 commit comments

Comments
 (0)