@@ -9,6 +9,7 @@ const fs = require('fs-extra');
99const path = require ( 'path' ) ;
1010const Paths = require ( './paths' ) ;
1111const { satisfies } = require ( 'semver' ) ;
12+ const { createHash } = require ( 'crypto' ) ;
1213
1314const 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+
2536function 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
73135setupE2e ( ) ;
74136
137+ log ( 'templates are ready, running tests' , '\n\n' ) ;
75138const argv = process . argv . slice ( 2 ) ;
76139jest . run ( argv ) ;
0 commit comments