Skip to content

Commit

Permalink
feat(dotenv-flow/config): add ability to configure `dotenv-flow/confi…
Browse files Browse the repository at this point in the history
…g` via environment variables, relates #11
  • Loading branch information
kerimdzhanov committed Apr 21, 2019
1 parent d94d21c commit 0118d27
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 10 deletions.
8 changes: 5 additions & 3 deletions config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
(function() {
require('./lib/dotenv-flow').config()
})()
'use strict';

const env_options = require('./lib/env-options');

require('./lib/dotenv-flow').config(env_options());
12 changes: 7 additions & 5 deletions lib/dotenv-flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,25 +60,27 @@ function getDotenvFilenames(cwd, node_env) {
* @param {object} options - options for parsing `.env*` files
* @param {string} [options.node_env=process.env.NODE_ENV] – environment to use (development/test/production/etc,.)
* @param {string} [options.default_node_env] – the default environment value
* @param {string} [options.cwd=process.cwd()] – path to `.env*` files directory
* @param {string} [options.path=process.cwd()] – path to `.env*` files directory
* @param {string} [options.encoding="utf8"] – encoding of `.env*` files
* @param {boolean} [options.purge_dotenv] – perform the {@link cleanupDotenvDefinedVars}
* @return {object} with a `parsed` key containing the loaded content or an `error` key if it failed
*/
*/
function config(options = {}) {
const {
node_env = (process.env.NODE_ENV || options.default_node_env),
cwd = process.cwd(),
encoding = 'utf8',
purge_dotenv = false
} = options;

// `options.cwd` is here just for backward compatibility
const path = options.path || options.cwd || process.cwd();

try {
if (purge_dotenv) {
cleanupDotenvDefinedVars(cwd, encoding);
cleanupDotenvDefinedVars(path, encoding);
}

const parsed = getDotenvFilenames(cwd, node_env)
const parsed = getDotenvFilenames(path, node_env)
.reduce((parsed, path) => {
const result = dotenv.config({ path, encoding });

Expand Down
25 changes: 25 additions & 0 deletions lib/env-options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';

const ENV_OPTIONS_MAP = {
NODE_ENV: 'node_env',
DEFAULT_NODE_ENV: 'default_node_env',
DOTENV_FLOW_PATH: 'path',
DOTENV_FLOW_ENCODING: 'encoding',
DOTENV_FLOW_PURGE_DOTENV: 'purge_dotenv'
};

/**
* Get environment variable defined options for `dotenv-flow#config()`.
*
* @param {object} [env=process.env]
* @return {{node_env?: string, default_node_env?: string, path?: string, encoding?: string, purge_dotenv?: string}}
*/
module.exports = function env_options(env = process.env) {
return Object.keys(ENV_OPTIONS_MAP)
.reduce((options, key) => {
if (key in env) {
options[ ENV_OPTIONS_MAP[key] ] = env[key];
}
return options;
}, {});
};
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
},
"main": "lib/dotenv-flow.js",
"files": [
"lib/dotenv-flow.js"
"lib/env-options.js",
"config.js"
],
"dependencies": {
"dotenv": "^7.0.0"
Expand All @@ -32,7 +33,7 @@
"tmp": "^0.1.0"
},
"scripts": {
"test": "mocha test/dotenv-flow.spec.js",
"test": "mocha test/*.spec.js",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
},
"author": "Dan Kerimdzhanov",
Expand Down
88 changes: 88 additions & 0 deletions test/config-preload.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
'use strict';

const path = require('path');
const util = require('util');
const execFile = util.promisify(require('child_process').execFile);
const {expect} = require('chai');

/**
* Get the path to a given fixture project.
*
* @param {string} name – fixture project name
* @return {string} – path to a fixture project
*/
function getFixtureProjectPath(name) {
return path.join(__dirname, 'fixtures', name);
}

/**
* Executes the preload helper script using the given fixture project as a working directory.
*
* @param {string} cwd – path to a fixture project
* @param {object} [env] – predefined environment variables
* @param {string[]} [args] – command line arguments
* @return {Promise<object>} – stdout parsed as a json
*/
async function execWithPreload(cwd, {env = {}, args = []} = {}) {
const {stdout} = await execFile(
process.argv[0], // ~= /usr/bin/node
[
'-r', '../config',
'-e', 'console.log(JSON.stringify(process.env));',
'--', ...args
],
{ cwd, env }
);

try {
return JSON.parse(stdout);
}
catch (e) {
console.error(e);
throw new Error(`Unable to parse the following as a JSON:\n${stdout}`);
}
}

describe('dotenv-flow/config', () => {
it('preloads `.env*` files defined environment variables', async () => {
const variables = await execWithPreload(getFixtureProjectPath('env'));

expect(variables)
.to.have.property('DEFAULT_ENV_VAR')
.that.is.equal('ok');
});

it('supports configuration via environment variables', async () => {
let variables = await execWithPreload(getFixtureProjectPath('env'), {
env: {
DEFAULT_NODE_ENV: 'development',
DOTENV_FLOW_PATH: getFixtureProjectPath('node-env')
}
});

expect(variables).to.include({
DEFAULT_NODE_ENV: 'development',
DEFAULT_ENV_VAR: 'ok',
DEVELOPMENT_ENV_VAR: 'ok',
DEVELOPMENT_ONLY_VAR: 'ok'
});

// --

variables = await execWithPreload(getFixtureProjectPath('env'), {
env: {
NODE_ENV: 'production',
DEFAULT_NODE_ENV: 'development',
DOTENV_FLOW_PATH: getFixtureProjectPath('node-env')
}
});

expect(variables).to.include({
NODE_ENV: 'production',
DEFAULT_NODE_ENV: 'development',
DEFAULT_ENV_VAR: 'ok',
PRODUCTION_ENV_VAR: 'ok',
PRODUCTION_ONLY_VAR: 'ok'
});
});
});
38 changes: 38 additions & 0 deletions test/env-options.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';

const {expect} = require('chai');
const env_options = require('../lib/env-options');

describe('env_options', () => {
it('maps related environment variables to options', () => {
expect(env_options({
NODE_ENV: 'production',
DEFAULT_NODE_ENV: 'development',
DOTENV_FLOW_PATH: '/path/to/project',
DOTENV_FLOW_ENCODING: 'latin1',
DOTENV_FLOW_PURGE_DOTENV: 'yes'
}))
.to.deep.equal({
node_env: 'production',
default_node_env: 'development',
path: '/path/to/project',
encoding: 'latin1',
purge_dotenv: 'yes'
});
});

it("doesn't include undefined environment variables", () => {
expect(env_options({
DEFAULT_NODE_ENV: 'development',
DOTENV_FLOW_ENCODING: 'latin1'
}))
.to.have.keys([
'default_node_env',
'encoding'
]);
});

it('ignores unrelated environment variables', () => {
expect(env_options({ PATH: '/usr/local/bin' })).to.be.empty;
});
});

0 comments on commit 0118d27

Please sign in to comment.