@madpilot rants

Setting up Buildbox when you run your own Git server

I’ve been trying to get a CI server for 88 Miles sorted out for ages. I tried to cobble something together before, but lost interest trying to keep track of previous builds and Ruby environments and other stuff. Me being me, I run my own Git server, so many of the existing CI servers out there won’t work for me (They assume GitHub), and I don’t really feel comfortable sending out source on a private project to a third party server. I also have a VM in my office that runs various dev machines, so I have the hardware to do it. Well, it turns out that a buddy of mine has been building a CI server that is a perfect fit for my purposes! It’s called Buildbox, and it comprises of an agent that you run on your hardware that manages builds for you. This is roughly what I did to get it running.

The Build Server

I setup a VM running Gentoo, with 1Gb of RAM and two virtual CPUs. It is as close to my prod environment as I can get it, running RVM – this is important, as there is a bit of a trick to this. I also set up a specific user (called build), that will do the work. I initiate the Buildbox daemon using monit, so if it ever dies, it should get restarted automatically.

Note: I’ve omitted the Buildbox setup instructions – The website does a better job than I could.

The wrapper script

Because I’m running RVM, and because monit is fairly dumb in setting up bash environments, I wrote a small wrapper script that will start and stop the Buildbox executable:

#!/bin/bash
case $1 in
        start)
                if [[ -s "$HOME/.rvm/scripts/rvm" ]]; then
                        source "$HOME/.rvm/scripts/rvm"
                elif [[ -s "/usr/local/rvm/scripts/rvm" ]]; then
                        source "/usr/local/rvm/scripts/rvm"
                else
                        printf "ERROR: An RVM installation was not found.\n"
                        exit -1
                fi

                rvm use ruby-2.0.0-p247
                buildbox agent:start &
                echo $! > /var/run/buildbox/buildbox.pid
                ;;
        stop)
                kill `cat /var/run/buildbox/buildbox.pid`
                rm /var/run/buildbox/buildbox.pid
                ;;
        *)
                echo "Usage: buildbox-wrapper {start|stop}";;
esac
exit 0

If you call buildbox-wrapper start it sets up a RVM environment, then runs the buildbox agent and then saves the PID to /var/run/buildbox/buildbox.pid (Make sure the /var/run/buildbox directory is writable by the build user). Calling buildbox-wrapper stop reads the pid file and kills the agent.

The monit config

Add the following to your monitrc:

check process buildbox with pidfile /var/run/buildbox/buildbox.pid
        start program = "/bin/su - build /bin/bash --login -c '/home/build/scripts/buildbox-wrapper start'"
        stop program = "/bin/su - build /bin/bash --login -c '/home/build/scripts/buildbox-wrapper stop'"

This will change to the build user, then run the wrapper script.

My build script

You enter this into the code section of the web UI (I was a little confused by this – I didn’t realise it was editable!)

#!/bin/bash
set -e
set -x

if [ ! -d ".git" ]; then
  git clone "$BUILDBOX_REPO" . -q
fi

git clean -fd
git fetch -q
git checkout -qf "$BUILDBOX_COMMIT"

bundle install
bundle exec rake db:schema:load
bundle exec rake minitest:all

This is pretty much a cut and paste from the Buildbox website, except I run Minitest. I also tmp/screenshots/**/* and coverage/**/* to the artifacts section. Artifacts are get uploaded after a build is complete. I use them to upload my screenshots from all of my integration tests, as well as my coverage reports.

Git post-receive

This script belongs on your Git server in the hooks directory. Name is post-receive

#!/bin/bash

while read oldrev newrev ref
do
  branch=`echo $ref | cut -d/ -f3`
  author=`git log -1 HEAD --format="format:%an"`
  email=`git log -1 HEAD --format="format:%ae"`
  message=`git log -1 HEAD --format="format:%B"`

  echo "Pushing to Buildbox..."

  curl "https://api.buildbox.io/v1/projects/[username]/[projectname]/builds?api_key=[apikey]" \
          -s \
          -X POST \
          -F "commit=${newrev}" \
          -F "branch=${branch}" \
          -F "author[name]=${author}" \
          -F "author[email]=${email}" \
          -F "message=${message}"
  echo ""
done

Replace username, projectname and apikey with your own details. Make the file executable, and then push a change, and a build should start!