Continuous Integration and Delivery for iOS with Jenkins and Fastlane (Part 1)

Christoph Herrmann
8 min readMar 31, 2017

--

This is the first part of a series of articles that will give you a complete walkthrough for setting up a CI/CD environment for your iOS projects.

Jenkins + fastlane = ❤

In this part we will:

  • learn what Continuous Integration and Continuous Delivery is and why it is important
  • set up Jenkins on a MacMini
  • create a build job that checks out your project from a Github repository
  • install fastlane tools on your build server (and also on your local development machine)
  • integrate fastlane into your project and create an example lane

Note that I am using a MacMini as a dedicated build server. You can also follow along this article if you are using your MacBook. However, in a production scenario you might want to avoid running Jenkins on your local machine executing automated builds.

1. What is Continuous Integration and Continuous Delivery?

Continuous integration (CI) is the software engineering practice of frequently integrating isolated changes to a larger code base and testing them immediately.
The goal of Continuous Integration is to verify the correctness of those changes and to detect integration errors as quickly as possible.
For this it is quite common to run automated tests after every integration.

Continuous Delivery (CD) is the ability to build software that can be released to production at any time.
The goal of Continuous Delivery is to ensure the code of a software is always in a deployable state, no matter if it includes new features or just bug fixes.

2. Why is CI and CD important?

Every one who has worked in a development team with many developers knows that bringing together the different branches the team members have been working on can be problematic. Even if there aren’t any merge conflicts, there’s always a chance that you messed up some functionality without noticing or broke the build.
If you are using Continuous Integration your changes are tested right after the integration and you are notified almost immediately if there are any issues. Frequently executing integration tests ensures a considerably lower risk of shipping broken features.

Frequently executing integration tests ensures a considerably lower risk of shipping broken features.

Besides having new features and changes tested it is also important to be able to ship at any time. Imagine that there was a critical bug in the latest production version and you need to ship a bugfix release as soon as possible. If your delivery process takes you several days to get your release ready it could already be too late and some of the users have uninstalled your app.

3. Why should you use CI/CD in your iOS Projects?

No matter if you are uploading builds to testing services like TestFlight, Beta or Hockey on a regular basis or if you are submitting app updates on a short release cycle (which you should) you are most likely wasting a lot of time repeating the following steps over and over again:

  • perform regression tests
  • increment version/build number
  • take care of signing and provisioning
  • upload to iTunes Connect
  • update AppStore screenshots and metadata

Think about how you could do something productive instead. Well here’s the good news: you can easily automate this cumbersome process. 🚀

4. Set up Jenkins on a MacMini

1. Do a fresh installation of Mac OS X (Sierra by the time of this article)

2. Create a new administrator user account. (Jenkins will create a separate user account later)

3. Download the latest Mac OS installer from www.jenkins.io and run it. Alternatively you can install Jenkins using homebrew (brew install jenkins)

Download the Jenkins installer for Mac OS X

4. Once the installer is finished it’ll automatically open your browser and go to http://localhost:8080 which is the local address of your jenkins. (If you did a fresh installation of Mac OS you need to install Java first. Simply open your terminal, type jave and choose More Info… or download the latest version of the JDK from here)

5. After the installation is finished go back to your browser and reload. You need to unlock Jenkins using the initialAdminPassword.

Note that you need administrator rights in order to access the secrets directory. In your Terminal enter sudo su and open initialAdminPassword using vi.

6. After Jenkins is unlocked select Install jenkins with suggested plugins which will cover the most important plugins (most of which we won’t even need)

7. Jenkins will now ask you to provide credentials for a new admin user. Just select Continue as admin for now and go to admin > Configure in order to change the initial password or create a new user Jenkins > Manage Jenkins > Manager Users.

8. Your Jenkins is now set up and ready.

9. The installation wizard automatically created a user account for Jenkins on your system. Go to System Preferences > Users & Groups and notice that the user without a user name is the Jenkins account. Right click on the user and set a name under Advanced Settings. Make sure to also set a password.

10. Check Allow user to administer this computer. Select Login Options and select Jenkins for automatic login.

