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!