@adobe/sizewatcher 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +2 -57
- package/lib/checkout.js +40 -33
- package/lib/comparators/git.js +2 -2
- package/lib/comparators/node_modules.js +20 -3
- package/lib/compare.js +8 -7
- package/lib/sizewatcher.js +74 -0
- package/package.json +4 -3
package/index.js
CHANGED
|
@@ -14,60 +14,5 @@
|
|
|
14
14
|
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const debug = require("debug")("sizewatcher");
|
|
20
|
-
const gitCheckoutBeforeAndAfter = require("./lib/checkout");
|
|
21
|
-
const compare = require("./lib/compare");
|
|
22
|
-
const report = require("./lib/report");
|
|
23
|
-
const Git = require("simple-git/promise");
|
|
24
|
-
|
|
25
|
-
function printUsage() {
|
|
26
|
-
console.log(`Usage: sizewatcher [<options>] [<before> [<after>]]`);
|
|
27
|
-
console.log();
|
|
28
|
-
console.log("Arguments:");
|
|
29
|
-
console.log(" <before> Before branch/commit for comparison. Defaults to default branch or main/master.");
|
|
30
|
-
console.log(" <after> After branch/commit for comparison. Defaults to current branch.");
|
|
31
|
-
console.log();
|
|
32
|
-
console.log("Options:");
|
|
33
|
-
console.log(" -h Show help");
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async function main(argv) {
|
|
37
|
-
try {
|
|
38
|
-
// yes, this should probably use a framework like oclif or yargs.
|
|
39
|
-
// but cli arguments are very limited now and so manual handling is enough
|
|
40
|
-
if (argv[0] === "-h") {
|
|
41
|
-
printUsage();
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (!await Git().checkIsRepo()) {
|
|
46
|
-
throw new Error(`Not inside a git checkout: ${process.cwd()}`);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
console.log(`Checking out git branches...`);
|
|
50
|
-
const { before, after } = await gitCheckoutBeforeAndAfter(process.cwd(), argv[0], argv[1]);
|
|
51
|
-
|
|
52
|
-
if (before.branch === after.branch) {
|
|
53
|
-
console.log(`Branches are identical, nothing to compare (${before.branch}=${after.branch}). Compare selected branches using 'sizewatcher <before> <after>'.`);
|
|
54
|
-
process.exit();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
console.log(`Comparing changes from '${before.branch}' to '${after.branch}'\n`);
|
|
58
|
-
|
|
59
|
-
const deltas = await compare(before, after);
|
|
60
|
-
|
|
61
|
-
await report(deltas);
|
|
62
|
-
|
|
63
|
-
} catch (e) {
|
|
64
|
-
debug(e);
|
|
65
|
-
console.error("Error:", e.message || e);
|
|
66
|
-
process.exit(1);
|
|
67
|
-
} finally {
|
|
68
|
-
console.log("Done. Cleaning up...");
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
main(process.argv.slice(2));
|
|
17
|
+
const sizewatcher = require("./lib/sizewatcher");
|
|
18
|
+
sizewatcher(process.argv.slice(2));
|
package/lib/checkout.js
CHANGED
|
@@ -18,7 +18,7 @@ const debug = require("debug")("sizewatcher");
|
|
|
18
18
|
const tmp = require("tmp");
|
|
19
19
|
tmp.setGracefulCleanup();
|
|
20
20
|
const path = require("path");
|
|
21
|
-
const Git = require("simple-git
|
|
21
|
+
const Git = require("simple-git");
|
|
22
22
|
|
|
23
23
|
async function getGitRoot(dir) {
|
|
24
24
|
// --git-dir will return relative directories
|
|
@@ -43,10 +43,14 @@ async function currentSha(dir) {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
async function getDefaultBranch(dir) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
try {
|
|
47
|
+
const originInfo = await Git(dir).remote(["show", "origin"]);
|
|
48
|
+
const m = originInfo.match(/HEAD branch: (.*)$/m);
|
|
49
|
+
if (m) {
|
|
50
|
+
return m[1];
|
|
51
|
+
}
|
|
52
|
+
} catch (e) {
|
|
53
|
+
debug(`ignoring error in getDefaultBranch(): ${e.message}`);
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
|
|
@@ -54,22 +58,12 @@ async function hasBranch(dir, branch) {
|
|
|
54
58
|
try {
|
|
55
59
|
await Git(dir).revparse(["--verify", branch]);
|
|
56
60
|
return branch;
|
|
57
|
-
} catch (e) {
|
|
61
|
+
} catch (e) {
|
|
62
|
+
debug(`ignoring error in hasBranch(): ${e.message}`);
|
|
58
63
|
return undefined;
|
|
59
64
|
}
|
|
60
65
|
}
|
|
61
66
|
|
|
62
|
-
async function hasRemoteTrackingBranch(dir) {
|
|
63
|
-
const git = Git(dir);
|
|
64
|
-
try {
|
|
65
|
-
const remoteBranch = await git.revparse(["--abbrev-ref", "--symbolic-full-name", "@{u}"]);
|
|
66
|
-
console.log(remoteBranch);
|
|
67
|
-
return true;
|
|
68
|
-
} catch (e) { // eslint-disable-line no-unused-vars
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
67
|
async function getPullRequestBaseBranch() {
|
|
74
68
|
return process.env.GITHUB_BASE_REF
|
|
75
69
|
|| (process.env.TRAVIS_PULL_REQUEST !== "false" && process.env.TRAVIS_BRANCH);
|
|
@@ -110,14 +104,18 @@ async function cloneLocalAndCheckout(from, to, branch) {
|
|
|
110
104
|
const gitRoot = await getGitRoot(from);
|
|
111
105
|
|
|
112
106
|
debug(`local cloning ${gitRoot} into ${to}`);
|
|
113
|
-
await Git().clone(gitRoot, to, { local: true });
|
|
107
|
+
await Git().clone(gitRoot, to, { '--local' : true });
|
|
114
108
|
|
|
115
|
-
|
|
116
|
-
|
|
109
|
+
if (branch) {
|
|
110
|
+
debug(`checking out '${branch}'...`);
|
|
111
|
+
await Git(to).checkout(branch);
|
|
112
|
+
}
|
|
117
113
|
}
|
|
118
114
|
|
|
119
115
|
async function gitCheckoutBeforeAndAfter(gitDir, beforeBranch, afterBranch) {
|
|
116
|
+
debug(`retrieving before branch: ${beforeBranch}`);
|
|
120
117
|
beforeBranch = await getBeforeBranch(gitDir, beforeBranch);
|
|
118
|
+
debug(`retrieving after branch: ${afterBranch}`);
|
|
121
119
|
afterBranch = await getAfterBranch(gitDir, afterBranch);
|
|
122
120
|
if (beforeBranch === afterBranch) {
|
|
123
121
|
return {
|
|
@@ -135,24 +133,33 @@ async function gitCheckoutBeforeAndAfter(gitDir, beforeBranch, afterBranch) {
|
|
|
135
133
|
const tempDir = tmp.dirSync({unsafeCleanup: true}).name;
|
|
136
134
|
debug(`temporary directory: ${tempDir}`);
|
|
137
135
|
|
|
136
|
+
// before checkout --------------------------------------------------------------
|
|
137
|
+
|
|
138
138
|
const beforeDir = path.join(tempDir, "before");
|
|
139
|
-
|
|
139
|
+
|
|
140
|
+
// we can use the faster local clone only if the "branch" is present locally
|
|
141
|
+
if (await hasBranch(gitDir, beforeBranch)) {
|
|
142
|
+
debug(`[before] using local cloning because existing checkout already has before branch '${beforeBranch}'`);
|
|
143
|
+
await cloneLocalAndCheckout(gitDir, beforeDir, beforeBranch);
|
|
144
|
+
} else {
|
|
145
|
+
debug(`[before] using remote cloning, as existing checkout does not have before branch '${beforeBranch}'`);
|
|
146
|
+
// ...otherwise need to do a full remote clone
|
|
147
|
+
await cloneRemoteAndCheckout(gitDir, beforeDir, beforeBranch);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// after checkout --------------------------------------------------------------
|
|
140
151
|
|
|
141
152
|
const afterDir = path.join(tempDir, "after");
|
|
142
|
-
if (process.env.CI || await hasRemoteTrackingBranch(afterDir)) {
|
|
143
|
-
await cloneRemoteAndCheckout(gitDir, afterDir, afterBranch);
|
|
144
153
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
} catch (e) {
|
|
153
|
-
debug("ignoring error", e);
|
|
154
|
-
}
|
|
154
|
+
debug(`[after] using local cloning`);
|
|
155
|
+
await cloneLocalAndCheckout(gitDir, afterDir);
|
|
156
|
+
try {
|
|
157
|
+
// need to ensure before branch is available under local name
|
|
158
|
+
await Git(afterDir).branch([beforeBranch, "-t", `origin/${beforeBranch}`]);
|
|
159
|
+
} catch (e) {
|
|
160
|
+
debug("ignoring error", e);
|
|
155
161
|
}
|
|
162
|
+
debug(`[after] current branch: ${await currentBranch(afterDir)}`);
|
|
156
163
|
|
|
157
164
|
debug("folders ready");
|
|
158
165
|
|
package/lib/comparators/git.js
CHANGED
|
@@ -19,7 +19,7 @@ const du = require("du");
|
|
|
19
19
|
const path = require("path");
|
|
20
20
|
const fs = require("fs");
|
|
21
21
|
const { execSync } = require("child_process");
|
|
22
|
-
const Git = require("simple-git
|
|
22
|
+
const Git = require("simple-git");
|
|
23
23
|
|
|
24
24
|
async function getSize(dir) {
|
|
25
25
|
debug(`git garbage collection of '${dir}'...`);
|
|
@@ -50,7 +50,7 @@ module.exports = {
|
|
|
50
50
|
compare: async function(before, after) {
|
|
51
51
|
const beforeSize = await getSize(before.dir);
|
|
52
52
|
const afterSize = await getSize(after.dir);
|
|
53
|
-
const details = await largestCommits(after.dir, before.branch, after.
|
|
53
|
+
const details = await largestCommits(after.dir, before.branch, after.sha);
|
|
54
54
|
|
|
55
55
|
return {
|
|
56
56
|
beforeSize,
|
|
@@ -24,19 +24,36 @@ function isEmptyObject(obj) {
|
|
|
24
24
|
return Object.keys(obj).length === 0 && obj.constructor === Object;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
function hasPackageJson(dir) {
|
|
28
|
+
return fs.existsSync(path.join(dir, "package.json"));
|
|
29
|
+
}
|
|
30
|
+
|
|
27
31
|
async function getSize(dir) {
|
|
32
|
+
if (!hasPackageJson(dir)) {
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
28
35
|
process.chdir(dir);
|
|
36
|
+
|
|
29
37
|
debug(`installing node dependencies inside ${dir}...`);
|
|
30
38
|
if (fs.existsSync("package-lock.json") || fs.existsSync("npm-shrinkwrap.json")) {
|
|
31
39
|
execSync("npm ci");
|
|
32
40
|
} else {
|
|
33
41
|
execSync("npm install");
|
|
34
42
|
}
|
|
35
|
-
|
|
36
|
-
|
|
43
|
+
|
|
44
|
+
const nodeModules = path.join(dir, "node_modules");
|
|
45
|
+
if (fs.existsSync(nodeModules)) {
|
|
46
|
+
debug(`calculating folder size of ${nodeModules}...`);
|
|
47
|
+
return du(nodeModules);
|
|
48
|
+
} else {
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
37
51
|
}
|
|
38
52
|
|
|
39
53
|
async function costOfModules(dir) {
|
|
54
|
+
if (!hasPackageJson(dir)) {
|
|
55
|
+
return "(no package.json)";
|
|
56
|
+
}
|
|
40
57
|
process.chdir(dir);
|
|
41
58
|
|
|
42
59
|
const pkgJsonPath = path.join(dir, "package.json");
|
|
@@ -62,7 +79,7 @@ async function costOfModules(dir) {
|
|
|
62
79
|
module.exports = {
|
|
63
80
|
|
|
64
81
|
shouldRun: async function(beforeDir, afterDir) {
|
|
65
|
-
return
|
|
82
|
+
return hasPackageJson(beforeDir) || hasPackageJson(afterDir);
|
|
66
83
|
},
|
|
67
84
|
|
|
68
85
|
compare: async function(before, after) {
|
package/lib/compare.js
CHANGED
|
@@ -136,6 +136,7 @@ function process(deltas) {
|
|
|
136
136
|
};
|
|
137
137
|
|
|
138
138
|
for (const d of deltas) {
|
|
139
|
+
debug("processing delta:", d);
|
|
139
140
|
if (d.error) {
|
|
140
141
|
summary.error++;
|
|
141
142
|
continue;
|
|
@@ -147,14 +148,14 @@ function process(deltas) {
|
|
|
147
148
|
};
|
|
148
149
|
|
|
149
150
|
let increase;
|
|
150
|
-
if (d.beforeSize <= 0) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
151
|
+
if (d.beforeSize <= 0 && d.afterSize <= 0) {
|
|
152
|
+
increase = 0;
|
|
153
|
+
} else if (d.afterSize <= 0) {
|
|
154
|
+
increase = -100;
|
|
155
|
+
} else if (d.beforeSize <= 0) {
|
|
156
|
+
increase = 100;
|
|
156
157
|
} else {
|
|
157
|
-
increase =
|
|
158
|
+
increase = (d.afterSize - d.beforeSize) / d.beforeSize * 100;
|
|
158
159
|
}
|
|
159
160
|
d.increase = increase.toFixed(1);
|
|
160
161
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2020 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
// main cli entry point
|
|
16
|
+
|
|
17
|
+
const debug = require("debug")("sizewatcher");
|
|
18
|
+
const gitCheckoutBeforeAndAfter = require("./checkout");
|
|
19
|
+
const compare = require("./compare");
|
|
20
|
+
const report = require("./report");
|
|
21
|
+
const Git = require("simple-git");
|
|
22
|
+
|
|
23
|
+
function printUsage() {
|
|
24
|
+
console.error(`Usage: sizewatcher [<options>] [<before> [<after>]]`);
|
|
25
|
+
console.error();
|
|
26
|
+
console.error("Arguments:");
|
|
27
|
+
console.error(" <before> Before branch/commit for comparison. Defaults to default branch or main/master.");
|
|
28
|
+
console.error(" <after> After branch/commit for comparison. Defaults to current branch.");
|
|
29
|
+
console.error();
|
|
30
|
+
console.error("Options:");
|
|
31
|
+
console.error(" -h Show help");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function sizewatcher(argv) {
|
|
35
|
+
try {
|
|
36
|
+
if (!argv) argv = [];
|
|
37
|
+
|
|
38
|
+
// yes, this should probably use a framework like oclif or yargs.
|
|
39
|
+
// but cli arguments are very limited now and so manual handling is enough
|
|
40
|
+
if (argv[0] === "-h") {
|
|
41
|
+
printUsage();
|
|
42
|
+
return process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
debug(`Running inside ${process.cwd()}`);
|
|
46
|
+
|
|
47
|
+
if (!await Git().checkIsRepo()) {
|
|
48
|
+
throw new Error(`Not inside a git checkout: ${process.cwd()}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(`Checking out git branches...`);
|
|
52
|
+
const { before, after } = await gitCheckoutBeforeAndAfter(process.cwd(), argv[0], argv[1]);
|
|
53
|
+
|
|
54
|
+
if (before.branch === after.branch) {
|
|
55
|
+
console.log(`Branches are identical, nothing to compare (${before.branch}=${after.branch}). Compare selected branches using 'sizewatcher <before> <after>'.`);
|
|
56
|
+
return process.exit();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(`Comparing changes from '${before.branch}' to '${after.branch}'\n`);
|
|
60
|
+
|
|
61
|
+
const deltas = await compare(before, after);
|
|
62
|
+
|
|
63
|
+
await report(deltas);
|
|
64
|
+
|
|
65
|
+
console.log("Done. Cleaning up...");
|
|
66
|
+
|
|
67
|
+
} catch (e) {
|
|
68
|
+
debug(e);
|
|
69
|
+
console.error("Error:", e.message || e);
|
|
70
|
+
return process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = sizewatcher;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/sizewatcher",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Warns if your pull requests introduce large size increases.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"eslint": "^7.1.0",
|
|
31
31
|
"mocha": "^7.2.0",
|
|
32
32
|
"mock-fs": "^4.13.0",
|
|
33
|
-
"nyc": "^15.1.0"
|
|
33
|
+
"nyc": "^15.1.0",
|
|
34
|
+
"supports-color": "^8.1.1"
|
|
34
35
|
},
|
|
35
36
|
"dependencies": {
|
|
36
37
|
"@octokit/rest": "^18.0.3",
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
"js-yaml": "^3.14.0",
|
|
42
43
|
"pretty-bytes": "^5.3.0",
|
|
43
44
|
"require-dir": "^1.2.0",
|
|
44
|
-
"simple-git": "^
|
|
45
|
+
"simple-git": "^3.7.1",
|
|
45
46
|
"tmp": "^0.2.1",
|
|
46
47
|
"xbytes": "^1.6.2"
|
|
47
48
|
}
|