diff --git a/.travis.yml b/.travis.yml index 60efd06..f34b45c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,4 @@ sudo: false language: node_js node_js: - - "6" - - "5" - - "4" - - "iojs" - - "0.12" + - "node" 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/README.md b/README.md index d9a76b8..26242c2 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,32 @@ 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://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`. + +Install +--- +`$ npm i -g recursive-ci` + +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 + +`$ npm-recursive-ci --production` - Will not install dev dependencies + + License --- MIT 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/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 diff --git a/package-lock.json b/package-lock.json index 284f7c9..cfc3d05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,132 +1,166 @@ { - "name": "recursive-install", - "version": "1.3.0", + "name": "recursive-ci", + "version": "1.0.0", "lockfileVersion": 1, "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 59113b3..82bfb02 100644 --- a/package.json +++ b/package.json @@ -1,36 +1,36 @@ { - "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", - "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 new file mode 100644 index 0000000..d6c3bbe --- /dev/null +++ b/recursive-ci.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 npmCi (dir) { + var exitCode = 0; + try { + 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; + } + + return { + dirname: dir, + exitCode: exitCode + }; +} + +if (require.main === module) { + var exitCode = getPackageLockJsonLocations(argv.rootDir ? argv.rootDir : process.cwd()) + .filter(argv.skipRoot ? filterRoot : noop) + .map(npmCi) + .reduce(function (code, result) { + return result.exitCode > code ? result.exitCode : code; + }, 0); + + process.exit(exitCode); +} diff --git a/recursive-install.js b/recursive-install.js old mode 100755 new mode 100644 index 66e585b..2a46365 --- a/recursive-install.js +++ b/recursive-install.js @@ -1,51 +1,29 @@ #!/usr/bin/env node -var path = require('path') -var shell = require('shelljs') -var execSync = require('child_process').execSync -var argv = require('yargs').argv +require( __dirname + '/lib/tools.js')(); -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' - }) - .map(function (fname) { - return path.dirname(fname) - }) -} +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}) + 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 install', { 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 - } else { - return true - } + }; } if (require.main === module) { @@ -53,8 +31,8 @@ if (require.main === module) { .filter(argv.skipRoot ? filterRoot : noop) .map(npmInstall) .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/recursive-ci-tests.js b/test/recursive-ci-tests.js new file mode 100644 index 0000000..6c1eca1 --- /dev/null +++ b/test/recursive-ci-tests.js @@ -0,0 +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 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}; + + 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-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')); + }); + }); + + 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 ci takes 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 ci takes 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 ci takes 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) + ); + + 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); + 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 ci takes 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 invalid lock file', function () { + it('fails to install packages', function (done) { + cwd = getTempDir(); + fs.ensureDirSync(cwd); + 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 + 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(); + } + }); + }); +}); diff --git a/test/recursive-ci/test-package-fail-lock.json b/test/recursive-ci/test-package-fail-lock.json new file mode 100644 index 0000000..8916774 --- /dev/null +++ b/test/recursive-ci/test-package-fail-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://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/recursive-ci/test-package-fail.json b/test/recursive-ci/test-package-fail.json new file mode 100644 index 0000000..aa6ca98 --- /dev/null +++ b/test/recursive-ci/test-package-fail.json @@ -0,0 +1,10 @@ +{ + "name": "sample-app", + "version": "1.0.0", + "dependencies": { + "left-pad": "^1.3.0" + }, + "devDependencies": { + "right-pad": "^1.0.1" + } +} \ No newline at end of file diff --git a/test/recursive-ci/test-package-lock.json b/test/recursive-ci/test-package-lock.json new file mode 100644 index 0000000..5b5c15f --- /dev/null +++ b/test/recursive-ci/test-package-lock.json @@ -0,0 +1,19 @@ +{ + "name": "sample-app", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "left-pad": { + "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==" + }, + "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 + } + } +} diff --git a/test/recursive-ci/test-package.json b/test/recursive-ci/test-package.json new file mode 100644 index 0000000..f21e6bc --- /dev/null +++ b/test/recursive-ci/test-package.json @@ -0,0 +1,10 @@ +{ + "name": "sample-app", + "version": "1.0.0", + "dependencies": { + "left-pad": "^1.3.0" + }, + "devDependencies": { + "right-pad": "^1.0.1" + } +} diff --git a/test/index.js b/test/recursive-install-tests.js similarity index 63% rename from test/index.js rename to test/recursive-install-tests.js index 0869e0d..71e5244 100644 --- a/test/index.js +++ b/test/recursive-install-tests.js @@ -1,208 +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 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'); -var script = 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} + 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-install'.concat(uuidv4())) - fs.ensureDirSync(cwd) + 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')) - }) - }) + 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) + 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 install take 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 install take 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 install take 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) - ) - }) + ); + }); 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 --production', function () { beforeEach(function (done) { - this.timeout(60000) // update timeout in case npm install take time + 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() + 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 () { it('fails to install packages', function (done) { - cwd = path.join(os.tmpdir(), 'recursive-install'.concat(uuidv4())) - fs.ensureDirSync(cwd) - fs.copySync(path.join(__dirname, 'test-package-fail.json'), path.join(cwd, 'package.json')) - + 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') + 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() + ); + done(); } - }) - }) -}) + }); + }); +}); diff --git a/test/test-package-fail.json b/test/recursive-install/test-package-fail.json similarity index 100% rename from test/test-package-fail.json rename to test/recursive-install/test-package-fail.json diff --git a/test/test-package.json b/test/recursive-install/test-package.json similarity index 100% rename from test/test-package.json rename to test/recursive-install/test-package.json