Skip to content

Commit

Permalink
feat(PATH): add npm bin to path
Browse files Browse the repository at this point in the history
This will search for a local node_modules/.bin directory and attempt to
add it to the PATH (in a cross-platform way using `manage-path`).

Closes #27
  • Loading branch information
Kent C. Dodds committed Jul 26, 2016
1 parent a9a6a62 commit b149fe0
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 11 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
16 changes: 14 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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}) {
Expand All @@ -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
}
28 changes: 21 additions & 7 deletions src/index.test.js
Original file line number Diff line number Diff line change
@@ -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 => {
Expand Down Expand Up @@ -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()
Expand All @@ -93,6 +106,7 @@ function setup() {
const runPackageScript = proxyquire('./index', {
'spawn-command': spawnStubSpy,
'./get-logger': getLoggerSpy,
...stubOverrides,
}).default
return {spawnStubSpy, infoSpy, getLoggerSpy, onSpy, runPackageScript}
}

0 comments on commit b149fe0

Please sign in to comment.