README.md in envied-0.9.3 vs README.md in envied-0.10.0.alpha1

- old
+ new

@@ -1,30 +1,37 @@ -# ENVied [![pipeline status](https://gitlab.com/envied/envied/badges/0-9-releases/pipeline.svg)](https://gitlab.com/envied/envied/commits/0-9-releases) [![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://envied-rb.zulipchat.com/) +# ENVied [![pipeline status](https://gitlab.com/envied/envied/badges/master/pipeline.svg)](https://gitlab.com/envied/envied/commits/master) [![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://envied-rb.zulipchat.com/) +_Canonical Repository:_ https://gitlab.com/envied/envied/tree/master#envied + ### TL;DR ensure presence and type of your app's ENV-variables. -For the rationale behind this project, see this [blogpost](http://www.gertgoet.com/2014/10/14/envied-or-how-i-stopped-worrying-about-ruby-s-env.html). +For the rationale behind this project, see this [blogpost](https://www.gertgoet.com/2014/10/14/envied-or-how-i-stopped-worrying-about-ruby-s-env.html). -## Features: +## Features * check for presence and correctness of ENV-variables * access to typed ENV-variables (integers, booleans etc. instead of just strings) * check the presence and correctness of a Heroku config +## Non-features + +* provide or load ENV-values + ## Contents * [Quickstart](#quickstart) * [Installation](#installation) * [Configuration](#configuration) * [Types](#types) + * [Key alias](#key-alias-unreleased) + * [env-type](#env-type-unreleased) * [Groups](#groups) - * [Defaults](#defaults) - * [More examples](#more-examples) * [Command-line interface](#command-line-interface) -* [How do I...?](#how-do-i) +* [Best Practices](#best-practices) +* [FAQ](#faq) * [Testing](#testing) -* [Developing](#developing) +* [Development](#development) * [Contributing](#contributing) ## Quickstart ### 1) Configure @@ -43,12 +50,12 @@ # during initialization ENVied.require ``` This will throw an error if: -* both `ENV['FORCE_SSL']` and `ENV['PORT']` are *not present*. -* the values *cannot* be coerced to a boolean and integer. +* one of `ENV['FORCE_SSL']`, `ENV['PORT']` is absent. +* or: their values *cannot* be coerced (resp. to boolean and integer). ### 3) Use coerced variables Variables accessed via ENVied are of the correct type: @@ -79,29 +86,86 @@ ### Types The following types are supported: -* `:string` (implied) +* `:array` (e.g. 'tag1,tag2' becomes `['tag1', 'tag2']`) * `:boolean` (e.g. '0'/'1', 'f'/'t', 'false'/'true', 'off'/'on', 'no'/'yes' for resp. false and true) -* `:integer` +* `:date` (e.g. '2014-3-26') +* `:env` (similar to `:string`, but accessible via ENV - see [Key alias](#key-alias-unreleased) for details) * `:float` +* `:hash` (e.g. 'a=1&b=2' becomes `{'a' => '1', 'b' => '2'}`) +* `:integer` +* `:string` (implied) * `:symbol` -* `:date` (e.g. '2014-3-26') * `:time` (e.g. '14:00') -* `:hash` (e.g. 'a=1&b=2' becomes `{'a' => '1', 'b' => '2'}`) -* `:array` (e.g. 'tag1,tag2' becomes `['tag1', 'tag2']`) * `:uri` (e.g. 'http://www.google.com' becomes result of `URI.parse('http://www.google.com')`) + +### Key alias (unreleased) + +By default the value for variable `FOO` should be provided by `ENV['FOO']`. Sometimes though it's convenient to let a different key provide the value, based on some runtime condition. A key-alias will let you do this. + +Consider for example local development where `REDIS_URL` differs between the development and test environment. Normally you'd prepare different shells with different values for `REDIS_URL`: one shell you can run tests in, and other shells where you'd run the console/server etc. This is cumbersome and easy to get wrong. + +With a key alias that's calculated at runtime (e.g. `Rails.env`) you'd set values for both `REDIS_URL_TEST` and `REDIS_URL_DEVELOPMENT` and the right value will be used for test and development. + +Full example: +``` +# file: Envfile +key_alias! { Rails.env } + +variable :REDIS_URL, :uri +``` + +Source the following in your environment: +``` +# file: .envrc +export REDIS_URL_DEVELOPMENT=redis://localhost:6379/0 +export REDIS_URL_TEST=redis://localhost:6379/1 +``` +Now commands like `rails console` and `rails test` automatically point to the right redis database. + +Note that `ENV['REDIS_URL']` is still considered but `REDIS_URL_<key_alias>` takes precedence. +Also: any truthy value provided as key_alias is converted to an upcased string. +Finally: this setting is optional. + + +#### env-type (unreleased) + +Variables of type `:env` take the key alias into account when accessing `ENV['FOO']`. + +Say, your application uses `ENV['DATABASE_URL']` (wich you can't change to `ENVied.DATABASE_URL`). Normally this would mean that the key alias has no effect. For env-type variables however, the key alias is taken into account: + +``` +# file: Envfile + +key_alias! { Rails.env } + +variable :DATABASE_URL, :env +``` + +The following now works: +```shell +$ DATABASE_URL_DEVELOPMENT=postgres://localhost/blog_development rails runner "p ENV['DATABASE_URL']" +"postgres://localhost/blog_development" +``` + +Note: this also works for `ENV.fetch('FOO')`. +Also: no coercion is done (like you would expect when accessing ENV-values directly). + +This means that for Rails applications when you set values for `DATABASE_URL_DEVELOPMENT` and `DATABASE_URL_TEST`, you no longer need a `config/database.yml`. + + ### Groups Groups give you more flexibility to define when variables are needed. It's similar to groups in a Gemfile: ```ruby # file: Envfile -variable :FORCE_SSL, :boolean, default: 'false' +variable :FORCE_SSL, :boolean group :production do variable :SECRET_KEY_BASE end @@ -129,39 +193,10 @@ ENVied.require(:default) ENVied.require('default') ENVied.require(nil) ``` -### Defaults - -> *NOTE*: default values will be removed in the next minor-release (i.e. > v0.9). See https://gitlab.com/envied/envied/tree/master#what-happened-to-default-values for more information and how to migrate. -> While your project depends on this feature it's recommended to pin the gem to 0.9-releases, i.e. `gem 'envied', '~> 0.9.3'`. - -In order to let other developers easily bootstrap the application, you can assign defaults to variables. -Defaults can be a value or a `Proc` (see example below). - -Note that 'easily bootstrap' is quite the opposite of 'fail-fast when not all ENV-variables are present'. Therefore you should explicitly state when defaults are allowed: - -```ruby -# Envfile -enable_defaults! { ENV['RACK_ENV'] == 'development' } - -variable :FORCE_SSL, :boolean, default: 'false' -variable :PORT, :integer, default: proc {|envied| envied.FORCE_SSL ? 443 : 80 } -``` - -Please remember that ENVied only **reads** from ENV; it doesn't mutate ENV. -Don't let setting a default for, say `RAILS_ENV`, give you the impression that `ENV['RAILS_ENV']` is set. -As a rule of thumb you should only use defaults: -* for local development -* for ENV-variables that are solely used by your application (i.e. for `ENV['STAFF_EMAILS']`, not for `ENV['RAILS_ENV']`) - -### More examples - -* See the [examples](/examples)-folder for a more extensive Envfile -* See [the Envfile](https://github.com/eval/bunny_drain/blob/c54d7d977afb5e23a92da7a2fd0d39f6a7e29bf1/Envfile) for the bunny_drain application - ## Command-line interface For help on a specific command, use `envied help <command>`. ```bash @@ -175,23 +210,69 @@ envied init # Generates a default Envfile in the current working directory envied init:rails # Generate all files needed for a Rails project envied version, --version, -v # Shows version number ``` -## How do I +## Best Practices -### ...find all ENV-variables my app is currently using? +Some best practices when using ENVied or working with env-configurable applications in general. +### include a .envrc.sample + +While ENVied will warn you when you start an application that is 'under-configured', it won't tell users what good default values are. To solve this add a file to the root of your project that contains sane defaults and instructions: ``` +# file: .envrc.sample +# copy this file to .envrc and adjust values if needed +# then do `source .envrc` to load + +export DATABASE_URL=postgres://localhost/blog_development +# export FORCE_SSL=true # only needed for production + +# you can find this token on the Heroku-dashboard +export DEPLOY_TOKEN=1234-ABC-5678 +``` + +### let [direnv](https://direnv.net/) manage your environment + +[direnv](https://direnv.net/) will auto-(un)load values from `.envrc` when you switch folders. + +As a bonus it has some powerful commands in it's [stdlib](https://direnv.net/#man/direnv-stdlib.1). +For example: +``` +# this adds the project's bin-folder to $PATH +PATH_add bin +# so instead of `./bin/rails -h` you can do `rails -h` from anywhere (deep) in the project + +# the following will use the .envrc.sample as a basis +# when new variables are introduced upstream, you'll automatically use these defaults +if [ -f .envrc.sample ]; then + source_env .envrc.sample +fi +...your overrides + +# a variant of this is source_up +# an .envrc in a subfolder can load the .envrc from the root of the project and override specific values +# this would allow e.g. for a specific test-environment in the subfolder: +# in my-project/test/.envrc +source_up .envrc +export DATABASE_URL=the-test-db-url +``` + + +## FAQ + +### How to find all ENV-variables my app is currently using? + +``` $ bundle exec envied extract ``` This comes in handy when you're not using ENVied yet. It will find all `ENV['KEY']` and `ENV.fetch('KEY')` statements in your project. It assumes a standard project layout (see the default value for the globs-option). -### ...check the config of a Heroku app? +### How to check the config of a Heroku app? The easiest/quickest is to run: ``` $ heroku config --json | bundle exec envied check:heroku @@ -210,21 +291,40 @@ This way you can do stuff like: ``` $ ./bin/heroku-env-check && git push live master ``` -## Testing +### What happened to default values?? -```bash -bundle install -bundle exec rspec -``` +The short version: simplicity, i.e. the best tool for the job. -## Developing +In the early days of ENVied it was possible to provide default values for a variable. +While convenient, it had several drawbacks: +- it would introduce a value for ENVied.FOO, while ENV['FOO'] was nil: confusing and a potential source of bugs. +- it hides the fact that an application can actually be configged via the environment. +- it creates an in-process environment which is hard to inspect (as opposed to doing `printenv FOO` in a shell, after or before starting the application). +- there are better ways: e.g. a sample file in a project with a bunch of exports (ie `export FOO=sane-default # and even some documentation`) that someone can source in their shell (see [Best Practices](#best-practices)). +- made the code quite complex. +As an alternative include a file `.envrc.sample` in the root of your project containing default values (ie `export FOO=bar`) that users can source in their shell. See also [Best Practices](#best-practices). + + +## Development + ```bash -bin/console +$ ./bin/setup + +# run tests +$ ./bin/rspec + +# hack with pry +$ ./bin/console + +# run CLI: +$ ./bin/envied ``` + +There's a `.envrc.sample` included that can be used in combination with [direnv](http://direnv.net/). ## Contributing To suggest a new feature, [open an Issue](https://gitlab.com/envied/envied/issues/new) before opening a PR.