ENVied travis

TL;DR ensure presence and type of your app's ENV-variables.

This gem will provide:

  • A fail-fast check for presence of ENV-variables
  • A fail-fast check whether the values can be coerced to the correct type
  • Access to typed ENV-variables (instead of just strings)

Quickstart

1) Configure

Let's configure the ENV-variables we need:

ENVied.configure do
  variable :FORCE_SSL, :Boolean
  variable :PORT, :Integer
end

2) Check for presence and coercibility

ENVied.require

This will throw an error if:

  • not both ENV['FORCE_SSL'] and ENV['PORT'] are present.
  • the values can't be coerced to resp. Boolean and Integer.

3) Use coerced variables

Variables accessed via ENVied are of the correct type:

ENVied.PORT # => 3001
ENVied.FORCE_SSL # => false

Configuration

Groups

Groups give you more flexibility to define when variables are needed.
It's similar to groups in a Gemfile:

ENVied.configure do
  variable :FORCE_SSL, :Boolean

  group :production do
    variable :NEW_RELIC_LICENSE_KEY
  end
end

# For local development you would typically do:
ENVied.require(:default) #=> Only ENV['FORCE_SSL'] is required
# On the server:
ENVied.require(:default, :production) #=> ...also ENV['NEW_RELIC_LICENSE_KEY'] is required

# BTW the following are equivalent:
ENVied.require
ENVied.require(:default)
ENVied.require('default')
ENVied.require(nil)

Types

The following types are supported:

  • :String (implied)
  • :Boolean (e.g. '0'/'1', 'f'/'t', 'false'/'true', 'off'/'on', 'yes','no' for resp. true or false)
  • :Integer
  • :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'])

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'. Therefor you should explicitly state whén defaults are allowed:

ENVied.configure(enable_defaults: ENV['RACK_ENV'] == 'development') do
  variable :FORCE_SSL, :Boolean, default: false
  variable :PORT, :Integer, default: proc {|envied| envied.FORCE_SSL ? 443 : 80 }
end

Please remember that ENVied only reads from ENV; it doesn't set ENV-variables. 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 your application introduces (i.e. for ENV['STAFF_EMAILS'] not for ENV['REDIS_URL'])

A more extensive example:

# We allow defaults for local development (and local tests), but want our CI
# to mimic our production as much as possible.
# New developers that don't have RACK_ENV set, will in this way not be presented with a huge
# list of missing variables, as defaults are still enabled.
not_production_nor_ci = ->{ !(ENV['RACK_ENV'] == 'production' || ENV['CI']) }
ENVied.configure(enable_defaults: &not_production_nor_ci) do
  # Your code will likely not use ENVied.RACK_ENV (better use Rails.env),
  # we want it to be present though; heck, we're using it in this file!
  variable :RACK_ENV

  variable :FORCE_SSL, :Boolean, default: false
  variable :PORT, :Integer, default: 3000
  # generate the default value using the value of PORT:
  variable :PUBLIC_HOST_WITH_PORT, :String, default: proc {|envied| "localhost:#{envied.PORT}" }

  group :production do
    variable :MAIL_PAAS_USERNAME
    variable :DATABASE_URL
  end

  group :ci do
    # ci-only stuff
  end

  group :not_ci do
    # CI needs no puma-threads, and sidekiq-stuff etc.
    # Define that here:
    variable :MIN_THREADS, :Integer, default: 1
    # more...
  end
end

# Depending on our situation, we can now require the groups needed:
# At local machines:
ENVied.require(:default, :development, :not_ci) or
ENVied.require(:default, :test, :not_ci)

# At the server:
ENVied.require(:default, :production, :not_ci)

# At CI:
ENVied.require(:default, :test, :ci)

# All in one line:
ENVied.require(:default, ENV['RACK_ENV'], (ENV['CI'] ? :ci : :not_ci))

Installation

Add this line to your application's Gemfile:

gem 'envied'

And then execute:

$ bundle

Testing

bundle install --binstubs

bin/rspec
# or
bin/rake

Developing

bin/pry --gem

Contributing

  1. Fork it ( http://github.com/eval/envied/fork )
  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 new Pull Request