Buildkite & Fastlane — the key to better sleep for iOS developers

David Frenkel
6 min readNov 7, 2018

Today, before a pull request for our iOS app can be merged in, two things must happen.

  1. Another developer must approve the changes
  2. CI must report back that the tests have passed

Before we started building the Swift version of the Tink app we didn’t have constraints like these in place. Most developers, when they start work on a new project, they have ambitions and goals they want to achieve.

Clean code. No warnings. Good test coverage. Master branch should always build.

One way for us to achieve this was to set up a continuous integration & continuous delivery system. When discussion around this started, we looked into what options we could use. We generally found two options — hosted and self-hosted solutions.

With hosted services (like Circle, Bitrise) we found that we had to hand over too much access to our GitHub repositories. As our app handles hundreds of thousands of customer’s financial data, security is paramount and we would prefer not do that.

You might notice as you read our engineering blog, we are big on security. It’s our and our customers’ finances at stake.

We opted to use a self-hosted solution instead. Other teams at Tink already used Buildkite for their CI/CD needs so it was obvious that using the same system would be beneficial for us in the long run. The knowledge to set it up, use it and fix any issues that might occur was already in the building. We just had to tap it.

Buildkite

We found an old 15" MacBook Pro with a dented body, malfunctioning video card and ancient specs in the office. It quickly became our first build machine. As we upgraded our laptops to the new USB-C MacBook Pros a second older MacBook Pro became available as well — our second build machine.

Setting up our build machine is fairly easy and only requires nine steps. These deal with the setup process for getting our builds running on the machine. We also have additional steps for setting up the machines, like setting up File Vault which we won’t go into detail here.

Our server room currently houses our two build machines.

It’s important to highlight the Trigger a build on all the lanes on the new build machine. That’s so the build folder is created by Buildkite and we can copy the keys file with secrets into it.

On Buildkite itself, we have 3 pipelines set up.

Check PR

The name says it all. Originally, it just built the pull request to verify that builds in master would not break. This actually allowed us to catch a lot of small issues; an accidentally added character; multiple merges not resolving correctly. It allowed us to keep our master branch always ready to release. Lately, we have also included unit tests and UI tests in this pipeline. All these tests are run on different iOS versions, allowing us to make sure our builds and tests pass everywhere and giving all of us a great reason to add even more tests.

Deploy Tink iOS to Hockeyapp

We work really quickly. Releasing to the App Store 2–3 times a month, features getting added daily, bugs being fixed around the clock. We needed to make sure that everything always works and looks amazing. To help us achieve this, anytime a pull request is merged in a new release is made available on HockeyApp. A number of our fellow Tinkers, our design team and us, the developers, all use our HockeyApp releases daily to try out new features and verify that everything still works before it gets before or users. This has become such a draw that all our new hires seek out the iOS team members to give them access to our HockeyApp builds.

Clean up Build Machine

A simple maintenance pipeline. It takes care of updating dependencies and removes the generated archives which add up to around 400Gb every 6 weeks per machine. This pipeline is designed to run once a week automatically. Setting it’s parallelism to two (in our case the number of build machines) and the block steps (>) it guarantees that all steps run on all our machines at the same time.

Fastlane

The other part of our solution was Fastlane. If you haven’t heard of, Fastlane is the automation tool for iOS projects. Part of what makes it popular is that it can be used locally as well as in a CI/CD environment. What that means is that you can run your lanes locally on your Mac, fine tune them as needed and then just install Fastlane on your build machine to trigger the same commands as before.

I’d like to focus on our 2 critical Buildkite pipelines and what Fastlane does when they are triggered.

Check PR

This pipeline starts with something we came up with. Usually you just want to run the tests and see if they pass or not, sometimes however that is not the case. We at Tink are design first, meaning that most projects get touched by our design team early on. This also means thats most of our features requires extensive design QA.

When working on larger projects the design might change multiple times therefore multiple test releases are required, so we came up with this solution.

What prcheck_or_build does is it checks the last commit message, and if it contains [hockey] it will also create a HockeyApp build from the PR besides running tests. This takes the toll off the developer to make test builds for our design team.

Otherwise our testing strategy is pretty simple. We run all the tests on an iPhone 7 iOS 11.4 simulator and an iPhone X simulator running the most recent iOS version. This gives us a good iOS and screen size coverage, but we are thinking about expanding this in both ways.

Deploy Tink iOS to Hockeyapp

This is the same lane called when we include [hockey] in our commit message. It’s also called when a PR gets merged in. After some tinkering this is the logic we settled on.

Importantly we can pass in options, so we can set a build number manually or default to the number of commits. The number of commits is a great way to guarantee that every release will have a new larger number. This allowed us to just say to our colleagues to always download the one with the largest number. Easy!

Our HockeyApp settings specify that we don’t notify all our test users when we release a new version as we can have up to 5 releases a day.

What’s next?

We’re already thinking about the next steps. The current project is to also automate App Store releases. In a similar fashion as when we release builds from a PR, we want to be able to trigger an App Store release. This is currently work in progress but we hope to roll it out in the next couple of weeks.

The long term goal is to move as much of the automate-able features to our build machines. Part of this is just finding what’s obviously doable and writing a lane for it. Overall, adding Buildkite into our workflow helped immensely and has allowed us to sleep better at night. The “is master releasable” worry disappeared from our minds and now we’re working on automating even more of our flows.

--

--