Continuos Integration is the practice of integrating changes from many people as often as possible. Instead of merging changes once a month and spending time handling merge errors you try integrate every day, perhaps even every hour. Each integration is built and tested on a server. If there are build errors or test failures, you and your team will be notified right away.
This is the second part of the blog post I wrote about TDD in XCode. Make sure you’ve followed that tutorial before continuing here, or at least have a project of your own with OCUnit tests ready.
The server which we’ll use is called Hudson and is very popular in the Java community. It does not readily support XCode projects but it does allow shell commands, so we’ll use that to make our Calculator project compatible. We also want to fetch new versions of the source code as soon as it’s checked in. We’ll be a bit fancy and use Git as source control software. Here’s a summary of what we want to do:
- Download and install the Hudson continuos integration server
- Download, install and setup the Git source control software as well as the Git plugin for Hudson
- Download and install a script that converts OCUnit test results to JUnit format
- Setup a new job in Hudson that checks out our XCode project and builds and tests it
- Set up a notification and try it out
Downloading and Installing Hudson
In order to keep the instructions in this tutorial simple, we will have the source code repository and the build server itself on localhost. In real life you’ll probably want to setup a dedicated machine.
Head over to the Hudson web site and download your copy of the server. Follow their included installation instructions, it’s quite simple. Once you have Hudson up and running you can visit http://localhost:8080 to see the welcome screen. By the way, when you’re ready to install Hudson on a real remote server I recommend running it as a Servlet inside Apache Tomcat instead.
Downloading and Setting Up Git
Next we want to install Git. There are several ways to install it. The simplest might be to use the OS X installer, but I personally prefer MacPorts. Either way, go ahead and install it and make sure that you can use the “git” command from Terminal.app when you’re done.
In the Terminal, change directory to your XCode project folder and type:
You now have a working source code repository in your project folder. Neat. Before you continue create a text file called .gitignore and let it contain:
build/* *.pbxuser *.mode1v3 .DS_Store test-reports/*
That’s a listing of the files and folders that should not be version controlled, since they are temporary or just used for XCode. Feel free to add any other files that you think only should be present locally. Now add all files (that aren’t ignored) using:
git add *
and finally commit them to a first version using:
git commit -m "Initial import"
Fetching the Script
We need to fetch one more thing, ocunit2junit.rb, which is a little Ruby script that I wrote. Since you now have git, you can also download it using git (or clone the repo, which is the correct term). Change directory to /tmp and then type like this:
git clone git://github.com/ciryon/OCUnit2JUnit.git
Copy the script from /tmp/OCUnit2JUnit/ anywhere, like to /usr/local/bin/. Make sure it’s executable by typing chmod +x ocunit2junit.rb.
The script will parse output from xcodebuild (the console command for building your XCode project) and look for output from OCUnit. The test results (success, failure, time passed etc) will be saved in the “test-reports” folder in the same XML format that JUnit uses. This also happens to be a format that Hudson understands.
Setting Up Hudson
Now head back to your Hudson welcome screen. Select Manage Hudson, Manage plugins and check “Hudson GIT plugin” under Available. Hudson will automatically download and install the plugin. Afterwards just restart Hudson.
We’re ready to create a job in Hudson for our project. From the main screen select “New job”, Build a free-style software project and call it “Calculator”. There are some settings which you should fill in:
Select to use git as source code management tool. The URL should be the file path to your project, like:
Select to poll SCM with Schedule:
* * * * *
That means it’ll check every minute if there are changes. If you want to check less often, do that.
Add new build step and select to execute shell. Use this command (make sure to point to the version of the iPhone SDK you want to use):
xcodebuild -target "UnitTests" -sdk /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator3.1.2.sdk/ -configuration "Debug" | /usr/local/bin/ocunit2junit.rb
Select to also publish a JUnit test result report and the Test report XMLs reside at
Trying it out
This is the moment of truth. Try to change your CalculatorTest.m so that one of the test cases fail. Type:
git -a commit CalculatorTest.m "Broke the test, on purpose"
and see what happens. If all goes well, and you have entered everything correctly, Hudson should automatically notice there’s a new version available, build it and try to run the test suite. Check the results and how it reports the test failure. Nice, eh? Fix the error and commit the test class again to see how Hudson reacts.
There are many settings, plugins and cool things to try out in Hudson. Go into Manage Hudson-> Configure system and setup your email settings, to allow Hudson to send mail. Then go back to configure your Calculator job and at the bottom select E-mail Notification. Enter your own email address and see how it works after you commits a file that breaks the build. If you don’t want a mail, you can get an instant message, or perhaps have the server play a loud annoying sound? Everyone in your team should be aware of when a build fails, so it can be fixed right away. This is one of the great advantages of having a continuos integration server.