Getting started with Xcode Cloud: Pull Request (PR) Workflow

Pranav Kasetti
Kin + Carta Created
13 min readMar 8, 2022
Figure 1: Xcode Cloud development cycle
Figure 1: Xcode Cloud Development Cycle

This tutorial is for people who know about Version Control, what CI and CD are about and are looking to try out Xcode Cloud on their project. We will be covering getting set up to CI and CD with Xcode Cloud, and walkthrough a GitHub Pull Request (PR) workflow.

Xcode Cloud is currently in private beta, however, I am in a lucky position because I am one of the first developers who has been provided free access. Hopefully, this series will help those looking to set up Xcode Cloud as Apple provides wider access to the community.

I recommend reading my “missing handbook for Continuous Integration & Continuous Deployment” article first if you’re new to CI and CD.

Prerequisites

  • Apple Developer Program membership ($99 / yr) 💸
  • Xcode Cloud (beta at the time of writing) access
  • Xcode 13.3 beta or above

If you already meet the pre-requisites to use Xcode Cloud, congratulations! 🥳Only about 10,000 developers worldwide have free access at the time of writing. If you don’t, don’t worry! You can easily sign up for the Xcode Cloud beta in App Store Connect as a Developer Program Member from your App pages by selecting and requesting access on the new Xcode Cloud tab. Or here.

PRO TIP 😉: Sign up for the beta from every developer account in your team. I think demonstrating eagerness helped me get early access 👀.

To follow along with the tutorial, clone and open the Xcode project from the CloudJokes repo.

Article Agenda

  1. What is Xcode Cloud? ☁️
  2. What are Workflows? 💼
  3. What’s a Pull Request Workflow? 🕵️
  4. Set up a PR Workflow 🦦
  5. Set up Code Signing ✍️
  6. Add new Remote 📺
  7. Create a Workflow ✨
  8. PR Workflow General 🏠
  9. PR Workflow Environment 🌳
  10. PR Workflow Start Conditions 🎬
  11. PR Workflow Actions 👷‍♀️
  12. Grant Access to your Source Code 🔓
  13. Create App on App Store Connect 🔗
  14. PR Workflow Post-Actions 🎁

What is Xcode Cloud? ☁️

Figure 2: Xcode Cloud tightly integrates Testflight, App Store Connect and Xcode

Xcode Cloud is Apple’s hosted CI and CD service that integrates Xcode with Testflight and App Store Connect to build, test, and distribute apps for the Apple ecosystem (as shown in Figure 2). Apple currently offers a self-hosted solution with Xcode Server, but developers complained that build issues are hard to debug, machines need to be maintained with DevOps teams, and there are fewer integrations with Slack or PR webhooks. 😭

GitHub Actions, Bitrise, Fastlane, and CircleCI offer very popular hosted CI solutions. Fastlane has 34k ⭐️s on GitHub, and Bitrise has millions of daily builds 🛠. Apple currently does not offer a competitive product in the hosted developer tooling space.

That all changes with Xcode Cloud 🎉.

Xcode Cloud is Apple’s answer to Fastlane, Bitrise and Actions for its ecosystem. Apple tried to acquire Fastlane a few years ago but failed. Apple has since then been working hard to develop its infrastructure, for example, by acquiring BuddyBuild. Apple released the App Store Connect API in 2019 and are now leveraging the API to build a higher-level CD and CI platform.

Xcode Cloud supports builds across iOS, macOS, watchOS and tvOS. Apple doesn’t offer cross-platform support with Android 🤖 or Windows 🪟 though. As a result, Xcode Cloud may not make financial sense for cross-functional development teams because it’s less flexible than other excellent providers like GitHub Actions.

Xcode Cloud was designed by Apple with simplicity, ease of use and great user experience in mind. As with most Apple products, technical details are abstracted away from the user, enabling powerful functionality for the essential Apple development workflows. Xcode Cloud supports Swift Package dependencies out of the box along with CocoaPods and Carthage. 🏆

NOTE: Xcode Cloud does NOT support projects using the Legacy Build System. This isn’t a problem for newer projects but can be a blocker when migrating legacy projects to Xcode Cloud.

What are Workflows? 💼

