The Japanese version of this blog post can be found here:
Hello, I'm Tadashi Nemoto from the Platform Engineering team(previously DevOps team).
In the last article, I introduced how to improve an API / Frontend deployment flow using GitHub Actions + GitLab Flow.
I also improved the continuous delivery process of an iOS app by using GitHub Actions, and I would like to introduce it in this article.
I believe this continuous delivery can be applied not only to iOS, but also to Android and other multi-platform frameworks such as Flutter.
- Adoption of Git Flow・Brief explanation of Git Flow
- Continuous Delivery of iOS using GitHub Actions + Fastlane
Adoption of Git Flow・Brief explanation of Git Flow
In the last article, I mentioned that we adopted GitLab Flow for our API / Frontend deployment flow and branching strategy.
However, I thought that GitLab Flow or GitHub Flow would be incompatible with our mobile release process because of the following factors:
- We need to update the version number for each release.
- A review from Apple / Google is needed for each release, so we cannot release all the time
On the other hand, some companies use trunk-based development as the release flow for mobile apps.
However, trunk-based development more suitable for relatively large-scale app development and deployment schedules, such as releasing once a week, and I thought that it did not match the current state of our mobile development.
For the above reasons, I chose Git Flow, for our mobile app deployment flow branching strategy.
To make the rest of this explanation easier to understand, let's take a brief look at Git Flow.
① Create a feature branch from the develop branch when you add a new feature. When its task and review are done, merge this to the develop branch.
② Create a release branch from the develop branch when it's ready for preparing the release.
③ After some checks and modifications on the release branch, merge this to the develop・master branches.
④ After merging the release branch to the master branch, add a tag and release to production (For mobile development, submit the app to Apple Store Connect)
⑤ If there are fatal bugs after release, hotfix release. First, create a hotfix release branch from the master branch.
⑥ When you have finished fixing and checking on the release branch for the hotfix and are ready to release, merge it into the master・develop branch and release it again to the production environment.
In the next section, I'll explain how we achieved continuous delivery within this Git Flow.
Continuous Delivery of iOS using GitHub Actions + Fastlane
Create release branch and Pull Requests
Release branches are often created manually, but in this case, I was able to automate the process by using GitHub Actions + Fastlane.
First of all, we want to use Semantic Versioning to specify the release version.
With Semantic Versioning, we can regularize the versioning of releases by a Major, Minor, and Patch version increase. (I won’t explain Semantic Versioning in-depth here, as it's already explained well on other websites).
Fastlane provides an Action called increment_version_number and it increments the version number bypassing parameters(Major, Minor, Patch).
And below Fastlane will do the followings:
- Increment the version number based on Semantic Versioning and commit files.
- Create a release branch and push to GitHub
- Create a Pull Request to the master and develop branches
Currently, increment_version_number only supports iOS, the below article describes how to increment version number automatically for Android.
Finally, we'll make this Fastlane run via GitHub Actions
There are several types of workflow triggers in GitHub Actions, but in this case, we will use workflow_dispatch, which can be triggered manually from the GitHub Action UI, since we want to be able to run at any time.
Also since workflow_dispatch also accepts arguments, we can pass Major or Minor for this upgrade (Patch is only used for hotfix releases, so we won't use it here).
By doing this, I was able to automate the process of updating the release version and creating release branches and pull requests by triggering the workflow by specifying Major or Minor in the GitHub Actions UI.
Merging two Pull Requests at the same time
In the previous step, two pull requests were automatically created from the release branch to the master・develop branches.
Then, as explained in section ③, when the release branch is ready to be released, you can merge it into the master・develop branches.
Of course, you can merge the two pull requests manually, but there is a possibility that you might forget to merge one of them.
To merge the two pull requests at the same time without forgetting, I created the following GitHub Actions workflow.
This workflow allows you to merge two pull requests for the develop and master branches at the same time if you add the label
release to the pull request.
Creating a Tag & GitHub Release, submit App Store Connect
When the release branch is merged into the develop・master branches and a new commit is made in the master branch, you can create a tag and release it to the production environment as described in ⑤ in Git Flow. In the case of iOS development, this is often the time to submit to App Store Connect.
Creating a Tag & GitHub Release triggered by a commit to the master branch can be automated with the following GitHub Actions.
We will also build and upload the release version of the app to App Store Connect at this time.
Here we are utilizing Fastlane's Deliver Action.
The Deliver Action allows you to not only upload to Apple Store Connect, but also upload metadata screenshots, submit, and automatically release after approval.
The above is the normal release flow.
In addition to the regular release flow, we will conduct a hotfix release if a serious bug is found after the release.
Follow the steps ⑤ and ⑥ to create a release branch for the hotfix from the master branch, and then merge it into the master/develop branch for release.
When we do a hotfix release, we follow Semantic Versioning and update only the Patch part (x.x.0 → x.x.1).
Then, in GitHub Actions, checkouts from the master branch create a release branch and Pull requests.
Then, after the fix and confirmation on the hotfix release branch is done, you can do the same thing as a normal release
- Add the label
releaseto the Pull Request and merge it into the master・develop branch.
- After the commit is made on the master branch, a Tag & GitHub Release is automatically created, and the release version app is submitted to App Store Connect.
【Optional】Distribute debug app (Firebase App Distribution)
Although not directly related to Git Flow, I will also briefly explain how to use GitHub Actions to distribute debug apps.
To check the behavior of the application before release, we often use the following services to distribute and check the debug version of the application.
You can automate the building and uploading of the debug version of your app using GitHub Actions.
With Git Flow, you can trigger it when you finish feature development on the feature branch and merge it into the develop branch, or when you commit to the release branch.
The workflow in GitHub Actions is as follows.
In the above workflow, we have a workflow_dispatch as a trigger, in addition to committing to a specific branch.
When you are developing a feature in ①, you may often find yourself in a situation where you don't want to merge it into the develop/release branch yet, but you want to build and distribute a specific feature branch.
You can specify the branch and trigger workflow in GitHub Actions page, using workflow_dispatch.
Finally, I'll summarize the steps I've taken so far in using GitHub Actions for iOS continuous delivery.
【Normal release flow】
Create a feature branch, merge it into the develop branch
When you are ready to prepare the next release, go to the GitHub Actions page and trigger the workflow for preparing the next release. You should choose the bump type parameter(major or minor).
GitHub Actions checks out the develop branch, bumps the version based on the parameter, creates a release branch, and creates Pull Requests to develop・master branches.
At this time, the debug version of the app will be built and distributed to Firebase App Distribution, so you can check its behavior with actual devices.
When it is time to release, Add the label
releaseto Pull Request and merge it into the develop・master branches at the same time.
Commits are made to the master branch, automatic Tag & GitHub Release creation, and submission to App Store Connect.
【Hotfix release flow】
- When you're ready to prepare a hotfix release, run the hotfix release preparation workflow from the GitHub Actions UI
- Update the release version (Patch), create a release branch, and create Pull Requests to the master・develop branch.
- Commit the bug fix to the above release branch.
- Each commit to the release branch automatically builds a debug version of the app and distributes it to Firebase App Distribution, so you can check how it works on an actual device.
- Once the fix is confirmed, Add the label
releaseto Pull Request and merge it into the develop and master branches at the same time.
- Commits are made to the master branch, and a Tag and GitHub Release are automatically created and submitted to App Store Connect.
This has allowed us to complete most of the work required for the release on GitHub! (Depending on how much of the work to Apple Store Connect is automated by Fastlane's Deliver action.)
While releases in mobile app development tend to be less frequent than API and front-end development, there is a lot of work that needs to be done for a release.
With this continuous delivery process, I hope to become:
- Able to release app improvements to the market with more agility
- More focused on product development itself
- Using Github Actions to Automate Our Release Process – Rebecca Franks - @riggaroo
The GitHub Actions workflow described in this article is based on the self-hosted runner, so there are some differences between it and the GitHub host runner.
Some of GitHub Actions workflows use Personal Access Token to trigger other workflows.