diff --git a/README.md b/README.md index 0400471..b9f59e1 100644 --- a/README.md +++ b/README.md @@ -204,8 +204,12 @@ module.exports = { simple: 'echo "this is easy"', // npm start simple test: { default: { - script: 'echo "test things!"', // npm start test - description: 'just pass it on to npm... Do not take this config very seriously :-)', + script: 'ava', // npm start test + description: 'Run tests with ava', + // your scripts will be run with node_modules/.bin in the PATH, so you can use locally installed packages. + // this is done in a cross-platform way, so your scripts will work on Mac and Windows :) + // NOTE: if you need to set environment variables, I recommend you check out the cross-env package, which works + // gret with p-s }, otherStuff: { // this one can be executed two different ways: diff --git a/package.json b/package.json index c5f370d..45a5e89 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "commander": "2.9.0", "find-up": "1.1.2", "lodash": "4.14.0", + "manage-path": "2.0.0", "prefix-matches": "0.0.9", "shell-escape": "0.2.0", "spawn-command": "0.0.2" diff --git a/src/index.js b/src/index.js index 0e97339..49c7627 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,9 @@ import spawn from 'spawn-command' import async from 'async' import colors from 'colors/safe' -import {isString, find} from 'lodash' +import {isString, find, clone} from 'lodash' +import {sync as findUpSync} from 'find-up' +import managePath from 'manage-path' import arrify from 'arrify' import getScriptToRun from './get-script-to-run' import getScriptsFromConfig from './get-scripts-from-config' @@ -45,7 +47,7 @@ function runPackageScript({scriptConfig, options = {}, scriptName, args}) { const command = [script, args].join(' ').trim() const log = getLogger(getLogLevel(options)) log.info(colors.gray('p-s executing: ') + colors.green(command)) - return spawn(command, {stdio: 'inherit', env: process.env}) + return spawn(command, {stdio: 'inherit', env: getEnv()}) } function getLogLevel({silent, logLevel}) { @@ -57,3 +59,13 @@ function getLogLevel({silent, logLevel}) { return undefined } } + +function getEnv() { + const env = clone(process.env) + const alterPath = managePath(env) + const npmBin = findUpSync('node_modules/.bin') + if (npmBin) { + alterPath.unshift(npmBin) + } + return env +} diff --git a/src/index.test.js b/src/index.test.js index 17846c1..bf69117 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -1,13 +1,25 @@ +import {resolve} from 'path' import test from 'ava' import {spy} from 'sinon' import color from 'colors/safe' +import {clone} from 'lodash' +import managePath from 'manage-path' import proxyquire from 'proxyquire' proxyquire.noCallThru() -test('spawn called with the parent process.env', t => { +test('spawn called with the parent process.env + npm path', t => { const {options: {env}} = testSpawnCallWithDefaults(t) - t.is(env, process.env) + const copy = clone(process.env) + managePath(copy).unshift(resolve('../node_modules/.bin')) + t.deepEqual(env, copy) +}) + +test('does not blow up if there is no node_modules/.bin', t => { + const {options: {env}} = testSpawnCallWithDefaults(t, undefined, { + 'find-up': {sync: () => null}, + }) + t.deepEqual(env, process.env) }) test('spawn called with the expected command', t => { @@ -73,18 +85,19 @@ test.cb('runs scripts in parallel if given an array of input', t => { // util functions -function testSpawnCallWithDefaults(t, options) { - return testSpawnCall(t, undefined, undefined, options) +function testSpawnCallWithDefaults(t, options, stubOverrides) { + return testSpawnCall(t, undefined, undefined, options, undefined, stubOverrides) } -function testSpawnCall(t, scriptConfig = {build: 'webpack'}, scripts = 'build', psOptions, args) { - const {runPackageScript, spawnStubSpy, ...otherRet} = setup() +function testSpawnCall(t, scriptConfig = {build: 'webpack'}, scripts = 'build', psOptions, args, stubOverrides) { + /* eslint max-params:[2, 6] */ // TODO: refactor + const {runPackageScript, spawnStubSpy, ...otherRet} = setup(stubOverrides) runPackageScript({scriptConfig, options: psOptions, scripts, args}) t.true(spawnStubSpy.calledOnce) const [command, options] = spawnStubSpy.firstCall.args return {command, options, spawnStubSpy, ...otherRet} } -function setup() { +function setup(stubOverrides = {}) { const onSpy = spy((event, cb) => cb()) const spawnStub = () => ({on: onSpy}) // eslint-disable-line func-style const infoSpy = spy() @@ -93,6 +106,7 @@ function setup() { const runPackageScript = proxyquire('./index', { 'spawn-command': spawnStubSpy, './get-logger': getLoggerSpy, + ...stubOverrides, }).default return {spawnStubSpy, infoSpy, getLoggerSpy, onSpy, runPackageScript} }