Workflows define the steps taken for every CI job in chronological order. Workflows are Xcode Cloud’s equivalent to a single GitHub Action or Bitrise Workflows. Workflows are categorised into 4 stages:

  1. Environment 🌳: The environment includes the macOS and Xcode versions used by the CI runners and environment settings such as environment variables or clean builds.
  2. Start conditions 🎬: Xcode Cloud enables 4 start conditions — Branch Changes, PR Changes (the focus of this article), Tag Changes or On a Schedule. Xcode Cloud integrates with VCS providers like GitHub and BitBucket to enable actions by subscribing to webhooks. We can further customise each category in the Workflow Editor.
  3. Actions 👷‍♀️: The majority of build time will be spent performing the main workflow tasks called Actions. Xcode Cloud has 4 action categories — Build, Test, Analyze and Archive. We can customise the scheme, platform and action-specific settings within each category.
  4. Post-Actions 🎁: Post-Actions are either distribution actions to Testflight or Notifications. We use the output from the Archive action to deploy the app and can customise Notifications for Slack, email and build status.

Let’s go through how to set up these components for a basic Pull Request (PR) workflow. 🙌

What’s a Pull Request Workflow? 🕵️

Pull Request? 🤷‍♂️

Pull Requests are a feature of version control providers such as GitHub or BitBucket. They integrate with git projects and form the backbone of code review within software development teams. Pull requests are used for apps that are pushed into production and are usually performed within the browser.

GitHub explains their Pull Request as follows:

Pull requests let you tell others about changes you’ve pushed to a branch in a repository on GitHub. Once a pull request is opened, you can discuss and review the potential changes with collaborators and add follow-up commits before your changes are merged into the base branch.

PSA 🚨: git is a free and open-source distributed version control system. GitHub (short for GitHub, Inc.) is a provider of Internet hosting for software development and version control using Git.

Pull Request Workflow? ☕️

As the name suggests, the PR workflow uses GitHub / BitBucket webhooks to run Xcode Cloud on PR changes. A Pull Request workflow works well with software development teams developing production apps. Apple recommends a PR Workflow to test and analyze codebases before internal distribution (via TestFlight).

Set up a PR Workflow 🦦

After Apple grants you access to Xcode Cloud, we need to do 5 main steps to get started:

  1. Set up automatic code-signing. Xcode Cloud does not currently work with manually signed apps.
  2. Set up a new remote for the repository on your own GitHub account.
  3. Create a workflow for your app.
  4. Link your hosted repository with Xcode Cloud via your VCS provider in Xcode.
  5. Start your first build.

Apple likes to make things easy, and Xcode Cloud is no exception. We’ll focus this article on implementing the PR workflow for our simple jokes app.

Set up Code Signing ✍️

First, we’ll need to change our bundle identifier and our code-signing configuration to use a new development team with Xcode Cloud access.

Follow the steps outlined below, as visualised in Figures 3 and 4:

Figure 3: Change the bundle identifier in Xcode for CloudJokes
Figure 4: Change the code signing configuration in Xcode for CloudJokes
  1. Select your root CloudJokes.xcproject file from the File Navigator
  2. Select the CloudJokes (iOS) target as shown in Figure 3.
  3. Change the Bundle Identifier text field to be your own Organisation Identifier followed by CloudJokes. For example, I have used com.kasprasolutions.CloudJokes but we could use com.kinandcarta.CloudJokes for a new project. We need to change the Organisation Identifier because App Store Connect prevents us from creating new app records that use the same bundle identifier as another registered app.
  4. Select the “Signing & Capabilities” tab.
  5. Check that the “Automatically Manage Signing” checkbox is enabled.
  6. Change the development team to your organisation / personal Apple development team that has Xcode Cloud access.
  7. Repeat steps 3–6 for the CloudJokes (macOS), Tests iOS and Tests macOS targets as shown in Figures 3 and 4.
  8. Resolve any organisation code signing errors and verify the project builds.

Add new Remote 📺

Use the GitHub CLI to push the existing repository to a new remote on your personal GitHub account.

$ cd CloudJokes && gh repo create

Use the “Push an existing local repository to GitHub” option, name the new remote something different to origin, and push the commits to the new remote. Xcode Cloud requires you to have admin permissions on your repository, so we need to create a new repository with admin access.

