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

Safeguard tests from using .env #1277

Merged
merged 6 commits into from
Sep 22, 2017
Merged

Conversation

kanaabe
Copy link
Contributor

@kanaabe kanaabe commented Sep 13, 2017

This PR safeguards against a bug where importing/requiring this test helper after importing/requiring the app will cause the helper to use your .env file instead of .env.test.

Problem

To replicate the issue, require the app before the helper. (Don't try this now unless you're pointing to a local database in your .env)

app = require 'api/index.coffee'
{ empty } = require 'api/test/helpers/db.coffee'

This causes app to be loaded with no process.env.NODE_ENV set which means this line gets executed and all subapps get loaded with your local .env settings. If you swap the order of the require, it behaves correctly. This is why:

{ empty } = require 'api/test/helpers/db.coffee'
    # in this file, we run:
    # env path.resolve(__dirname, '../../../.env.test')
    # which sets process.env.NODE_ENV
app = require 'api/index.coffee'
    # now that we have process.env.NODE_ENV,
    # https://github.com/artsy/positron/blob/master/api/index.coffee#L1
    # no longer is executed and the subapps use the correct environment

We've been miraculously getting by without issues until now, when I accidentally wiped out staging yesterday when running a test locally with the problematic order.

Solution

We need to ensure that our NODE_ENV in a test setting is working properly. By setting the NODE_ENV on the mocha.opts level, we can ensure that every test that runs with the right environment. The jest settings don't need to be updated since this only affects API work.

  1. Ensure that we're passing in NODE_ENV=test on all mocha tests
  2. Update api/index.coffee to switch environments based on NODE_ENV.

cc @joeyAghion @eessex @damassi

Makefile Outdated
NODE_ENV=test $(BIN)/mocha $(shell find api -name '*.test.coffee')
NODE_ENV=test $(BIN)/mocha $(shell find api -name '*.test.js')
NODE_ENV=test $(BIN)/mocha $(shell find client -name '*.test.coffee')
NODE_ENV=test $(BIN)/jest $(shell find client -name '*.test.js')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is necessary since mocha will pick up on test/mocha.opts but JIC..

@craigspaeth
Copy link
Contributor

craigspaeth commented Sep 13, 2017

While we're looking at the env file, maybe it'd be better to use dotenv to preload the separate files via mocha -r dotenv/config dotenv_config_path=env.test and node -r dotenv/config. I think that'd solve this as well as removing the switch boilerplate.

@kanaabe
Copy link
Contributor Author

kanaabe commented Sep 13, 2017

@craigspaeth you're right, that's a much cleaner solution 👍

@artsy-peril
Copy link
Contributor

artsy-peril bot commented Sep 18, 2017

Typos for README.md

