Skip to content

Commit 89ebf2d

Browse files
Merge pull request #475 from browserstack/package-diff
🎨 added instrumentation for package diff and pushing package.json
2 parents 60de54d + 97446bd commit 89ebf2d

File tree

5 files changed

+159
-6
lines changed

5 files changed

+159
-6
lines changed

bin/commands/runs.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ const archiver = require("../helpers/archiver"),
1919
downloadBuildArtifacts = require('../helpers/buildArtifacts').downloadBuildArtifacts,
2020
downloadBuildStacktrace = require('../helpers/downloadBuildStacktrace').downloadBuildStacktrace,
2121
updateNotifier = require('update-notifier'),
22-
pkg = require('../../package.json');
22+
pkg = require('../../package.json'),
23+
packageDiff = require('../helpers/package-diff');
2324
const { getStackTraceUrl } = require('../helpers/sync/syncSpecsLogs');
2425

2526
module.exports = function run(args, rawArgs) {
@@ -158,13 +159,21 @@ module.exports = function run(args, rawArgs) {
158159
// Archive the spec files
159160
logger.debug("Started archiving test suite");
160161
markBlockStart('zip.archive');
161-
return archiver.archive(bsConfig.run_settings, config.fileName, args.exclude, md5data).then(function (data) {
162+
return archiver.archive(bsConfig.run_settings, config.fileName, args.exclude, md5data).then(async function (data) {
162163
logger.debug("Completed archiving test suite");
163164
markBlockEnd('zip.archive');
164165

165166
let test_zip_size = utils.fetchZipSize(path.join(process.cwd(), config.fileName));
166167
let npm_zip_size = utils.fetchZipSize(path.join(process.cwd(), config.packageFileName));
167-
168+
let node_modules_size = await utils.fetchFolderSize(path.join(process.cwd(), "node_modules"))
169+
170+
//Package diff
171+
let isPackageDiff = false;
172+
if(!md5data.zipUrlPresent){
173+
isPackageDiff = packageDiff.run(`package.json`, `${config.packageDirName}/package.json`);
174+
logger.debug(`Package difference was ${isPackageDiff ? `found` : `not found`}`);
175+
}
176+
168177
// Uploaded zip file
169178
logger.debug("Started uploading the test suite zip");
170179
logger.debug("Started uploading the node_module zip");
@@ -267,9 +276,13 @@ module.exports = function run(args, rawArgs) {
267276
build_id: data.build_id,
268277
test_zip_size: test_zip_size,
269278
npm_zip_size: npm_zip_size,
279+
node_modules_size: node_modules_size,
270280
test_suite_zip_upload: md5data.zipUrlPresent ? 0 : 1,
271281
package_zip_upload: md5data.packageUrlPresent ? 0 : 1
272282
};
283+
if(dataToSend.test_suite_zip_upload === 1 ){
284+
dataToSend['is_package_diff'] = isPackageDiff;
285+
}
273286

274287
if (!md5data.zipUrlPresent && zip.tests_upload_time) {
275288
dataToSend.test_suite_zip_size = parseFloat((test_zip_size / 1024).toFixed(2));

bin/helpers/archiver.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
'use strict';
2+
const config = require('./config.js');
23
const fs = require("fs"),
34
path = require("path");
45

@@ -76,6 +77,14 @@ const archiveSpecs = (runSettings, filePath, excludeFiles, md5data) => {
7677
archive.append(packageJSONString, {name: `${cypressAppendFilesZipLocation}browserstack-package.json`});
7778
}
7879

80+
//Create copy of package.json
81+
if(fs.existsSync('package.json')){
82+
let originalPackageJson = JSON.parse(fs.readFileSync('package.json'));
83+
let originalPackageJsonString = JSON.stringify(originalPackageJson, null, 4);
84+
archive.append(originalPackageJsonString, {name: `${cypressAppendFilesZipLocation}userPackage.json`});
85+
logger.debug(`Created copy of package.json in ${config.packageDirName} folder`)
86+
}
87+
7988
// do not add cypress.json if arg provided is false
8089
if (
8190
runSettings.cypress_config_file &&

bin/helpers/package-diff.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"use strict";
2+
const fs = require("fs");
3+
const path = require("path");
4+
const logger = require("./logger").winstonLogger;
5+
6+
exports.run = (basePath, comparePath) => {
7+
if (!basePath || !comparePath) {
8+
logger.debug("Skipping package difference check.");
9+
}
10+
11+
let base;
12+
let compare;
13+
let isDiff = false;
14+
try {
15+
base = readModules(basePath);
16+
compare = readModules(comparePath);
17+
} catch (error) {
18+
logger.debug('Unable to process package difference');
19+
return isDiff;
20+
}
21+
22+
Object.keys(base.deps).forEach((baseKey) => {
23+
if (baseKey in compare.deps) {
24+
if (base.deps[baseKey] !== compare.deps[baseKey]) {
25+
isDiff = true;
26+
return;
27+
}
28+
} else {
29+
isDiff = true;
30+
return;
31+
}
32+
});
33+
return isDiff;
34+
};
35+
const readModules = (location) => {
36+
const table = {};
37+
38+
// Resolve package dependencies
39+
if (location.indexOf("package.json") !== -1) {
40+
const data = fs.readFileSync(location.replace(":dev", ""), "utf-8");
41+
let parsed;
42+
try {
43+
parsed = JSON.parse(data);
44+
} catch (e) {
45+
parsed = false;
46+
}
47+
if (!parsed) {
48+
return;
49+
}
50+
51+
const depsKey =
52+
location.indexOf(":dev") !== -1 ? "devDependencies" : "dependencies";
53+
const deps = parsed[depsKey]
54+
? parsed[depsKey]
55+
: parsed.dependencies || parsed.devDependencies;
56+
57+
Object.keys(deps).forEach((key) => {
58+
deps[key] = deps[key].replace(/\^|~/g, "");
59+
});
60+
return {
61+
name: `${location} {${depsKey}}`,
62+
deps,
63+
};
64+
}
65+
66+
fs.readdirSync(location)
67+
.filter((name) => name !== ".bin")
68+
.map((name) => {
69+
const pkg = path.join(location, name, "package.json");
70+
const exists = fs.existsSync(pkg);
71+
if (!exists) {
72+
return;
73+
}
74+
75+
const data = fs.readFileSync(pkg, "utf-8");
76+
let parsed;
77+
78+
try {
79+
parsed = JSON.parse(data);
80+
} catch (e) {
81+
parsed = false;
82+
}
83+
if (!parsed) {
84+
return;
85+
}
86+
87+
table[name] = parsed.version;
88+
});
89+
return {
90+
name: location,
91+
deps: table,
92+
};
93+
};

bin/helpers/utils.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ const { v4: uuidv4 } = require('uuid');
88
const browserstack = require('browserstack-local');
99
const crypto = require('crypto');
1010
const util = require('util');
11+
const { promisify } = require('util');
12+
const readdir = promisify(fs.readdir);
13+
const stat = promisify(fs.stat);
1114

1215
const usageReporting = require("./usageReporting"),
1316
logger = require("./logger").winstonLogger,
@@ -1278,6 +1281,34 @@ exports.fetchZipSize = (fileName) => {
12781281
}
12791282
}
12801283

1284+
const getDirectorySize = async function(dir) {
1285+
try{
1286+
const subdirs = (await readdir(dir));
1287+
const files = await Promise.all(subdirs.map(async (subdir) => {
1288+
const res = path.resolve(dir, subdir);
1289+
const s = (await stat(res));
1290+
return s.isDirectory() ? getDirectorySize(res) : (s.size);
1291+
}));
1292+
return files.reduce((a, f) => a+f, 0);
1293+
}catch(e){
1294+
console.log(`Error ${e}`)
1295+
logger.debug('Failed to get file or directory.');
1296+
return 0;
1297+
}
1298+
};
1299+
1300+
exports.fetchFolderSize = async (dir) => {
1301+
try {
1302+
if(fs.existsSync(dir)){
1303+
return (await getDirectorySize(dir) / 1024 / 1024);
1304+
}
1305+
return 0;
1306+
} catch (error) {
1307+
logger.debug(`Failed to get directory size.`);
1308+
return 0;
1309+
}
1310+
}
1311+
12811312
exports.getVideoConfig = (cypressConfig) => {
12821313
let conf = {
12831314
video: true,

test/unit/bin/helpers/utils.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,13 @@ describe('utils', () => {
10421042
});
10431043
});
10441044

1045+
describe('getDirectorySize', () => {
1046+
it('should return size of directory', async() => {
1047+
expect(await utils.fetchFolderSize('/absolute/path')).to
1048+
.be.equal(0);
1049+
});
1050+
});
1051+
10451052
describe('getLocalFlag', () => {
10461053
it('should return false if connectionSettings is undefined', () => {
10471054
expect(utils.getLocalFlag(undefined)).to.be.false;
@@ -1834,7 +1841,7 @@ describe('utils', () => {
18341841
describe('setCypressTestSuiteType', () => {
18351842

18361843
it('sets correct cypressTestSuiteType when cypress.json is the cypress config file ', () => {
1837-
bsConfig = {
1844+
let bsConfig = {
18381845
run_settings: {
18391846
cypressConfigFilePath: 'cypress.json',
18401847
},
@@ -1846,7 +1853,7 @@ describe('utils', () => {
18461853
});
18471854

18481855
it('sets correct cypressTestSuiteType when cypress.config.js|.ts|.cjs|.mjs is the cypress config file ', () => {
1849-
bsConfig = {
1856+
let bsConfig = {
18501857
run_settings: {
18511858
cypressConfigFilePath: 'cypress.config.js',
18521859
},
@@ -1880,7 +1887,7 @@ describe('utils', () => {
18801887
});
18811888

18821889
it('by default assumes that CYPRESS_V9_AND_OLDER_TYPE is the test suite type', () => {
1883-
bsConfig = {
1890+
let bsConfig = {
18841891
run_settings: {},
18851892
};
18861893
utils.setCypressTestSuiteType(bsConfig);

0 commit comments

Comments
 (0)