From ea8002130477f044e66508179394eea485583b2a Mon Sep 17 00:00:00 2001 From: Hugo Wood Date: Wed, 15 Mar 2017 15:09:38 +0100 Subject: [PATCH] feat(spawn): add support for quoted scripts * feat(spawn): add support for quoted scripts Use the shell option of spawn introduced in Node.js 4.8 (see https://github.com/nodejs/node/pull/4598) to pass the command to the OS shell. Supersedes #77. * docs(readme): add gotchas Add Gotchas paragraph about passing variables to multiple scripts. * docs(readme): add required node version badge Replace the Prerequisite paragraph by a badge showing the require version of Node.js required to run cross-env. * test(spawn): add test for quoted scripts See https://github.com/kentcdodds/cross-env/pull/89#pullrequestreview-27055572. BREAKING CHANGE: Changes the behavior when passed quoted scripts or special characters interpreted by the shell. --- README.md | 19 +++++++++++++++---- package.json | 2 +- src/index.js | 6 +++++- src/index.test.js | 15 +++++++++++++++ 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d2fedad..74d32c0 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Run scripts that set and use environment variables across platforms [![Code Coverage][coverage-badge]][coverage] [![Dependencies][dependencyci-badge]][dependencyci] [![version][version-badge]][package] +[![node-version][node-version-badge]][node] [![downloads][downloads-badge]][npm-stat] [![MIT License][license-badge]][LICENSE] @@ -36,10 +37,6 @@ setting or using the environment variable properly for the platform. Just set it like you would if it's running on a POSIX system, and `cross-env` will take care of setting it properly. -## Prerequisites - -- [NodeJS][node] version 4.0 or greater. - ## Installation This module is distributed via [npm][npm] which is bundled with [node][node] and @@ -87,6 +84,19 @@ the parent. This is quite useful for launching the same command with different env variables or when the environment variables are too long to have everything in one line. +## Gotchas + +If you want to have the environment variable apply to several commands in series +then you will need to wrap those in quotes in your script. For example: + +```json +{ + "scripts": { + "greet": "cross-env GREETING=Hi NAME=Joe \"echo $GREETING && echo $NAME\"" + } +} +``` + ## Inspiration I originally created this to solve a problem I was having with my npm scripts in @@ -129,6 +139,7 @@ MIT [dependencyci]: https://dependencyci.com/github/kentcdodds/cross-env [version-badge]: https://img.shields.io/npm/v/cross-env.svg?style=flat-square [package]: https://www.npmjs.com/package/cross-env +[node-version-badge]: https://img.shields.io/badge/node-%3E%3D%204.8-orange.svg?style=flat-square [downloads-badge]: https://img.shields.io/npm/dm/cross-env.svg?style=flat-square [npm-stat]: http://npm-stat.com/charts.html?package=cross-env&from=2016-04-01 [license-badge]: https://img.shields.io/npm/l/cross-env.svg?style=flat-square diff --git a/package.json b/package.json index 0695643..8455fdd 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "cross-env": "dist/bin/cross-env.js" }, "engines": { - "node": ">=4.0" + "node": ">=4.8" }, "scripts": { "start": "nps", diff --git a/src/index.js b/src/index.js index 876ae2c..9a4a7a7 100644 --- a/src/index.js +++ b/src/index.js @@ -8,7 +8,11 @@ const envSetterRegex = /(\w+)=('(.+)'|"(.+)"|(.+))/ function crossEnv(args) { const [command, commandArgs, env] = getCommandArgsAndEnvVars(args) if (command) { - const proc = spawn(command, commandArgs, {stdio: 'inherit', env}) + const proc = spawn(command, commandArgs, { + stdio: 'inherit', + shell: true, + env, + }) process.on('SIGTERM', () => proc.kill('SIGTERM')) process.on('SIGINT', () => proc.kill('SIGINT')) process.on('SIGBREAK', () => proc.kill('SIGBREAK')) diff --git a/src/index.test.js b/src/index.test.js index b60d40f..f63b647 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -43,6 +43,20 @@ it(`should handle equality signs in quoted strings`, () => { testEnvSetting({FOO_ENV: 'foo=bar'}, 'FOO_ENV="foo=bar"') }) +it(`should handle quoted scripts`, () => { + crossEnv(['GREETING=Hi', 'NAME=Joe', 'echo $GREETING && echo $NAME']) + expect( + crossSpawnMock.spawn, + ).toHaveBeenCalledWith('echo $GREETING && echo $NAME', [], { + stdio: 'inherit', + shell: true, + env: Object.assign({}, process.env, { + GREETING: 'Hi', + NAME: 'Joe', + }), + }) +}) + it(`should do nothing given no command`, () => { crossEnv([]) expect(crossSpawnMock.spawn).toHaveBeenCalledTimes(0) @@ -80,6 +94,7 @@ function testEnvSetting(expected, ...envSettings) { expect(crossSpawnMock.spawn).toHaveBeenCalledTimes(1) expect(crossSpawnMock.spawn).toHaveBeenCalledWith('echo', ['hello world'], { stdio: 'inherit', + shell: true, env: Object.assign({}, process.env, env), })