var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var stdin_exports = {}; __export(stdin_exports, { default: () => _2021_02_27_github_actions_xcode_tests, metadata: () => metadata }); module.exports = __toCommonJS(stdin_exports); var import_index_10ac95e2 = require("./index-10ac95e2.js"); const metadata = { "title": "How to run Xcode tests for a SwiftUI iOS codebase with GitHub Actions", "author": "Thomas Wilson", "date": "2021-02-27T00:00:00.000Z", "draft": false, "slug": "2021-02-27-github-actions-xcode-tests", "tags": ["swift", "github-actions"] }; const _2021_02_27_github_actions_xcode_tests = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { return `
Tl;dr
yourproject/.github/workflows/main.yml:yourprojects and YourProjects with your file namegit add .github/workflows/main.yml && git commit -m "Add test GitHub action" && git push${`# Run My App's tests whenever someone pushes to `main` or creates a PR into `main`
name: CI
on:
# Triggers the workflow on push or pull request events but only for the main branch.
push:
branches: [ main ]
pull_request:
branches: [ main ]
# We're only going to have one job, `test` but you can add this
jobs:
test:
runs-on: macOS-latest
steps:
# Checkout the code to the working directory
- uses: actions/checkout@v2
# Install xcbeautify so the logs are human-friendly
- name: install xcbeautify
run: brew install xcbeautify
# Run the tests
- name: Run the xcode tests
run: xcodebuild clean test -project YourProject.xcodeproj -scheme YourProject -destination "platform=iOS Simulator,name=iPhone 12" | xcbeautify
`}
They\u2019re bits of code you write which are executed whenever something happens on your GitHub repo. These bits of code can do whatever (they\u2019re just functions that run on a container), like:
If you\u2019ve used other tools, GitHub actions are like TeamCity, CircleCI, Jenkins, or any other CI/CD pipeline tool, but built right into GitHub. If you\u2019ve not heard of, or used those tools, I explain a bit more about it below.
We don\u2019t actually write \u201Cactions\u201D, we write workflows, which contain one or more jobs, which contain one or more steps.
The details for a single workflow is written in yaml, as common plaintext format used by a lot of DevOps tools.
We put the yaml file in yourproject/.github/workflows/workflow-name.yml where yourproject is the root directory of your project and workflow-name is the name you wish to give the workflow.
There are three root-level yaml properties we\u2019re going to set:
name Is the human-readable name for the entire workflow. Call this \u201CCI\u201D or \u201CRun all tests\u201D or \u201CSend e-mail\u201D.on configures what exactly needs to happen for this workflow to run. By default, every job and step will run on every event.jobs Is a list of the jobs we\u2019ll be doing. In this example there\u2019s just one: running the tests${`name: CI
on:
# Triggers the workflow on push or pull request events but only for the main branch.
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: macOS-latest`}
Not how we\u2019re telling the test job that we\u2019re going to run on macOS-latest. Github gets us a container running that environment, which is cool.
By default, a job in a GitHub action just gives us an empty container, so we need to tell it to copy the code into our current working directory.
There\u2019s an easy way to do that: the checkout action is a third-party GitHub action that checks out our current working branch to the current working directory. Here are the Checkout docs.
By adding the following we make sure we have access to our code:
${`jobs:
test:
runs-on: macOS-latest
steps:
# Checkout the code to the working directory
- uses: actions/checkout@v2`}
The default Xcode logs are horrible: they\u2019re verbose and unintelligible. Xcbeautify is a CLI tool that formats them to give us more readable useful information.
Luckily the macOS-latest platform comes with homebrew, the MacOS package manager, already installed, so we just need to tell our test job to install it:
${`jobs:
test:
runs-on: macOS-latest
steps:
# Checkout the code to the working directory
- uses: actions/checkout@v2
- name: Install xcbeautify
run: brew install xcbeautify`}
This step in our job has two things:
name is a human-readable name, useful for us and the UI in GitHubrun is the thing you want to type onto the CLI. When that\u2019s done, the job will move on to the next stepThe last step in the job is to run the tests using the xcodebuild CLI tool. This is actually pretty easy and simple, just make sure you clean-up the names and details in the script below.
Node how we\u2019re piping (i.e. the | character) the results from xcodebuild through the xcbeautiful command. That\u2019s a unix-ism, it\u2019s pretty powerful (or so I\u2019m told, I\u2019m just a frontend engineer here).
${`jobs:
test:
runs-on: macOS-latest
steps:
# Checkout the code to the working directory
- uses: actions/checkout@v2
# Install xcbeautify so the logs are human-friendly
- name: install xcbeautify
run: brew install xcbeautify
# Run the tests
- name: Run the xcode tests
run: xcodebuild clean test -project YourProject.xcodeproj -scheme YourProject -destination "platform=iOS Simulator,name=iPhone 12" | xcbeautify`}
You\u2019re good to go, let\u2019s add the file we made to our git repo, make a single commit and push it up git add .github/workflows/main.yml && git commit -m "Add test GitHub action" && git push
(We\u2019re assuming the main.yml file is the one you made, if you called it something different, change that).
Go to your GitHub repo, click the \u201CActions\u201D tab, and watch with glee.
You can. If you already know why, you can skip this section.
I come from a frontend engineering background, where having test coverage has typically been difficult or different to the backend world. So answering this question is as much about learning facts/words as it is about understanding that the software design, development, and deploy process can be different. I know. I\u2019m sure some engineers are tutting or shaking their heads at me. TUT AWAY, FRIENDS I\u2019m standing in my truth here.
GitHub\u2019s actions are part of a broader practice of CI/CD (continuous integration and delivery) in software. The idea of CI/CD is to commit code frequently, and have automated processes in place to detect the introduction of errors to the codebase.
CI/CD can also automate any other previously manual processes, like building, deploying, or publishing software. The roles of CI/CD and automation can grow and expand as your team or product become more complicated. In this example we\u2019re just using it to run tests because well written tests give you confidence that your code does what you think it does.
As teams grow, having actions run automatically means that institutional and team policies (like having all tests pass before anything goes into main, formatting code, running a smoke-test before publish) are adhered to without manual intervention. This reduces the barrier to actually publishing code.
Integrating the CI/CD pipeline right where your code is hosted is different to having a third-party service watch your git repo. It\u2019s first-party and also probably cheaper (maybe).
GitHub actions are versatile \u201Csomething\u201D that triggers these bits of code to run can be:
main branchFor a full list, see Github\u2019s full list of events that can trigger a workflow.
`; });