Add --use-shell option

- Added test cases for new option
- Fixed up other test cases
- Fixed code coverage issue
This commit is contained in:
Todd Bluhm 2019-05-04 04:41:05 -05:00
parent 86edc944ed
commit 3534069ece
11 changed files with 62 additions and 19 deletions

View File

@ -1,6 +1,10 @@
sudo: required
dist: trusty
os:
- linux
# - windows Can not use windows at this time as secrets are not supported yet
language: node_js
node_js:
- "8"

View File

@ -7,6 +7,7 @@
- **Change**: Update package-lock.json file
- **Feature**: Added support for asyncronous .env and .rc files
- **Feature**: Added support for a programmatic API
- **Feature**: Added --use-shell option
- **Fix**: Keep newline (`\n`) characters intact when parsing env files
- **Change**: Added node v10 and v12 to build automation

View File

@ -89,7 +89,6 @@ later environments overwritting earlier ones.
Prevents overwritting of existing env vars on `process.env`
### `--fallback` file usage option
You can specify a `.env.local` (or any name) env file, add that to your `.gitignore` and use that
@ -97,6 +96,16 @@ in your local development environment. Then you can use a regular `.env` file in
with production configs that you can commit to a private/protected repo. When `env-cmd` cannot
find the `.env.local` file it will fallback to looking for a regular `.env` file.
### `--use-shell`
Executes the command within a new shell instance. This is useful if you want to string multiple
commands together and share the same env vars.
**Terminal**
```sh
./node_modules/.bin/env-cmd -f ./test/.env --use-shell "node run lint && node test"
```
### Asynchronous env file support
EnvCmd supports reading from asynchronous `.env` files. Instead of using a `.env` file, pass in a `.js`
@ -151,7 +160,8 @@ Executes a command in a new child process with the given options
- **`environments`** { `string[]` }: List of environment to read from the `.rc` file
- **`filePath`** { `string` }: Custom path to the `.rc` file (defaults to: `./.env-cmdrc(|.js|.json)`)
- **`options`** { `object` }
- **`noOverride`** { `boolean` }: Prevent `.env` file vars from overriding existing `process.env` vars
- **`noOverride`** { `boolean` }: Prevent `.env` file vars from overriding existing `process.env` vars (default: `false`)
- **`useShell`** { `boolean` }: Runs command inside a new shell instance (default: `false`)
- **Returns** { `Promise<object>` }: key is env var name and value is the env var value
### `GetEnvVars`

View File

