Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Override #595

Merged
merged 5 commits into from Jan 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. See [standa

## [Unreleased](https://github.com/motdotla/dotenv/compare/v14.0.0...master)

- Support `override` option 🎉 ([#595](https://github.com/motdotla/dotenv/pull/595))

## [14.0.1](https://github.com/motdotla/dotenv/compare/v14.0.0...v14.0.1) (2022-01-16)

### Added
Expand Down
26 changes: 18 additions & 8 deletions README.md
Expand Up @@ -97,10 +97,10 @@ See [examples](https://github.com/dotenv-org/examples) of using dotenv with vari

Dotenv exposes two functions:

* `dotenv.config`
* `dotenv.parse`
* `config`
* `parse`

### `dotenv.config`
### Config

`config` will read your `.env` file, parse the contents, assign it to
[`process.env`](https://nodejs.org/docs/latest/api/process.html#process_process_env),
Expand All @@ -124,7 +124,7 @@ You can additionally, pass options to `config`.

Default: `path.resolve(process.cwd(), '.env')`

You may specify a custom path if your file containing environment variables is located elsewhere.
Specify a custom path if your file containing environment variables is located elsewhere.

```js
require('dotenv').config({ path: '/custom/path/to/.env' })
Expand All @@ -134,7 +134,7 @@ require('dotenv').config({ path: '/custom/path/to/.env' })

Default: `utf8`

You may specify the encoding of your file containing environment variables.
Specify the encoding of your file containing environment variables.

```js
require('dotenv').config({ encoding: 'latin1' })
Expand All @@ -144,13 +144,23 @@ require('dotenv').config({ encoding: 'latin1' })

Default: `false`

You may turn on logging to help debug why certain keys or values are not being set as you expect.
Turn on logging to help debug why certain keys or values are not being set as you expect.

```js
require('dotenv').config({ debug: process.env.DEBUG })
```

### `dotenv.parse`
##### Override

Default: `false`

Override any environment variables that have already been set on your machine with values from your .env file.

```js
require('dotenv').config({ override: true })
```

### Parse

The engine which parses the contents of your file containing environment
variables is available to use. It accepts a String or Buffer and will return
Expand All @@ -169,7 +179,7 @@ console.log(typeof config, config) // object { BASIC : 'basic' }

Default: `false`

You may turn on logging to help debug why certain keys or values are not being set as you expect.
Turn on logging to help debug why certain keys or values are not being set as you expect.

```js
const dotenv = require('dotenv')
Expand Down
35 changes: 30 additions & 5 deletions lib/main.d.ts
Expand Up @@ -3,7 +3,11 @@

export interface DotenvParseOptions {
/**
* You may turn on logging to help debug why certain keys or values are not being set as you expect.
* Default: `false`
*
* Turn on logging to help debug why certain keys or values are not being set as you expect.
*
* example: `dotenv.parse('KEY=value', { debug: true })`
*/
debug?: boolean;
}
Expand All @@ -28,19 +32,40 @@ export function parse<T extends DotenvParseOutput = DotenvParseOutput>(

export interface DotenvConfigOptions {
/**
* You may specify a custom path if your file containing environment variables is located elsewhere.
* Default: `path.resolve(process.cwd(), '.env')`
*
* Specify a custom path if your file containing environment variables is located elsewhere.
*
* example: `require('dotenv').config({ path: '/custom/path/to/.env' })`
*/
path?: string;

/**
* You may specify the encoding of your file containing environment variables.
* Default: `utf8`
*
* Specify the encoding of your file containing environment variables.
*
* example: `require('dotenv').config({ encoding: 'latin1' })`
*/
encoding?: string;

/**
* You may turn on logging to help debug why certain keys or values are not being set as you expect.
* Default: `false`
*
* Turn on logging to help debug why certain keys or values are not being set as you expect.
*
* example: `require('dotenv').config({ debug: process.env.DEBUG })`
*/
debug?: boolean;

/**
* Default: `false`
*
* Override any environment variables that have already been set on your machine with values from your .env file.
*
* example: `require('dotenv').config({ override: true })`
*/
override?: boolean;
}

export interface DotenvConfigOutput {
Expand All @@ -53,7 +78,7 @@ export interface DotenvConfigOutput {
*
* See https://docs.dotenv.org
*
* @param options - additional options. example: `{ path: './custom/path', encoding: 'latin1', debug: true }`
* @param options - additional options. example: `{ path: './custom/path', encoding: 'latin1', debug: true, override: false }`
* @returns an object with a `parsed` key if successful or `error` key if an error occurred. example: { parsed: { KEY: 'value' } }
*
*/
Expand Down
15 changes: 13 additions & 2 deletions lib/main.js
Expand Up @@ -65,6 +65,7 @@ function config (options) {
let dotenvPath = path.resolve(process.cwd(), '.env')
let encoding = 'utf8'
const debug = Boolean(options && options.debug)
const override = Boolean(options && options.override)

if (options) {
if (options.path != null) {
Expand All @@ -82,8 +83,18 @@ function config (options) {
Object.keys(parsed).forEach(function (key) {
if (!Object.prototype.hasOwnProperty.call(process.env, key)) {
process.env[key] = parsed[key]
} else if (debug) {
log(`"${key}" is already defined in \`process.env\` and will not be overwritten`)
} else {
if (override === true) {
process.env[key] = parsed[key]
}

if (debug) {
if (override === true) {
log(`"${key}" is already defined in \`process.env\` and WAS overwritten`)
} else {
log(`"${key}" is already defined in \`process.env\` and was NOT overwritten`)
}
}
}
})

Expand Down
42 changes: 41 additions & 1 deletion tests/test-config.js
Expand Up @@ -11,7 +11,7 @@ const mockParseResponse = { test: 'foo' }
let readFileSyncStub
let parseStub

t.plan(10)
t.plan(13)

t.beforeEach(done => {
readFileSyncStub = sinon.stub(fs, 'readFileSync').returns('test=foo')
Expand Down Expand Up @@ -86,6 +86,18 @@ t.test('does not write over keys already in process.env', ct => {
ct.equal(process.env.test, existing)
})

t.test('does write over keys already in process.env if override turned on', ct => {
ct.plan(2)

const existing = 'bar'
process.env.test = existing
// 'foo' returned as value in `beforeEach`. should keep this 'bar'
const env = dotenv.config({ override: true })

ct.equal(env.parsed && env.parsed.test, mockParseResponse.test)
ct.equal(process.env.test, 'foo')
})

t.test(
'does not write over keys already in process.env if the key has a falsy value',
ct => {
Expand All @@ -102,6 +114,22 @@ t.test(
}
)

t.test(
'does write over keys already in process.env if the key has a falsy value but override is set to true',
ct => {
ct.plan(2)

const existing = ''
process.env.test = existing
// 'foo' returned as value in `beforeEach`. should keep this ''
const env = dotenv.config({ override: true })

ct.equal(env.parsed && env.parsed.test, mockParseResponse.test)
// NB: process.env.test becomes undefined on Windows
ct.ok(process.env.test)
}
)

t.test('returns parsed object', ct => {
ct.plan(2)

Expand Down Expand Up @@ -133,3 +161,15 @@ t.test('logs any errors thrown from reading file or parsing when in debug mode',

logStub.restore()
})

t.test('logs any errors parsing when in debug and override mode', ct => {
ct.plan(1)

const logStub = sinon.stub(console, 'log')

dotenv.config({ debug: true, override: true })

ct.ok(logStub.called)

logStub.restore()
})