Hawaiʻi's Technology Community

Continuous Delivery with Ruby on Rails and Heroku

So I figured that as a follow-up of my overview on continuous delivery, I shall present past experiences of establishing such systems in various environments.

Version control systems (VCS) and continuous integration systems (CIS) are essential to me in software development so I like to set up a system to provide these features before I am involved with a software project.

I've been recently working with Ruby on Rails projects that are deployed to Heroku.

In this post, I describe the setup I established to make use of CD in similar projects.

Version Control

While almost any VCS with branching support will work, for this example, I will be using git.

We will make use of the release branches for continuous delivery.

Briefly describing the release branches: developers branch off of the mainline and work in parallel with the mainline. When a developer is ready to introduce changes to the mainline, the changes are merged with the mainline. When a specific point in the mainline is ready for promotion to the staging environment for user testing, the mainline at that point is merged with the release line. Likewise, when a specific point in the release line is ready for production, that specific point in the release line is merged with production (the master branch in this example).

Any changes introduced to the release lines, including the production line, will result in the deployment of that specific point in the release line to the appropriate environment. That way, the releases are traceable to the merges made.

The following diagram illustrates what the branch flow looks like with git:

Continuous Integration

Continuous integration comes into play with the mainline and release lines shown above. That is, main, v1, and master will continuously go through integration and testing. For the release lines, each change will go through integration and then deployment, thus providing a continuous delivery system.

In the diagram above, notice that the production environment never sees new development until the final merge with the mainline (main.2) while the staging environment sees continuous updates from latest developments. Note that merges with the mainline need not be promoted to the release branches so it's also possible for the mainline, the release branch, and production branch to all deviate.

In this example, I will use cruisecontrol.rb (cc.rb).

CC.rb Setup

CC.rb is simply a rails app so it's very simple to get running. All you need to do is extract the downloaded contents to some directory and run "cruise start". For additional details, please refer to its official website.

Server Setup

While installing cc.rb is pretty trivial, there are a few server setup tasks to be done prior to running your cc.rb server:

  • To make use of E-mail notification, either install sendmail or get your SMTP settings handy
  • Install the heroku toolbelt
  • Configure your ssh client to use private keys for your git repository and heroku
  • Install whatever packages you needed to get a local copy of your codebase to build and run tests successfully
    • This task may include rvm, node, npm, etc.

Site Configuration

You can configure the cc.rb site by editing the file located in $HOME/.cruise/site_config.rb. Here is what I modified:

ActionMailer::Base.smtp_settings = {
  :address =>        "localhost",
  :domain =>         "myhost.local",

CruiseControl::Configuration.email_from = ''

CruiseControl::Configuration.dashboard_url = 'http://myhost:3333/'


I find that instead of adding a new project via the command line, it's easier to just get the server running, and click on the "Add Project" tab and fill in the initial project info then jump into the project's configuration file to make the fine-tune changes.


You configure your project in $HOME/.cruise/projects/{project}/cruise_config.rb.

Here is where you set notification E-mails and the build command.


The E-mail notification sends an E-mail only when a build breaks and a changeset fixes a broken build. If you want additional notification, check out the system tray applications.

Build, Test and Deploy

I simply place a bash shell script named "" in the project directory just outside the work directory.

In the script, I attempt to run the tests and if they fail, I do a non-zero exit to fail the build. Here is an example of a build script that sets up the environment, run tests, and deploys:

export PATH
export RAILS_ENV=test

function check_response {
  if [ $1 -ne 0 ] ; then
    echo "Build failed"

    exit $1

echo "=== PREPARE ENVIRONMENT (Step 1/6) ==="

# A bunch of things to run to ensure that our environment is ready to run the
# tests

echo "Using ruby ${RUBY_VERSION}"
source /usr/local/rvm/scripts/rvm
rvm install ${RUBY_VERSION}
rvm use ${RUBY_VERSION}
check_response $?

echo "Installing gems"
bundle install
check_response $?

echo "Installing nodes"
npm install
check_response $?

echo "=== MIGRATE DATABASE (Step 2/6) ==="

echo "Running migration"
rake db:migrate
check_response $?

# This bit was added just to check that the change didn't introduce a database
# migration that's irreversible.

echo "Checking that migration is reversible"
rake db:rollback
check_response $?
rake db:migrate
check_response $?

echo "Resetting database"
rake db:reset
check_response $?

echo "=== BACKEND TESTS (Step 4/6) ==="

# This runs the specs

echo "Running rake"
check_response $?

echo "=== FRONTEND TESTS (Step 5/6) ==="

# This runs the front-end tests. In this example, there is a specific task for
# this. You may need to add additional tasks as needed.

rake karma:run
check_response $?

echo "=== DEPLOY TO HEROKU (Step 6/6) ==="

# If all is good, we finally deploy to heroku and run the database migration
# remotely in case it's needed. If it's not needed, then the migration command
# does nothing.

echo "Pushing to heroku remote"
git push heroku master && heroku run rake --trace db:migrate --app $HEROKU_APP
check_response $?

# This bit allows CI to automatically tag deployments in git. It's using the
# latest heroku release version as the build version and the latest major/minor
# version to produce the final latest version.

version=`git tag | xargs -I@ git log --format=format:"%ai @%n" -1 @ | sort | \
awk '{print $4}' | grep [[:digit:]]$ | grep -o v[[:digit:]]*\.[[:digit:]]* | \
tail -n 1`

build=`heroku releases -a $HEROKU_APP | cut -f 1 -d " " | sed 's/v//' | \
head -n 2 | tail -n 1`


echo "Latest version: ${latest}"

git tag -a $latest -m "Automatically tagging latest heroku release" 2> /dev/null

if [ $? -eq 0 ] ; then
  echo "Now pushing tag to git"
  git push origin $latest

echo "Build successful"

Views: 513


You need to be a member of TechHui to add comments!

Join TechHui

Comment by David Chung on December 22, 2014 at 11:33pm

CruiseControl is pretty simple to set up and it's free. It offers simple reporting options and for my needs at the time, I found it to be suitable.

I'm familiar with other proprietary CI solutions such as JetBrain's TeamCity and Atlassian's Bamboo.

Without going into further details (probably save it for another blog post), the proprietary solutions have better reporting tools and expandability. They are very easy to install and configure builds since a lot of that is done through their web UI. I also like how build artifacts can be passed around build configurations to forward the build chain.

In summary, I see CC.rb as a quick and simple tool while I see TeamCity and Bamboo as enterprise-level suites that can scale with the organization. Either solution can do CI but the proprietary solutions offer a lot more.

Comment by Joseph Lui on December 22, 2014 at 5:53pm
Any opinion on CruiseControl versus its alternatives?


web design, web development, localization

© 2024   Created by Daniel Leuck.   Powered by

Badges  |  Report an Issue  |  Terms of Service