Recently I have received several requests to explain how to automate iOS builds from checkin to Testflight. Since I have been using Jenkins to automate iOS applications for almost 2 years, I feel like it is time to share. In this series of posts I will explain how I automate my iOS projects to perform the following steps:
- Compile the App and build an IPA file
- Execute Clang scan-build and fail when leaks are detected
- Execute copy-paste detection and fail when infractions are found
- Execute GHUnit tests with code coverage and fail when tests fail
- Generate AppleDoc documentation
- Upload the IPA to Testflight with a proper build number and commit history
- A Mac OSX computer to serve as a Jenkins server or Jenkins slave. Must have Xcode installed.
- iOS App source code accessible from a common source code control system such as Git, Subversion, Perforce, etc.
- The ability to download and install open source software.
- A Testflight account with a team already configured.
For those of you who are not familiar with Jenkins, it is an open-source continuous integration server. Jenkins is written in Java but can be used to automate almost anything. Jenkins is backed by a vibrant community of developers who continually contribute bug fixes and new plugins. If you have never setup Jenkins on a Mac, you should begin by running the Jenkins Mac OSX installer which can be found on the Jenkins home page. If you plan to use a Windows or Unix machine as a Jenkins master, you will have to configure your Mac as a slave machine.
Once you have Jenkins installed and running, you should use the Jenkins update center to install all of the necessary plugins. You can access the plugin update center by clicking ‘Manage Jenkins’ and then clicking ‘Manage Plugins’. Next, go to the ‘Available’ tab and begin checking the plugins you wish to install. I have broken the plugins down by function below in order to help you figure out which ones you need to install:
- Compile App and build IPA = SICCI for Xcode Plugin
- Execute Clang scan-build = Clang Scan-Build Plugin
- Execute copy-paste detection = Dry Plugin
- Execute GHUnit tests with code coverage = Cobertura Plugin
- Upload IPA to testflight = Testflight Plugin
- A suitable plugin for your source code control system. Jenkins has source control plugins for just about everything.
After you have installed all of the plugins for the features you wish to implement, you’ll need to create a new freestyle job in Jenkins which will perform the automation. If you plan to automate more than one App you would create a freestyle job for each App. Create your job by clicking ‘New Job’ in the upper left, providing a job name, and choosing the ‘Build a free-style software project’ option. I recommend not using spaces in your job names because they can cause some scripts to function improperly.
Once you have created a freestyle job for your App, you should configure the Job to connect to your source control system and pull the source code to the Job’s workspace. Open your Job in Jenkins and click on the ‘Configure’ link on the left to access build settings. You can setup your source control in the ‘Source Code Management’ section. If you do not see an option for your source control server you’ll need to go install a suitable plugin. The Jenkins job configuration page also has a ‘Build Triggers’ section which will allow you to configure source code polling. I usually enter something like ‘*/5 * * * *’ in the ‘schedule’ field so that Jenkins will poll my source control server for changes every 5 minutes.
After you have configured your Job to pull your source code you should execute a build by clicking ‘Build Now’ on the left side of the screen. Jenkins should execute successfully (blue ball instead of red) and your source code should now be visible in the Job’s workspace. You can confirm this by clicking the ‘Workspace’ link on the left side of the Job page. If you see your code in the workspace you are ready to move onto the next step. If you do not see your source code, try clicking on a failed build and viewing the console output for clues.
Compile the App and build an IPA
A note for XCode 4.3 users: Apple recently began distributing Xcode via the Mac App Store. When Apple made this change they also split XCode into several separately installed components. Many of the tools detailed in this post require the ‘XCode command line tools’ download. You can install this download by opening Xcode on your build server and going to ‘Preferences’. Once you have opened XCode preferences, click the ‘Downloads’ tab and install the ‘Command line tools’ download. After the ‘Command line tools’ are installed you should test them by opening Terminal on your build server and execute the ‘xcodebuild’ command. If you get an error stating that no /Developer directory could be found, execute the following command from Terminal: sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer
The most basic Jenkins/iOS continuous integration system should at least compile the App. This ensures that commits made by developers are not missing files which would cause headaches for the rest of the team. There are currently two ways you can configure Jenkins to compile an iOS App. You can either use xcodebuild directly from an ‘Execute Shell’ build step or use the SICCI for XCode plugin. I have been using the SICCI for XCode plugin for about a year and have found that it is reliable and easy to use. This guide will assume you are using the SICCI for XCode plugin.
The SICCI for Xcode plugin requires access to your XCode workspace/project so that it can list out the targets/schemes for your App. Because of this, you will need to make sure that Jenkins is happily pulling your source code into the workspace before you move on with this step. Once you have confirmed that your source code is being pulled properly, you will need to go to the job’s ‘Configure’ page. On the Configure page locate and click the ‘Add Build Step’ button. Once you click the ‘Add Build Step’ button you should see a popup with a list of build step types. You should choose ‘SICCI for Xcode’. Jenkins will add the SICCI for Xcode build step and you should see a list of the build targets in your project. If you do not see your project folder and a list of build targets, your source code is probably not in the job’s workspace.
To have the SICCI for XCode plugin compile your App you should change the platform to ‘iOS’ and check the checkbox next to your App’s main target or scheme. Once you check a target or scheme, the SICCI for XCode plugin will display several options. You should check ‘clean before build’ and ‘create IPA’. If you wish to have the SICCI for XCode plugin also zip up the App’s DSYM, you should also check ‘archive App’.
You may also wish to change the SICCI for XCode ‘Filename template’ to something more simple. I usually use something like ‘AppName_<BUILD>’ where AppName is anything you want. The <BUILD> token will be replaced automatically with the Jenkins build number during a build. I also recommend that the you don’t use spaces in the ‘Filename template’.
Next, save your configuration changes by clicking the ‘Save’ button and run your Job by clicking the ‘Build Now’ link. If your job passes, you are ready to move onto the next step. If you job fails, you should click the failed job link on the left to view the job details page and then click the ‘Console Output’ link. In order to see the entire console output you may need to click the ‘Raw’ link.
The job console will show the typical build output from xcodebuild and will show any compile errors that may have occurred. If you still can’t figure out how to get your code to compile you should try running xcodebuild directly on your project from your local workspace using Terminal.
In the next part, I will explain how automate GHUnit tests in Jenkins.