CI on iOS: An Epic
In today's post Fábio Oliveira, iOS Engineer, details how his team moved from manual to automated Continuous Integration for mobile app development.
First approach at an automated Continuous Integration
At GetYourGuide, we’ve been talking for a while now about how we build and deploy our apps; the curious thing is, until recently, we actually didn’t have a Continuous Integration setup that built and deployed in an automated way. For those who are unfamiliar, Continuous Integration (CI), as defined by ThoughtWorks, is “a development practice that requires developers to integrate code into a shared repository several times a day. Each check-in is then verified by an automated build, allowing teams to detect problems early.”
We created our first CI setup with the help of Travis.ci 3 years ago, initially with a collection of shell scripts and then with fastlane scripts that built and pushed test versions to HockeyApp. However, as the team went through some transformations, the benefit of having a constant flow of builds no longer outweighed the cost of maintaining the CI scripts with an environment that was difficult to reproduce locally. Sometime in 2016 we decided to drop the use of Travis.ci and instead kept building manually from our machines, using some fastlane lanes.
Living without an automated CI
Back then, we were often building and merging with only a few stakeholders involved in the testing, so we’d mostly use our store lane to push release candidates to Testflight. With the extra time we gained from not having to maintain other lanes, and the help of all the amazing actions that have been added to fastlane throughout the years, we wrote lanes to help us with the many steps required for our release. This included importing localized assets into the project, submitting release notes and all other localized copy to iTunes Connect, running tests, updating all the certificates, and more.
This changed in 2017 when our team grew and we needed to provide stakeholders with test builds they could install on their own device more frequently. However, the task of automating the CI landed in the darkest and dustiest corner of every technology company: the backlog!
Although it was becoming more and more taxing, with each engineer taking turns in deploying test builds and struggling to find the time to do so, we were still able to take some small steps towards improvement:
Given our limited experience with external services, we decided to secure an iOS-compatible macOS machine. The laptop exclusively ran the tasks needed to have a new build. We started with this step since it gave us physical access to the machine.
We started simplifying our signing process through the use of fastlane match.
We set up the dedicated machine to run our fastlane scripts.
And that was it.
For some time.
A new approach
As our team continued to grow, we started tackling some bigger projects. We also had fresh pairs of eyes looking at the app, so the backlog started growing faster.
This meant bad luck for the smaller tasks in the backlog. We didn’t have the time to tackle these tasks, some of which we might have been particularly passionate about or could have been a quick win for the team.
To remedy this situation, we introduced the Focus Day.
During a Focus Day we are free to work on a chosen project about which the team feels passionate. Prior to the day, we meet, seek feedback on our ideas, select one idea to focus on. Then, during the focus day itself, we work without distractions from other ongoing projects. Read our blog post about Focus Days to learn more!
On our first Focus Day, even though I was eager for an opportunity to work on some new technologies I believed could help our customers, I decided to spend the day working to improve our CI process through automation. The pain of not having this automated process was so great that it outweighed anything else I could have built in a single day.
For the task to have been a success it needed to fit the following parameters:
A job was triggered once a commit was pushed to the master branch of our repository
The job generated three builds:
A build to HockeyApp with no real payment and no tracking;
A build to HockeyApp with real payments but no tracking;
A production build to TestFlight.
Received some kind of reporting at the end of the successful build or upon error
How I did it:
Verified that our build machine could still build different lanes
Researched options & decided to go for Jenkins since the Android CI was already running there and we could use this expertise in case something went awry
Installed Jenkins and made it run
Created a single lane that could be called from the Jenkins job and built everything we needed
Created a Jenkins project that checked our repository every 15 minutes for a new commit
Used ‘slack’ fastlane action to report success or failure in a Slack channel created to keep track of the automated builds
Dotted the i’s and crossed the t’s
There were some hiccups, of course: signing kept breaking despite our use of fastlane match and I had to change some Java reconfiguration to install Jenkins. But, more importantly, most of what we wanted to achieve was achieved on the first day and the rest of the project was tackled in short iterations in the following days. Within a week, we finally had a working automated CI environment!
Not much has changed since then, which says a lot about how little there was to do.
The few changes we made have been smooth: adding a test phase before everything runs, improving the way we calculate our build numbers, adding another job to be triggered when we push something to a hotfix branch running in parallel to our master, and we’re still constantly looking for ways to improve.
This wouldn’t have been possible without the Focus Day. We were able to make this big change only because we could stop and focus on one single thing for one single day. A day normally may not sound like much, but it can be all it takes to transform something.
We also benefited in ways we didn’t anticipate (like when we rebranded the whole app, and our build machine was able to push new builds to our stakeholders with every little change).
Do you have something that could improve your process?
Can you take a small step today towards this improvement?
(btw, you can replace “process” with anything you want!)