Skip to content

Commit 2a3da21

Browse files
committed
perf: detects changes in templates and bundle
1 parent 9343c7d commit 2a3da21

1 file changed

Lines changed: 76 additions & 13 deletions

File tree

scripts/e2e.js

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const fs = require('fs-extra');
99
const path = require('path');
1010
const Paths = require('./paths');
1111
const { satisfies } = require('semver');
12+
const { createHash } = require('crypto');
1213

1314
const npmVersion = spawnSync('npm', ['-s', '--version'])
1415
.stdout.toString()
@@ -22,23 +23,38 @@ function getDirectories(rootDir) {
2223
});
2324
}
2425

26+
function sha1(...data) {
27+
const hash = createHash('sha1');
28+
data.forEach(item => hash.update(item));
29+
return hash.digest('base64').toString();
30+
}
31+
32+
function log(...msg) {
33+
console.log(`[e2e]`, ...msg);
34+
}
35+
2536
function setupE2e() {
2637
// this will trigger the build as well (not using yarn since yarn pack is bugy)
2738
// keep on to so that the build is triggered beforehand (pack => prepublish => clean-build => build)
2839
// Except that on npm < 4.0.0 the prepare doesn't exists
2940
if (!npmHasPrepare) {
30-
spawnSync('npm', ['-s', 'run', 'build'], {
31-
cwd: Paths.rootDir,
32-
stdio: 'inherit',
33-
});
41+
log('building ts-jest');
42+
spawnSync('npm', ['-s', 'run', 'build'], { cwd: Paths.rootDir });
3443
}
44+
log('creating bundle');
3545
const res = spawnSync('npm', ['-s', 'pack'], { cwd: Paths.rootDir });
3646
const bundle = path.join(Paths.rootDir, res.stdout.toString().trim());
47+
log('bundle create at ', bundle);
48+
49+
// get the hash of the bundle (to know if we should install it again or not)
50+
const bundleHash = sha1(fs.readFileSync(bundle));
51+
log('bundle SHA1: ', bundleHash);
3752

3853
// ensure directory exists before copying over
3954
fs.mkdirpSync(Paths.e2eWorkTemplatesDir);
4055

4156
// create the template packages from which node_modules will be originally copied from
57+
log('copying templates to the work directory');
4258
fs.copySync(
4359
path.join(Paths.e2eTemplatesDir),
4460
path.join(Paths.e2eWorkTemplatesDir)
@@ -47,30 +63,77 @@ function setupE2e() {
4763
// link locally so we could find it easily
4864
if (!fs.existsSync(Paths.e2eWotkDirLink)) {
4965
fs.symlinkSync(Paths.e2eWorkDir, Paths.e2eWotkDirLink, 'dir');
66+
log(
67+
'symbolic link to the work directory created at: ',
68+
Paths.e2eWotkDirLink
69+
);
5070
}
5171

5272
// install with `npm ci` in each template, this is the fastest but needs a package lock file,
5373
// that is why we end with the npm install of our bundle
54-
getDirectories(Paths.e2eWorkTemplatesDir).forEach(tmplDir => {
55-
const dir = path.join(Paths.e2eWorkTemplatesDir, tmplDir);
74+
getDirectories(Paths.e2eWorkTemplatesDir).forEach(name => {
75+
log('checking temlate ', name);
76+
const dir = path.join(Paths.e2eWorkTemplatesDir, name);
77+
const nodeModulesDir = path.join(dir, 'node_modules');
78+
const pkgLockFile = path.join(
79+
Paths.e2eTemplatesDir,
80+
name,
81+
'package-lock.json'
82+
);
83+
const e2eFile = path.join(nodeModulesDir, '.ts-jest-e2e.json');
5684

5785
// no package-lock.json => this template doesn't provide any package-set
58-
if (!fs.existsSync(path.join(dir, 'package-lock.json'))) return;
86+
if (!fs.existsSync(pkgLockFile)) {
87+
log(` [template: ${name}]`, 'not a package-set template, nothing to do');
88+
return;
89+
}
90+
91+
const pkgLockHash = sha1(fs.readFileSync(pkgLockFile));
5992

6093
// TODO: create a hash of package-lock.json as well as the bundle, and test it over one copied in each
6194
// template dir, to know if we should re-install or not
62-
if (fs.existsSync(path.join(dir, 'node_modules'))) return;
95+
const e2eData = fs.existsSync(e2eFile) ? fs.readJsonSync(e2eFile) : {};
96+
let bundleOk = e2eData.bundleHash === bundleHash;
97+
let packagesOk = e2eData.packageLockHash === pkgLockHash;
98+
99+
if (fs.existsSync(nodeModulesDir)) {
100+
log(` [template: ${name}]`, 'manifest: ', JSON.stringify(e2eData));
101+
log(` [template: ${name}]`, 'bundle: ', bundleOk ? 'HIT' : 'MISS');
102+
log(` [template: ${name}]`, 'packages: ', packagesOk ? 'HIT' : 'MISS');
103+
if (bundleOk && packagesOk) {
104+
log(
105+
` [template: ${name}]`,
106+
'bundle and packages unchanged, nothing to do'
107+
);
108+
return;
109+
}
110+
}
63111

64-
if (npmHasCiCommand) {
65-
spawnSync('npm', ['ci'], { cwd: dir, stdio: 'inherit' });
66-
} else {
67-
spawnSync('npm', ['i'], { cwd: dir, stdio: 'inherit' });
112+
if (!packagesOk) {
113+
if (npmHasCiCommand) {
114+
log(` [template: ${name}]`, 'installing packages using "npm ci"');
115+
spawnSync('npm', ['ci'], { cwd: dir });
116+
} else {
117+
log(` [template: ${name}]`, 'installing packages using "npm install"');
118+
spawnSync('npm', ['i'], { cwd: dir });
119+
}
120+
bundleOk = false;
68121
}
69-
spawnSync('npm', ['i', '-D', bundle], { cwd: dir, stdio: 'inherit' });
122+
if (!bundleOk) {
123+
log(` [template: ${name}]`, 'installing bundle');
124+
spawnSync('npm', ['i', '-D', bundle], { cwd: dir });
125+
}
126+
127+
// write our data
128+
e2eData.bundleHash = bundleHash;
129+
e2eData.packageLockHash = pkgLockHash;
130+
log(` [template: ${name}]`, 'writing manifest: ', JSON.stringify(e2eData));
131+
fs.outputJsonSync(e2eFile, e2eData, { space: 2 });
70132
});
71133
}
72134

73135
setupE2e();
74136

137+
log('templates are ready, running tests', '\n\n');
75138
const argv = process.argv.slice(2);
76139
jest.run(argv);

0 commit comments

Comments
 (0)