Skip to content

dev-iayush27/CICDPipeline

Repository files navigation

CI/CD Pipeline for iOS

CI Pipeline setup

We want to automatically run Unit Tests for each pull request.

Workflow process diagramm

Create Xcode project and open it in VS code for further setup.

Workflow initial setup

Create .github/workflows/pullRequest.yml file. I will just copy and paste the following to save time, but we'll go over everything:

name: Pull Request

on:
  pull_request:
    branches:
      - main
  workflow_dispatch:

jobs:
  test:
    runs-on: macos-14.1
    steps:
      - uses: actions/checkout@v2

      - name: Cancel Previous Runs
        uses: styfle/cancel-workflow-action@0.9.1
        with:
          access_token: ${{ github.token }}

      - uses: maxim-lobanov/setup-xcode@v1
        with:
          xcode-version: latest-stable

      - uses: ruby/setup-ruby@v1

      - name: Install Bundler
        run: gem install bundler

      - name: Install gems
        run: bundle install

      - name: Swift Packages Cache
        uses: actions/cache@v2
        id: cache
        with:
          path: |
            Build/SourcePackages
            Build/Build/Products
          key: ${{ runner.os }}-deps-v1-${{ hashFiles('BILDsolid.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}
          restore-keys: ${{ runner.os }}-deps-v1-

I won't go into detail, because each platform, in our case it's Github Actions, has it's own syntax, it's more important to understand the principles and overall those config files are usually very easy to understand.

on: We describe when we want to run the workflow, or what will trigger it. In out case it's pull request against develop branch. workflow_dispatch means that we want to be able to trigger the workflow manually on Github.

jobs: Now we actually start to describe what we want to do. We have the first and the only job called test (can be named anything else). runs-on: macos-14.1 - Self-explanatory.

steps: Each job can have many of them.

actions/checkout@v2 - pull the repository code to the machine that was given us for this run. We start with a clean state.

cancel-workflow-action - basically if we already running the same workflow from the same branch, we want to first cancel the old one, and only then start the new execution. We discard the result of the previous workflow.

We can actually pass values or variables as a parameters to the step with with: keyword.

access_token: ${{ github.token }}

You see, github.token is actually a variable here. How do we now that it's available? - Documentation.

setup-xcode@v1 - install xcode

ruby/setup-ruby@v1 - install ruby - we will need it later.

Please add .ruby-version file to the root with the following contents: 2.7.2

gem install bundler and bundle install are needed to install Bundler, that's needed to manage ruby dependencies (kind of like SPM) and install all the gems (kind of like packages) that include fastlane. We will define the Gemfile later. But essentially all this installs fastlane.

actions/cache@v2 - we want to cache SPM modules to not refetch them again and again.

That's it. Now we can push and see how it works, but the most important part is missing - the unit tests.

Fastlane

To run them we will use fastlane. Let's setup a simple fastlane project:

First of all we need to install fastlane locally, for it let's create a Gemfile (no extension) in the root folder:

source 'https://rubygems.org'

gem 'fastlane'

Now please install ruby and Rubygems, there is a high chance that you already have them on your machine.

gem install bundler

Now run bundle install - it will read the Gemfile and install or update fastlane.

Okay let's create the first fastlane file: Fastlane/Fastfile

fastlane_version '2.157'
default_platform :ios

platform :ios do
    
end

And now finally add unit tests lane:

platform :ios do
    desc 'Builds project and executes unit tests'
    lane :unit_test do |options|
      scan(
        clean: options[:clean],
        skip_package_dependencies_resolution: options[:skip_package_dependencies_resolution]
      )
    end
end

Now, obviously it's not all it takes to run the test. We want to specify the project and the scheme among other things. Let's create Fastlane/Scanfile:

# For more information about this configuration visit
# https://github.com/fastlane/scan#scanfile

workspace "CICDPipeline.xcodeproj/project.xcworkspace"
scheme "CICDPipeline"
sdk "iphonesimulator"
device "iPhone 15"
code_coverage true
xcargs '-parallelizeTargets'
prelaunch_simulator true
derived_data_path "Build/"

Most of it is self explanatory, everything else - just read docs if you wanna understand it.

Please create .gitignore to avoid committing build artefacts and cache:

Build

# fastlane
Fastlane/report.xml
Fastlane/test_output

Okay, let's test how the fastlane works locally. In the terminal, from the root folder of the project, run:

fastlane unit_test

You'll see the simulator running our tests! How exciting! Now we just have to do the same on the CI - Super easy!

Let's go back to our workflow file pullRequest.yml and finally add this at the end of the file:

      - name: Run Tests
        run: bundle exec fastlane unit_test

Now we actually make use of the cache and check if it's there, here's how:

      - name: Run Tests (No Cache)
        if: steps.setup.outputs.cache-hit != 'true'
        run: bundle exec fastlane unit_test
      
      - name: Run Tests (Cache)
        if: steps.setup.outputs.cache-hit == 'true'
        run: bundle exec fastlane unit_test skip_package_dependencies_resolution:true

Now let's actually see if it works

Push the code!

If you'll raise a pull request from your branch

Screenshot 2022-07-06 at 14 54 58

After a few minutes you'll see beautiful green mark!

Thanks!

About

CI/CD Pipeline for iOS

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published