11. You might want to start Safari and the Jenkins Dashboard whenever the computer is restarted. So again in System Preferences > User & Groups add Safari.app to the Login items of the Jenkins user account. Open Safari, go to Preferences/General and select Safari open with: A new window, New windows open with: Homepage and set the homepage to http://localhost:8080.

5. Create a build job to check out your project from Github

For the purpose of this article I created a public repository.

You can find it here: https://github.com/christophherrmann/JenkinsFastlaneExample.git

If you have a private repository you need to create an ssh key for your jenkins and add it to github or provide your credentials if you are using HTTPS. Also consider creating a separate github user for your jenkins. Note that additional steps may be necessary if you are using some other version control software.

1. Start downloading Xcode from the Mac App Store if you haven’t already. We will need it soon.

2. Create a new job and choose Freestyle project.

3. To check out our project from the public Github repository we use the Jenkins git plugin which we installed earlier. Check Git in the section Source Code Management and enter the url of the public repository.

4. As soon as you hit save you’ll see a prompt telling you that the git command requires command line developer tools to be installed, so make sure you have Xcode and command line developer tools installed.

5. After installing command line tools select Build now to run your Jenkins job. If everything works there should be a blue dot next to the run once it is finished. (check out this plugin if you are more into green)

In the Jenkins Home directory under /Users/Shared/Jenkins/Home/workspace/[your job name] you should find your workspace checked out.

6. Install fastlane on your build server

Fastlane is a set of tools written in Ruby which helps you automate your Continuous Deployment process. Fastlane is created by Felix Krause and has become a very well maintained open source project with a great community.

1. You can either install fastlane directly (like I will now using RubyGems) or you can use a Gemfile as suggested in the fastlane docs https://docs.fastlane.tools/getting-started/ios/setup/ in order to define the used fastlane version.

2. You can simply install fastlane with sudo gem install fastlane. However if you install fastlane with sudo it will be installed in the /usr/bin directory, which is Apple’s System ruby you might not want to touch. I recommend to install the Ruby Version Manager which will install each Ruby version in a hidden folder in your home folder so you don’t affect the system Ruby. To do that check out this great installation guide.

3. Once you are done enter gem env into your terminal and see that there are gem paths other than your system ruby now:

/Users/Shared/Jenkins/.rvm/gems/ruby-2.4.0/bin
/Users/Shared/Jenkins/.rvm/gems/ruby-2.4.0@global/bin

4. Finally run gem install fastlane which will install fastlane tools and the necessary dependencies.

5. I recommend to install fastlane on your local development machine as well since you are going to try out different configurations until you have your final setup which will pollute your git and build history.

7. Integrate fastlane 🚀 into your project

1. In your project’s root folder run fastlane init which will start the fastlane setup. The setup asks for your Apple-ID and Password (which will be stored in your keychain) and offers to create an App-ID in the Member Center and an App in iTunes Connect. A folder fastlane is generated which contains two new files, the Appfile and the Fastfile. If you do not want to enter any credentials yet, you can manually add a Fastfile with the minimum required configuration and put it a folder called fastlane inside of your project folder.

fastlane_version "2.24.0"default_platform :iosplatform :ios do
lane :example do
puts("this is my first 🚀 lane")
end
end

2. Push the changes to your repository, then go to your Jenkins job and under Configure add an Execute Shell build step with the command fastlane example

3. Run your job and in the Console Output you should now see:

Example lane was successful

3a. When using RVM and RubyGems to install fastlane I encountered that the Jenkins job was not able to find fastlane. The solution for issue was to install the Jenkins RVM plugin and specify your Ruby version like this:

Secpify the Ruby version in an RVM-managed environment

Great, you are now able to check out your repository from Github and run fastlane!

In the second part of the tutorial will create and schedule a nighty build job that automatically downloads your developer certificate and provisioning profile from the Apple Developer Center, builds your app, increments the version number and uploads the resulting build to TestFlight.

Stay tuned for Part 2!

--

--

Christoph Herrmann

agile product engineer | cs graduate | ux/ui lover | sports enthusiast | wannabe singer/songwriter from munich/germany