From adde995a64dbc9a9b4a283e7a0c4dc5b7581aadb Mon Sep 17 00:00:00 2001 From: ReinoutW Date: Wed, 2 Jan 2019 14:52:08 +0100 Subject: [PATCH 01/12] Update README.md --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d9a76b8..783ae8e 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,18 @@ -recursive-install [![Build Status](https://travis-ci.org/emgeee/recursive-install.svg?branch=master)](https://travis-ci.org/emgeee/recursive-install) +recursive-install [![Build Status](https://github.com/ReinoutW/recursive-ci.svg?branch=master)](https://github.com/ReinoutW/recursive-ci) === -A small utility to recursively run `npm install` in any child directory that has a `package.json` file excluding sub directories of `node_modules`. +A small utility to recursively run `npm ci` in any child directory that has a `package.json` file excluding sub directories of `node_modules`. Install --- -`$ npm i -g recursive-install` +`$ npm i -g recursive-ci` Usage --- -`$ npm-recursive-install` +`$ npm-recursive-ci` -`$ npm-recursive-install --skip-root` - Will not install in `process.cwd()` -`$ npm-recursive-install --rootDir=lib` - Will only install from lib directory -`$ npm-recursive-install --production` - Will not install dev dependencies +`$ npm-recursive-ci --skip-root` - Will not install in `process.cwd()` +`$ npm-recursive-ci --rootDir=lib` - Will only install from lib directory License From 8abbcbf31fa48775cc0c0ac965fa88b9cebacc5d Mon Sep 17 00:00:00 2001 From: Reinout Waelput Date: Wed, 2 Jan 2019 15:08:27 +0100 Subject: [PATCH 02/12] Replaced recursive-install.js with recursive-ci.js. Updated npm install to npm ci. --- package-lock.json | 4 ++-- package.json | 20 ++++++++++---------- recursive-install.js => recursive-ci.js | 13 ++++--------- test/index.js | 19 +++++++------------ test/test-package-fail-lock.json | 13 +++++++++++++ test/test-package-lock.json | 13 +++++++++++++ test/test-package.json | 2 +- 7 files changed, 50 insertions(+), 34 deletions(-) rename recursive-install.js => recursive-ci.js (77%) mode change 100755 => 100644 create mode 100644 test/test-package-fail-lock.json create mode 100644 test/test-package-lock.json diff --git a/package-lock.json b/package-lock.json index 284f7c9..ea90afc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { - "name": "recursive-install", - "version": "1.3.0", + "name": "recursive-ci", + "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 59113b3..7255277 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,27 @@ { - "name": "recursive-install", - "version": "1.4.0", - "description": "CLI tool to recursive search child directories and run 'npm install' when a package.json file is found.", - "main": "recursive-install.js", + "name": "recursive-ci", + "version": "1.0.0", + "description": "CLI tool to recursive search child directories and run 'npm ci' when a package.json file is found.", + "main": "recursive-ci.js", "keywords": [ - "install", + "ci", "recursive", - "npm install" + "npm ci" ], "scripts": { "test": "./node_modules/.bin/mocha" }, "bin": { - "npm-recursive-install": "./recursive-install.js" + "npm-recursive-ci": "./recursive-ci.js" }, "repository": { "type": "git", - "url": "https://github.com/emgeee/recursive-install" + "url": "https://github.com/ReinoutW/recursive-ci" }, - "author": "Matt Green (https://greenin.space)", + "author": "Reinout Waelput", "license": "MIT", "bugs": { - "url": "https://github.com/emgeee/recursive-install/issues" + "url": "https://github.com/ReinoutW/recursive-ci/issues" }, "dependencies": { "shelljs": "^0.7.0", diff --git a/recursive-install.js b/recursive-ci.js old mode 100755 new mode 100644 similarity index 77% rename from recursive-install.js rename to recursive-ci.js index 66e585b..7cd78dc --- a/recursive-install.js +++ b/recursive-ci.js @@ -18,16 +18,11 @@ function getPackageJsonLocations (dirname) { }) } -function npmInstall (dir) { +function npmCi (dir) { var exitCode = 0; try { - if(argv.production) { - console.log('Installing ' + dir + '/package.json with --production option') - execSync('npm install --production', { cwd: dir}) - } else { - console.log('Installing ' + dir + '/package.json') - execSync('npm install', { cwd: dir}) - } + console.log('Installing ' + dir + '/package.json') + execSync('npm ci', { cwd: dir}) console.log('') } catch (err) { exitCode = err.status @@ -51,7 +46,7 @@ function filterRoot (dir) { if (require.main === module) { var exitCode = getPackageJsonLocations(argv.rootDir ? argv.rootDir : process.cwd()) .filter(argv.skipRoot ? filterRoot : noop) - .map(npmInstall) + .map(npmCi) .reduce(function (code, result) { return result.exitCode > code ? result.exitCode : code }, 0) diff --git a/test/index.js b/test/index.js index 0869e0d..ce0ddac 100644 --- a/test/index.js +++ b/test/index.js @@ -6,9 +6,9 @@ var os = require('os') var execSync = require('child_process').execSync -var script = path.join(__dirname, '../recursive-install.js') +var script = path.join(__dirname, '../recursive-ci.js') -describe('recursive install', function () { +describe('recursive ci', function () { var cwd var installedPaths var notInstalledPaths @@ -25,7 +25,7 @@ describe('recursive install', function () { '/notInstalledPaths/node_modules/a-module' ] - cwd = path.join(os.tmpdir(), 'recursive-install'.concat(uuidv4())) + cwd = path.join(os.tmpdir(), 'recursive-ci'.concat(uuidv4())) fs.ensureDirSync(cwd) installedPaths.concat(notInstalledPaths).forEach(function (p) { @@ -144,11 +144,11 @@ describe('recursive install', function () { }) }) - describe('test with options --skip-root --production', function () { + describe('test with options --skip-root', function () { beforeEach(function (done) { - this.timeout(60000) // update timeout in case npm install take time + this.timeout(60000) // update timeout in case npm ci takes time try { - execSync(script.concat(' --skip-root --production'), { cwd: cwd }) // Throw an error if exec fail + execSync(script.concat(' --skip-root'), { cwd: cwd }) // Throw an error if exec fail done() } catch (err) { done(err) @@ -168,11 +168,6 @@ describe('recursive install', function () { fs.lstatSync(path.join(workingDir, 'node_modules')).isDirectory(), 'Failed to install for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) ) - - assert( - !fs.existsSync(path.join(workingDir, 'node_modules', 'right-pad')), - 'Should not install dev dependencies for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) - ) }) }) @@ -189,7 +184,7 @@ describe('recursive install', function () { describe('test with fail', function () { it('fails to install packages', function (done) { - cwd = path.join(os.tmpdir(), 'recursive-install'.concat(uuidv4())) + cwd = path.join(os.tmpdir(), 'recursive-ci'.concat(uuidv4())) fs.ensureDirSync(cwd) fs.copySync(path.join(__dirname, 'test-package-fail.json'), path.join(cwd, 'package.json')) diff --git a/test/test-package-fail-lock.json b/test/test-package-fail-lock.json new file mode 100644 index 0000000..c70e57f --- /dev/null +++ b/test/test-package-fail-lock.json @@ -0,0 +1,13 @@ +{ + "name": "recursive-ci", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "left-pad": { + "version": "xxx", + "resolved": "xxx", + "integrity": "xxx" + } + } +} diff --git a/test/test-package-lock.json b/test/test-package-lock.json new file mode 100644 index 0000000..23c8aa5 --- /dev/null +++ b/test/test-package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "sample-app", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" + } + } +} diff --git a/test/test-package.json b/test/test-package.json index e0ccaaf..f21e6bc 100644 --- a/test/test-package.json +++ b/test/test-package.json @@ -2,7 +2,7 @@ "name": "sample-app", "version": "1.0.0", "dependencies": { - "left-pad": "^1.1.0" + "left-pad": "^1.3.0" }, "devDependencies": { "right-pad": "^1.0.1" From 22f402fc44b2c5ec968b866611600b26c42e931b Mon Sep 17 00:00:00 2001 From: ReinoutW Date: Wed, 2 Jan 2019 15:10:10 +0100 Subject: [PATCH 03/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 783ae8e..5b59b09 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -recursive-install [![Build Status](https://github.com/ReinoutW/recursive-ci.svg?branch=master)](https://github.com/ReinoutW/recursive-ci) +recursive-ci [![Build Status](https://github.com/ReinoutW/recursive-ci.svg?branch=master)](https://github.com/ReinoutW/recursive-ci) === A small utility to recursively run `npm ci` in any child directory that has a `package.json` file excluding sub directories of `node_modules`. From 7a325cbd895f5a44146f641f37ca60ba3c18515e Mon Sep 17 00:00:00 2001 From: ReinoutW Date: Wed, 2 Jan 2019 15:11:17 +0100 Subject: [PATCH 04/12] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5b59b09..180919c 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Usage `$ npm-recursive-ci` `$ npm-recursive-ci --skip-root` - Will not install in `process.cwd()` + `$ npm-recursive-ci --rootDir=lib` - Will only install from lib directory From d3528b53b5149793df23fae2d603d442197ca87b Mon Sep 17 00:00:00 2001 From: Reinout Waelput Date: Thu, 3 Jan 2019 16:54:32 +0100 Subject: [PATCH 05/12] Resolving code styling issues. Supporting production parameter. Resolving tests: - no longer rely on node being the application associated with .js files on Windows. - added a test for an invalid package-lock.json file. Upgraded dependencies and devDependencies to the latest versions. --- .vscode/launch.json | 24 + package-lock.json | 734 ++++++++++++++++--------------- package.json | 10 +- recursive-ci.js | 43 +- test/index.js | 210 +++++---- test/test-package-fail-lock.json | 10 +- test/test-package-fail.json | 7 +- test/test-package-lock.json | 8 +- 8 files changed, 556 insertions(+), 490 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e50aec6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Mocha Tests recursive-ci", + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "args": [ + "-u", + "tdd", + "--timeout", + "999999", + "--colors", + "${workspaceFolder}/test" + ], + "internalConsoleOptions": "openOnSessionStart" + } + + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ea90afc..cfc3d05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,128 +5,162 @@ "requires": true, "dependencies": { "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "version": "3.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true }, "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + "version": "5.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==" }, "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "version": "4.1.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", "wrap-ansi": "^2.0.0" } }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "commander": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", + "version": "2.15.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "version": "3.1.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { - "ms": "0.7.1" + "ms": "2.0.0" } }, "decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "version": "3.5.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "requires": { - "is-arrayish": "^0.2.1" + "once": "^1.4.0" } }, "escape-string-regexp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", + "version": "1.0.5", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "execa": { + "version": "1.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "3.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "locate-path": "^3.0.0" } }, "fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "version": "7.0.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "requires": { "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "get-caller-file": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha1-+Xj6TJDR3+f/LWvtoqUV5xO9z0o=" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.1.3", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -137,24 +171,32 @@ } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "version": "4.1.15", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true }, "growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "version": "1.10.5", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" + "he": { + "version": "1.1.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { "once": "^1.3.0", @@ -163,135 +205,100 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" + "version": "1.2.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" }, "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "requires": { - "builtin-modules": "^1.0.0" - } + "version": "2.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" }, "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "2.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + "is-stream": { + "version": "1.1.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, - "jade": { - "version": "0.26.3", - "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", - "dev": true, - "requires": { - "commander": "0.6.1", - "mkdirp": "0.3.0" - }, - "dependencies": { - "commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true - }, - "mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "dev": true - } - } + "isexe": { + "version": "2.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "version": "4.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { "graceful-fs": "^4.1.6" } }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", - "dev": true, + "lcid": { + "version": "2.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "requires": { - "graceful-fs": "^4.1.9" + "invert-kv": "^2.0.0" } }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "locate-path": { + "version": "3.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { - "invert-kv": "^1.0.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" } }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "p-defer": "^1.0.0" } }, - "lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" + "mem": { + "version": "4.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/mem/-/mem-4.0.0.tgz", + "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^1.1.0" + } }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -299,159 +306,150 @@ } }, "mocha": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", - "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", + "version": "5.2.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", "dev": true, "requires": { - "commander": "2.3.0", - "debug": "2.2.0", - "diff": "1.4.0", - "escape-string-regexp": "1.0.2", - "glob": "3.2.11", - "growl": "1.9.2", - "jade": "0.26.3", + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", "mkdirp": "0.5.1", - "supports-color": "1.2.0", - "to-iso-string": "0.0.2" + "supports-color": "5.4.0" }, "dependencies": { "glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "version": "7.1.2", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", "inherits": "2", - "minimatch": "0.3" - } - }, - "minimatch": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } }, "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "version": "2.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "nice-try": { + "version": "1.0.5", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "path-key": "^2.0.0" } }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" } }, "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "version": "3.1.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "requires": { - "lcid": "^1.0.0" + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" } }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "^1.2.0" - } + "p-defer": { + "version": "1.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" }, - "path-exists": { + "p-finally": { + "version": "1.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" + }, + "p-limit": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "requires": { - "pinkie-promise": "^2.0.0" + "p-try": "^2.0.0" } }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "p-locate": { + "version": "3.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "p-limit": "^2.0.0" } }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "p-try": { + "version": "2.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, - "pinkie-promise": { + "path-key": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "^2.0.0" - } + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } + "path-parse": { + "version": "1.0.6", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "pump": { + "version": "3.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "rechoir": { "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/rechoir/-/rechoir-0.6.2.tgz", "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "requires": { "resolve": "^1.1.6" @@ -459,112 +457,95 @@ }, "require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-main-filename": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "version": "1.9.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/resolve/-/resolve-1.9.0.tgz", + "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==", "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "version": "5.6.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, - "shelljs": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", - "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "shebang-command": { + "version": "1.2.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "shebang-regex": "^1.0.0" } }, - "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "shelljs": { + "version": "0.8.3", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" } }, - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" + "signal-exit": { + "version": "3.0.2", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "2.1.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "4.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^3.0.0" } }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "requires": { - "is-utf8": "^0.2.0" - } + "strip-eof": { + "version": "1.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "supports-color": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", - "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", - "dev": true + "version": "5.4.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } }, - "to-iso-string": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", - "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", + "universalify": { + "version": "0.1.2", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, "uuid": { @@ -573,72 +554,97 @@ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", "dev": true }, - "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", + "which": { + "version": "1.3.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "isexe": "^2.0.0" } }, "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" - }, - "window-size": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", - "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=" + "version": "2.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } } }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + "version": "4.0.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" }, "yargs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz", - "integrity": "sha1-M1UUSXfQV1fbuG1uOOwFYSOzpm4=", + "version": "12.0.5", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", "requires": { - "cliui": "^3.2.0", - "decamelize": "^1.1.1", + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", "get-caller-file": "^1.0.1", - "lodash.assign": "^4.2.0", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", + "os-locale": "^3.0.0", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "window-size": "^0.2.0", - "y18n": "^3.2.1", - "yargs-parser": "^3.2.0" + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" } }, "yargs-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz", - "integrity": "sha1-UIE1XRnZ0MjF2BrakIy05tGGZk8=", + "version": "11.1.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", "requires": { - "camelcase": "^3.0.0", - "lodash.assign": "^4.1.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } diff --git a/package.json b/package.json index 7255277..82bfb02 100644 --- a/package.json +++ b/package.json @@ -24,13 +24,13 @@ "url": "https://github.com/ReinoutW/recursive-ci/issues" }, "dependencies": { - "shelljs": "^0.7.0", - "yargs": "^5.0.0" + "shelljs": "^0.8.3", + "yargs": "^12.0.5" }, "devDependencies": { - "fs-extra": "^1.0.0", - "mocha": "^2.5.3", - "uuid": "^3.2.1" + "fs-extra": "^7.0.1", + "mocha": "^5.2.0", + "uuid": "^3.3.2" }, "standard": { "ignore": [ diff --git a/recursive-ci.js b/recursive-ci.js index 7cd78dc..10a1b18 100644 --- a/recursive-ci.js +++ b/recursive-ci.js @@ -1,45 +1,50 @@ #!/usr/bin/env node -var path = require('path') -var shell = require('shelljs') -var execSync = require('child_process').execSync -var argv = require('yargs').argv +var path = require('path'); +var shell = require('shelljs'); +var execSync = require('child_process').execSync; +var argv = require('yargs').argv; -function noop (x) { return x } +function noop (x) { return x; } function getPackageJsonLocations (dirname) { return shell.find(dirname) .filter(function (fname) { return !(fname.indexOf('node_modules') > -1 || fname[0] === '.') && - path.basename(fname) === 'package.json' + path.basename(fname) === 'package-lock.json'; }) .map(function (fname) { - return path.dirname(fname) - }) + return path.dirname(fname); + }); } function npmCi (dir) { var exitCode = 0; try { - console.log('Installing ' + dir + '/package.json') - execSync('npm ci', { cwd: dir}) - console.log('') + if(argv.production) { + console.log('Installing [ci] ' + dir + '/package-lock.json with --only=production option'); + execSync('npm ci --only=production', { cwd: dir}); + } else { + console.log('Installing [ci] ' + dir + '/package-lock.json'); + execSync('npm ci', { cwd: dir}); + } + console.log(''); } catch (err) { - exitCode = err.status + exitCode = err.status; } return { dirname: dir, exitCode: exitCode - } + }; } function filterRoot (dir) { if (path.normalize(dir) === path.normalize(process.cwd())) { - console.log('Skipping root package.json') - return false + console.log('Skipping root package-lock.json'); + return false; } else { - return true + return true; } } @@ -48,8 +53,8 @@ if (require.main === module) { .filter(argv.skipRoot ? filterRoot : noop) .map(npmCi) .reduce(function (code, result) { - return result.exitCode > code ? result.exitCode : code - }, 0) + return result.exitCode > code ? result.exitCode : code; + }, 0); - process.exit(exitCode) + process.exit(exitCode); } diff --git a/test/index.js b/test/index.js index ce0ddac..ef15d0b 100644 --- a/test/index.js +++ b/test/index.js @@ -1,203 +1,225 @@ -var path = require('path') -var assert = require('assert') -var uuidv4 = require('uuid/v4') -var fs = require('fs-extra') -var os = require('os') -var execSync = require('child_process').execSync +var path = require('path'); +var assert = require('assert'); +var uuidv4 = require('uuid/v4'); +var fs = require('fs-extra'); +var os = require('os'); +var execSync = require('child_process').execSync; -var script = path.join(__dirname, '../recursive-ci.js') +var script = 'node ' + path.join(__dirname, '../recursive-ci.js'); + +function getTempDir() { + return path.join(os.tmpdir(), 'recursive-ci-'.concat(uuidv4())); +} describe('recursive ci', function () { - var cwd - var installedPaths - var notInstalledPaths - var result = {code: 0} + var cwd; + var installedPaths; + var notInstalledPaths; + var result = {code: 0}; beforeEach(function () { installedPaths = [ '.', '/hello/world', '/foo/bar' - ] + ]; notInstalledPaths = [ '/notInstalledPaths/node_modules/a-module' - ] + ]; - cwd = path.join(os.tmpdir(), 'recursive-ci'.concat(uuidv4())) - fs.ensureDirSync(cwd) + cwd = getTempDir(); //path.join(os.tmpdir(), 'recursive-ci'.concat(uuidv4())); + fs.ensureDirSync(cwd); installedPaths.concat(notInstalledPaths).forEach(function (p) { - var newPath = path.join(cwd, p) - fs.ensureDirSync(newPath) - fs.copySync(path.join(__dirname, 'test-package.json'), path.join(newPath, 'package.json')) - }) - }) + var newPath = path.join(cwd, p); + fs.ensureDirSync(newPath); + fs.copySync(path.join(__dirname, 'test-package.json'), path.join(newPath, 'package.json')); + fs.copySync(path.join(__dirname, 'test-package-lock.json'), path.join(newPath, 'package-lock.json')); + }); + }); afterEach(function () { if (fs.lstatSync(cwd).isDirectory()) { - fs.removeSync(cwd) + fs.removeSync(cwd); } - }) + }); describe('test without option', function () { beforeEach(function (done) { - this.timeout(60000) // update timeout in case npm install take time + this.timeout(60000); // update timeout in case npm ci takes time try { - execSync(script, { cwd: cwd }) // Throw an error if exec fail - done() + execSync(script, { cwd: cwd }); // Throw an error if exec fail + done(); } catch (err) { - done(err) + done(err); } - }) + }); it('installs all packages', function () { installedPaths.forEach(function (p) { - var workingDir = path.join(cwd, p) + var workingDir = path.join(cwd, p); assert( fs.lstatSync(path.join(workingDir, 'node_modules')).isDirectory(), 'Failed to install for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) - ) + ); assert( fs.lstatSync(path.join(workingDir, 'node_modules', 'right-pad')).isDirectory(), 'Failed to install dev dependencies for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) - ) - }) - }) + ); + }); + }); it('doesn\'t install packages in node_modules', function () { notInstalledPaths.forEach(function (p) { - var workingDir = path.join(cwd, p) + var workingDir = path.join(cwd, p); assert( !fs.existsSync(path.join(workingDir, 'node_modules')), 'Install incorrectly succeeded for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) - ) - }) - }) - }) + ); + }); + }); + }); describe('test with option --production', function () { beforeEach(function (done) { - this.timeout(60000) // update timeout in case npm install take time + this.timeout(60000); // update timeout in case npm ci takes time try { - execSync(script.concat(' --production'), { cwd: cwd }) // Throw an error if exec fail - done() + execSync(script.concat(' --production'), { cwd: cwd }); // Throw an error if exec fail + done(); } catch (err) { - done(err) + done(err); } - }) + }); it('installs packages, but not devDependencies', function () { installedPaths.forEach(function (p) { - var workingDir = path.join(cwd, p) + var workingDir = path.join(cwd, p); assert( fs.lstatSync(path.join(workingDir, 'node_modules')).isDirectory(), 'Failed to install for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) - ) + ); assert( !fs.existsSync(path.join(workingDir, 'node_modules', 'right-pad')), 'Should not install dev dependencies for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) - ) - }) - }) + ); + }); + }); it('doesn\'t install packages in node_modules', function () { notInstalledPaths.forEach(function (p) { - var workingDir = path.join(cwd, p) + var workingDir = path.join(cwd, p); assert( !fs.existsSync(path.join(workingDir, 'node_modules')), 'Install incorrectly succeeded for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) - ) - }) - }) - }) + ); + }); + }); + }); describe('test with option --skip-root', function () { beforeEach(function (done) { - this.timeout(60000) // update timeout in case npm install take time + this.timeout(60000); // update timeout in case npm ci takes time try { - execSync(script.concat(' --skip-root'), { cwd: cwd }) // Throw an error if exec fail - done() + execSync(script.concat(' --skip-root'), { cwd: cwd }); // Throw an error if exec fail + done(); } catch (err) { - done(err) + done(err); } - }) + }); it('installs packages, but not in root directory', function () { assert( !fs.existsSync(path.join(cwd, 'node_modules')), 'Should not install dependencies for root directory ' + cwd + '. Directory Listing: ' + fs.readdirSync(cwd) - ) - }) + ); + + installedPaths.shift(); // Remove root from installedPaths + installedPaths.forEach(function (p) { + var workingDir = path.join(cwd, p); + assert( + fs.lstatSync(path.join(workingDir, 'node_modules')).isDirectory(), + 'Failed to install for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + }); + }); it('doesn\'t install packages in node_modules', function () { notInstalledPaths.forEach(function (p) { - var workingDir = path.join(cwd, p) + var workingDir = path.join(cwd, p); assert( !fs.existsSync(path.join(workingDir, 'node_modules')), 'Install incorrectly succeeded for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) - ) - }) - }) - }) + ); + }); + }); + }); - describe('test with options --skip-root', function () { + describe('test with options --skip-root --production', function () { beforeEach(function (done) { - this.timeout(60000) // update timeout in case npm ci takes time + this.timeout(60000); // update timeout in case npm ci takes time try { - execSync(script.concat(' --skip-root'), { cwd: cwd }) // Throw an error if exec fail - done() + execSync(script.concat(' --skip-root --production'), { cwd: cwd }); // Throw an error if exec fail + done(); } catch (err) { - done(err) + done(err); } - }) + }); it('installs packages, but not in root directory', function () { assert( !fs.existsSync(path.join(cwd, 'node_modules')), 'Should not install dependencies for root directory ' + cwd + '. Directory Listing: ' + fs.readdirSync(cwd) - ) + ); - installedPaths.shift() // Remove root from installedPaths + installedPaths.shift(); // Remove root from installedPaths installedPaths.forEach(function (p) { - var workingDir = path.join(cwd, p) + var workingDir = path.join(cwd, p); assert( fs.lstatSync(path.join(workingDir, 'node_modules')).isDirectory(), 'Failed to install for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) - ) - }) - }) + ); + + assert( + !fs.existsSync(path.join(workingDir, 'node_modules', 'right-pad')), + 'Should not install dev dependencies for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + }); + }); it('doesn\'t install packages in node_modules', function () { notInstalledPaths.forEach(function (p) { - var workingDir = path.join(cwd, p) + var workingDir = path.join(cwd, p); assert( !fs.existsSync(path.join(workingDir, 'node_modules')), 'Install incorrectly succeeded for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) - ) - }) - }) - }) + ); + }); + }); + }); - describe('test with fail', function () { + describe('test with invalid lock file', function () { it('fails to install packages', function (done) { - cwd = path.join(os.tmpdir(), 'recursive-ci'.concat(uuidv4())) - fs.ensureDirSync(cwd) - fs.copySync(path.join(__dirname, 'test-package-fail.json'), path.join(cwd, 'package.json')) - - try { - execSync(script, { cwd: cwd }) // Throw an error if exec fail - done('Should not succeed') + cwd = getTempDir(); //path.join(os.tmpdir(), 'recursive-ci'.concat(uuidv4())); + fs.ensureDirSync(cwd); + fs.copySync(path.join(__dirname, 'test-package-fail.json'), path.join(cwd, 'package.json')); + fs.copySync(path.join(__dirname, 'test-package-fail-lock.json'), path.join(cwd, 'package-lock.json')); + this.timeout(10000); // update timeout in case npm ci takes time + try { + execSync(script, { cwd: cwd }); // Throw an error if exec fail + done('Should not succeed'); } catch (err) { + // cipm can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. Please update your lock file with `npm install` before continuing. + // Missing: right-pad@^1.0.1 assert( (err.status === 1), 'Exist status should be 1, not '+ err.status - ) - done() + ); + done(); } - }) - }) -}) + }); + }); +}); diff --git a/test/test-package-fail-lock.json b/test/test-package-fail-lock.json index c70e57f..8916774 100644 --- a/test/test-package-fail-lock.json +++ b/test/test-package-fail-lock.json @@ -1,13 +1,13 @@ { - "name": "recursive-ci", + "name": "sample-app", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "left-pad": { - "version": "xxx", - "resolved": "xxx", - "integrity": "xxx" + "version": "1.3.0", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" } } -} +} \ No newline at end of file diff --git a/test/test-package-fail.json b/test/test-package-fail.json index 28c544b..aa6ca98 100644 --- a/test/test-package-fail.json +++ b/test/test-package-fail.json @@ -2,6 +2,9 @@ "name": "sample-app", "version": "1.0.0", "dependencies": { - "left-pad": "^error&6" + "left-pad": "^1.3.0" + }, + "devDependencies": { + "right-pad": "^1.0.1" } -} +} \ No newline at end of file diff --git a/test/test-package-lock.json b/test/test-package-lock.json index 23c8aa5..5b5c15f 100644 --- a/test/test-package-lock.json +++ b/test/test-package-lock.json @@ -6,8 +6,14 @@ "dependencies": { "left-pad": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/left-pad/-/left-pad-1.3.0.tgz", "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" + }, + "right-pad": { + "version": "1.0.1", + "resolved": "https://nexus.wkfs-frc.local/repository/npm-public/right-pad/-/right-pad-1.0.1.tgz", + "integrity": "sha1-jKCMLLtbVedNr6lr9/0aJ9VoyNA=", + "dev": true } } } From 36529132cefbe5f0f9362eb1f6b90c9037f33017 Mon Sep 17 00:00:00 2001 From: ReinoutW Date: Thu, 3 Jan 2019 16:57:53 +0100 Subject: [PATCH 06/12] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 180919c..63d5a90 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ Usage `$ npm-recursive-ci --rootDir=lib` - Will only install from lib directory +`$ npm-recursive-ci --production` - Will not install dev dependencies + License --- From 0441c76917c9d2903438fa5be7d2cc646ab111db Mon Sep 17 00:00:00 2001 From: ReinoutW Date: Thu, 3 Jan 2019 17:03:33 +0100 Subject: [PATCH 07/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 63d5a90..8d28018 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ recursive-ci [![Build Status](https://github.com/ReinoutW/recursive-ci.svg?branch=master)](https://github.com/ReinoutW/recursive-ci) === -A small utility to recursively run `npm ci` in any child directory that has a `package.json` file excluding sub directories of `node_modules`. +A small utility to recursively run `npm ci` in any child directory that have both a `package.json` as well as a `package-lock.json` file, excluding sub directories of `node_modules`. Install --- From 18360e0fdc9deb2bb03276c43fe4f9edf771b2eb Mon Sep 17 00:00:00 2001 From: Reinout Waelput Date: Fri, 4 Jan 2019 08:35:16 +0100 Subject: [PATCH 08/12] Added license file (MIT). --- license | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 license diff --git a/license b/license new file mode 100644 index 0000000..e651869 --- /dev/null +++ b/license @@ -0,0 +1,9 @@ +The MIT License (MIT) - http://www.opensource.org/licenses/mit-license.php + +Copyright 2019 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file From 36a243a0639a586815c9ad30261b1a6040ede050 Mon Sep 17 00:00:00 2001 From: Reinout Waelput Date: Fri, 4 Jan 2019 10:03:20 +0100 Subject: [PATCH 09/12] Supporting both recursive-ci and recursive-install.js Restructured tests to accommodate tests for recursive-install as well as recursive-ci.js Added tools.js to re-use code between recursive-install and recursive-ci. --- lib/tools.js | 40 ++++ recursive-ci.js | 28 +-- recursive-install.js | 38 ++++ test/{index.js => recursive-ci-tests.js} | 12 +- .../test-package-fail-lock.json | 0 .../{ => recursive-ci}/test-package-fail.json | 0 .../{ => recursive-ci}/test-package-lock.json | 0 test/{ => recursive-ci}/test-package.json | 0 test/recursive-install-tests.js | 212 ++++++++++++++++++ test/recursive-install/test-package-fail.json | 7 + test/recursive-install/test-package.json | 10 + 11 files changed, 316 insertions(+), 31 deletions(-) create mode 100644 lib/tools.js create mode 100644 recursive-install.js rename test/{index.js => recursive-ci-tests.js} (92%) rename test/{ => recursive-ci}/test-package-fail-lock.json (100%) rename test/{ => recursive-ci}/test-package-fail.json (100%) rename test/{ => recursive-ci}/test-package-lock.json (100%) rename test/{ => recursive-ci}/test-package.json (100%) create mode 100644 test/recursive-install-tests.js create mode 100644 test/recursive-install/test-package-fail.json create mode 100644 test/recursive-install/test-package.json diff --git a/lib/tools.js b/lib/tools.js new file mode 100644 index 0000000..07ec234 --- /dev/null +++ b/lib/tools.js @@ -0,0 +1,40 @@ +// tools.js +// ======== + +var path = require('path'); +var shell = require('shelljs'); + +module.exports = function() { + this.noop = function(x) { + return x; + }; + + this.getPackageJsonLocations = function(dirname) { + return getPackageFileLocations(dirname, 'package.json'); + }; + + this.getPackageLockJsonLocations = function(dirname) { + return getPackageFileLocations(dirname, 'package-lock.json'); + }; + + this.filterRoot = function(dir) { + if (path.normalize(dir) === path.normalize(process.cwd())) { + console.log('Skipping root package-json & package-lock.json'); + return false; + } else { + return true; + } + }; + + function getPackageFileLocations(dirname, filename) { + return shell.find(dirname) + .filter(function (fname) { + return !(fname.indexOf('node_modules') > -1 || fname[0] === '.') && + path.basename(fname) === filename; + }) + .map(function (fname) { + return path.dirname(fname); + }); + } +}; + diff --git a/recursive-ci.js b/recursive-ci.js index 10a1b18..d6c3bbe 100644 --- a/recursive-ci.js +++ b/recursive-ci.js @@ -1,23 +1,10 @@ #!/usr/bin/env node -var path = require('path'); -var shell = require('shelljs'); +require( __dirname + '/lib/tools.js')(); + var execSync = require('child_process').execSync; var argv = require('yargs').argv; -function noop (x) { return x; } - -function getPackageJsonLocations (dirname) { - return shell.find(dirname) - .filter(function (fname) { - return !(fname.indexOf('node_modules') > -1 || fname[0] === '.') && - path.basename(fname) === 'package-lock.json'; - }) - .map(function (fname) { - return path.dirname(fname); - }); -} - function npmCi (dir) { var exitCode = 0; try { @@ -39,17 +26,8 @@ function npmCi (dir) { }; } -function filterRoot (dir) { - if (path.normalize(dir) === path.normalize(process.cwd())) { - console.log('Skipping root package-lock.json'); - return false; - } else { - return true; - } -} - if (require.main === module) { - var exitCode = getPackageJsonLocations(argv.rootDir ? argv.rootDir : process.cwd()) + var exitCode = getPackageLockJsonLocations(argv.rootDir ? argv.rootDir : process.cwd()) .filter(argv.skipRoot ? filterRoot : noop) .map(npmCi) .reduce(function (code, result) { diff --git a/recursive-install.js b/recursive-install.js new file mode 100644 index 0000000..2a46365 --- /dev/null +++ b/recursive-install.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node + +require( __dirname + '/lib/tools.js')(); + +var execSync = require('child_process').execSync; +var argv = require('yargs').argv; + +function npmInstall (dir) { + var exitCode = 0; + try { + if(argv.production) { + console.log('Installing ' + dir + '/package.json with --production option'); + execSync('npm install --production', { cwd: dir}); + } else { + console.log('Installing ' + dir + '/package.json'); + execSync('npm install', { cwd: dir}); + } + console.log('') + } catch (err) { + exitCode = err.status; + } + + return { + dirname: dir, + exitCode: exitCode + }; +} + +if (require.main === module) { + var exitCode = getPackageJsonLocations(argv.rootDir ? argv.rootDir : process.cwd()) + .filter(argv.skipRoot ? filterRoot : noop) + .map(npmInstall) + .reduce(function (code, result) { + return result.exitCode > code ? result.exitCode : code; + }, 0); + + process.exit(exitCode); +} diff --git a/test/index.js b/test/recursive-ci-tests.js similarity index 92% rename from test/index.js rename to test/recursive-ci-tests.js index ef15d0b..6c1eca1 100644 --- a/test/index.js +++ b/test/recursive-ci-tests.js @@ -29,14 +29,14 @@ describe('recursive ci', function () { '/notInstalledPaths/node_modules/a-module' ]; - cwd = getTempDir(); //path.join(os.tmpdir(), 'recursive-ci'.concat(uuidv4())); + cwd = getTempDir(); fs.ensureDirSync(cwd); installedPaths.concat(notInstalledPaths).forEach(function (p) { var newPath = path.join(cwd, p); fs.ensureDirSync(newPath); - fs.copySync(path.join(__dirname, 'test-package.json'), path.join(newPath, 'package.json')); - fs.copySync(path.join(__dirname, 'test-package-lock.json'), path.join(newPath, 'package-lock.json')); + fs.copySync(path.join(__dirname, 'recursive-ci/test-package.json'), path.join(newPath, 'package.json')); + fs.copySync(path.join(__dirname, 'recursive-ci/test-package-lock.json'), path.join(newPath, 'package-lock.json')); }); }); @@ -203,10 +203,10 @@ describe('recursive ci', function () { describe('test with invalid lock file', function () { it('fails to install packages', function (done) { - cwd = getTempDir(); //path.join(os.tmpdir(), 'recursive-ci'.concat(uuidv4())); + cwd = getTempDir(); fs.ensureDirSync(cwd); - fs.copySync(path.join(__dirname, 'test-package-fail.json'), path.join(cwd, 'package.json')); - fs.copySync(path.join(__dirname, 'test-package-fail-lock.json'), path.join(cwd, 'package-lock.json')); + fs.copySync(path.join(__dirname, 'recursive-ci/test-package-fail.json'), path.join(cwd, 'package.json')); + fs.copySync(path.join(__dirname, 'recursive-ci/test-package-fail-lock.json'), path.join(cwd, 'package-lock.json')); this.timeout(10000); // update timeout in case npm ci takes time try { execSync(script, { cwd: cwd }); // Throw an error if exec fail diff --git a/test/test-package-fail-lock.json b/test/recursive-ci/test-package-fail-lock.json similarity index 100% rename from test/test-package-fail-lock.json rename to test/recursive-ci/test-package-fail-lock.json diff --git a/test/test-package-fail.json b/test/recursive-ci/test-package-fail.json similarity index 100% rename from test/test-package-fail.json rename to test/recursive-ci/test-package-fail.json diff --git a/test/test-package-lock.json b/test/recursive-ci/test-package-lock.json similarity index 100% rename from test/test-package-lock.json rename to test/recursive-ci/test-package-lock.json diff --git a/test/test-package.json b/test/recursive-ci/test-package.json similarity index 100% rename from test/test-package.json rename to test/recursive-ci/test-package.json diff --git a/test/recursive-install-tests.js b/test/recursive-install-tests.js new file mode 100644 index 0000000..71e5244 --- /dev/null +++ b/test/recursive-install-tests.js @@ -0,0 +1,212 @@ +var path = require('path'); +var assert = require('assert'); +var uuidv4 = require('uuid/v4'); +var fs = require('fs-extra'); +var os = require('os'); +var execSync = require('child_process').execSync; + +var script = 'node ' + path.join(__dirname, '../recursive-install.js'); + +function getTempDir() { + return path.join(os.tmpdir(), 'recursive-install-'.concat(uuidv4())); +} + +describe('recursive install', function () { + var cwd; + var installedPaths; + var notInstalledPaths; + var result = {code: 0}; + + beforeEach(function () { + installedPaths = [ + '.', + '/hello/world', + '/foo/bar' + ]; + + notInstalledPaths = [ + '/notInstalledPaths/node_modules/a-module' + ]; + + cwd = getTempDir(); + fs.ensureDirSync(cwd); + + installedPaths.concat(notInstalledPaths).forEach(function (p) { + var newPath = path.join(cwd, p); + fs.ensureDirSync(newPath); + fs.copySync(path.join(__dirname, 'recursive-install/test-package.json'), path.join(newPath, 'package.json')); + }); + }); + + afterEach(function () { + if (fs.lstatSync(cwd).isDirectory()) { + fs.removeSync(cwd); + } + }); + + describe('test without option', function () { + beforeEach(function (done) { + this.timeout(60000); // update timeout in case npm install take time + try { + execSync(script, { cwd: cwd }); // Throw an error if exec fail + done(); + } catch (err) { + done(err); + } + }); + + it('installs all packages', function () { + installedPaths.forEach(function (p) { + var workingDir = path.join(cwd, p); + assert( + fs.lstatSync(path.join(workingDir, 'node_modules')).isDirectory(), + 'Failed to install for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + + assert( + fs.lstatSync(path.join(workingDir, 'node_modules', 'right-pad')).isDirectory(), + 'Failed to install dev dependencies for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + }); + }); + + it('doesn\'t install packages in node_modules', function () { + notInstalledPaths.forEach(function (p) { + var workingDir = path.join(cwd, p); + assert( + !fs.existsSync(path.join(workingDir, 'node_modules')), + 'Install incorrectly succeeded for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + }); + }); + }); + + describe('test with option --production', function () { + beforeEach(function (done) { + this.timeout(60000); // update timeout in case npm install take time + try { + execSync(script.concat(' --production'), { cwd: cwd }); // Throw an error if exec fail + done(); + } catch (err) { + done(err); + } + }); + + it('installs packages, but not devDependencies', function () { + installedPaths.forEach(function (p) { + var workingDir = path.join(cwd, p); + assert( + fs.lstatSync(path.join(workingDir, 'node_modules')).isDirectory(), + 'Failed to install for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + + assert( + !fs.existsSync(path.join(workingDir, 'node_modules', 'right-pad')), + 'Should not install dev dependencies for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + }); + }); + + it('doesn\'t install packages in node_modules', function () { + notInstalledPaths.forEach(function (p) { + var workingDir = path.join(cwd, p); + assert( + !fs.existsSync(path.join(workingDir, 'node_modules')), + 'Install incorrectly succeeded for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + }); + }); + }); + + describe('test with option --skip-root', function () { + beforeEach(function (done) { + this.timeout(60000); // update timeout in case npm install take time + try { + execSync(script.concat(' --skip-root'), { cwd: cwd }); // Throw an error if exec fail + done(); + } catch (err) { + done(err); + } + }); + + it('installs packages, but not in root directory', function () { + assert( + !fs.existsSync(path.join(cwd, 'node_modules')), + 'Should not install dependencies for root directory ' + cwd + '. Directory Listing: ' + fs.readdirSync(cwd) + ); + }); + + it('doesn\'t install packages in node_modules', function () { + notInstalledPaths.forEach(function (p) { + var workingDir = path.join(cwd, p); + assert( + !fs.existsSync(path.join(workingDir, 'node_modules')), + 'Install incorrectly succeeded for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + }); + }); + }); + + describe('test with options --skip-root --production', function () { + beforeEach(function (done) { + this.timeout(60000); // update timeout in case npm install take time + try { + execSync(script.concat(' --skip-root --production'), { cwd: cwd }); // Throw an error if exec fail + done(); + } catch (err) { + done(err); + } + }); + + it('installs packages, but not in root directory', function () { + assert( + !fs.existsSync(path.join(cwd, 'node_modules')), + 'Should not install dependencies for root directory ' + cwd + '. Directory Listing: ' + fs.readdirSync(cwd) + ); + + installedPaths.shift(); // Remove root from installedPaths + installedPaths.forEach(function (p) { + var workingDir = path.join(cwd, p); + assert( + fs.lstatSync(path.join(workingDir, 'node_modules')).isDirectory(), + 'Failed to install for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + + assert( + !fs.existsSync(path.join(workingDir, 'node_modules', 'right-pad')), + 'Should not install dev dependencies for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + }); + }); + + it('doesn\'t install packages in node_modules', function () { + notInstalledPaths.forEach(function (p) { + var workingDir = path.join(cwd, p); + assert( + !fs.existsSync(path.join(workingDir, 'node_modules')), + 'Install incorrectly succeeded for ' + workingDir + '. Directory Listing: ' + fs.readdirSync(workingDir) + ); + }); + }); + }); + + describe('test with fail', function () { + it('fails to install packages', function (done) { + cwd = getTempDir(); + fs.ensureDirSync(cwd); + fs.copySync(path.join(__dirname, 'recursive-install/test-package-fail.json'), path.join(cwd, 'package.json')); + this.timeout(10000); // update timeout in case npm install takes time + + try { + execSync(script, { cwd: cwd }); // Throw an error if exec fail + done('Should not succeed'); + } catch (err) { + assert( + (err.status === 1), + 'Exist status should be 1, not '+ err.status + ); + done(); + } + }); + }); +}); diff --git a/test/recursive-install/test-package-fail.json b/test/recursive-install/test-package-fail.json new file mode 100644 index 0000000..28c544b --- /dev/null +++ b/test/recursive-install/test-package-fail.json @@ -0,0 +1,7 @@ +{ + "name": "sample-app", + "version": "1.0.0", + "dependencies": { + "left-pad": "^error&6" + } +} diff --git a/test/recursive-install/test-package.json b/test/recursive-install/test-package.json new file mode 100644 index 0000000..e0ccaaf --- /dev/null +++ b/test/recursive-install/test-package.json @@ -0,0 +1,10 @@ +{ + "name": "sample-app", + "version": "1.0.0", + "dependencies": { + "left-pad": "^1.1.0" + }, + "devDependencies": { + "right-pad": "^1.0.1" + } +} From ae1b7d3c77d70c11ba5ff44a693b8f91d22fd674 Mon Sep 17 00:00:00 2001 From: ReinoutW Date: Fri, 4 Jan 2019 10:05:05 +0100 Subject: [PATCH 10/12] Update README.md --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 8d28018..62ef124 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,23 @@ +recursive-install [![Build Status](https://travis-ci.org/emgeee/recursive-install.svg?branch=master)](https://travis-ci.org/emgeee/recursive-install) +=== + +A small utility to recursively run `npm install` in any child directory that has a `package.json` file excluding sub directories of `node_modules`. + +Install +--- +`$ npm i -g recursive-install` + +Usage +--- +`$ npm-recursive-install` + +`$ npm-recursive-install --skip-root` - Will not install in `process.cwd()` + +`$ npm-recursive-install --rootDir=lib` - Will only install from lib directory + +`$ npm-recursive-install --production` - Will not install dev dependencies + + recursive-ci [![Build Status](https://github.com/ReinoutW/recursive-ci.svg?branch=master)](https://github.com/ReinoutW/recursive-ci) === From 56f54e03edc20d822028555c45c341083756a1c0 Mon Sep 17 00:00:00 2001 From: Reinout Waelput Date: Fri, 4 Jan 2019 10:12:56 +0100 Subject: [PATCH 11/12] Updated .travis.yml file. --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 60efd06..7e0a92d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,5 @@ sudo: false language: node_js node_js: - - "6" - - "5" - - "4" - "iojs" - - "0.12" + - "7" From e01c344de819bdc09def6a4b47fd81fb817a87a0 Mon Sep 17 00:00:00 2001 From: ReinoutW Date: Fri, 4 Jan 2019 10:17:42 +0100 Subject: [PATCH 12/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62ef124..26242c2 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Usage `$ npm-recursive-install --production` - Will not install dev dependencies -recursive-ci [![Build Status](https://github.com/ReinoutW/recursive-ci.svg?branch=master)](https://github.com/ReinoutW/recursive-ci) +recursive-ci [![Build Status](https://travis-ci.org/ReinoutW/recursive-ci.svg?branch=master)](https://github.com/ReinoutW/recursive-ci) === A small utility to recursively run `npm ci` in any child directory that have both a `package.json` as well as a `package-lock.json` file, excluding sub directories of `node_modules`.