Rails does many things well, but one of the best is providing a framework for easy and complete testing. However, continuous integration, theoretically a by-product of easy testability, doesn’t seem to be a major player in the Rails landscape yet. One good reason is that there’s not yet a continuous integration application like CruiseControl or AntHill out for ruby. Sure, there have been sightings of such tools like CIA (seems to have been deprecated) and Damage Control, and there is the handy Autotest which kind of gives you a continuous integration feel – but what about real continuous integration?
Well, we do have an option in the form of the continuous_builder plugin. Is it a slick web-app that lets you configure your build process within the comforts of a GUI? No. But, it does automatically run all your tests on every subversion commit and send a nasty-gram calling out the person who broke it, and that’s pretty much what continuous integration is right?
On a side note, I would love to see an open-source CruiseControl for Rails developed and suspect one will be out shortly as the community grows even further
So how does one get the continuous builder plugin up and running? Read on…
Install continuous_builder Plugin
Installing the continuous_builder plugin is a cinch since it’s part of the rails source tree and is a recognized plugin repository.
cd app
script/plugin install continuous_builder
You can also manually install it if the plugin install doesn’t work for you – though I don’t know why it wouldn’t.
cd app
cd vendor/plugins
svn export http://dev.rubyonrails.com/svn/rails/plugins/continuous_builder
Configure Environment & Mailer
The builder plugin runs as a rake task triggered by subversion’s post-commit trigger. However, it needs a few things before it can just work.
The first thing to note about the plugin is that it’s a bit of a dichotomy. When it runs the rake task to perform the tests (all unit, functional and integration tests) it runs under the test environment. That part is easy and expected. However, what you should also know is that the builder runs inside the development environment by default (which is normal for all other rails commands but slightly unintuitive in this particular situation). This means that, if left as is, the builder will pull the action mailer config from the config/environments/development.rb configuration (or config/environment.rb if there’s one configuration for all environments). So to summarize, the builder configuration wil pull from the development environment config and the rake testing task operates in the test environment.
This could be an issue if your development config doesn’t send real emails (your test config probably wouldn’t either since you’d usually be using ActionMailer’s mock delivery to unit test email functionality). What I would suggest doing to keep your builder configuration seperate from your other environments is to create a new build environment config file. This involves
- Creating an
config/environments/build.rbconfig file with a working ActionMailer config - Updating
config/database.ymlto point to a build database (this can be an empty db as all it will do is create an initial connection (though I wouldn’t suggest pointing to the test or production db)
Now we can safely tell the builder to use the “build” environment to get its mailer configuration, and we can leave the other environments untouched.
Test Configuration
Once you have your build configuration setup (or even if you haven’t chosen to do that), you’re going to want to test the builder. This can be done on your local machine, though it requires some little hacks to make the mail function trigger.
The mail functionality will trigger when the build or tests fail and there’s code to update from the repository. To simulate this I created a unit test that always failed, and reverted one small portion of the code to a previous version (using svn update -r _previous revision#_ ). Once you’ve got this simulated failure setup, run the following:
# Omit "RAILS_ENV=build" if you did not set up a seperate environment
# Include the BIN_PATH if your rake executable is not located
# at /usr/local/bin (and include the trailing "/"!)
RAILS_ENV=build BIN_PATH=/usr/bin/ rake -t test_latest_revision \
NAME=app_name RECIPIENTS="[email protected]" \
SENDER="[email protected]"
If all is setup correctly, you will see the standard test output and should see the build status output to the log/last_build.log file. If anything is wrong it should be recognizeable as a build or test error. Fix it and try again :) (and don’t forget to re-setup the fake failure situation described before)
Setup Environment on Build Server
Now that you know your plugin is working, you have to duplicate that setup on the build server – which has to be the same server that subversion is running. Here’s the process I went through:
- SSH to the subversion machine as the user that subversion runs as
- Make a directory where the builder can check out your source to (I’ve used
/tmp/rails/app) - Checkout the code to that directory from the command line – just to make sure you can
- Edit the
hooks/post-commitfile located in your subversion repository directory to look like this (for me this was~svn/repo/hooks/post-commit)
#!/bin/sh
# Set vars (if necessary)
BUILD_DIR=/tmp/rails/app
BIN_PATH=/usr/bin
# Execute builder (use the same command that worked on your local
machine in the previous test scenario)
cd $BUILD_DIR && \
# Make sure we have the latest and greatest db structure
$BIN_PATH/rake migrate VERSION=0 && \
$BIN_PATH/rake migrate && \
# Run continuous build task!
RAILS_ENV=build BIN_PATH=$BIN_PATH $BIN_PATH/rake -t test_latest_revision \
NAME="App" \
RECIPIENTS="[email protected]" \
SENDER="[email protected]"
Once the post-commit file is in place, you need to do make sure of a few things:
- That your post-commit file is owned by the user that the subversion process runs as
- That your post-commit file is executable by that user
- That the subversion user can checkout code to the build directory (easy as setting that user to be the owner of the build dir)
An easy way to test this setup is to run the post-commit file from the command line. Since it’s executable you should be able to just run ./post-commit. If you’ve recreated the fake failure scenario on the build server as you did on your local machine you should get the nasty-gram email sent to the [email protected] email address. If not you should at least see the process output.
Test in Production
Now the only thing left to do is to test the builder on an actual commit. This is pretty easy, all you have to do is commit a test that fails. You should see an email pop up in your inbox saying that you wreaked havoc on the build, bringing the scorn of the developers upon you.
Damn – that was a lot. Hopefully you’re now living in continuous build nirvana…
Resources:
http://dev.rubyonrails.org/browser/plugins/continuous_builder
CIA Stuff:
http://wiki.rubyonrails.org/rails/pages/How+To+Use+CIA+For+Continuous+Integration http://article.gmane.org/gmane.comp.lang.ruby.rails.core/790 http://blog.innerewut.de/articles/2005/09/18/setting-up-cia-with-rails-and-subversion
tags: rubyonrails, continuous integration, agile
