Continuous Integration in iOS Apps using Bitrise

Featured with Bitrise API to export test results URL from the build’s artifacts

Dogan Altinbas
Plus Minus One
10 min readDec 28, 2020

--

In this article, I will focus on creating a workflow in Bitrise to automate the process of running the unit tests. Additionally, I will show you how to send a message to the Slack channel that the CI build is successful or failed. Last but not least, you will learn how to export test results URL.

Problem Statement and Proposed Solution

In PlusMinusOne, we develop, maintain, and deploy many iOS applications. As we have more apps we require a reliable delivery process for each project. One way to achieve this is to write unit tests. Once we add a new feature to our projects, we also write unit tests to make sure that even the smallest piece of code in the new feature works properly and does not introduce any failures.

Until recently, we were running those written tests manually. In other words, before we’d opened a pull request to developers in our team, we had always run all the tests written up to that time and make sure that it works correctly.

As the number of written unit tests is increased, it takes a lot of time to run them and makes us wait until all the tests are carried out. Considering all of these, we came up with automating the process of running tests. So, we decided to use a Continuous Integration (CI) pipeline for our project.

Continuous integration (CI) is the practice of automating the integration of code changes from multiple contributors into a single software project.

By establishing a successful CI build, we validate code and its correctness, identify and fix bugs at the early stage. So, the following services and tools are lined up for a CI pipeline:

Bitbucket: a hosting service where we host our repositories.

Bitrise: Offers a collection of tools and services that assist us with the development and automation of our iOS app.

SwiftLint: A tool that will help you identify and flag parts of your code that may not be following the code formatting rules that either the community or your team has settled on.

Slack: A channel-based messaging platform that we’ve already used for team communication. Here, we use to get notified if a CI build is successful or failed.

Prerequisites

Create a Git Repository

We use Bitbucket to collaborate and manage our iOS projects since it offers unlimited private repositories (up to 5 users is free). If you don’t have any repository yet, you can create one by following the instructions here.

Install CocoaPods on Your Computer

We use CocoaPods as a package dependency manager. If you have not installed CocoaPods, you may follow this guide.

Add CocoaPods to Your Project

We must add CocoaPods to our project, so we can use the SwiftLint tool or any other libraries. You can find the details here.

Adding the SwiftLint Tool to Your Project

Open Podfile.lock and add SwiftLint pod.

Adding SwiftLint to Podfile

Then, open Terminal, go to your project directory, typepod install and press Enter. You’ve added SwiftLint to your project. You can customize SwiftLint rules in the swiftlint.yml file. You can find more details here.

Create a Bitrise Application

We use Bitrise to create our CI pipeline. So if you are not familiar with it, the following article helps you grasp it fully and thoroughly.

Acquire a Personal Access Token in Bitrise

To acquire a Personal Access Token (PAT) for your user, sign in with that user on bitrise.io, go to your Account Settings page, and select the Security tab on the left side. Create a PAT and note it. That will be used for Bitrise API requests.

Creating a New Workflow

We start with creating a new workflow that will only be responsible for running tests.

  1. Go to the Workflow tab and press +Workflow button.
  2. In the prompted screen, type a workflow name and choose a base workflow that you’ve already had or start with an empty workflow. I name it DebugTest with an empty workflow.
  3. Press Enter, You’ve successfully created a new workflow.
Adding a New Workflow

Adding Steps

Currently, you have an empty workflow, now it is time to add steps and configure them. Finally, our workflow will take its final form below. Let’s take a look at what has been done with those steps.

Final Form of Workflow

Activate SSH Key

This Step makes sure Bitrise has access to your repository and been authorized to clone your application to its virtual machines. No need to modify input variables, leave it as it is.

Git Clone Repository

As the step’s name suggests, it is used to target your application repository and create its clone.

Run CocoaPods install

executes pod install command to install your dependencies. No change is required for this step.

Xcode Test For iOS

Runs all tests that are included in your project. You don’t need to change any other variables.

  1. Set Scheme Name, Device, OS Version and Platform input fields. You can

Note:Please make sure that application scheme's Shared attribute is enabled in Xcode. Otherwise you will not be able to get successful builds.

Marking Scheme as Shared

This step generates the following outputs. The first one will be used in the next steps. Also, it will be available on the build’s Apps & Artifacts tab as xcode-test-results-.html.

SwiftLint

Runs Swiftlint on the project to provide clean code. No need to modify input variables, leave it as it is. You can get SwiftLint reports from the build’s Apps & Artifacts tab.

Deploy to Bitrise.io — Apps, Logs, Artifacts

Deploys build artifacts to make them available for the user on the build’s APPS & ARTIFACTS tab. When you need to check the output of your current or previous builds, you can access it here. In this workflow, test results and SwiftLint reports will be available like below:

Apps & Artifacts

Script

In this step we are going to export xcode-test-results-.html — a build’s artifact — as a URL to be sent in Slack message. So, we should use Bitrise API. We are going to make 2 GET requests. You can see the parameters for each endpoint here.

GET Requests in Bitrise
  1. The first endpoint will be called to get the list of the build’s artifacts. We will use the created build artifact slugs from the response.
  2. The second endpoint will be called to retrieve data of a specific build artifact.

Now I will explain, how you can do with a custom bash script.

Bash Script to Export Test Results URL

