iOS Continuous Integration with Xcode#
This guide gives an overview of CI/CD with Semaphore for apps created with Xcode that run on iOS, macOS, watchOS, or tvOS.
Semaphore supports building, testing, and deploying Swift, Objective-C, and
React Native projects. Projects can be built with
Xcode 13 running on a macOS a1-standard-4
or higher machine type.
Example project#
Semaphore maintains an example iOS app written in Swift 5.1 with SwiftUI to demonstrate how to get an Xcode CI/CD environment up and running:
This example project includes an annotated Semaphore configuration file,
.semaphore/semaphore.yml
and uses
fastlane for its CI pipeline with the
Semaphore fastlane plugin.
Overview of the CI pipeline#
The Semaphore pipeline is configured to:
- Run all unit and UI tests
- Build the app and generate an
ipa
archive - Generate automated App Store screenshots
- Upload archived
ipa
and screenshots as job artifacts
Taking the .semaphore/semaphore.yml
file from this example project can be a
good way to get your app up and running with Semaphore.
Related guides:#
Sample pipeline configuration#
The following .semaphore/semaphore.yml
configuration is used in the
example project:
# Use the latest stable version of Semaphore 2.0 YML syntax:
version: v1.0
# Name your pipeline. If you choose to connect multiple pipelines with
# promotions, the pipeline names will help you differentiate between
# them. For example, you might have a build phase and a delivery phase.
# For more information on promotions, see:
# https://docs.semaphoreci.com/essentials/deploying-with-promotions/
name: Tallest Towers
# The agent defines the environment in which your CI runs. It is a combination
# of a machine type and an operating system image. For a project built with
# Xcode, you must use one of the Apple machine types coupled with a macOS image
# running Xcode 13.
# See https://docs.semaphoreci.com/ci-cd-environment/machine-types/
# https://docs.semaphoreci.com/ci-cd-environment/macos-xcode-13-image/
agent:
machine:
type: a1-standard-4
os_image: macos-xcode13
# Blocks are the heart of a pipeline and are executed sequentially. Each block
# has a task that defines one or more parallel jobs. Jobs define commands that
# should be executed by the pipeline.
# See https://docs.semaphoreci.com/essentials/concepts/
blocks:
- name: Run tests
task:
# Set environment variables that your project requires.
# See https://docs.semaphoreci.com/essentials/environment-variables/
env_vars:
- name: LANG
value: en_US.UTF-8
prologue:
commands:
# Download source code from GitHub.
- checkout
# Restore dependencies from the cache. This command will not fail in
# the event of a cache miss. In the event of a cache hit, bundle install will
# complete in about a second.
# See https://docs.semaphoreci.com/essentials/caching-dependencies-and-directories/
- cache restore
- bundle install --path vendor/bundle
- cache store
jobs:
- name: Test
commands:
# Select an Xcode version.
# See https://docs.semaphoreci.com/ci-cd-environment/macos-xcode-13-image/
- xcversion select 13.4.1
# Run tests for iOS and Mac apps on a simulator or connected device.
# See https://docs.fastlane.tools/actions/scan/
- bundle exec fastlane test
- name: Build app
task:
env_vars:
- name: LANG
value: en_US.UTF-8
secrets:
# Make the SSH key for the certificate repository and the MATCH_PASSWORD
# environment variable available.
# See https://docs.semaphoreci.com/essentials/using-private-dependencies/
- name: match-secrets
prologue:
commands:
# Add the key for the match certificate repository to ssh
# See https://docs.semaphoreci.com/essentials/using-private-dependencies/
- chmod 0600 ~/.ssh/*
- ssh-add ~/.ssh/match-repository-private-key
# Continue with checkout as normal
- checkout
- cache restore
- bundle install --path vendor/bundle
- cache store
jobs:
- name: Build
commands:
- xcversion select 13.4.1
- bundle exec fastlane build
# Upload the IPA file as a job artifact.
# See https://docs.semaphoreci.com/essentials/artifacts/
- artifact push job TallestTowers.ipa
- name: Take screenshots
task:
env_vars:
- name: LANG
value: en_US.UTF-8
prologue:
commands:
- checkout
- cache restore
- bundle install --path vendor/bundle
- cache store
jobs:
- name: Screenshots
commands:
- xcversion select 13.4.1
- bundle exec fastlane screenshots
# Upload the screenshots directory as a project artifact.
# See https://docs.semaphoreci.com/essentials/artifacts/
- artifact push job screenshots
Configuration walkthrough#
Naming your pipeline#
version: v1.0
name: Tallest Towers
Note: If you choose to connect multiple pipelines with promotions, the pipeline names will help you differentiate between them. For example, you might have a build phase and a delivery phase.
Defining the agent#
The agent defines the environment in which your CI runs. It is a combination of a machine type and an operating system image. For a project built with Xcode, you must use one of the Apple machine types, coupled with a macOS image running Xcode 13.
agent:
machine:
type: a1-standard-4
os_image: macos-xcode13
Defining blocks#
Blocks are the heart of a pipeline and are executed sequentially. Each block has a task that defines one or more parallel jobs. Jobs define commands that should be executed by the pipeline.
Blocks, tasks, and jobs are Semaphore's core concepts.
blocks:
- name: Run tests
task:
# This environment variable is exported in every job within this block:
env_vars:
- name: LANG
value: en_US.UTF-8
prologue:
commands:
- # Commands to run before *every* parallel job
jobs:
- name: Run tests
commands:
- xcversion select 13.4.1
- bundle exec fastlane test
- name: Second parallel job
commands:
- # Commands for the second parallel job
- # ...
- name: Third parallel job
commands:
- # Commands for the third parallel job
- # ...
Downloading code#
To download your code in a job, use checkout
, an
[open source script][checkout-source provided by Semaphore.
By default checkout
performs a shallow git clone from a remote origin. If you
need a full clone that will be cached by Semaphore, use checkout --use-cache
.
commands:
- checkout
Installing dependencies#
Your project dependencies can be cached by Semaphore to improve performance when running your CI/CD workflows.
The cache restore
command will not fail if there is a cache miss, and
bundle install
will complete in about a second when the cache hits. More
information on the exact functionality of cache
can be found in
the Toolbox Reference.
commands:
- cache restore
- bundle install --path vendor/bundle
- cache store
Selecting an Xcode version#
You can find the list of available versions of Xcode in the
Xcode 13 image references.
Select the desired version for your project with xcversion
.
commands:
- xcversion select 13.4.1
Running tests#
Semaphore can run both unit and UI tests using any of the iOS simulators that are installed with Xcode. If you're using fastlane, see the fastlane scan documentation. .
commands:
- bundle exec fastlane test
Building your app#
The example project is set to build the app with fastlane build
.
By default, the Semaphore fastlane plugin creates a fresh,
temporary keychain.
commands:
- bundle exec fastlane build
Accessing encrypted certificates and provisioning profiles#
The Fastfile
in this example project executes the match
command, which requires access to a private certificate store or git repository.
Use private dependencies to keep secrets separate from
the rest of the project.
secrets:
- name: match-secrets
The example project README also includes a detailed walkthrough for configuring the project to use a private git repository with encrypted certificates and provisioning profiles.
Uploading build artifacts#
Any files generated by a continuous integration pipeline may be uploaded as artifacts to a job, workflow, or project store.
Once the .ipa
file has been built and archived, the example project uploads
it as a job artifact.
commands:
- artifact push job TallestTowers.ipa
Automating the generation of App Store screenshots#
The example project is also configured to run snapshot
to automate the generation of a small set of sample App Store screenshots and
upload them as job artifacts.
commands:
- bundle exec fastlane screenshots
- artifact push job screenshots
Fastfile#
The example project uses the Semaphore fastlane plugin:
default_platform(:ios)
before_all do
# Install with `fastlane add_plugin semaphore`
setup_semaphore
end
platform :ios do
lane :build do
gym(scheme: 'TallestTowers',
skip_package_ipa: true,
skip_archive: true,
clean: true)
end
lane :test do
run_tests(scheme: 'TallestTowers',
devices: ['iPhone 8', 'iPhone 11 Pro'])
end
end
Releasing your app#
To manage your developer credentials on Semaphore, use encrypted secrets. To manage releases, set up promotions to trigger additional pipelines.
Run the example project yourself#
A good way to start using Semaphore is to take a demo project and run it yourself. Here’s how to build the demo project with your own account:
- Fork the project on GitHub to your own account.
- Clone the repository to your local machine.
- In Semaphore, follow the link in the sidebar to create a new project.
- Create your secret as per the instructions above.
- Edit any file and push to GitHub, and Semaphore will run the CI/CD pipeline.