Blog Post

Continuous Integration for Small iOS/macOS Teams

Illustration: Continuous Integration for Small iOS/macOS Teams

There are quite a few case studies out there highlighting how industry giants like Shopify and Pandora manage their Mac continuous integration (CI) fleets. However, it’s much more difficult to find good advice for smaller teams that can’t dedicate an entire team to CI management or aren’t willing to invest five-figure sums (or more) per year for their setup.

In this new series, we’re sharing our cost-efficient approach to macOS continuous integration. Make sure to check back so you don’t miss out on all the posts!

History and Early Experiments

In the early years of PSPDFKit, we experimented with Travis CI, BuddyBuild, and CircleCI. Unfortunately, all of these solutions ended up being too slow and inflexible for us.

Our codebase is large (1.5 MLOC), and compiling can take about 30 minutes. Most of the available virtualized hardware is simply not powerful enough to get results back within a reasonable amount of time. We consider 30 minutes the absolute maximum acceptable amount of time, but of course the faster, the better.

GitHub Actions, for example, specifies 2-core CPU and 7 GB of RAM, and 14 GB disk space. With such a configuration, a VM wouldn’t finish compiling in the usual 60-minute limit. We hit similar timeouts with BuddyBuild and, to a lesser degree, CircleCI.

Our Approach

This article is the beginning of a series; we’ll release articles about our approach in the coming weeks.

Testing Knowledge

We write about our approach to testing and CI occasionally, and while technology constantly evolves, many of the choices we made still work well for us today.

  • In the MacStadium panel about CI best practices for iOS and macOS app development, I discussed our approach to testing, virtualization, and hardware management alongside panelists from Aspyr Media and Pandora.

  • There’s nothing better than having someone automatically yell at you if your code might not be optimal. Learn how we’re using clang-tidy for linting, and how it can be integrated into your CI workflow.

  • Just as style guides and linters enforce code formatting rules, having similar rules around other forms of writing can help ensure quality and define a more consistent tone across communications. Learn how to add spellchecking to your tests.

  • Running UI tests on iOS with ludicrous speed is an approach that uses KIF (Keep It Functional), but many of the tricks here are useful no matter which UI testing framework you use.

  • To ensure we’re actually testing all the crucial code segments, we need a way to visualize what has been touched by our test code and what has not. This is where continuous iOS code coverage with Jenkins and Slather comes into play.

  • To increase code sharing, we decided to move all our code to a monorepo. Everything was great, except the time it took to run tests on a PR. Here’s how selective pull request testing can help.

  • We convert Xcode test runs to JUnit, the fast way, using a fastlane plugin — as opposed to xcpretty — for more reliable testing output.

Talk: Continuous Integration for the Rest of Us - Peter Steinberger

Our Founder Peter Steinberger gave a talk about this topic at iOS Conf Singapore 2021, the largest iOS developer conference in Southeast Asia.

Continued Reading

The next posts in this series will dive deeper into our approach to CI, including how we manage hardware, how we automate CI, and how we orchestrate our builds. Be sure to check them out!

Related Products
Share Post

Related Articles

Explore more
DEVELOPMENT  |  SwiftUI • iOS

SwiftUI In Production

RELEASES  |  iOS • Products

PSPDFKit 10.3 for iOS Adds Electronic Signatures and Instant Comments

TUTORIALS  |  iOS • Development • How To • PDF • Swift

Creating and Filling Forms Programmatically in Swift