Many macOS apps like SourceTree are distributed outside of the Mac App Store and provide in-app updates via a popular open source framework – Sparkle. Using Sparkle, SourceTree pushes out updates to all users simultaneously whenever the
file is updated. While suitable for its intended purpose, these days many web services favor rolling out updates to groups of users in an incremental fashion, providing a safety valve for issues not found during testing or that crop up unexpectedly. Smoother releases were something our team wanted to implement in order to minimize impact these issues can have on the entire user base. The team explored options and ultimately decided to build our own utilizing Sparkle and fastlane, and we’re proud to announce the open sourcing of the code that progressively rolls out new updates for SourceTree.
What’s in the box
From the beginning we sought to have a minimal footprint for these changes, delivering the functionality we wanted with minimal disruption. Each component is easily digestible and ready to be tweaked for your needs. While written in Objective-C it works just as well in Swift via bridging – in fact, the demo app and all unit tests are written purely in Swift!
- PRGUpdateHelper – the primary class encapsulating randomized group management logic
- PRGGroupPercentageTransformer – simple transformer for mapping group numbers → logical percentages
- NSString+PRGHashing – simple category for generating a SHA1 hash
- ProgressiveUpdater (demo app) – a small app that demonstrates how to use the class and visually verify results
Once the client was aware that multiple feeds were available we needed to make sure the appropriate feeds were actually there. We were already using the equally well-known toolset, fastlane, for distributing our builds (along with several other tasks) so it was natural to take advantage of its richness.
This project includes a distilled version of our distribution logic in the Fastfile. Default lanes such as alpha and beta generate builds tailored to those updates and there’s now one called custom which provides one-off builds for testing that disable updating. The star of the show is the update lane which takes a percentage and builds the appropriate deploy artifacts for uploading to your server. When brought together these lanes make it efficient to manage testing across a range of options and ensures a smooth rollout to your users with minimal fuss.
Airbags aren’t optional
We implemented phased releases in SourceTree because of substantial, potentially disruptive changes that were underway in the 2.4 release. We added OAuth 2 authentication and an SSH Helper to make setup simple and easy, but complicated challenges around topics such as these have the potential to create problems despite good intentions. We released 2.3.2 in late October with the phased release functionality baked in and, in early December, we started rolling out 2.4 to an increasingly large group of users based on the timeline we discussed previously.
Is it working? Absolutely. We’ve had a manageable flow of reports coming in through our various support and bug report channels along with monitoring comments on Twitter and elsewhere to follow up with users encountering problems. These reports have been invaluable in hardening 2.4 for general consumption. Less than 25% of users have been offered the update, and with the telemetry received so far we’ve shipped at least 5 builds with a lot of reliability, usability, and functionality improvements that traditionally would have necessitated one or more rapid dot releases. Rather than cause a large amount of churn for everyone, we’ve now got an additional airbag in place beyond our Trusters Testers beta group that provides a bit more peace of mind for users and breathing room for us.
In the end we hope others will benefit from having these resources at their disposal. If you’re updating your app outside of the Mac App Store you should definitely check it out. There’s a public Git repo available via our Atlassian Labs group on Bitbucket that’s a quick clone away, and it’s the same code used in SourceTree today. We encourage you to file bug reports and feature requests via the repository’s public issue tracker and pull requests are always welcome!