Continuous Integration with CiJoe

It is more than likely you write tests for your Ruby code. There are many forms of testing we can employ from isolated unit level to full stack integration. A common workflow for this is to pull the latest “clean” commit of the codebase, perform some actions and then prepare the code to be merged back into the current branch of development. Introducing a team of developers into the mix, that workflow will grow in complexity. You have to deal with merge conflicts, sometimes you will even have to talk to fellow developers to resolve changes form both a high and low level perspective of the application.

Before the commit you need to pull any changes in the codebase, merge them and ensure the application meets the all green metric for the test suite. Automated Continuous Integration (CI) provides an important helping hand to teams of developers ensuring they have a verified and correct version of the application to hand.

The Sole Developer

A slight caveat is the lonesome, isolated and blissfully happy developer. A common conception is that CI, be it vital for teams is not applicable to the solo/freelance developer. I understand the viewpoint that if a single developer is solely responsible for a repository of code, and he/she runs their test suite before every commit then yeah, what else could go wrong?

Well for me that test suite should be ran on a similar (exactly) environment to where the production code is going to land. I find my local development machine is always least applicable. Also, c’mon. We are all human and a few times in the past I may have a green test suite but forget to commit a newly added file, or configure a resource properly. CI saves us from the pain of deploying broken or incomplete code. We must be slaves to ‘The Build’ if frequent or even just plain ole reliable releases are to occur.

What’s Out There?

There are many CI solutions on the web. Honestly, pick a name and slap ‘-ci.org’ on the end and see what you get. Jenkins and Hudson seem to steal a lot of the commercial limelight and if you are working in the Open Source world then I don’t need to tell you about Travis.

For my 9-5 employment we use Jenkins. It’s flexible, and straight forward enough to get up and running, provided you are savvy working on the server command line. For an open source project (to my shame I have none, but want to change that) Travis would meet my needs completely, being hosted and free to OS. But for personal/commercial projects, what do I use?

Red and Blue Lasers

CiJoe is a CI solution that is lightweight, simple and a snap to get running regardless of your server admin skills. You install the gem, pull repositories, and run Joe.

It is not Ruby specific, but does require a command line test command that will respond with a non-zero on failure. Literally, within 5 minutes I had 3 personal projects under CI. That was a huge win for me and not sure I would have got those results as quickly using anything else.

The following is a walkthrough of getting the same results, regardless if you a sole developer or part of a team. If you don’t have CI, and like the idea of getting a stable build / deploy workflow then, this is for you.

Gumbo Builds Muscles! Right, Doc?

Apart from being a huge GiJoe fanboy (Even though it was called Action Force over in the UK for a while), CiJoe appeals to me on so many more levels. I like lightweight. I use rbenv over RVM, prefer Vim to RubyMine. To get started with CiJoe, all you need is a box that runs Ruby. No need for Java, Redis, or anything else to be installed. So the only requisites are to have a remote server (preferably configured as close to your production environment as possible) which has the capability to run Ruby and Gems. Currently, I’m running CiJoe on a VPS with Ubuntu installed, Git installed, and Ruby 1.9.3 built from source.

Problem Before We Even Start

I experienced one problem getting the CiJoe server to run. This is a known issue but hash’t been addressed in the master branch. It’s a real shame really, as it looks like the project is no longer maintained. At the time of writing, the last commit was over a year ago. But the patch supplied by Anton Lindqvist is simple to implement in your own fork of the project, or you could even just use his fork.

This makes the gem a little harder to install. We are not using Gemfiles here, so defining the Github url will be of no help to you. Time for some old school gem building. Basically clone the gem to your server, git clone git://github.com/mptre/cijoe.git. Navigate to the new cijoe directory and build the gem using gem build cijoe.gemspec. Now, to finally install the gem, run sudo gem install cijoe.gem

Time to Get Going (fureal)

In the home directory for my user I create a folder named cijoe. This is where I intend to build my applications for test.

That’s pretty much it for setting up CiJoe in it’s most basic form. But of course we need to get the source into this folder. Don’t know about you, but I’m using GitHub. Github makes this process really simple buy allowing deploy keys on projects. If you are not sure how to do this all you need to do is create an ssh key and add this key as a deploy key for the project we want under CI.

