Fix the # comment in env var name issue

This commit is contained in:
Todd Bluhm 2017-03-02 19:18:33 -05:00
parent 907bf640d9
commit 909df18ddb
No known key found for this signature in database
GPG Key ID: 9CF312607477B8AB
3 changed files with 66 additions and 80 deletions

View File

@ -11,25 +11,44 @@ A simple node program for executing commands using an environment from an env fi
## Install
`npm install env-cmd` or `npm install -g env-cmd`
## Usage
### Environment File Usage
If the specified environment file can't be found, an error message is logged.
If then `.env` fallback file can't be found too, an error is thrown.
## Basic Usage
**Environment file `./test/.env`**
```
# This is a comment
ENV1=THANKS # Yay inline comments support
ENV1=THANKS
ENV2=FOR ALL
ENV3 THE FISH # This format is also accepted
ENV3=THE FISH
```
# Surround value in double quotes when using a # symbol in the value
ENV4="ValueContains#Symbol"
**Package.json**
```json
{
"scripts": {
"test": "env-cmd ./test/.env mocha -R spec"
}
}
```
or
# If using double quotes as part of the value, you must surround the value in double quotes
ENV5=""Value includes double quotes""
**Terminal**
```sh
# uses ./test/.env
./node_modules/.bin/env-cmd ./test/.env node index.js
```
## Advanced Usage
### Fallback file usage
You can specify an `.env.local` (or any name) env file, add that to your `.gitignore` and use that in your local development environment. Then you can use a regular `.env` file in root directory with production configs that can get committed to a private/protected repo. When `env-cmd` cannot find the `.env.local` file it will fallback to looking for a regular `.env` file.
**Environment file `./.env.local`**
```
# This is a comment
ENV1=THANKS
ENV2=FOR ALL
ENV3=THE FISH
```
**Fallback Environment file `./.env`**
```
@ -42,20 +61,11 @@ ENV5=gorge
```
**Package.json**
to use `./test/.env`
```json
{
"scripts": {
"test": "env-cmd ./test/.env mocha -R spec"
}
}
```
uses `./.env` as a fallback
```json
{
"scripts": {
"test": "env-cmd ./test/.doesntExist mocha -R spec"
"test": "env-cmd ./.env.local mocha -R spec"
}
}
```
@ -63,15 +73,14 @@ or
**Terminal**
```sh
# uses ./test/.env
./node_modules/.bin/env-cmd ./test/.env node index.js
# uses ./.env as a fallback, because i can't find `./test/.myEnv`
./node_modules/.bin/env-cmd ./test/.myEnv node index.js
# uses ./.env as a fallback, because it can't find `./.env.local`
./node_modules/.bin/env-cmd ./.env.local node index.js
```
### .rc file usage
For more complex projects, a `.env-cmdrc` file can be defined in the root directory and supports as many environments as you want. Instead of passing the path to a `.env` file to `env-cmd`, simple pass the name of the environment you want use thats in your `.env-cmdrc` file.
**.rc file `.env-cmdrc`**
```json
@ -95,7 +104,6 @@ or
These are the currently accepted environment file formats. If any other formats are desired please create an issue.
- `key=value`
- `key value`
- Key/value pairs as JSON
- JavaScript file exporting an object
- `.env-cmdrc` file (as valid json) in execution directory
@ -118,6 +126,7 @@ Special thanks to [`cross-env`](https://github.com/kentcdodds/cross-env) for ins
- Eric Lanehart
- Jon Scheiding
- Alexander Praetorius
## Contributing Guide
I welcome all pull requests. Please make sure you add appropriate test cases for any features added. Before opening a PR please make sure to run the following scripts:

View File

@ -56,11 +56,11 @@ function ParseArgs (args) {
// Strips out comments from env file string
function StripComments (envString) {
const commentsRegex = /("{1}.*"{1})*?([ ]*#.*$)/gim
const commentsRegex = /(^#.*$)/gim
let match = commentsRegex.exec(envString)
let newString = envString
while (match != null) {
newString = newString.replace(match[2], '')
newString = newString.replace(match[1], '')
match = commentsRegex.exec(envString)
}
return newString
@ -72,21 +72,9 @@ function StripEmptyLines (envString) {
return envString.replace(emptyLinesRegex, '')
}
// Stripes out double quotes to allow for usage for special # in values
function StripDoubleQuotes (envString) {
const doubleQuotesRegex = /"{1}(.*)"{1}/gim
let match = doubleQuotesRegex.exec(envString)
let newString = envString
while (match != null) {
newString = newString.replace(match[0], match[1])
match = doubleQuotesRegex.exec(envString)
}
return newString
}
// Parse out all env vars from an env file string
function ParseEnvVars (envString) {
const envParseRegex = /^((.+?)[ =](.*))$/gim
const envParseRegex = /^((.+?)[=](.*))$/gim
const matches = {}
let match
while ((match = envParseRegex.exec(envString)) !== null) {
@ -104,9 +92,6 @@ function ParseEnvString (envFileString) {
// Next we stripe out all the empty lines
envFileString = StripEmptyLines(envFileString)
// Finally we stripe out all the double quotes for special charactes
envFileString = StripDoubleQuotes(envFileString)
// Parse the envs vars out
const envs = ParseEnvVars(envFileString)
@ -123,7 +108,16 @@ function ParseRCFile (fileData) {
function UseRCFile (parsedArgs) {
const fileData = fs.readFileSync(rcFileLocation, { encoding: 'utf8' })
const parsedData = ParseRCFile(fileData)
return parsedData[parsedArgs.envFile]
const envVars = parsedData[parsedArgs.envFile]
if (!envVars) {
console.error(`Error:
Could not find environment:
${parsedArgs.envFile}
in .rc file:
${rcFileLocation}`)
throw new Error(`Missing environment ${parsedArgs.envFile} in .env-cmdrc file.`)
}
return envVars
}
// Uses the cli passed env file to get env vars
@ -141,6 +135,10 @@ function UseCmdLine (parsedArgs) {
Trying to fallback to read:
${envFilePathDefault}
`)
}
// If we don't have a main file try the fallback file
if (!file) {
try {
file = fs.readFileSync(envFilePathDefault)
} catch (e) {
@ -148,6 +146,7 @@ function UseCmdLine (parsedArgs) {
}
}
// Get the file extension
const ext = path.extname(envFilePath).toLowerCase()
// Parse the env file string using the correct parser
@ -188,7 +187,6 @@ module.exports = {
HandleUncaughtExceptions,
StripComments,
StripEmptyLines,
StripDoubleQuotes,
ParseEnvVars,
ParseRCFile,
UseRCFile,

View File

@ -40,7 +40,6 @@ const PrintHelp = lib.PrintHelp
const HandleUncaughtExceptions = lib.HandleUncaughtExceptions
const StripComments = lib.StripComments
const StripEmptyLines = lib.StripEmptyLines
const StripDoubleQuotes = lib.StripDoubleQuotes
const ParseEnvVars = lib.ParseEnvVars
describe('env-cmd', function () {
@ -90,16 +89,6 @@ describe('env-cmd', function () {
const envString = StripComments('#BOB=COOL\nNODE_ENV=dev\nANSWER=42 AND COUNTING\n#AnotherComment\n')
assert(envString === '\nNODE_ENV=dev\nANSWER=42 AND COUNTING\n\n')
})
it('should strip out all inline comments and preceding spaces', function () {
const envString = StripComments('BOB=COOL#inline1\nNODE_ENV=dev #cool\nANSWER=42 AND COUNTING #multiple-spaces\n')
assert(envString === 'BOB=COOL\nNODE_ENV=dev\nANSWER=42 AND COUNTING\n')
})
it('should not strip out values that are surrouned in double quotes', function () {
const envString = StripComments('BOB="#COOL"#inline1\nNODE_ENV=dev #cool\nANSWER="#42 AND COUNTING" #multiple-spaces\n')
assert(envString === 'BOB="#COOL"\nNODE_ENV=dev\nANSWER="#42 AND COUNTING"\n')
})
})
describe('StripEmptyLines', function () {
@ -109,13 +98,6 @@ describe('env-cmd', function () {
})
})
describe('StripDoubleQuotes', function () {
it('should strip out single double quotes', function () {
const envString = StripDoubleQuotes(`BOB="#COOL"\nNODE_ENV=dev\nANSWER="42 AND #COUNTING"\nCOOL=""quoted""\nAwesome="'singles'"`)
assert(envString === `BOB=#COOL\nNODE_ENV=dev\nANSWER=42 AND #COUNTING\nCOOL="quoted"\nAwesome='singles'`)
})
})
describe('ParseEnvVars', function () {
it('should parse out all env vars in string when not ending with \'\\n\'', function () {
const envVars = ParseEnvVars('BOB=COOL\nNODE_ENV=dev\nANSWER=42 AND COUNTING')
@ -131,20 +113,6 @@ describe('env-cmd', function () {
assert(envVars.ANSWER === '42 AND COUNTING')
})
it('should parse out all env vars in string with format \'key value\'', function () {
const envVars = ParseEnvVars('BOB COOL\nNODE_ENV dev\nANSWER 42 AND COUNTING\n')
assert(envVars.BOB === 'COOL')
assert(envVars.NODE_ENV === 'dev')
assert(envVars.ANSWER === '42 AND COUNTING')
})
it('should parse out all env vars in string with mixed format \'key=value\' & \'key value\'', function () {
const envVars = ParseEnvVars('BOB=COOL\nNODE_ENV dev\nANSWER=42 AND COUNTING\n')
assert(envVars.BOB === 'COOL')
assert(envVars.NODE_ENV === 'dev')
assert(envVars.ANSWER === '42 AND COUNTING')
})
it('should ignore invalid lines', function () {
const envVars = ParseEnvVars('BOB=COOL\nTHISIS$ANDINVALIDLINE\nANSWER=42 AND COUNTING\n')
assert(Object.keys(envVars).length === 2)
@ -218,6 +186,7 @@ describe('env-cmd', function () {
assert(spawnStub.args[0][2].env.NODE_ENV === 'dev')
assert(spawnStub.args[0][2].env.ANSWER === '42')
})
it('should parse env vars from .env-cmdrc file using production env', function () {
EnvCmd(['production', 'echo', '$BOB'])
assert(spawnStub.args[0][0] === 'echo')
@ -226,6 +195,16 @@ describe('env-cmd', function () {
assert(spawnStub.args[0][2].env.NODE_ENV === 'prod')
assert(spawnStub.args[0][2].env.ANSWER === '43')
})
it('should throw error if env not in .rc file', function () {
try {
EnvCmd(['staging', 'echo', '$BOB'])
assert(!'Should throw missing environment error.')
} catch (e) {
assert(e.message.includes('staging'))
assert(e.message.includes(`.env-cmdrc`))
}
})
})
describe('EnvCmd', function () {