@ -50,6 +50,7 @@ function EnvCmd({ command, commandArgs, envFile, rc, options }) {
// Execute the command with the given environment variables
const proc = spawn_1.spawn(command, commandArgs, {
stdio: 'inherit',
shell: options.useShell,
env
});
// Handle any termination signals for parent and child proceses

View File

@ -15,27 +15,23 @@ function parseArgs(args) {
.option('-e, --environments [env1,env2,...]', 'The rc-file environments to select', utils_1.parseArgList)
.option('--fallback', 'Enables auto fallback to default env file location ./.env')
.option('--no-override', 'Do not override existing env vars on process.env')
.option('--use-shell', 'Make env variables available to multiple commands and as command line arguments')
.parse(['_', '_', ...args]);
// get the command and command args
const command = program.args[0];
const commandArgs = program.args.slice(1);
const noOverride = !program.override;
const useShell = !!program.useShell;
let rc;
if (program.environments && program.environments.length) {
rc = rc || {};
rc.environments = program.environments;
}
if (program.rcFile) {
rc = rc || {};
rc.filePath = program.rcFile;
}
let envFile;
if (program.file) {
envFile = envFile || {};
envFile.filePath = program.file;
}
if (program.fallback != null) {
envFile = envFile || {};
envFile.fallback = program.fallback;
}
return {
@ -44,7 +40,8 @@ function parseArgs(args) {
envFile,
rc,
options: {
noOverride
noOverride,
useShell
}
};
}

View File

@ -42,6 +42,7 @@ export async function EnvCmd (
// Execute the command with the given environment variables
const proc = spawn(command, commandArgs, {
stdio: 'inherit',
shell: options.useShell,
env
})

View File

@ -15,20 +15,19 @@ export function parseArgs (args: string[]): EnvCmdOptions {
.option('-e, --environments [env1,env2,...]', 'The rc-file environments to select', parseArgList)
.option('--fallback', 'Enables auto fallback to default env file location ./.env')
.option('--no-override', 'Do not override existing env vars on process.env')
.option('--use-shell', 'Make env variables available to multiple commands and as command line arguments')
.parse(['_', '_', ...args])
// get the command and command args
const command = program.args[0]
const commandArgs = program.args.slice(1)
const noOverride = !program.override
const useShell = !!program.useShell
let rc: any
if (program.environments && program.environments.length) {
rc = rc || {}
rc.environments = program.environments
}
if (program.rcFile) {
rc = rc || {}
rc.filePath = program.rcFile
}
@ -36,9 +35,6 @@ export function parseArgs (args: string[]): EnvCmdOptions {
if (program.file) {
envFile = envFile || {}
envFile.filePath = program.file
}
if (program.fallback != null) {
envFile = envFile || {}
envFile.fallback = program.fallback
}
@ -48,7 +44,8 @@ export function parseArgs (args: string[]): EnvCmdOptions {
envFile,
rc,
options: {
noOverride
noOverride,
useShell
}
}
}

View File

@ -80,4 +80,4 @@ export function stripComments (envString: string): string {
export function stripEmptyLines (envString: string): string {
const emptyLinesRegex = /(^\n)/gim
return envString.replace(emptyLinesRegex, '')
}
}

View File

@ -14,5 +14,6 @@ export interface EnvCmdOptions extends GetEnvVarOptions {
commandArgs: string[]
options?: {
noOverride?: boolean
useShell?: boolean
}
}

View File

@ -60,7 +60,7 @@ describe('EnvCmd', (): void => {
assert.equal(spawnStub.callCount, 1)
})
it('should if noOverride option is false/missing it should override existing env vars',
it('should should override existing env vars if noOverride option is false/missing',
async (): Promise<void> => {
process.env.BOB = 'cool'
getEnvVarsStub.returns({ BOB: 'test' })
@ -82,7 +82,7 @@ describe('EnvCmd', (): void => {
}
)
it('should if noOverride option is true it should not override existing env vars',
it('should should not override existing env vars if noOverride option is true',
async (): Promise<void> => {
process.env.BOB = 'cool'
getEnvVarsStub.returns({ BOB: 'test' })
@ -106,4 +106,29 @@ describe('EnvCmd', (): void => {
assert.equal(spawnStub.args[0][2].env.BOB, 'cool')
}
)
it('should should spawn process with shell option if useShell option is true',
async (): Promise<void> => {
process.env.BOB = 'cool'
getEnvVarsStub.returns({ BOB: 'test' })
await envCmdLib.EnvCmd({
command: 'node',
commandArgs: ['-v'],
envFile: {
filePath: './.env',
fallback: true
},
rc: {
environments: ['dev'],
filePath: './.rc'
},
options: {
useShell: true
}
})
assert.equal(getEnvVarsStub.callCount, 1)
assert.equal(spawnStub.callCount, 1)
assert.equal(spawnStub.args[0][2].shell, true)
}
)
})

View File

@ -36,6 +36,12 @@ describe('parseArgs', (): void => {
assert.isTrue(res.options!.noOverride)
})
it('should parse use shell option', (): void => {
const res = parseArgs(['-e', environments[0], '--use-shell', command, ...commandArgs])
assert.exists(res.options)
assert.isTrue(res.options!.useShell)
})
it('should parse rc file path', (): void => {
const res = parseArgs(['-e', environments[0], '-r', rcFilePath, command, ...commandArgs])
assert.exists(res.rc)