Line Typo
34 ed Docker instance that boots MongoDB, ElasticSearch and Node. Chan
34 instance that boots MongoDB, ElasticSearch and Node. Changes made to sou
61 - Positron uses MongoDB as a database. To install Mon
61 oDB as a database. To install MongoDB using homebrew do the followi
61 y check the documentation at [MongoDB](http://docs.mongodb.org/manu
67 - Start the MongoDB database
73 - Install and run elasticsearch
85 artner gallery channel (David Zwirner).
93 - Make sure you have mongo running in the background or
Got false positives?

Make changes to the global settings spellcheck.json in /artsy/artsy-danger.

New dependencies added: dotenv.

dotenv

Author: scottmotte

Description: Loads environment variables from .env file

Homepage: https://github.com/motdotla/dotenv#readme

Createdabout 4 years ago
Last Updatedabout 2 hours ago
LicenseBSD-2-Clause
Maintainers4
Releases27
Direct Dependencies
Keywordsdotenv, env, .env, environment, variables, config and settings
README

dotenv

dotenv

Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env. Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology.

BuildStatus
NPM version
js-standard-style
Coverage Status

Install

npm install dotenv --save

Usage

As early as possible in your application, require and configure dotenv.

require('dotenv').config()

Create a .env file in the root directory of your project. Add
environment-specific variables on new lines in the form of NAME=VALUE.
For example:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

That's it.

process.env now has the keys and values you defined in your .env file.

var db = require('db')
db.connect({
  host: process.env.DB_HOST,
  username: process.env.DB_USER,
  password: process.env.DB_PASS
})

Preload

If you are using iojs-v1.6.0 or later, you can use the --require (-r) command line option to preload dotenv. By doing this, you do not need to require and load dotenv in your application code.

$ node -r dotenv/config your_script.js

The configuration options below are supported as command line arguments in the format dotenv_config_<option>=value

$ node -r dotenv/config your_script.js dotenv_config_path=/custom/path/to/your/env/vars

Config

Alias: load

config will read your .env file, parse the contents, assign it to
process.env,
and return an Object with a parsed key containing the loaded content or an error key if it failed.
You can additionally, pass options to config.

Options

Path

Default: .env

You can specify a custom path if your file containing environment variables is
named or located differently.

require('dotenv').config({path: '/custom/path/to/your/env/vars'})

Encoding

Default: utf8

You may specify the encoding of your file containing environment variables
using this option.

require('dotenv').config({encoding: 'base64'})

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
an Object with the parsed keys and values.

var dotenv = require('dotenv')
var buf = new Buffer('BASIC=basic')
var config = dotenv.parse(buf) // will return an object
console.log(typeof config, config) // object { BASIC : 'basic' }

Rules

The parsing engine currently supports the following rules:

  • BASIC=basic becomes {BASIC: 'basic'}
  • empty lines are skipped
  • lines beginning with # are treated as comments
  • empty values become empty strings (EMPTY= becomes {EMPTY: ''})
  • single and double quoted values are escaped (SINGLE_QUOTE='quoted' becomes {SINGLE_QUOTE: "quoted"})
  • new lines are expanded if in double quotes (MULTILINE="new\nline" becomes
{MULTILINE: 'new
line'}
  • inner quotes are maintained (think JSON) (JSON={"foo": "bar"} becomes {JSON:"{\"foo\": \"bar\"}")

FAQ

Should I commit my .env file?

No. We strongly recommend against committing your .env file to version
control. It should only include environment-specific values such as database
passwords or API keys. Your production database should have a different
password than your development database.

Should I have multiple .env files?

No. We strongly recommend against having a "main" .env file and an "environment" .env file like .env.test. Your config should vary between deploys, and you should not be sharing values between environments.

In a twelve-factor app, env vars are granular controls, each fully orthogonal to other env vars. They are never grouped together as “environments”, but instead are independently managed for each deploy. This is a model that scales up smoothly as the app naturally expands into more deploys over its lifetime.

The Twelve-Factor App

What happens to environment variables that were already set?

We will never modify any environment variables that have already been set. In particular, if there is a variable in your .env file which collides with one that already exists in your environment, then that variable will be skipped. This behavior allows you to override all .env configurations with a machine-specific environment, although it is not recommended.

If you want to override process.env you can do something like this:

const fs = require('fs')
const dotenv = require('dotenv')
const envConfig = dotenv.parse(fs.readFileSync('.env.override'))
for (var k in envConfig) {
  process.env[k] = envConfig[k]
}

Can I customize/write plugins for dotenv?

For [email protected]: Yes. dotenv.config() now returns an object representing
the parsed .env file. This gives you everything you need to continue
setting values on process.env. For example:

var dotenv = require('dotenv')
var variableExpansion = require('dotenv-expand')
const myEnv = dotenv.config()
variableExpansion(myEnv)

What about variable expansion?

For [email protected]: Use dotenv-expand.

For [email protected]: We haven't been presented with a compelling use case for expanding variables and believe it leads to env vars that are not "fully orthogonal" as The Twelve-Factor App outlines.[1][2] Please open an issue if you have a compelling use case.

Contributing Guide

See CONTRIBUTING.md

Change Log

See CHANGELOG.md

License

See LICENSE

Who's using dotenv

Here's just a few of many repositories using dotenv:

Go well with dotenv

Here's some projects that expand on dotenv. Check them out.

Generated by 🚫 dangerJS

@kanaabe kanaabe merged commit 960bb58 into artsy:master Sep 22, 2017
@craigspaeth
Copy link
Contributor

Nice! Thanks for embarking on this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants