-
Notifications
You must be signed in to change notification settings - Fork 39
Support for custom reporters and build artifacts #151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
d2cabb6
Merge branch 'master' of github.com:browserstack/browserstack-cypress…
9d21523
send reporter and reporter options
d348877
Merge branch 'ACE_2714_env' of github.com:browserstack/browserstack-c…
e14a9ff
add code for generate-downloads command
95f6acf
add sleep before downloading artifacts
ecc8fbf
update and add unit tests
834cf6d
add axios library
5ac2140
don't call build artifacts if downloads key empty or nil
13852e0
update messages for reporter options
b9b33cf
do not upload build_artifacts folder in zip
b433621
put to post for backend call
cab3e32
add alias for reporter and reporter-options
e64fd6d
Merge branch 'master' of github.com:browserstack/browserstack-cypress…
318ec54
Merge branch 'master' of github.com:browserstack/browserstack-cypress…
b067ef2
update method name and other small changes
855d6f6
handle cypressProjectDir while fetching json and global var
d75476a
add tests for generateDownloads.js
3b16fa4
add tests for generateDownloads.js
24ad351
fix failing unit tes
8bdf184
handle null and empty array in downloads
6210bf1
clean up malformed zips
de3ed8e
Merge branch 'master' into custom_reporting
nagpalkaran95 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
'use strict'; | ||
|
||
const logger = require("../helpers/logger").winstonLogger, | ||
Constants = require("../helpers/constants"), | ||
utils = require("../helpers/utils"), | ||
downloadBuildArtifacts = require('../helpers/buildArtifacts').downloadBuildArtifacts; | ||
|
||
|
||
module.exports = async function generateDownloads(args) { | ||
let bsConfigPath = utils.getConfigPath(args.cf); | ||
|
||
return utils.validateBstackJson(bsConfigPath).then(async function (bsConfig) { | ||
// setting setDefaults to {} if not present and set via env variables or via args. | ||
utils.setDefaults(bsConfig, args); | ||
|
||
// accept the username from command line if provided | ||
utils.setUsername(bsConfig, args); | ||
|
||
// accept the access key from command line if provided | ||
utils.setAccessKey(bsConfig, args); | ||
|
||
utils.setUsageReportingFlag(bsConfig, args.disableUsageReporting); | ||
|
||
// set cypress config filename | ||
utils.setCypressConfigFilename(bsConfig, args); | ||
|
||
let messageType = Constants.messageTypes.INFO; | ||
let errorCode = null; | ||
let buildId = args._[1]; | ||
|
||
await downloadBuildArtifacts(bsConfig, buildId, args); | ||
utils.sendUsageReport(bsConfig, args, Constants.usageReportingConstants.GENERATE_DOWNLOADS, messageType, errorCode); | ||
}).catch(function (err) { | ||
logger.error(err); | ||
utils.setUsageReportingFlag(null, args.disableUsageReporting); | ||
utils.sendUsageReport(null, args, err.message, Constants.messageTypes.ERROR, utils.getErrorCodeFromErr(err)); | ||
karanshah-browserstack marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
'use strict'; | ||
|
||
const fs = require('fs'), | ||
path = require('path'); | ||
|
||
const axios = require('axios'), | ||
unzipper = require('unzipper'); | ||
|
||
const logger = require('./logger').winstonLogger, | ||
utils = require("./utils"), | ||
Constants = require("./constants"), | ||
config = require("./config"); | ||
|
||
|
||
let BUILD_ARTIFACTS_TOTAL_COUNT = 0; | ||
let BUILD_ARTIFACTS_FAIL_COUNT = 0; | ||
|
||
const parseAndDownloadArtifacts = async (buildId, data) => { | ||
return new Promise(async (resolve, reject) => { | ||
let all_promises = []; | ||
let combs = Object.keys(data); | ||
for(let i = 0; i < combs.length; i++) { | ||
let comb = combs[i]; | ||
let sessions = Object.keys(data[comb]); | ||
for(let j = 0; j < sessions.length; j++) { | ||
let sessionId = sessions[j]; | ||
let filePath = path.join('./', 'build_artifacts', buildId, comb, sessionId); | ||
let fileName = 'build_artifacts.zip'; | ||
BUILD_ARTIFACTS_TOTAL_COUNT += 1; | ||
all_promises.push(downloadAndUnzip(filePath, fileName, data[comb][sessionId]).catch((error) => { | ||
BUILD_ARTIFACTS_FAIL_COUNT += 1; | ||
// delete malformed zip if present | ||
let tmpFilePath = path.join(filePath, fileName); | ||
nagpalkaran95 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if(fs.existsSync(tmpFilePath)){ | ||
fs.unlinkSync(tmpFilePath); | ||
} | ||
})); | ||
} | ||
} | ||
await Promise.all(all_promises); | ||
resolve(); | ||
}); | ||
} | ||
|
||
const createDirIfNotPresent = async (dir) => { | ||
return new Promise((resolve) => { | ||
if (!fs.existsSync(dir)){ | ||
fs.mkdirSync(dir); | ||
} | ||
resolve(); | ||
}); | ||
} | ||
|
||
const createDirectories = async (buildId, data) => { | ||
// create dir for build_artifacts if not already present | ||
let artifactsDir = path.join('./', 'build_artifacts'); | ||
if (!fs.existsSync(artifactsDir)){ | ||
fs.mkdirSync(artifactsDir); | ||
} | ||
|
||
// create dir for buildId if not already present | ||
let buildDir = path.join('./', 'build_artifacts', buildId); | ||
if (fs.existsSync(buildDir)){ | ||
// remove dir in case already exists | ||
fs.rmdirSync(buildDir, { recursive: true, force: true }); | ||
} | ||
fs.mkdirSync(buildDir); | ||
|
||
let combDirs = []; | ||
let sessionDirs = []; | ||
let combs = Object.keys(data); | ||
|
||
for(let i = 0; i < combs.length; i++) { | ||
let comb = combs[i]; | ||
let combDir = path.join('./', 'build_artifacts', buildId, comb); | ||
combDirs.push(createDirIfNotPresent(combDir)); | ||
let sessions = Object.keys(data[comb]); | ||
for(let j = 0; j < sessions.length; j++) { | ||
let sessionId = sessions[j]; | ||
let sessionDir = path.join('./', 'build_artifacts', buildId, comb, sessionId); | ||
sessionDirs.push(createDirIfNotPresent(sessionDir)); | ||
} | ||
} | ||
|
||
return new Promise(async (resolve) => { | ||
// create sub dirs for each combination in build | ||
await Promise.all(combDirs); | ||
// create sub dirs for each machine id in combination | ||
await Promise.all(sessionDirs); | ||
resolve(); | ||
}); | ||
} | ||
|
||
const downloadAndUnzip = async (filePath, fileName, url) => { | ||
let tmpFilePath = path.join(filePath, fileName); | ||
const writer = fs.createWriteStream(tmpFilePath); | ||
|
||
return axios({ | ||
method: 'get', | ||
url: url, | ||
responseType: 'stream', | ||
}).then(response => { | ||
|
||
//ensure that the user can call `then()` only when the file has | ||
//been downloaded entirely. | ||
|
||
return new Promise(async (resolve, reject) => { | ||
response.data.pipe(writer); | ||
let error = null; | ||
writer.on('error', err => { | ||
error = err; | ||
writer.close(); | ||
reject(err); | ||
}); | ||
writer.on('close', async () => { | ||
if (!error) { | ||
await unzipFile(filePath, fileName); | ||
fs.unlinkSync(tmpFilePath); | ||
resolve(true); | ||
} | ||
//no need to call the reject here, as it will have been called in the | ||
//'error' stream; | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
const unzipFile = async (filePath, fileName) => { | ||
return new Promise( async (resolve, reject) => { | ||
await unzipper.Open.file(path.join(filePath, fileName)) | ||
.then(d => d.extract({path: filePath, concurrency: 5})) | ||
.catch((err) => reject(err)); | ||
resolve(); | ||
}); | ||
} | ||
|
||
const sendUpdatesToBstack = async (bsConfig, buildId, args, options) => { | ||
let url = `${config.buildUrl}${buildId}/build_artifacts/status`; | ||
|
||
let cypressJSON = utils.getCypressJSON(bsConfig); | ||
|
||
let reporter = null; | ||
if(!utils.isUndefined(args.reporter)) { | ||
reporter = args.reporter; | ||
} else if(cypressJSON !== undefined){ | ||
reporter = cypressJSON.reporter; | ||
} | ||
|
||
let data = { | ||
feature_usage: { | ||
downloads: { | ||
eligible_download_folders: BUILD_ARTIFACTS_TOTAL_COUNT, | ||
successfully_downloaded_folders: BUILD_ARTIFACTS_TOTAL_COUNT - BUILD_ARTIFACTS_FAIL_COUNT | ||
}, | ||
reporter: reporter | ||
} | ||
} | ||
|
||
try { | ||
await axios.post(url, data, options); | ||
} catch (err) { | ||
utils.sendUsageReport(bsConfig, args, err, Constants.messageTypes.ERROR, 'api_failed_build_artifacts_status_update'); | ||
} | ||
} | ||
|
||
exports.downloadBuildArtifacts = async (bsConfig, buildId, args) => { | ||
BUILD_ARTIFACTS_FAIL_COUNT = 0; | ||
BUILD_ARTIFACTS_TOTAL_COUNT = 0; | ||
|
||
let url = `${config.buildUrl}${buildId}/build_artifacts`; | ||
let options = { | ||
auth: { | ||
username: bsConfig.auth.username, | ||
password: bsConfig.auth.access_key, | ||
}, | ||
headers: { | ||
'User-Agent': utils.getUserAgent(), | ||
}, | ||
}; | ||
|
||
let message = null; | ||
let messageType = null; | ||
let errorCode = null; | ||
|
||
try { | ||
const res = await axios.get(url, options); | ||
let buildDetails = res.data; | ||
|
||
await createDirectories(buildId, buildDetails); | ||
await parseAndDownloadArtifacts(buildId, buildDetails); | ||
|
||
if (BUILD_ARTIFACTS_FAIL_COUNT > 0) { | ||
messageType = Constants.messageTypes.ERROR; | ||
message = Constants.userMessages.DOWNLOAD_BUILD_ARTIFACTS_FAILED.replace('<build-id>', buildId).replace('<machine-count>', BUILD_ARTIFACTS_FAIL_COUNT); | ||
logger.error(message); | ||
} else { | ||
messageType = Constants.messageTypes.SUCCESS; | ||
message = Constants.userMessages.DOWNLOAD_BUILD_ARTIFACTS_SUCCESS.replace('<build-id>', buildId).replace('<user-path>', process.cwd()); | ||
logger.info(message); | ||
} | ||
|
||
await sendUpdatesToBstack(bsConfig, buildId, args, options); | ||
utils.sendUsageReport(bsConfig, args, message, messageType, null); | ||
} catch (err) { | ||
messageType = Constants.messageTypes.ERROR; | ||
errorCode = 'api_failed_build_artifacts'; | ||
|
||
if (BUILD_ARTIFACTS_FAIL_COUNT > 0) { | ||
messageType = Constants.messageTypes.ERROR; | ||
message = Constants.userMessages.DOWNLOAD_BUILD_ARTIFACTS_FAILED.replace('<build-id>', buildId).replace('<machine-count>', BUILD_ARTIFACTS_FAIL_COUNT); | ||
logger.error(message); | ||
} else { | ||
logger.error('Downloading the build artifacts failed.'); | ||
} | ||
|
||
utils.sendUsageReport(bsConfig, args, err, messageType, errorCode); | ||
} | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.