Continuous integration is a well-known practice amongst agile developers with numerous benefits that make it a must on a nearly any software development project. At ChaiONE, we have a Mac Mini that we use to house some internal apps, as well as drive a big flat screen TV that greets our guests. Since building iPhone apps requires a Mac environment, this makes a perfect continuous integration server.
Choosing a CI Tool
There are plenty of tools to help build your software continuously, but two are clear leaders:
Jenkins (formerly Hudson) - Free, open source, plenty of plugins
Team City - Free version, excellent configuration wizard
Choose the one that suits you best. You really can't go wrong. I have some experience with Team City, but I decided to try out Jenkins. I found the UI to be pretty terrible, but configuring it couldn't be easier and definitely feels more lightweight than Team City.
We'll need to configure a few plugins before we're ready. Click on "Manage Jenkins" and then "Manage Plugins". We store our source code at GitHub, so we'll need the Git plugin to be able to poll for changes. In addition, I'll snag a few additional plugins for various notification options. Browse the plugins and check off the ones that look interesting. Here's what I installed:
Instant Messaging Plugin (required for a few others)
Once they are installed, go ahead and restart Jenkins. Most of these plugins need to be configured. We configured Jabber for notifying responsible parties of broken builds. Note that the Skype plugin is a bit finicky, and might not work on 64-bit OS X. In addition, we like to have a bot sitting in our IRC channel, allowing us to query status and kick off jobs.
Oops! Looks like we need to fix that Android build.
Creating Your First Job
Head back to the Dashboard and click "New Job". Give it a name and select "Build a free software project". Then click "OK".
Next, scroll down to the section on source control. Since we already added the Git plugin, there should be a section for it here.
Next, we need to tell Jenkins when to kick off the build. Under Build Triggers, check "Poll SCM". This gives you a non-descript text box that accepts cron style schedules. To have it poll every minute, set it to "* * * * *".
At this point you can save and run the build. It won't do anything but clone the project, but it will let you know if the SSH keys are all properly set up for fetching from Github. Go back to the dashboard, if you see a blue light, you're all good.
Next we need to actually have Jenkins compile our source code.
Prepping Your Project for Automation
To do that, it's important that you can run it locally. For most projects, something similar to the following should do the trick:
Once this works locally, you might consider putting it in a shell script or Rakefile so future command line builds are as easy as typing build. You might also need to include common commands, such as fetching git submodules, so make sure this is all covered in your build script.
Adding a Build Step in Jenkins
Assuming you've created build.sh and given it execute permissions, we simply need to call this from a Build Step in Jenkins. Go back to the dashboard, click on the project, click "Configure". Go down to Build Steps and click "Add Build Step". You'll choose Execute Shell. We simply need a terminal command, "./build.sh".
Save the project and kick off another build. If all is good, you should see Jenkins running your build. Take a look at the console to see the output.
Using this system, we now have a regular pulse check on the project. If someone commits code that doesn't compile, the build will break, and you can be notified via Google Talk, IRC, email, or whatever you prefer.
Where to go from here?
Having your project compiled for you is a good, valuable process, but it's just the foundation upon which much more valuable tasks can be performed. For example, you can:
Run your automated tests with SenTestKit, GHUnit, KIF, or anything else that supports command line builds
This is just the tip of the iceberg. Continuous integration is a very effective tool for decreasing the risk of integrating software. Hopefully this article gave you a quick look at how Jenkins can be used for automating iOS builds!