README.md in envied-0.10.0.alpha3 vs README.md in envied-0.10.0

- old
+ new

@@ -1,38 +1,29 @@ -# 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/) +# ENVied [![Tests](https://github.com/javierjulio/envied/actions/workflows/tests.yml/badge.svg)](https://github.com/javierjulio/envied/actions/workflows/tests.yml) -_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](https://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](http://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) -* [Best Practices](#best-practices) -* [FAQ](#faq) -* [Testing](#testing) +* [How do I...?](#how-do-i) * [Development](#development) -* [Contributing](#contributing) ## Quickstart ### 1) Configure @@ -45,17 +36,17 @@ ``` ### 2) Check for presence and coercibility ```ruby -# during initialization +# during initialization and in a pre-deploy confirmation workflow ENVied.require ``` This will throw an error if: -* one of `ENV['FORCE_SSL']`, `ENV['PORT']` is absent. -* or: their values *cannot* be coerced (resp. to boolean and integer). +* both `ENV['FORCE_SSL']` and `ENV['PORT']` are *not present*. +* the values *cannot* be coerced to a boolean and integer. ### 3) Use coerced variables Variables accessed via ENVied are of the correct type: @@ -64,108 +55,79 @@ ENVied.FORCE_SSL # => false ``` ## Installation -Add this line to your application's Gemfile: +Add `envied` to your `Gemfile`: - gem 'envied' +```ruby +gem 'envied' +``` -...then bundle: +If you are using Rails, add this to `config/application.rb` immediately after `Bundler.require(*Rails.groups)`: - $ bundle - -...then for Rails applications: - - $ bundle exec envied init:rails - -...or for non-Rails applications: - - $ bundle exec envied init - -## Configuration - -### Types - -The following types are supported: - -* `: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) -* `: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` -* `:time` (e.g. '14:00') -* `: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: +```ruby +ENVied.require(*ENV['ENVIED_GROUPS'] || Rails.groups) ``` -# file: Envfile -key_alias! { Rails.env } -variable :REDIS_URL, :uri -``` +If you are not using Rails, add the following snippet (or similar) to your app's initialization: -Source the following in your environment: +```ruby +ENVied.require(*ENV['ENVIED_GROUPS'] || [:default, ENV['RACK_ENV']]) ``` -# 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. +Create an `Envfile` with the following as a starter: +```ruby +enable_defaults! { ENV['RACK_ENV'] != 'production' } -#### env-type (unreleased) +variable :LOG_LEVEL, :string, default: 'debug' -Variables of type `:env` take the key alias into account when accessing `ENV['FOO']`. +group :production do + variable :SECRET_KEY_BASE +end +``` -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: +Refer to the [Types](#types) section to start configuring your project's environment variables. -``` -# file: Envfile +### Pre-deploy ENV check -key_alias! { Rails.env } +To confirm that your ENV variables are set in a pre-deploy workflow, provide the application's current ENV to a Ruby script that loads it and runs the envied check. -variable :DATABASE_URL, :env +```ruby +ENV.replace(your_current_env) +ENVied.require(*RAILS_GROUPS) +puts "All required ENV variables are present and valid." ``` -The following now works: -```shell -$ DATABASE_URL_DEVELOPMENT=postgres://localhost/blog_development rails runner "p ENV['DATABASE_URL']" -"postgres://localhost/blog_development" -``` +If any required ENV are missing, then the check will fail with an error message listing the missing environment variable names. -Note: this also works for `ENV.fetch('FOO')`. -Also: no coercion is done (like you would expect when accessing ENV-values directly). +## Configuration -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`. +### Types +The following types are supported: +* `:string` (implied) +* `:boolean` (e.g. '0'/'1', 'f'/'t', 'false'/'true', 'off'/'on', 'no'/'yes' for resp. false and true) +* `:integer` +* `:float` +* `: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')`) + ### 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 +variable :FORCE_SSL, :boolean, default: 'false' group :production do variable :SECRET_KEY_BASE end @@ -193,10 +155,36 @@ ENVied.require(:default) ENVied.require('default') ENVied.require(nil) ``` +### Defaults + +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 @@ -210,69 +198,23 @@ 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 ``` -## Best Practices +## How do I -Some best practices when using ENVied or working with env-configurable applications in general. +### ...find all ENV-variables my app is currently using? -### 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). -### How to check the config of a Heroku app? +### ...check the config of a Heroku app? The easiest/quickest is to run: ``` $ heroku config --json | bundle exec envied check:heroku @@ -291,46 +233,10 @@ This way you can do stuff like: ``` $ ./bin/heroku-env-check && git push live master ``` -### What happened to default values?? - -The short version: simplicity, i.e. the best tool for the job. - -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/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. - -1. Fork it: https://gitlab.com/envied/envied/-/forks/new -2. Create your feature branch: `git checkout -b my-new-feature` -3. Commit your changes: `git commit -am 'Add some feature'` -4. Push to the branch: `git push origin my-new-feature` -5. Create a new pull request for your feature branch +- `bin/setup` +- Run tests: `RUBYOPT="-W:deprecated" bundle exec rspec` +- For an interactive console: `bin/console`