NB: I prefer using the GH CLI instead of following the website flow or forking, but YMMV.

Create a Workflow ✨

The next step we need to take is to Create an Xcode Cloud Workflow. Make sure the Report navigator is visible, select the Cloud tab, and then click Create Workflow.

Figure 5: “Create Workflow” prompt in Xcode for CloudJokes

Clicking this button will prompt you to select a product to configure Xcode Cloud as below:

Figure 6: “Select a Product” prompt in Xcode for CloudJokes

If you are part of multiple developer teams within App Store Connect you will have an additional “Team” column where you can select an Xcode Cloud eligible developer account. If you have multiple accounts with access to Xcode Cloud, try to be consistent by using the same team with Xcode Cloud that you selected previously for code signing.

Once you’ve selected a compatible product and team, the “Next” button will become clickable. Click “Next”.

You’ll now be able to review Xcode Cloud’s default Workflow. Click “Edit Workflow” to bring up the Workflow Editor.

PR Workflow General 🏠

Figure 7: “General” prompt in Xcode Cloud Workflow Editor
  1. Set the “Name” of your Workflow to “Pull Requests”.
  2. Set the description to whatever you like.
  3. Restrict Editing to Admins or App Managers only by selecting the checkbox.
  4. Select the Primary Repository to the new CloudJokes remote you created earlier (Important!).
  5. Select the CloudJokes.xcodeproj project.

PR Workflow Environment 🌳

Figure 8: “Environment” prompt in Xcode Cloud Workflow Editor

Within the PR Workflow, we’ve set the Xcode and Mac environment we want our runners to use and haven’t set any environment variables. Environment variables are the same as with GitHub Actions or other CIs.

What should we choose for the Xcode environment?

We can stick to the Latest Release of Xcode, the Latest Beta or manually select a version. The great thing about choosing the Latest Release option is we don’t need to manually change the version as Xcode gets updated. This can also mean however that builds break over time as languages or frameworks evolve. Beta releases may enable newer language features, however may be unstable and unsuitable for legacy projects. Choosing the right Xcode is a trade-off that depends on the project.

The same considerations apply to choosing the Latest macOS version, Latest Beta macOS or a specific OS version.

For our purposes, using the Latest Release is sufficient, so we’ll stick with the default options Xcode created.

Clean builds?

We also need to consider the option to enable “Clean builds” in our environment. Clean builds slow down build times without using DerivedData, however, they make sense for functionality-critical workflows. For Distributing apps via Testflight, we need to enable the “clean build” setting to prevent using cached functionality that is no longer up to date for deployment.

Enable Clean Builds for CloudJokes by selecting the checkbox.

Environment Variables (envvars)?

The final environment option is environment variables. Environment variables are similar to fastlane + Bitrise environment variables. We can choose to make the variables secret for hiding sensitive information, like API Keys, so that they are encrypted and securely stored. We can use envvars for anything we don’t want to check into source control or to configure runtime behaviour. Environment variables are also helpful when mocking an API in UI tests for example.

Environments in the Workflow Editor don’t include scripts, these need to be added in the ci_scripts folder in the project’s root directory. We'll cover configuring CI scripts in a future article.

We won’t need any envvars for this project.

PR Workflow Start Conditions 🎬

Figure 9: “Pull Request Changes” prompt in Xcode Cloud Workflow Editor

When we open Xcode’s Default Workflow, we get a “Branch Changes” start condition automatically. In order to replace this start condition, let’s create a new “PR Changes” start condition.

  1. Click the + button beside the "Start Conditions" title in the sidebar of the Workflow editor, and select "Pull Request Changes".
  2. Select the Branch Changes Start Condition, and delete the step by clicking the 🗑 icon in the top right of the Workflow Editor.
  3. Set up the PR Changes step as outlined in Figure 9 above.

Apple has now enabled multiple start conditions in the latest beta, allowing more versatility for different stages of your development workflow. Start conditions are the conditions that trigger Workflow Actions.

We can trigger a Workflow for combinations of Any or Custom Source and Target branches for PRs. We can also further narrow the start condition to only trigger upon changes to certain files or folders in the project.

For our purposes, we will leave the defaults as above. Auto-Cancelling builds is a best practice for saving billing time since we only want to distribute the latest PR commits. Unlike Release Workflows, we don’t need the build artefacts (IPAs) of every commit, so we check Auto-cancel builds.

