GitHub Actions for iOS



If you work on a production app then chances are you have some sort of automation in your development pipeline. In this post, I’ll walk through the PR pipeline we use, to help you get up and running quickly with GitHub Actions for iOS automation.

There are many tools available such as Jenkins, Bitrise, CircleCI and GitHub Actions. If you use GitHub to manage your source code, GitHub Actions can be a powerful tool to build out your automation. At Nye Health (where I work), we have recently migrated our continuous integration and continuous deployment (CICD) pipelines for our iOS app to GitHub actions. We have workflows for running unit tests once a pull request (PR) has been created, and for deploying our app to TestFlight for internal testing.

 

Would you like to work at Nye? If so, you're in luck, we're currently hiring!

Check out our open roles here!

 

Workflows

Let’s start by describing a GitHub Action Workflow.


Workflows are defined in YAML files and they must be stored in the .github/workflows path in our repository for GitHub Actions to see them.


A workflow can be broken down into 2 main parts:

  1. a trigger that tells the workflow when it should run,

  2. and a list of jobs that the workflow will run.


The jobs within a workflow can also be broken into 2 parts:

  1. the environment used to run the job (Windows, Linux or macOS, see https://github.com/actions/virtual-environments,

  2. and a list of steps that the job will execute.

This is the basic structure of a workflow file:


Pull Request Workflow for iOS

In your project root create a file at the path .github/workflows.pr.yml.


At the top of the file, we’ll add the workflow name and trigger.


Trigger

The name parameter is optional however I like to add it as it describes what the workflow is used for.


Next, we define the event trigger. We want this workflow to run when a PR has been created so we define the pull_request event as our trigger. The synchronize types tells the workflow to also run when a new commit is pushed to the open pull request.


Job environment

We only need a single job in our workflow, which I’ve named pr-pipeline.


As we are building this workflow for an iOS app, we need to run it on macOS.


The timeout-minutes value allows us to define the maximum time that our job could run for. The default value is 360 minutes, so adding our own value is important to ensure that we don’t waste resources if a step in our job hangs for some reason. Note that every 1 minute of macOS time is charged at a rate of 10 minutes usage against our actions allowance. Public repositories can use GitHub Actions for free, private repositories get a free allowance of minutes being incurring a charge. See GitHub pricing for more details.


Job steps

Now that the job environment is set up we can turn our attention to the steps our job needs to perform. Let’s first grab our code so that we have something to work with.


GitHub Actions has a marketplace where prebuilt Actions are available to help us create powerful workflows quickly. We’ll use one of these Actions to fetch our code.

The Action is called actions/checkout@v2. As the workflow is triggered by a PR the Action will pull down the branch that is being compared to the base branch into our workspace.


The name field is optional when defining a step. I like to label each step for the readability reason I mentioned before.


The next step is to set the version of Xcode that will be used to build and test our project. This step runs a terminal command as shown below.

Dependences are next. Our project requires both Ruby and Cocoapods. There is a predefined action available for Ruby, which has a cache option. Cocoapods are installed with a terminal command.

The final steps are to run our unit tests, execute our Danger script and collect the build logs.


Our tests are run using Fastlane so we use a terminal command to run the test lane. Note the env value in the Run unit tests step. Our app scheme is passed to Fastlane as an environment variable.


Once the tests are complete we run Danger, which is a tool for automating part of the PR process. We use it for reporting SwiftLint warnings and our code coverage for tests. Danger will add its findings to our PR as a comment. To allow it to do this it needs access to a GitHub token. We have created a specific token for Danger and have added it as a secret in our repository settings. It can be accessed using ${{ secrets.DANGER_GITHUB_API_TOKEN }}.


Finally, we collect the Xcode build log, which is made available to us through the GitHub Actions interface. This step uses an expression as seen in the line if: always(). This ensures that even if the Xcode build step fails, and Fastlane exits before running the tests, we get a log that we can use to debug what’s gone wrong. See this GitHub learning article for more on expressions.

All going well, our final job should look like this:

Optimationsing our Workflow

Before we finish there are a couple of extra steps we can add to our workflow.


Let’s add a new step at the beginning of our job using an Action called cancel-workflow-action. This cancels any currently running instances of our workflow job for our PR. This ensures that if you push multiple changes to your PR in quick succession then the workflow will only be running for the most recent change which stops us from wasting resources.

Another saving we can make is by adding a cache for Cocopads. This step is run immediately before the Cocoapods installation. The path tells the cache which directory in our project structure contains the pods. The cache is based on the Podfile.lock. If this file changes, when new pods are installed for example, then the cache will no longer be valid and the pods will be installed fresh. At the end of the workflow, the newly installed pods will be cached for the next time.



With those additional steps in place our final workflow looks like this:

There’s nothing left to do now except to test your workflow by creating a pull request and clicking on the Actions tab to see your workflows’ progress.

I hope you found this useful and it aids you in your first steps with GitHub Actions. It is a powerful tool, and there is a lot more that is possible. The documentation is a great place to go next and be sure to explore the Actions marketplace!


Check out these links for more info:

https://docs.github.com/en/actions

https://github.com/actions/virtual-environments

https://github.com/marketplace?type=actions

https://github.com/pricing


 

Would you like to work at Nye? If so, you're in luck, we're currently hiring!

Check out our open roles here!