thoughtbot/parity

Load environment variables from dotenv file

vovimayhem opened this issue · 9 comments

As an alternative to #106, it would be useful if parity could load variables from a .env file (if it exists).

The problem we have right now is that our config/database.yml will not contain any information about our development host, port, etc, because it's read out from the DATABASE_URL env variable (which is set up in our compose file, working the same way heroku does):

default: &default
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  schema_search_path: public,partitioning

development:
  <<: *default
  database: my_app_development

test:
  <<: *default
  database: my_app_test

production:
  <<: *default

Not having these values on the config/database.yml file causes pg_restore to try to connect to the local postgres' unix socket - which in our case does not exist:

development restore-from production
dropdb: could not connect to database template1: could not connect to server: No such file or directory
	Is the server running locally and accepting
	connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
pg_restore: connecting to database for restore
pg_restore: [archiver (db)] connection to database "my_app_development" failed: could not connect to server: No such file or directory
	Is the server running locally and accepting
	connections on Unix domain socket "/tmp/.s.PGSQL.5432"?

But we do map our host port 5432 to the postgres container port, so we can reach it at localhost:5432:

PGHOST=localhost PGUSER=postgres development restore-from production
...
pg_restore: connecting to database for restore (working like a charm)

We don't need parity to do anything special other than read variables such as PGHOST and PGUSER values from the dotenv file, so the pg_restore command connects to the intended development database.

This way, we could keep parity unaware about the details on how the app runs in the developer machine (docker? rocket? on the host? Virtualized? It won't matter!)

Hi @vovimayhem this is an interesting use case. We supported environment variables at one point for DB config, but removed it because maintaining gem dependencies for a non-Rubygems executable ended up being overly complicated and brittle. I'm open to revisiting this if there's a solution that's reliable for packaging on macOS (Homebrew) and apt and Rubygems that works.

One question: could you get around this by making a bin/development binstub for your app that invokes the command with those environment variables?

A binstub like you propose will certainly work - although we'll deviate from documentation using bin/development do-something production instead of just development do-something production...

Back to the issue, I'm aware that runtime gem dependencies have been avoided in this project (parity has none!). I originally thought about including bkeepers/dotenv, but maybe that won't be necessary / or not work exactly as I intended to...

I've previously gone away with prepending env $(cat .env | grep ^[A-Z] | xargs) to any command that requires the env vars... how do you feel about going on with something like this?

Do you have any development guidelines/goals of this project? (besides the style & commit message guidelines?)

Hrm. I think cating the .env file isn't going to be a globally applicable solution because some groups are using .env.local, etc. Let's both think about what we can do to accommodate this use case that won't break or be confusing to other users of the utility.

I'd be +1 on env variables if we kept this principle in mind:

12-factor apps encourage you to use environment vars for configuration, and I think that’s fine, provided each var is also defined as a flag. Explicitness is important: changing the runtime behavior of an application should happen in ways that are discoverable and documented.

https://peter.bourgon.org/go-best-practices-2016/#configuration

I'm having a bit of a change in heart regarding this... or at least our use case anyway.

I'm realizing that we (the ones using docker / virtualized services for development, including yours truly and @walreyes) should just include parity (and the heroku toolbelt) in our development container image, and run parity from within the running development container itself.

BUT, and following @croaky previous comment about 12-factor apps, we SHOULD use the database described in the environment variable DATABASE_URL as the default configured target for pg_restore...

What do you guys think of this?

A solution here would likely be a portion of the total solution required to accomplish #125.

I'm closing the issue out, but I'm open to PRs that might solve this but are still distributable outside of Rubygems.

Hi there,
I have the same issue trying to run development restore-from staging.
I have the following error:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  117k  100  117k    0     0  47882      0  0:00:02  0:00:02 --:--:-- 50152
dropdb: could not connect to database template1: could not connect to server: No such file or directory
	Is the server running locally and accepting
	connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
pg_restore: [archiver] unsupported version (1.14) in file header
psql: could not connect to server: No such file or directory
	Is the server running locally and accepting
	connections on Unix domain socket "/tmp/.s.PGSQL.5432"?

I'm using docker / virtualized services for development. So there is no socket, but a connection to 5432 port on localhost would work.

Is there a workaround for this issue?

Cheers!

cythb commented

Hi @jeantristan,
this workaround works for me:

export PGHOST=localhost
export PGUSER=root