Skip to content

🎨 added instrumentation for package diff and pushing package.json #475

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 3 commits into from
Mar 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions bin/commands/runs.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const archiver = require("../helpers/archiver"),
downloadBuildArtifacts = require('../helpers/buildArtifacts').downloadBuildArtifacts,
downloadBuildStacktrace = require('../helpers/downloadBuildStacktrace').downloadBuildStacktrace,
updateNotifier = require('update-notifier'),
pkg = require('../../package.json');
pkg = require('../../package.json'),
packageDiff = require('../helpers/package-diff');
const { getStackTraceUrl } = require('../helpers/sync/syncSpecsLogs');

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

let test_zip_size = utils.fetchZipSize(path.join(process.cwd(), config.fileName));
let npm_zip_size = utils.fetchZipSize(path.join(process.cwd(), config.packageFileName));

let node_modules_size = await utils.fetchFolderSize(path.join(process.cwd(), "node_modules"))

//Package diff
let isPackageDiff = false;
if(!md5data.zipUrlPresent){
isPackageDiff = packageDiff.run(`package.json`, `${config.packageDirName}/package.json`);
logger.debug(`Package difference was ${isPackageDiff ? `found` : `not found`}`);
}

// Uploaded zip file
logger.debug("Started uploading the test suite zip");
logger.debug("Started uploading the node_module zip");
Expand Down Expand Up @@ -267,9 +276,13 @@ module.exports = function run(args, rawArgs) {
build_id: data.build_id,
test_zip_size: test_zip_size,
npm_zip_size: npm_zip_size,
node_modules_size: node_modules_size,
test_suite_zip_upload: md5data.zipUrlPresent ? 0 : 1,
package_zip_upload: md5data.packageUrlPresent ? 0 : 1
};
if(dataToSend.test_suite_zip_upload === 1 ){
dataToSend['is_package_diff'] = isPackageDiff;
}

if (!md5data.zipUrlPresent && zip.tests_upload_time) {
dataToSend.test_suite_zip_size = parseFloat((test_zip_size / 1024).toFixed(2));
Expand Down
9 changes: 9 additions & 0 deletions bin/helpers/archiver.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
'use strict';
const config = require('./config.js');
const fs = require("fs"),
path = require("path");

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

//Create copy of package.json
if(fs.existsSync('package.json')){
let originalPackageJson = JSON.parse(fs.readFileSync('package.json'));
let originalPackageJsonString = JSON.stringify(originalPackageJson, null, 4);
archive.append(originalPackageJsonString, {name: `${cypressAppendFilesZipLocation}userPackage.json`});
logger.debug(`Created copy of package.json in ${config.packageDirName} folder`)
}

// do not add cypress.json if arg provided is false
if (
runSettings.cypress_config_file &&
Expand Down
93 changes: 93 additions & 0 deletions bin/helpers/package-diff.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"use strict";
const fs = require("fs");
const path = require("path");
const logger = require("./logger").winstonLogger;

exports.run = (basePath, comparePath) => {
if (!basePath || !comparePath) {
logger.debug("Skipping package difference check.");
}

let base;
let compare;
let isDiff = false;
try {
base = readModules(basePath);
compare = readModules(comparePath);
} catch (error) {
logger.debug('Unable to process package difference');
return isDiff;
}

Object.keys(base.deps).forEach((baseKey) => {
if (baseKey in compare.deps) {
if (base.deps[baseKey] !== compare.deps[baseKey]) {
isDiff = true;
return;
}
} else {
isDiff = true;
return;
}
});
return isDiff;
};
const readModules = (location) => {
const table = {};

// Resolve package dependencies
if (location.indexOf("package.json") !== -1) {
const data = fs.readFileSync(location.replace(":dev", ""), "utf-8");
let parsed;
try {
parsed = JSON.parse(data);
} catch (e) {
parsed = false;
}
if (!parsed) {
return;
}

const depsKey =
location.indexOf(":dev") !== -1 ? "devDependencies" : "dependencies";
const deps = parsed[depsKey]
? parsed[depsKey]
: parsed.dependencies || parsed.devDependencies;

Object.keys(deps).forEach((key) => {
deps[key] = deps[key].replace(/\^|~/g, "");
});
return {
name: `${location} {${depsKey}}`,
deps,
};
}

fs.readdirSync(location)
.filter((name) => name !== ".bin")
.map((name) => {
const pkg = path.join(location, name, "package.json");
const exists = fs.existsSync(pkg);
if (!exists) {
return;
}

const data = fs.readFileSync(pkg, "utf-8");
let parsed;

try {
parsed = JSON.parse(data);
} catch (e) {
parsed = false;
}
if (!parsed) {
return;
}

table[name] = parsed.version;
});
return {
name: location,
deps: table,
};
};
31 changes: 31 additions & 0 deletions bin/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const { v4: uuidv4 } = require('uuid');
const browserstack = require('browserstack-local');
const crypto = require('crypto');
const util = require('util');
const { promisify } = require('util');
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);

const usageReporting = require("./usageReporting"),
logger = require("./logger").winstonLogger,
Expand Down Expand Up @@ -1278,6 +1281,34 @@ exports.fetchZipSize = (fileName) => {
}
}

const getDirectorySize = async function(dir) {
try{
const subdirs = (await readdir(dir));
const files = await Promise.all(subdirs.map(async (subdir) => {
const res = path.resolve(dir, subdir);
const s = (await stat(res));
return s.isDirectory() ? getDirectorySize(res) : (s.size);
}));
return files.reduce((a, f) => a+f, 0);
}catch(e){
console.log(`Error ${e}`)
logger.debug('Failed to get file or directory.');
return 0;
}
};

exports.fetchFolderSize = async (dir) => {
try {
if(fs.existsSync(dir)){
return (await getDirectorySize(dir) / 1024 / 1024);
}
return 0;
} catch (error) {
logger.debug(`Failed to get directory size.`);
return 0;
}
}

exports.getVideoConfig = (cypressConfig) => {
let conf = {
video: true,
Expand Down
13 changes: 10 additions & 3 deletions test/unit/bin/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,13 @@ describe('utils', () => {
});
});

describe('getDirectorySize', () => {
it('should return size of directory', async() => {
expect(await utils.fetchFolderSize('/absolute/path')).to
.be.equal(0);
});
});

describe('getLocalFlag', () => {
it('should return false if connectionSettings is undefined', () => {
expect(utils.getLocalFlag(undefined)).to.be.false;
Expand Down Expand Up @@ -1834,7 +1841,7 @@ describe('utils', () => {
describe('setCypressTestSuiteType', () => {

it('sets correct cypressTestSuiteType when cypress.json is the cypress config file ', () => {
bsConfig = {
let bsConfig = {
run_settings: {
cypressConfigFilePath: 'cypress.json',
},
Expand All @@ -1846,7 +1853,7 @@ describe('utils', () => {
});

it('sets correct cypressTestSuiteType when cypress.config.js|.ts|.cjs|.mjs is the cypress config file ', () => {
bsConfig = {
let bsConfig = {
run_settings: {
cypressConfigFilePath: 'cypress.config.js',
},
Expand Down Expand Up @@ -1880,7 +1887,7 @@ describe('utils', () => {
});

it('by default assumes that CYPRESS_V9_AND_OLDER_TYPE is the test suite type', () => {
bsConfig = {
let bsConfig = {
run_settings: {},
};
utils.setCypressTestSuiteType(bsConfig);
Expand Down