Line 9–11. URL variable is created by using BITRISE_APP_SLUG and BITRISE_BUILD_SLUG variables. These variables are given by Bitrise as default. You can see all available variables supported by Bitrise here. Also, [YOUR PERSONAL ACCESS TOKEN] will be replaced with your Personal Access Token.

Line 14–16. We call the first endpoint and parse data array from JSON. Also, I print it for logging.

Artifacts List

Line 18. Since I want to get xcode-test-results-.html’s slug, I will search in artifact titles that match with “.html”. So I defined HTML variable.

Line 20–23. In a for loop, I try to find an artifact’s title that contains “.html”.

Line 24–25. After I find the artifact, I take its slug and used it as a parameter for the second endpoint.

Line 26. The second endpoint is called and the artifact’s download URL is parsed from JSON.

Artifact Details

Line 27. Export artifact’s download URL as an Environment Variable.

Line 28. Also, I print the URL for logging.

Now, you have a $TEST_RESULTS_URL variable. You will use it in the next step.

Send a Slack Message

Here, we would like to send a message to the Slack channel that the build is successful or failed. To do that, we should register a Slack Webhook URL or Slack API Token. I’ll go with the incoming webhook URL since I am more familiar to use them.

Note: Please do not register both URL and Token; otherwise Bitrise will not be able to deliver the message to Slack.

  1. Go to https://api.slack.com/apps
  2. Choose to Create New App
  3. Set app name and select your Slack workspace. Press Create New App

Now, you should configure an incoming webhook for your app. Choose the following feature:

4. After that, activate incoming webhooks.

Activate Incoming Webhooks

5. Click Add New Webhook to Workspace button at the bottom of the page

6. Choose a channel from the dropdown list to post to as an app and press Allow. You’ve successfully created an incoming webhook URL.

Webhook URL

7. Copy Webhook URL, then go to your Bitrise setup page. Create a secret variable. Expose Slack Webhook URL for Pull Request. Otherwise, Bitrise will not be able to send messages to the Slack channel, when the build is triggered by a pull request.

Exposing Secret Variable for Pull Requests

8. Assign it to the Slack Webhook URL field in the Send a Slack Message Step.

Slack Webhook URL

9. Set Target Slack Channel that you want to receive messages from.

10. Add TEST_RESULTS_URL — which you had above — to the list buttons that act like a link. You will see the View Test Results button in the Slack message once you get a successful CI Build.

Adding Test Results URL to Slack Message

You can leave the rest of the variables as they are. Later on, you can change it and see the results by trial and error.

All good with Slack!

You’ve done with the Steps.

Triggering CI Builds with Pull Requests

We want to trigger CI builds once we open a pull request. Firstly, we need to add a webhook URL in Bitbucket. This URL will be used to notify Bitrise to start a CI Build.

  1. Get a Bitbucket Incoming Webhook URL
  • Go to the Code tab.
  • In the INCOMING WEBHOOKS section, Select Setup Manually and choose Bitbucket from the dropdown list.
  • Copy the URL generated below.
Getting Bitbucket Webhook URL
  • Go to Repository Settings in Bitbucket
  • Select Webhooks
  • Press Add webhook
  • Paste the webhook URL you previously created.
Adding Webhook URL in Bitbucket

So far, we’ve created a workflow and added steps that run CI builds. Moreover, we’ve added a webhook URL to Bitbucket. Now, we must add a trigger rule in Bitrise since we want to run tests for every pull request like I mentioned earlier at the beginning.

2. Add Trigger Rule for Pull Request

  • Open the Workflow Editor.
  • Select the Triggers tab.
  • Select the PULL REQUEST option.
  • Type the names of the source branch and the target branch. Make sure they must be exactly the same as in your repository. Otherwise, the trigger won’t work. If you leave both the source and target branch fields empty, every pull request will trigger a build. I will leave the source branch empty and set the target branch to develop — it is the branch that we merge all the features before releasing them — which means every pull request to develop from any source branch will trigger a build.
  • Select the workflow you wish to trigger (I created as DebugTest earlier.)
  • Click Save.
Setting Up Pull Request Trigger

Let’s test your CI Pipeline!

You should create a pull request to trigger a CI Build on Bitrise. You can create on Bitbucket or SourceTree App. I will go with Bitbucket.

  1. Go to your repository in Bitbucket.
  2. Choose Pull Request on the left side.
  3. Press Create pull request on the upper right side.
Creating a Pull Request

4. Select your source and target branches (Remember your trigger rules on Bitrise) and press Create pull request

Creating a Pull Request

If you do everything right, you suppose to see build status in the upper-right site on the next page.

Build Status on BitBucket

Also, you will see that a CI Build is triggered on Bitrise:

Running CI Build on Bitrise

Once it is successfully built, you will get a message from the Slack channel like below:

Retrieving Slack Message

You can download test results by pressing View Test Results Button. It looks as follows:

Test Results

Also, you can view the build’s SwiftLint report in Apps & Artifacts tab.

SwiftLint Report

Wrapping Up

I have tried to share the practices we have learned from CI so far. I hope it may motivate and encourage you to integrate a CI pipeline into your applications.

To learn more about our development experiences you can look at our medium page. At Plus Minus One, we love to learn and share our experiences. We hope this article makes your life easier 🙏🏻

--

--