Travis CI Multi Database Rails

27 Sep 2013 By: Greg Molnar

I started to use Travis CI for continous integration. They have a free plan for open source which makes a good opportunity to try out the service. Travis supports various runtimes and databases and I was going to test my app against ruby 1.9 and ruby 2 and 3 different databases: sqlite, mysql, postgres. To setup these runtimes I created a travis.yml config file like this:

language: ruby
rvm:
  - 2.0.0
  - 1.9.3
env:
  - DB=sqlite
  - DB=mysql
  - DB=postgresql

We need a bit more work to make this work though as we need to specify the database config for each runtime. In my Gemfile I decide which database gem to bundle from the database config but on travis that won't exists so the bundle command will fail.<!--more--> Travis sets a DB environment variable which we can use to determine which gem to bundle:

require 'yaml'

env = ENV["RAILS_ENV"] || 'development'
dbconfig = File.expand_path("../config/database.yml", __FILE__)

raise "You need to configure config/database.yml first" unless File.exists?(dbconfig)
require 'erb'
config = YAML.load(ERB.new(File.read(dbconfig)).result)

environment = config[env]

adapter = environment['adapter'] if environment
raise "Please set an adapter in database.yml for #{env} environment" if adapter.nil?
case adapter
when 'sqlite3'
  gem 'sqlite3'
when 'postgresql'
  gem 'pg'
when 'mysql2'
  gem 'mysql2'
else
  raise "Not supported database adapter: #{adapter}"
end

Note that we process the database.yml with ERB first. It needs because we use the ENV['DB'] variable in the yaml file. I don't have a database.yml in source control just an example for the different database options and I thought the best way would be to keep all the travis related db config in a separate file so I created a database.travis.yml file:

sqlite: &sqlite
  adapter: sqlite3
  database: db/<%= ENV['RAILS_ENV'] %>.sqlite3

mysql: &mysql
  adapter: mysql2
  username: root
  password:
  database: invoicer_<%= ENV['RAILS_ENV'] %>

postgresql: &postgresql
  adapter: postgresql
  username: postgres
  password:
  database: invoicer_<%= ENV['RAILS_ENV'] %>
  min_messages: ERROR

defaults: &defaults
  pool: 5
  timeout: 5000
  host: localhost
  <<: *<%= ENV['DB'] || "sqlite" %>

development:
  <<: *defaults

test:
  <<: *defaults

production:
  <<: *defaults

With this in place we just need to extend the travis config to set the rails environment and run a before script:

language: ruby
rvm:
  - 2.0.0
  - 1.9.3
env:
  - DB=sqlite
  - DB=mysql
  - DB=postgresql
before_install: cp config/database.travis.yml config/database.yml
script:
  - export RAILS_ENV=test
  - bundle exec rake db:create db:migrate
  - bundle exec rake db:test:prepare

Now we just need to push a commit and wait for the build result.

PS: If you want to get updates from me please subscribe to my email list.
I hate spam as much as you do, so I won't send you anything else than Ruby/Rails related updates occasionally, and of course you can unsubcribe anytime.