At Authentiq we have been optimising the process by which we develop, build, test, and publish our mobile apps for iOS and Android. In this post we share our current workflow, a marriage of Gitflow, NeverCode, Fabric and TestFlight.
Like many mobile app developers, we started out with our source code in a hosted Git repository like GitHub or GitLab, building the apps in the respective IDE—XCode and Android Studio—and then manually distributing test versions to both internal and external testers. When we had a good version we published it on the spot. Presto!
Obviously there are several issues with this approach, which we identified as follows.
Parallel feature work
The simplistic flow did work reasonably well for a linear, master-only, development model, where commits are always in order. However, such a model has disadvantages, and our process broke down entirely as soon as we had multiple developers and several features being worked on and tested in parallel.
One benefit of Continuous Integration is that it relieves the developer from the mental burden of making sure that all tests pass before publishing a release. But not being told instantly what change “broke the build” becomes a critical problem once the team grows, or even when features are just developed asynchronously. Test automation is an essential ingredient for a mobile development workflow.
If rolling out updates to testers is laborious, then the feedback cycle isn’t optimal either. If publishing releases to the app stores is hard work, then releases are just going to fall through the cracks since chances are the process is just abandoned while waiting for one of the steps. Our simplistic process didn’t automate either of these at first, and later only test releases via Crashlytics.
Test group management
We didn’t have an easy way to manage groups of testers. Collecting device identifiers of the testers, and adding them to the Apple Developer Dashboard and the ad hoc provisioning profile was clumsy. Moreover, distributing
.apk files to testers, especially for iOS, wasn’t ideal (although this became much easier when Apple acquired TestFlight).
After identifying these problems, we set out to find a more elegant, more scalable workflow, backed by tools and practices accepted by the industry. We wanted our new workflow to do at least the following:
- Build upon, and integrate with Git;
- Run tests after every commit;
- Make new builds available to testers automatically;
- Support parallel feature development;
- Automate publishing to the app stores;
- Have a process to roll out hotfixes;
- Post build notifications to Slack.
Our workflow is entirely driven off of Git, and we find that Gitflow maps wonderfully on to our desired release process. The following mapping of Git branches to releases is used:
||Continuous feature testing||Internal testers|
||Continuous bugfix testing||Internal testers|
||Continuous integration testing||Internal testers|
||Release candidates||External testers|
||Hotfix release candidates||External testers|
||Latest public release||Generally available|
Next, we used NeverCode as the glue between Git, Crashlytics, TestFlight, and the app stores. It picks up changes from the various branches, runs unit and UI tests, and sends build artefacts to either Crashlytics or one of the app stores, as shown in the following diagram.
As a developer you start new work by creating a
git flow feature start make-a-space-rocket
Publishing feature branches to the central repository will continuously trigger a build pipeline on NeverCode. This will build and test the app, and make a new release available to the internal test group with the branch name visible in the Crashlytics artefact, e.g.
git flow feature publish make-a-space-rocket
Build notifications are posted in the corresponding channel in Slack, making this is a great way to get quick feedback from a select group of internal users.
Internal integration testing
Once a feature is complete, the developer merges it into the
git flow feature finish make-a-space-rocket
Doing so will build and publish another internal artefact to Crashlytics, this time built from the
develop branch and thus integrating all unreleased features. To easily distinguish it from the feature branches in Crashlytics we simply append a
-develop label to its name.
As builds from the
develop branch are in fact candidates for the next public app release we use them regularly for internal beta testing.
External release candidates
Periodically, and once integration tests were successful, we initiate the public release cycle by creating a release branch for the desired version. We use semantic versioning and reserve the patch level for hotfixes. Therefore a new release always has a patch level of zero, as follows:
git flow release start 1.3.0
Release branches allow us to make final adjustments to the code and set a version number.
Pushing a release branch to the central repository will trigger the public release pipeline on NeverCode, which will cause a new version of the app be made available immediately to all registered beta users for Android and iOS respectively.
git flow release publish 1.3.0
We keep this branch open during the entire external testing phase, which enables us to incorporate feedback from external testers swiftly without interfering with the normal feature development workflow. Note that we do try to minimise commits (or rather pushes) to this branch, so that testers don’t get overwhelmed by a flurry of beta releases.
The only thing left now, is to release the app for review in the corresponding app store. We keep the release branch open during the review phase as well, in case any last minute change comes in. A commit will automatically trigger a new external release candidate, which we can easily advance to the review stage again.
Once the new app version is approved, we release it in the app store and finally merge the release branch into the master and develop branches with the following command.
git flow release finish 1.3.0
This makes sure that all last minute fixes for the release make their way into the version control trunks.
Lastly, serious or time sensitive bug fixes are rolled out using Gitflow as well. The process is similar to a normal release, but for a hotfix we increment the version patch level each time.
git flow hotfix start 1.3.1
Pushing a hotfix will immediately generate a new external beta release, which can be advanced to app store review straight away after testing.
git flow hotfix publish 1.3.1
Once the app has passed review and is ready for release we merge the hotfix into
git flow hotfix finish 1.3.1
We’ve discussed Gitflow already, so let’s have a look at how NeverCode glues everything together for us. We define a project for each platform: Android and iOS.
Within each project we need two workflows: One for builds from the development branches to Crashlytics; the other from the release branches to the corresponding app store.
Within each workflow there are two important screens: Build, which defines what branches to monitor, and Publishing, which controls how and where the build artefact gets published.
On the build configuration screen for the development workflow, set the Main Branch to “develop”, while you set the Watched branch pattern to a special pattern that matches feature and bugfix branches:
On the other hand, on the build configuration screen for the release workflow, set the Main Branch to “master”, while you set the Watched branch pattern to a pattern that matches release and hotfix branches:
Next, on the Publishing screen in the workflow configuration, select Publish to Beta by Crashlytics in the development workflow, while enabling Publish to TestFlight Beta Testing in iTunes Connect in the release workflow. Do the same for the Android build, but selecting Publish to Google Play in the release workflow.
Watch your builds being published…
In our workflow a mobile developer only needs to interact with Git, and we use NeverCode as the automation pipeline to trigger builds off a Git branch and ship the artefacts to the appropriate release channel: Crashlytics, TestFlight or Play Store.
As a bonus, we elegantly get hotfixes for free, instead of requiring separate procedures.
Also, don’t forget to subscribe to our newsletter to keep up-to-date with everything passwordless.