Painless Automated iOS Builds with fastlane and Buildkite

By Doug Suriano

Here at HotelTonight, we use HockeyApp alongside an Apple Enterprise Distribution account to send internal betas around the company. We like HockeyApp because of its flexibility. We are often developing simultaneous features and have to generate builds for QA, Designers, Product Managers, Platform Engineers, and other departments throughout our company. Being able to make builds easily and quickly greatly increases our productivity.

However in the past, automating this process was painful. While many CI services do a fantastic job running test suites, uploading builds to HockeyApp (or another distribution service) always seems to be a frustrating and time-wasting experience.

Thankfully we found two awesome tools to overcome this complexity:

By switching to fastlane + Buildkite, we were able to simplify our build process to just 2 simple Ruby function calls and a 2 line shell script.

Let’s show you how to do it for your own project.

Part 1 - Setting up fastlane

To install fastlane, fire up your terminal and type:

$ sudo gem install fastlane --verbose

After the gem is installed, run the fastlane init command inside your project’s directory:

$ cd path/to/xcode/project
$ fastlane init

After a quick setup process this will create a fastlane/ directory inside your project. Inside that directory lives the Fastfile. This is fastlane’s equivalent of CocoaPods’s Podfile; all the magic happens here. Like Podfile, the Fastfile is a Ruby file so you can easily do some sophisticated things.

fastlane allows you to describe lanes, which represent different build actions. We are going to create a lane for our development build and upload it to HockeyApp. Open the Fastfile in your favorite text editor and add the following lane:

desc "Builds development target and uploads to HockeyApp"
lane :development do
    gym(
      workspace: "HotelTonight.xcworkspace",
      configuration: "Release",
      scheme: "development",
      silent: true,
      clean: true,
      export_method: "enterprise"
    )

    if ENV['BUILDKITE_BRANCH'].nil? || ENV['BUILDKITE_BRANCH'].empty?
      branch_name = git_branch
    else
      branch_name = ENV['BUILDKITE_BRANCH']
    end

    hockey(
      api_token: HOCKEY_API_TOKEN,
      public_identifier: HOCKEY_APP_ID,
      notes: "Changelog",
      notify: '0',
      notes:git_branch + ' (Uploaded via fastlane).'
    )
  end

The above lane uses gym1 to build our development scheme, archive it, and then export our app for enterprise distribution. Then, it uses fastlane’s HockeyApp integration2 to upload our build to archive.

Let’s give our lane a shot. Go back to terminal and type:

$ cd path/to/xcode/project
$ fastlane development

fastlane should build you app, then upload it to HockeyApp, reducing what is typically a multiple step process to one easy command. Now let’s automate this.

Part 2 - Setting up Buildkite

Unlike other hosted CI services, Buildkite uses Agents you set up and run on your own machines. What makes this nice for generating iOS builds is if your local fastlane command runs, then Buildkite’s agent will work. It’s the best of both worlds: an easy to use web interface you can access from anywhere and the ability to quickly debug any build issues locally. Goodbye complicated and hard-to-debug post-build hook shell scripts.

So let’s get Buildkite building. First step: head over to Buildkite’s signup page and create an account. After you have an account, install the Buildkite agent on the Mac being used as build server via Homebrew:

$ brew tap buildkite/buildkite
$ brew install --token='INSERT-YOUR-AGENT-TOKEN-HERE' buildkite-agent

Follow the instructions after installing to enable the Buildkite agent on startup.

Next, we need to create a script that our agent will use to make builds:

$ cd path/to/xcode/directory
$ touch buildkite.sh

Now open buildkite.sh with your favorite text editor. Now just type the fastlane lane command (or commands) you wish to run on each build.

#!/usr/bin/env bash

fastlane development

Now, go to your Buildkite Dashboard. Click on the Create Project Button. First add your project name and the git address of your repo:

Create Project

Then, click the Add Step button and select Run Script:

Add Step

Next, fill in the information about the script. Give the step a good name, then type the name of the script (buildkite.sh) in the Command text field.

Add Script

Notice above you need to add the following environment variables in order for fastlane to work:

LANG=en_US.UTF-8
LANGUAGE=en_US.UTF-8
LC_ALL=en_US.UTF-8

If you want to limit which branches are built, you can specify those in the Branch Filtering field. At HotelTonight, our main working branch is called develop, and our feature branches are prefixed with develop_ (so develop_MyAwesomeNewFeature). Buildkite allows us to use wildcards, so develop develop_* matches all of our branches we want built automatically. You shoud adjust this to fit your team’s git policy.

Buildkite will then prompt you to add a webhook to your GitHub project, then you are good to go! Simply push to Github, and Buildkite will kick off your build and upload it to HockeyApp.

The iOS team here at HT thinks that using fastlane + Buildkite is a simple and powerful solution for automating builds for iOS. With this switch we have dramatically sped up our build making process3. The reception in the office to our new system has been extremely positive. We are excited to expand our use of both fastlane and Buildkite to further automate more parts of our development process.

Let us know what you think!

Links

Footnotes

  1. You can easily find all the parameters for gym right here
  2. If you have mutliple HockeyApp apps on your account then set your public_identifer to HockeyApp’s AppId, otherwise you don’t need to include public_identifer.
  3. Our old CI system typically took 25+ minutes to make 1 build and upload it to HockeyApp.
Written by Doug Suriano

Read more posts by Doug, and follow Doug on Twitter.

Interested in building something great?

Join us in building the worlds most loved hotel app.
View our open engineering positions.