├── .eslintignore ├── .gitattributes ├── .gitignore ├── lib ├── __tests__ │ ├── assert.env │ ├── .travis.yml │ ├── more │ │ └── package.json │ └── nvx.test.js ├── errors.json ├── cli-test.js ├── index.js └── cli.js ├── .prettierrc ├── .travis.yml ├── greenkeeper.json ├── .editorconfig ├── LICENSE ├── README.md └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | -------------------------------------------------------------------------------- /lib/__tests__/assert.env: -------------------------------------------------------------------------------- 1 | TEST_TIMEOUT 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /lib/__tests__/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 6 4 | - 4 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 10 4 | - 8 5 | install: npm install 6 | after_script: 'cat ./coverage/lcov.info | coveralls' 7 | -------------------------------------------------------------------------------- /lib/__tests__/more/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "more", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "test": "node -v" 6 | }, 7 | "license": "ISC" 8 | } 9 | -------------------------------------------------------------------------------- /lib/errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | "No versions of Node were provided or found in a .travis.yml or circle.yml file", 3 | "Must provide ", 4 | "Error: must provide \" -- \"" 5 | ] 6 | -------------------------------------------------------------------------------- /greenkeeper.json: -------------------------------------------------------------------------------- 1 | { 2 | "groups": { 3 | "default": { 4 | "packages": [ 5 | "lib/__tests__/more/package.json", 6 | "package.json" 7 | ] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Buster Collings (https://about.me/buster) 2 | 3 | Permission to use, copy, modify, and/or distribute this software for 4 | any purpose with or without fee is hereby granted, provided that the 5 | above copyright notice and this permission notice appear in all 6 | copies. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 9 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 10 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 11 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 13 | PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 14 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 | PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /lib/cli-test.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | const meow = require('meow'); 4 | const nvx = require('./'); 5 | const knownErrors = require('./errors.json'); 6 | 7 | const cli = meow( 8 | ` 9 | Usage 10 | 11 | $ nvx-test [version ...] 12 | 13 | Examples 14 | 15 | # Run "npm test" using versions found 16 | # in .travis.yml or circle.yml 17 | $ nvx-test 18 | 19 | # Specifically use versions: 0.12 and 8 20 | $ nvx-test 0.12 8 21 | `, 22 | { 23 | flags: { 24 | help: { 25 | alias: 'h' 26 | }, 27 | version: { 28 | alias: 'v' 29 | } 30 | } 31 | } 32 | ); 33 | 34 | nvx(cli.input, ['npm', 'test']).catch(error => { 35 | return showError(error); 36 | }); 37 | 38 | function showError(error) { 39 | console.error(`\n ${error}`); 40 | if (knownErrors.indexOf(error) > -1) { 41 | cli.showHelp(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const execa = require('execa'); 4 | const nodeVersions = require('travis-or-circle'); 5 | const map = require('p-map-series'); 6 | const pFinally = require('promise.prototype.finally'); 7 | 8 | pFinally.shim(); 9 | 10 | module.exports = function(versions, command) { 11 | versions = 12 | Array.isArray(versions) && versions.length > 0 13 | ? versions 14 | : nodeVersions(process.cwd()) || []; 15 | command = Array.isArray(command) && command.length > 0 ? command : []; 16 | return Promise.resolve(true).then(() => { 17 | if (versions.length === 0) { 18 | throw Error( 19 | 'No versions of Node were provided or found in a .travis.yml or circle.yml file' 20 | ); 21 | } 22 | 23 | if (command.length === 0) { 24 | throw Error('Must provide '); 25 | } 26 | 27 | return map(versions, version => { 28 | let vCommand = versionedCommand(version, command); 29 | return execa(`npx`, vCommand, { 30 | stdio: 'inherit' 31 | }); 32 | }); 33 | }); 34 | }; 35 | 36 | function versionedCommand(version, command) { 37 | let vc = [`-p`, `node@${version}`]; 38 | command.forEach(c => { 39 | vc.push(c); 40 | }); 41 | return vc; 42 | } 43 | -------------------------------------------------------------------------------- /lib/__tests__/nvx.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const nvx = require('../index.js'); 3 | 4 | describe('nvx', () => { 5 | process.chdir('./lib/__tests__'); 6 | require('assert-dotenv')(); 7 | jest.setTimeout(process.env.TEST_TIMEOUT); 8 | 9 | it('uses multiple versons as specified by arguments', () => { 10 | return nvx(['7.7', '4.2.1'], ['node', '-v']).then(results => { 11 | assert(results[0].command === 'npx -p node@7.7 node -v'); 12 | assert(results[1].command === 'npx -p node@4.2.1 node -v'); 13 | }); 14 | }); 15 | 16 | it('uses multiple versons as found in .travis.yml or circle.yml', () => { 17 | return nvx([], ['node', '-v']).then(results => { 18 | assert(results[0].command === 'npx -p node@6 node -v'); 19 | assert(results[1].command === 'npx -p node@4 node -v'); 20 | }); 21 | }); 22 | 23 | it('fails when no command is provided', () => { 24 | return nvx([]) 25 | .then(() => { 26 | assert(false); 27 | }) 28 | .catch(error => { 29 | assert(error); 30 | }); 31 | }); 32 | 33 | it('fails when no versions are provided or found', () => { 34 | process.chdir('./more'); 35 | return nvx() 36 | .then(() => { 37 | assert(false); 38 | }) 39 | .catch(error => { 40 | assert(error); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | const meow = require('meow'); 4 | const nvx = require('./'); 5 | const knownErrors = require('./errors.json'); 6 | 7 | const cli = meow( 8 | ` 9 | Usage 10 | 11 | $ nvx [version ...] -- 12 | 13 | Examples 14 | 15 | # Use versions found in .travis.yml or circle.yml 16 | $ nvx -- npm test 17 | 18 | # Specifically use versions: 0.12 and 8 19 | $ nvx 0.12 8 -- npm test 20 | 21 | # Not limited to just npm test 22 | $ nvx 0.12 8 -- node oicu812.js 23 | 24 | 25 | ## shorthand command for npm test ## 26 | ## nvx-test ## 27 | 28 | 29 | # Run "npm test" using versions found 30 | # in .travis.yml or circle.yml 31 | $ nvx-test 32 | 33 | # Specifically use versions: 0.12 and 8 34 | $ nvx-test 0.12 8 35 | `, 36 | { 37 | flags: { 38 | help: { 39 | alias: 'h' 40 | }, 41 | version: { 42 | alias: 'v' 43 | }, 44 | '--': true 45 | } 46 | } 47 | ); 48 | 49 | (() => { 50 | if (!cli.flags['--'] || cli.flags['--'].length === 0) { 51 | return showError('Error: must provide " -- "'); 52 | } 53 | 54 | nvx(cli.input, cli.flags['--']).catch(error => { 55 | return showError(error); 56 | }); 57 | })(cli); 58 | 59 | function showError(error) { 60 | console.error(`\n ${error}`); 61 | if (knownErrors.indexOf(error) > -1) { 62 | cli.showHelp(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nvx [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] [![Coverage percentage][coveralls-image]][coveralls-url] [![Greenkeeper badge][greenkeeper-image]][greenkeeper-url] 2 | 3 | > Run commands on any specified Node version, or as defined in .travis.yml or circle.yml 4 | 5 | ## Prerequisites 6 | 7 | - Only requires `npx` so, >= `npm@5.2.0` 8 | - Includes `nvx` and `nvx-test` CLI commands (also `nvxt` alias for `nvx-test`) 9 | 10 | ## Installation 11 | 12 | ```sh 13 | $ npm install nvx --global 14 | ``` 15 | 16 | ## CLI Usage 17 | 18 | ```sh 19 | $ nvx --help 20 | 21 | Usage 22 | 23 | $ nvx [version ...] -- 24 | 25 | Examples 26 | 27 | # Use versions found in .travis.yml or circle.yml 28 | $ nvx -- npm test 29 | 30 | # Specifically use versions: 0.12 and 8 31 | $ nvx 0.12 8 -- npm test 32 | 33 | # Not limited to just npm test 34 | $ nvx 8.1.2 -- node ./oicu812.js 35 | 36 | 37 | ## shorthand commands for npm test ## 38 | ## nvx-test ## 39 | ## nvxt ## 40 | 41 | 42 | # Run "npm test" using versions found 43 | # in .travis.yml or circle.yml 44 | $ nvx-test 45 | 46 | # Specifically use versions: 0.12 and 8 47 | $ nvx-test 0.12 8 48 | ``` 49 | 50 | ## License 51 | 52 | ISC © [Buster Collings](https://about.me/buster) 53 | 54 | [npm-image]: https://badge.fury.io/js/nvx.svg 55 | [npm-url]: https://npmjs.org/package/nvx 56 | [travis-image]: https://travis-ci.org/busterc/nvx.svg?branch=master 57 | [travis-url]: https://travis-ci.org/busterc/nvx 58 | [daviddm-image]: https://david-dm.org/busterc/nvx.svg?theme=shields.io 59 | [daviddm-url]: https://david-dm.org/busterc/nvx 60 | [coveralls-image]: https://coveralls.io/repos/busterc/nvx/badge.svg 61 | [coveralls-url]: https://coveralls.io/r/busterc/nvx 62 | [greenkeeper-image]: https://badges.greenkeeper.io/busterc/nvx.svg 63 | [greenkeeper-url]: https://greenkeeper.io/ 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nvx", 3 | "description": "Run commands on any specified Node version, or as defined in .travis.yml or circle.yml", 4 | "license": "ISC", 5 | "author": "Buster Collings (https://about.me/buster)", 6 | "repository": "busterc/nvx", 7 | "version": "1.0.7", 8 | "main": "lib/index.js", 9 | "bin": { 10 | "nvx": "lib/cli.js", 11 | "nvx-test": "lib/cli-test.js", 12 | "nvxt": "lib/cli-test.js" 13 | }, 14 | "files": [ 15 | "lib" 16 | ], 17 | "scripts": { 18 | "precommit": "lint-staged", 19 | "pretest": "eslint .", 20 | "test": "jest --coverage --detectOpenHandles" 21 | }, 22 | "dependencies": { 23 | "execa": "^4.0.0", 24 | "meow": "^6.0.0", 25 | "p-map-series": "^2.1.0", 26 | "promise.prototype.finally": "^3.1.2", 27 | "travis-or-circle": "^1.0.2" 28 | }, 29 | "devDependencies": { 30 | "assert-dotenv": "^3.0.0", 31 | "coveralls": "^3.0.9", 32 | "eslint": "^6.8.0", 33 | "eslint-config-prettier": "^6.10.0", 34 | "eslint-config-xo": "^0.27.2", 35 | "eslint-plugin-json": "^2.0.1", 36 | "eslint-plugin-prettier": "^3.1.2", 37 | "husky": "^4.2.1", 38 | "jest": "^25.1.0", 39 | "jest-cli": "^25.1.0", 40 | "lint-staged": "^10.0.7", 41 | "prettier": "^1.19.1", 42 | "prettier-package-json": "^2.1.3" 43 | }, 44 | "keywords": [ 45 | "circle", 46 | "circle-ci", 47 | "exec", 48 | "n", 49 | "node", 50 | "npx", 51 | "nve", 52 | "nvm", 53 | "nvm-test", 54 | "tav", 55 | "test", 56 | "testen", 57 | "testing", 58 | "tests", 59 | "travis", 60 | "travis-ci", 61 | "version", 62 | "versions" 63 | ], 64 | "eslintConfig": { 65 | "extends": [ 66 | "xo", 67 | "prettier" 68 | ], 69 | "env": { 70 | "jest": true, 71 | "node": true 72 | }, 73 | "rules": { 74 | "prettier/prettier": "error" 75 | }, 76 | "plugins": [ 77 | "prettier", 78 | "json" 79 | ] 80 | }, 81 | "jest": { 82 | "testEnvironment": "node", 83 | "coveragePathIgnorePatterns": [ 84 | "__tests__" 85 | ] 86 | }, 87 | "lint-staged": { 88 | "*.js": [ 89 | "eslint --fix", 90 | "git add" 91 | ], 92 | "*.json": [ 93 | "prettier --write", 94 | "git add" 95 | ], 96 | "package.json": [ 97 | "prettier-package-json --write", 98 | "git add" 99 | ] 100 | } 101 | } 102 | --------------------------------------------------------------------------------