Now it’s a case of cloning the project into our cijoe directory as normal, and running cijoe reponame. This starts up a Sinatra application we can access by going to server_ip:4567 and checking the output of the test, or indeed starting off another build.

Making the CI More Manageable

Now CI is supposed to make our lives easier. The idea of committing changes, logging into the CI server, pulling the latest changes, starting CiJoe again, navigating to the CiJoe page and clicking the ‘Build’ button is a complete nightmare. As you have guessed it doesn’t need to be this way.

First of all, navigating to an IP address is lame. So add a DNS record that points to ci.yourdomain.tld.

I’m using apache to serve my domains, so I need a “site” that responds to the new domain. This is the same as creating any domain on your server. You can see an example of what I use in this gist. I have setup some basic authentication for the root of this domain. Howeever, that won’t be used here and you will see why in a minute.

As I mentioned earlier, CiJoe uses Sinatra as a front end. This means adding basic authentication in the apache configuration will be of no help. We will be accessing the CI on ci.example.com:<port_number>.

Build Configuration via Git

CiJoe uses git configuration to change the behaviour of the build. One of these options is using basic auth. On your local repository setup this config using


git config --add cijoe.user username
git config --add cijoe.pass secret_password

Now when we navigate to the CI server we will be prompted for said username and password. Yes, this is futile (and dangerous) if the project is public on Github, but we are only concerned with private projects here.

The build of the project is also managed via git configuration settings. Here we are defining the setup and running off our test environment. It’s a single line deal so you will have to use && to chain executable steps together.


git config --add cijoe.runner "bundle install && bundle exec rake db:drop db:create db:migrate && bundle exec rake spec"

Or even better create a rake task that combines the lot. I use a task ci for this purpose.


desc "Setup the CI env"
task :ci do
Rake::Task['db:drop'].invoke
Rake::Task['db:create'].invoke
Rake::Task['db:migrate'].invoke
Rake::Task['db:test:prepare'].invoke
Rake::Task['spec'].invoke
end

With this in place our previous config setup is transformed to:


git config --add cijoe.runner "bundle install && bundle exec rake ci"

Watching It Go Green

With all that in place, we can now kick off a build. On the command line of the server, navigate to where the projects have been cloned and run cijoe <project_name>. If you look at ci.example.com:4567, you will see the CiJoe interface and clicking the “Build”" button will kick off the build and the results will be displayed.

As we talked before all this doesn’t feel all that automated. One of the well known dirty secrets of CiJoe is that it will start a build on receiving a post request, and Github knows how to do this. But first we need to run the CiJoe server in the background. Simply using nohup we can get this going and define the port on which the CI server runs.


nohup cijoe -p 4000 <your_repo> &

It’s worth noting that CiJoe will only run one build at a time unless the build queue is enabled. Again, it’s a git config defined like git config --add cijoe.buildqueue true. This is definitely suitable for teams or solo developers with multiple pushes in a short space of time, or conversely, significant build latency.

In thid Github admin interface under “Service Hooks” van add “Webhook URL” to the domain running the CI server, in this case with authentication that would be http://username:secret@ci.example.com:4000. Clicking the test button for this hook will set off a CI build. Want more projects under CI as well? It is simply a case of cloning the project and starting nohup again.


nohup cijoe -p 4001 <your_other_repo> &

Convinced?

Reading back over the article, I had to rethink the closing a little. Describing all the setup and detailing the fix for the initial problems sounds, well, painful. But I assure you it isn’t. Personally, it was literally 5 minutes including googling for the error, installing the forked gem and getting the basic CI server running. Setting up extra domains, web hooks and notifications does take a bit longer.

However, you have to compare that to setting up Jenkins or Hudson and all it’s dependancies. Putting all that aside CiJoe is great tool in the chain of providing releasable software at a regular pace.

It’s a bit of a shame that the project no longer seems to be maintained, it is a cracking little project that, for me, makes CI really accessible to small teams and loners. Maybe the open source directory on my dev box will see CiJoe find himself once more. CiJane anyone?

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.