iOS CI/CD Integration using Gitlab CI and Fastlane


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.

Why Gitlab CI/CD?

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.

Gitlab Vs Jenkins?

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.

Why Fastlane?

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”

Setting up Gitlab CI in Mac

Setting up your project in Gitlab

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.

Note: You may end up with some error like “fatal – remote origin already exists” incase you are pushing your existing repo into gitlab. Use the below commands.
git remote rm origin
git remote add origin {$GITLAB_REPO_URL}.git
git add .
git commit
git push origin master

Installing GitLab Runner in MacOS

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.

Steps for Manual Runner Installation:

  1. Download the binary for your system:
  2. sudo curl --output /usr/local/bin/gitlab-runner 
    https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64
    
  3. Give it permissions to execute:
  4. sudo chmod +x /usr/local/bin/gitlab-runner
    
    Note: The rest of commands to be executed as the user who will run the Runner.(This is a limitation on macOS)
  5. Install the Runner as service and start it:
  6. cd ~
    gitlab-runner install
    gitlab-runner start
    

Steps for Registering a Runner:

  1. To register a Runner under macOS, run the below command first.
  2. gitlab-runner register
  3. Enter your GitLab instance URL when prompted in the next step.
  4. Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
    https://gitlab.com
    
  5. Enter the token you obtained to register the Runner:
  6. Please enter the gitlab-ci token for this runner
    xxx
    
    steps for register in gitlab
  7. Enter a description for the Runner, you can change this later in GitLab’s UI:
  8. Please enter the gitlab-ci description for this runner
    Local Runner
    
  9. Enter the tags associated with the Runner,you can change this later in GitLab’s UI:
  10. Please enter the gitlab-ci tags for this runner (comma separated):
    ios,another-tag
    
  11. Enter the tags associated with the Runner,you can change this later in GitLab’s UI:
  12. 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.

git-runnner-setup

Adding Our .gitlab.yml:

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.

Installing Fastlane in Mac

Fastlane setup is the crucial step in the whole process since it is the backbone of the deployment process. To install Fastlane in your system, please go through the below steps: Install the latest Xcode command line tools:
sudo gem install fastlane -NV
Install fastlane using
# 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:

1. fastlane/Appfile

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

fastlane/Fastfile

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

fastlane/Gymfile

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)

Connecting the Dots for Code signing using fastlane match

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.

And it’s finally ready
There are some special environment variables we need to set to avoid the jobs failing due to 2FA from Apple that were made mandatory recently.
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.

Conclusion

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.

Comments

Popular posts from this blog

Cách đăng nhập VPS bằng SSH trên MAC OS

Cách kiểm tra Website trên VPS sống hay chết

How to Install and Configure Nginx on CentOS 7