PR Workflow Actions 👷‍♀️

Figure 10: “Test” Action prompt in Xcode Cloud Workflow Editor

For now, we can delete the “Archive — macOS” step (using the 🗑 icon as before), add the “Test — iOS” and “Analyze — iOS” step to the set of Actions. Click the + icon (as we clicked for the Start Conditions) beside the "Actions" tab in the sidebar, add a Test action and add an Analyze action. iOS should be the preselected platform for these actions by default

We need to further configure the Test action as shown in Figure 10:

  1. Select the “iOS” Platform.
  2. Select the “CloudJokes (iOS)” Scheme.
  3. Select “Required to Pass”.
  4. Select “Use Scheme Settings”.
  5. Click the + button just below the "Destination -> OS Version" table. You will see that Apple's "Recommended iPhones" stack for tests automagically populates the table. 🪄 If you click the + button once more, you will see a stack of “Recommended iPads” as well. We will stick to iPhones only for now to streamline build times.

Xcode Cloud updates a Recommended stack of iPhones and iPads to run tests on which means we don’t need to manually update workflows. This is very helpful to ensure the app is being tested across a range of screen sizes and works well on the latest devices. We don’t need to manually update and maintain this stack, which offers developers greater convenience.

BONUS NOTES 🍀: Xcode Cloud enables test plans within different workflows, so we can distribute the load accordingly. In fact, this is the same setup as the Apple swift repo with separate Actions for Smoke Tests and the full suite for Release and PR workflows. This flexibility is helpful to balance CI load for large scale apps where running the whole test suite isn’t feasible on every PR but is essential for changes to production branches.

Since we haven’t created the Workflow yet, we will need to configure Post-Actions later. For now, click the “Save” button in the bottom right corner of the Workflow Editor. Xcode navigates us back to the “Review Workflow scene”, where we can now select “Next”.

Grant Access to your Source Code 🔓

Follow Xcode’s prompt to grant access to your Source Code:

Figure 11: “Grant Access to Your Source Code” prompt in Xcode Cloud

After you’ve granted Xcode Cloud access, you’ll be navigated back into Xcode. Click “Next”.

Create App on App Store Connect 🔗

Figure 12: “Create App on App Store Connect” prompt in Xcode

Confirm the details are all correct and click “Complete” to create an App Store Connect record for CloudJokes. If all went well, you should see the success screen 🎉:

Figure 13: “CloudJokes is now configured” prompt in Xcode

Since we haven’t fully configured the Workflow yet, click “Close”.

PR Workflow Post-Actions 🎁

We now have a template Pull Requests workflow in our Report Navigator on the left side of Xcode’s editor. Right-click on the “Pull Requests” section and select “Edit Workflow”. You should now see the same Workflow Editor as before but with more options.

  1. Select “Testflight (Internal Testing Only)” for the Deployment Preparation section within the Archive action.
  2. Add a new Post-Action “Testflight Internal Distribution” for an internal App Store Connect group (set this up on the App Store Connect web portal if you don’t have one already).
  3. Add a Notify Post-Action adding your email address as a subscriber.
  4. Save your changes.

Post Actions are additional actions that use the outputs from the Action stages to either deploy builds or send notifications. We can enable Notifications via Slack or Emails and can customise them for successes only, failures only or all outcomes. Unfortunately, deployment options are currently only limited to Testflight or App Store Connect within Xcode Cloud.

You can now trigger a test build, by right-clicking on the “Pull Requests” section and selecting the “Start Build” option for your “main” branch. 🛠

You should now be able to track your build status within Xcode by selecting Build 1 in the Report Navigator. 🎊🎉 The build should succeed but may not at the moment because Xcode Cloud is going through some teething issues on the server-side.

If you want to test out your workflow more thoroughly, try creating a new branch and PR on GitHub to trigger the workflow automatically.

Thanks for reading! If you enjoyed this article and want to hear more from me, please follow me on Twitter. Happy coding! 👨‍💻

Special thanks to Felipe Ricieri for providing feedback.

--

--

Pranav Kasetti
Kin + Carta Created

Multiplatform engineer specialising in iOS Development at Sky (London).