A&D has a private Travis-CI server that is used to verify changes to our private repos. Initially, this repo did not use travis, since it didn’t really have any automated tests to run.
As I (Tamara) started adding RSpec tests, my colleague Jason recommended including the repo in the travis CI environment as well. This wasn’t quite as straight-forward as initially thought, so this attempts to document the pieces in pulling this together.
The first part of getting a repository ready to run under Travis is to
.travis.yml file to tell Travis how to build and test your
The Travis documentation is fairly easy to understand, but no set of documentation is going to understand your specific repository’s needs. There aren’t enough examples for every possibly scenario, thus you need to really understand the environment needs of your application.
There are various elements that you need to set up:
- The language and language version
- Environment variables
- Other applications, libraries, servers, and so on that your application needs in order to run (e.g. Postgresql)
- Travis behavioural elements, such as caching, building, and so on
.travis.yml is (obviously) a YAML file, which is the standard for
Setting the language
Since we’re testing a Rails application here, ruby is our
language. The version we’re using is 2.0.0 (with no particular build
set at this point). The two sections we need in the
language: ruby rvm: - 2.0.0
You can set multiple values in the
rvm section, to tell travis to
run a build on each version. This can explode into a large build
matrix, though, so be circumspect. This repo contains a
.ruby-version file so it was easy to limit the versions to build
This would be the minimum required to get any Rails app running, but ours has a few more requirements.
$repo has some values it needs to pick up from the
environment to run correctly. With the current set of tests, the
Devise configuration parameter
secret_key_base must be set. The
env_vars-sample.rb file is used as a template for the
file that is used to set defaults if the values aren’t set explicitly
in the environment.
For the current set of tests, the only env_var needed is
SECRET_KEY_BASE to make the Devise gem happy. Environment variables
are set in the
env section of the
env: SECRET_KEY_BASE="$(bundle exec rake secret)"
There is some secret sauce going on here. The
rake secret task is
one provided by the standard Rails installation that will re-generate
a secret token, which is just a hashed string, and is quite suitable
for the secret key base. The above setting results in travis running
the following at the start of the build:
export SECRET_KEY_BASE="$(bundle exec rake secret)"
which gives us exactly what we need for the run.
Although it is a travis default, I’ve also set the
'test' to ensure we’re running in a test situation.
The database used in $repo is Postgresql version 9.2,
because it makes use of the JSON variable type that was introduced at
that version. Travis by default uses Postgresql v. 9.1, so we need to
tell it what to use. The
addons section lets us specify the version:
addons: postgresql: 9.2
Travis has hooks that will run before and after certain events in the build. We need to make sure we have the right configuration files created and the database created that will work for our repo.
before_script section lets us give bash commands that will run
just before the test script starts.
Every Rails app needs a
config/database.yml file which must be
modified by the user when starting up the application. However, a good
rails practice is to make a sample configuration file which can be
included in the repository, but not the specific configuration file
which might contain passwords or other credentials that you don’t want
to put out in public or even semi-public.
In addition, $repo has an environment variable
initialization file, that has similar credential secrets that we don’t
want explicitly in the repository, so there is a
config/env_vars.sample.rb file that is copied and modified if
Since the sample defaults will work for our needs in the Travis CI environment, we can just copy them over directly. If the specific values in the non-sample files need to be set, you could run the sample file through sed, awk, perl, ruby or whatever to make the appropriate edits.
We want to make sure we’re putting our work in the proper
directory. Travis provides a few environment variables to us, one of
which is the
TRAVIS_BUILD_DIR envar, that points to the directory of
the current build.
(Note these might be done quite differently when creating the production environment.)
before_script: - /bin/cp $TRAVIS_BUILD_DIR/config/database.sample.yml $TRAVIS_BUILD_DIR/config/database.yml - /bin/cp $TRAVIS_BUILD_DIR/config/env_vars.sample.rb $TRAVIS_BUILD_DIR/config/env_vars.rb
Creating The Testing Database
For each travis run, we must create the testing database anew (travis
does not persist databases across runs). Since we’re using Postgresql,
we simply run the client and create the database with the default
postgres as specified by travis.
before_script: - psql -c 'create database howto_repo_test;' -U postgres
Combining the previous two subsections, the resultant
section that runs all these is:
before_script: - /bin/cp $TRAVIS_BUILD_DIR/config/database.sample.yml $TRAVIS_BUILD_DIR/config/database.yml - /bin/cp $TRAVIS_BUILD_DIR/config/env_vars.sample.rb $TRAVIS_BUILD_DIR/config/env_vars.rb - psql -c 'create database howto_repo_test;' -U postgres
One thing that Travis can do for is cache our bundle operations, thus saving considerable time each build in creating the bundle environment. For this repo, there is a huge time savings from having to recompile local versions of native code (Nokogiri in particular takes a long time to build the native version).
We can tell Travis to cache the bundle within the
Normally, Travis runs bundler with just the
--deployment option, but
pry to the Gemfile to enable me to run
continuous testing and debugging locally. We don’t want these in the
CI run, however, so I’ve put all the local stuff inside a
group within the Gemfile. We need to tell Travis not to include it:
bundler_args: --without guard --deployment
which tells bundler to omit the
guard section, and install things as
if this were a deployment.
Putting the whole thing together:
language: ruby cache: bundler bundler_args: --without guard --deployment rvm: - 2.0.0 before_script: - /bin/cp $TRAVIS_BUILD_DIR/config/database.sample.yml $TRAVIS_BUILD_DIR/config/database.yml - /bin/cp $TRAVIS_BUILD_DIR/config/env_vars.sample.rb $TRAVIS_BUILD_DIR/config/env_vars.rb - psql -c 'create database howto_repo_test;' -U postgres env: RAILS_ENV=test SECRET_KEY_BASE="$(bundle exec rake secret)" addons: postgresql: 9.2
Triggering a Travis Run
Normally, Travis will begin a build whenever code is pushed to the
repository if the repository contains a
.travis.yml file. The thing
you also need to do is turn on the service hooks for the repository to
interact with TravisCI. To do this, you need to be able to change the
settings of the repo on Github. Since I didn’t have such permissions,
Jason did this, but then it wasn’t clear why builds were not starting.
The other issue with this is that if you’ve already created a pull request for a given branch, adding to that branch does not seem to trigger Travis builds. Once that PR was merged, then Travis builds began as expected.
At present, Travis will happily build anytime there is a push to any branch on Github, including new feature, bugfix, and chore branches. This includes any new or existing branches, so we don’t have the first-time issue any more.
My thanks in particular to Jason Bucki for his help on pushing me to do this and getting this up and running. Also thanks to Kyle Kestell for his help on understanding the application and getting me up to speed.