Find environment variables in Ruby projects

Every time i deal with a new (legacy/third-party) Ruby/Rails application i want to try to deploy it somewhere real quick to test things out before i dig into the code. In most cases the application is Heroku-friendly, i.e has a Procfile or readme instructions on how to start all necessary processes.

When it comes to deployment, often it takes a few failed attempts until you get things right. Majority of those failures are usually related to missing environment variables or other configuration settings. In development we mostly rely on having an .env file wilh all the vars set for local work, but that file is never checked into the repo, so in other words - you have to scan your whole application to find out which environment variables need to be set before you can run the damn thing.

Let's automate this. In ruby code many components fetch variables from the ENV object: ENV["MY_VAR"] or ENV.fetch("MY_VAR"). Later is better since it'll error out when variable is not present. Next, to find out which files have any mention of ENV we can use grep. As an example, i run the following command against Gitlab's master branch:

grep -rnw . -e "ENV"

We'll see files where ENV is used (shortened):

./app/views/layouts/_search.html.haml:46:    = button_tag 'Go' if ENV['RAILS_ENV'] == 'test'
./app/views/projects/merge_requests/_show.html.haml:50:      .merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') }
./app/workers/post_receive.rb:15:    Sidekiq.logger.info "changes: #{changes.inspect}" if ENV['SIDEKIQ_LOG_ARGUMENTS']
./bin/bundle:2:ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
./bin/pkgr_before_precompile.sh:10:config=$(echo '<% gitlab_url = URI(ENV["GITLAB_URL"] || "http://localhost:80") %>' | cat - config/gitlab.yml)
./bin/spring:6:unless (defined?(Spring) || ENV['ENABLE_SPRING'] != '1') && File.basename($0) != 'spring'
./config/application.rb:148:    ENV['GITLAB_PATH_OUTSIDE_HOOK'] = ENV['PATH']
./config/boot.rb:6:require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
./config/database.yml.env:6:  adapter: <%= ENV['GITLAB_DATABASE_ADAPTER'] || 'postgresql' %>
./config/database.yml.env:11:  port: <%= ENV['GITLAB_DATABASE_PORT'] || '5432' %>
./config/database.yml.env:16:  encoding: <%= ENV['GITLAB_DATABASE_ENCODING'] || 'unicode' %>
./config/database.yml.env:17:  pool: <%= ENV['GITLAB_DATABASE_POOL'] || '10' %>
./config/environments/development.rb:41:  config.action_mailer.perform_deliveries = (ENV['BOOTSTRAP'] != '1')
./config/initializers/0_post_deployment_migrations.rb:4:unless ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS']
./config/initializers/1_settings.rb:4:  source ENV.fetch('GITLAB_CONFIG') { "#{Rails.root}/config/gitlab.yml" }

Finally, if you really need a list of all vars, i wrote a small ruby script that does just that:

#!/usr/bin/env ruby

items = []

`grep -rnw . -e "ENV"`.split("\n").each do |line|
  if line =~ /ENV.fetch\(['"](\w+)['"]\)/ || line =~ /ENV\[['"](\w+)['"]\]/
    items << $1
  end
end

if items.size > 0
  puts "Found these environment variables:"
  puts items.uniq.sort
else
  puts "No mention of environment variables found"
end

In the output you'll see a list of all variables (shortened):

GITLAB_DATABASE_POOL
GITLAB_DATABASE_PORT
GITLAB_DATABASE_USERNAME
GITLAB_EMAIL_DISPLAY_NAME
GITLAB_EMAIL_FROM
GITLAB_EMAIL_REPLY_TO
GITLAB_EMAIL_SUBJECT_SUFFIX
GITLAB_HOST
GITLAB_PATH_OUTSIDE_HOOK
GITLAB_ROOT_EMAIL
GITLAB_ROOT_PASSWORD
GITLAB_UNICORN_MEMORY_MAX
GITLAB_UNICORN_MEMORY_MIN
GITLAB_URL
MAIL_ROOM_GITLAB_CONFIG_FILE
MYSQL_PWD
NAMESPACE
NO_KNAPSACK

Save the script somewhere in your system (maybe as /usr/local/bin/showenv). Next time you're in the project's root, just run it:

$ showenv

Bam. Easy Peasy.