This blog details about the process of setting up CI/CD pipeline for iOS mobile apps using Gitlab CI and fastlane. This would be hugely beneficial for developers who are currently using Gitlab as a code repository for their projects.
Nevertheless, the steps detailed with fastlane can be used to collaborate with almost any CI/CD tool of your choice that is currently available in the market.
One of the major benefits of using Gitlab CI/CD is that you are freed from the cumbersome process of creating workflows using a lot of third party plugins and tools.
Why use some other third-party tools when you can play around with in-built tools which just a few clicks away from your source code repository.
One caveat not to be concealed is that if you are a person who loves GUI and wary of command line, then this might be a little difficult for you.
Gitlab CI/CD can be ideal for small to mid-sized development teams, especially of startups and blitzscaling companies. It proves to be economical to use compared to CI tools in the market and simple to set up relatively in a shorter period of time.
The process to be followed by is obvious to the developers and are seldom done by the Devops team.
Gitlab CI/CD can be swiftly made up and running in your own dedicated systems compared to docker based CI tools that have a lot of dependency software to be installed on the first-go.
With GitLab CI, you can set up your own runner with all dependencies pre-installed, and jobs could be executed really fast and consequently the system would be clocking improved efficiency and reliability.
Gitlab CI tool can also prove to be useful for big development teams that maintain hundreds of CI pipelines in terms of cost and security.
First, most of the CI tools are not cost effective when it comes to large number of CI pipelines (e.g. Travis CI starts at $129/month minimum), and the ones that provide free services have limited functionalities.
In the security front, you need not part with your SSH keys and sensitive data as you can use environment variables to set and access them which is one of the best practices recommended in the domain of Devops.
Jenkins is one of the most popular self-managed open source build automation and CI/CD developer tool in the world. It derives it’s incredible flexibility from incorporating capabilities from it’s hundreds of available plugins, enabling it to support building, deploying and automating any project.
One of the major weaknesses of Jenkins to be noticed is extending the native functionality of Jenkins is done through plugins. Plugins are expensive to maintain, secure, and upgrade.
However, GitLab is a complete DevOps platform, delivered as a single application. It provides a seamless workflow between SCM & CI and no third-party plugin assembly is required.
Jenkins users frequently experience service instability from running bigger workloads with a large number of plugins.
In sharp contrast, GitLab as a single application, decreases toolchain downtime and eliminates error-prone integrations. This allows teams to increase agility so they can deliver apps faster.
Plugins are only part of the problem. Jenkins requires dedicated resources, admins, and maintenance – increasing the total cost of ownership.
But, on the contrary, GitLab requires fewer steps to deploy code and significantly reduces the software development cycle time.
Developers can spend more time writing code and less time maintaining the toolchain.
Fastlane is the easiest way to automate beta deployments and releases for your iOS and Android apps. 🚀 It handles all tedious tasks, like generating screenshots, dealing with code signing, and releasing your application.
Fastlane has been an amazing tool to dabble for developers in order to automate their deployment workflows and easy to integrate in applications by virtue of its clear documentation. Fastlane devours the need of granting specific access to third party tools for automating workflows since it completely runs on your machine and you have entire control over your data.
Fastlane also allows users to extend functionalities for their custom needs through plugins and not dependent on third party vendors.
Fastlane saves a lot of time for the developers and anybody can start deploying an app from any machine with a single line command making the process independent of developers and machines.Especially in case of iOS app deployment, it helps a hell lot regarding code signing issues using match.
“Too much talking. Let’s get some hands-on with Gitlab Runner & Fastlane”
If you are currently maintaining your project in Gitlab, feel free to skip this section and move on to the next one.
Lest, if you are maintaining the project in other SCM tools, please clone your remote repository in the local machine and follow the below commands to push it a new gitlab repo.
First, initialise a new git repo with/without README file in Gitlab and note down the repo URL.
git remote rm origin git remote add origin {$GITLAB_REPO_URL}.git git add . git commit git push origin master
Now with Gitlab setup finished, navigate to “Settings->CI/CD”  under your project. You’ll see “Runners” section from where the jobs are run once the pipeline triggers a specific job.
You can use the shared runners from Gitlab.com or configure your own specific runner to avoid contingencies since shared runners can be preemptively stopped by Gitlab servers sometimes and becomes unavailable for jobs.
In case of specific runners for the case iOS Deployments, you can install them in local Mac machines/Mac servers(MacStadium). Below are the steps to configure runners in macOS and OS X.
sudo curl --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64
sudo chmod +x /usr/local/bin/gitlab-runnerNote: The rest of commands to be executed as the user who will run the Runner.(This is a limitation on macOS)
cd ~ gitlab-runner install gitlab-runner start
gitlab-runner register
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com ) https://gitlab.com
Please enter the gitlab-ci token for this runner xxx
Please enter the gitlab-ci description for this runner Local Runner
Please enter the gitlab-ci tags for this runner (comma separated): ios,another-tag
Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell: shell
If everything goes well, you should see activated runners for your project like in the below image.
Now, it’s time to add a sort of config file for running jobs in the GitLab pipelines that triggers on every commit to a particular repo.
The best practices for git-branching model can be referred from this article. For the sake of simplicity, let us consider only our “master” branch. We assume that any commit to master repo need to trigger a job in the CI pipeline.
Let us configure the gitlab.yml file which needs to be placed in the root of the repo.Â
stages: - test_flight variables: LC_ALL: "en_US.UTF-8" LANG: "en_US.UTF-8" before_script: - gem install bundler - pod install test_flight_build: dependencies: [] stage: test_flight artifacts: paths: - fastlane/logs script: - fastlane beta tags: - ios only: - master
This configuration fires a job in the CI pipeline of “master” branch alone that executes the job with a stage ”test_flight” which in turn runs the script “fastlane beta” with the given environment variables on the runner “tagged as ios”.
The specified “before script” as the name suggests is executed before the job and the artifacts available in the specified path once the job is completed successfully.
sudo gem install fastlane -NV
# Using RubyGems sudo gem install fastlane -NV
# Alternatively using Homebrew brew cask install fastlane
To start using fastlane in your project, you’ll need to run fastlane init from your project directory in command line.
fastlane will ask you for some basic configuration and then create a folder called fastlane in your project which will contain mainly two files:
This file is straightforward, so you just want to check to make sure that the Apple ID and app ID that you set up earlier are correct.
app_identifier("APP IDENTIFIER") # The bundle identifier of your app apple_id("APPLE ID") # Your Apple email address
The Fastfile defines the build steps. Since we’re using a lot of the built-in capability of fastlane this is really straightforward. We create a single lane which increments build number,gets certificates, builds, and uploads the new build to TestFlight. Of course, you may want to split these out into different jobs depending on your use case. Each of these steps, get_certificates, get_provisioning_profile,match, gym, and upload_to_testflight are pre-bundled actions already included with fastlane.
get_certificates and get_provisioning_profile are actions associated with the cert and sigh approach to codesigning; if you’re using match,you may need to update this by commenting get_certificates and get_provisioning_profile.
default_platform(:ios) platform :ios do desc "Build the application" lane :beta do increment_build_number( build_number: latest_testflight_build_number + 1, xcodeproj: "${PROJECT_NAME}.xcodeproj" ) get_certificates get_provisioning_profile # match(type: "appstore",read_only: true) gym upload_to_testflight end end
This file is optional, but created manually in order to override the default output directory and place the output in the current folder. This makes things a bit easier for CI. You can read more about gym
and its options in the gym documentation.
output_directory("./") clean(true) scheme("${PROJECT_NAME}") workspace("${PROJECT_NAME}.xcworkspace") include_bitcode(true)
Code Signing is the most important aspect of iOS app deployment, we as iOS developers know the pain of handling code signing issues.
“match” creates all required certificates & provisioning profiles and stores them in a separate git repository. Every team member with access to the repo can use those credentials for code signing. match also automatically repairs broken and expired credentials. It’s the easiest way to share signing credentials across team.
fastlane match improves drastically the code signing process,even for small teams as it is the implementation of code signing concept.
For initialising match afresh in your project, follow these steps. One caveat, is that we need to generate fresh provisioning profiles and certificates.Â
But it is a show stop for anyone trying to use it on existing projects. But there is a way to trick fastlane match to use your existing certificates. Try to go through the steps in this article.
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD
and FASTLANE_SESSION
In order to authenticate against the App Store for the TestFlight upload, fastlane must be able to authenticate. In order to do this, you need to create an app-specific password to be used by CI. You can read more about this process in this documentation.
FASTLANE_USER
and FASTLANE_PASSWORD
In order for cert and sigh to be able to fetch the provisioning profile and certificates on demand, the FASTLANE_USER
and FASTLANE_PASSWORD
variables must be set. You can read more about this here. You may not need these if you are using some other approach to signing.
Ah!! Kudos to you!!! We have finally configured our own CI/CD workflow with GitLab CI/CD and Fastlane as our primary tools.
Thanks for reading this article. Hope it proves to be helpful for you for configuring a robust CI/CD workflow for automating your iOS app deployment process.