Learn how Xcode Cloud can help teams of all shapes and sizes in their development process. We'll share different ways to configure actions to help you create simple yet powerful workflows, and show you how to extend Xcode Cloud when you integrate with additional tools.
♪ ♪ Romain: Hi, my name is Romain, and I'm an engineer working on Xcode Cloud. Xcode Cloud is a powerful tool, flexible enough to be integrated right into a team's development process. It can increase their productivity and help them deliver better apps to their customers. In this session, I'm going to talk about creating workflows in Xcode Cloud, based on situations you could meet in the real world. Teams come in all shapes and sizes, with diverse and unique development processes. To help us design some practical workflows, we'll imagine three hypothetical case studies. Each of these case study will resemble common situations that people might see when adopting Xcode Cloud.
We'll start by looking at a solo developer working on a single app. Then, we'll work our way up to a large team dealing with legacy code and a complex development process. In this session, we'll demonstrate some of the many options available to create and customize workflows that are well-suited to any team.
Let's start off with our first case study. Say we have a solo developer. They have one app that is available on both iOS and macOS. Most of their coding work is done on the main branch, where all the new code changes are pushed. Sure, they'll occasionally use a different branch when experimenting with new APIs and platform features, but for the most part, they use the main branch. Their code relies on a couple of dependencies and they chose Cocoapods to download and integrate them into their project. Lastly, they deploy builds of their app through TestFlight to some friends and family members who can test and provide feedback on the app. Every now and then, they manually release a new version of their app onto the App Store. This developer is a one-person show. They're managing everything from building their app, to distributing it on the App Store all by themselves. For them, simplicity is going to be key. They'll need something they can rely on and maintain. With Xcode Cloud, their entire process of pushing new code, building their app, and distributing to their testers can be achieved in one small, but mighty workflow. Before I dive into what this workflow would look like, let's pause and refresh on what an Xcode Cloud workflow is. For example, building your application, running tests, distributing to your testers, and so on. The "where" is the version of Xcode and the version of macOS you want to use, plus any other configuration such as environment variables. Together, they form the environment you want your workflow to run in. Finally, the "when" is when do you want these actions to happen.
Do you want it to start when you're pushing code to a specific branch? Or say, every day at 4:00 p.m.? Defining one or more start conditions sets the criteria for when you want a workflow to run. Great. With that now fresh in our memory, let's apply the "what", "where", and "when" to our solo developer's situation. I'm going to create an Xcode Cloud workflow they can use to automate all of their process. Here, I have the project already set up in Xcode Cloud. In the report navigator, I select the cloud icon and right click on my product name, then select "manage workflows".
This opens my workflow editor where I will click on the plus sign to open the menu, and select the first item, to create a new workflow for my app. In the name field, I will enter "CI Workflow". I'm going to skip the description field, but feel free to add details. Now, let's take a look at the environment section. Over in this section, I can see that the latest version of Xcode and the latest version of MacOS are selected by default. This looks good to me, so I won't make any changes there. Each new workflow comes with a default start condition. Let's take a look.
This start condition will create a build every time changes are pushed to the default branch; in this case, main. This is almost correct, but this solo developer wants to start builds when code is pushed to any branch, not just the main one. I will change the source branch option to "Any Branch".
The goal of this workflow is to build and distribute the application. We need an archive action, that prepares the build for distribution. I'm going to click on the plus side next to the Actions section and select Archive.
As you can see, the iOS platform is already selected, so I'm just going to select the "TestFlight and App Store" option in the Deployment Preparation section.
Now that our workflow will produce a build that can be distributed, I'm going to add a post-action that uploads the build to App Store Connect. To do that, I will click on the plus sign in the post actions section and select "TestFlight External Testing".
From there, I'm going to click on the plus side in the Groups section and select the "Friends and Family" group of testers.
And just like that, we're almost done. Our solo developer works on an application that targets iOS and macOS, so I want my workflow to archive and release the app on both platforms. To do that, I'm going to add another archive action.
Select the macOS platform and the TestFlight App Store deployment preparation.
Then, I'm going to add another TestFlight External Testing post-action.
Select the "Archive - macOS" artifact.
And choose the same group for testers.
Finally, I'm going to press Save to create the workflow.
We mentioned earlier that this developer uses Cocoapods to include the dependencies their app needs. Out of the box, Xcode Cloud has support for the Swift Package Manager. It is built right into Xcode. But, other dependency managers can also be used in Xcode Cloud. All it takes is a small amount of configuration. There is some documentation on how to use some of the more popular dependency managers. That documentation can be used as a guide on how to use others. For this solo developer, the documentation suggests using a post-clone custom script to install and run the Cocoapods tool.
Custom build scripts provide a way to run additional actions at specific points of an Xcode Cloud build. In this example, the post-clone script is run after all the source code has been cloned into the temporary build environment. We'll see another example of custom script in a later case study. And that is the solo developer's workflow, ready to go! The next time they push some code, an Xcode Cloud build will start, and the app will be archived for both iOS and macOS. Then, a new build will get into the hands of a group of friends and family, who will test and provide feedback on the app. Now, let's take it up a notch and look at our second use case: a medium sized team.
Let's imagine a team composed of developers, project managers, and QA engineers, all spread across the world. They build an iOS app, available on iPhone and iPad. Each developer works in their own branches. They use pull requests to merge their changes back into a branch named "beta". Their internal QA team installs and tests builds made from that specific branch to ensure the app and its features are working as intended.
When they want to release a new version of the app, they merge the beta branch into a release branch and push a new tag to mark the release. To catch bugs and avoid regression, the app is very well tested with both unit and UI tests. They use TestFlight to deploy the app to internal and external testers at different points during development. Finally, they communicate and collaborate on their work over Slack. This is a pretty common example. They're using their tools to work and collaborate in parallel, while holding themselves to a high quality bar. Their process can be implemented with three Xcode Cloud workflows. First, I will create a pull request workflow, that helps getting changes into the beta branch. Then, I will create a beta workflow, that gets internal builds into the hands of the QA team. Lastly, I will create a final workflow to release new versions of the app to external testers and onto the App Store. Let's look at each of the workflows, in that order. The team uses pull requests to manage incorporating all new code changes into their app. When a developer opens a pull request, their teammates review their code, and they run their tests to make sure the app is working as expected. This first workflow is to make sure that when a new pull request is opened, or an existing one is updated, the tests are run. Let's create this workflow. First, I'm going to click on the plus sign to create a new workflow for my product. In the name field, I will type "Pull Requests". For this workflow, the team wants Xcode Cloud to start builds when a pull request is opened, but only when it targets the "beta" branch. For each of those builds, they want to run the tests. Let's start by adding a new start condition. I will click on the plus sign in the start conditions section and select the "Pull Request Changes" item. By default, it will start a build for any branches, so in the target branch section, I will select "custom branches" Then I will click on the plus sign button and type in "beta".
We only require the one start condition, so I can go ahead and remove the "branch changes" one.
Now I will add a new action to run the tests. I will click on the plus sign next to the Actions section and select "Test".
The app targets both iOS and iPadOS, so the team wants to make sure that the tests pass on devices of different screen sizes and capabilities. In the destination section, I will select one small iPhone, The iPhone 13, one large iPhone, The iPhone 14 Pro Max...
…one small iPad, The iPad mini...
..and finally, you guessed it, one large iPad, the iPad Pro.
Then I'm going to press save.
Awesome. Now, after a successful build on Xcode Cloud, and hopefully an exhaustive code review from their teammates, the developer will be able to merge their pull requests, and get their changes into the beta branch. Conveniently, this brings us to our next workflow: The beta build workflow.
The beta branch is where all upcoming changes are put. When a developer merges a pull request, the QA team wants to get a build of the app with those new changes included so that they can perform some verification tests. This will be the basis of this new workflow, deploying a build to the QA team. Let's jump back into Xcode and create this workflow.
This beta workflow is a mix of the workflows that I previously created.
The team wants to release a build every time a change is merged into the "beta" branch. They need a workflow that runs the tests, archive the app, and uploads it to App Store Connect. To achieve that, let's create a new workflow.
Name it “Beta Release".
And update the start condition accordingly. I will select the existing Branch Changes start condition and change the branch from main to beta.
Then, I'm going to add an archive build action.
And select the "TestFlight Internal Testing" under deployment preparation.
Here, we're using internal distribution, since we don't want this build to be deployed to production by mistake. Now, I'm going to add a post build action, that uploads to App Store Connect.
This post action will distribute the application to an internal group of testers. I will add a TestFlight Internal Testing post action.
Click on the plus sign under the groups section, and select "QA Team." All right, we could stop here, but we don't want to risk deploying a broken build. As a safety net, we're going to run the tests as part of that workflow as well. I'm going to repeat the testing action from the pull request workflow. Once again, I'm going to select one small iPhone, one large iPhone, one small iPad...
…and one large iPad.
I can now press Save to finalize the creation of this workflow.
The beta build workflow gets builds into the hands of the QA team, but there is one more thing the team wants to do. They would like to use an alternative app icon for their beta build. That way, they can quickly determine between which of the builds are internal, and which are App Store ready. This is another perfect situation where Xcode Cloud's custom scripts can help.
Earlier, we saw a custom script that ran after the source code has been cloned. Here, we'll use a pre-build script to change the icon.
Using the environment variables available in a script, I'm going to make sure that we only swap the icons in the build phase of our beta workflow. If you want to learn more about how to achieve this, please refer to the session from WWDC21, "Customize your advanced Xcode Cloud workflows" where this exact use case is covered in details. We've only used two of the three types of custom scripts available. If you're wondering what other script you can use, and which environment variables are available to you, our documentation explains all of this in details. And that's it for the beta build workflow. Let's now look at the final workflow for this team, the release workflow. After a number of changes have landed in the beta branch and been verified by QA, the team will prepare a new release.
Their process requires one of the developers to merge the beta branch into a release branch, then create a tag to mark the release.
The name of the tag has to start with the word release, then a version. Once this is done, the apps get built, uploaded to App Store Connect, and distributed to a group of internal stakeholders, and some eager customers.
Our third and final workflow is very similar to the beta workflow, except that we want builds to be created when a new release tag has been pushed. Let's go back to Xcode and create this workflow. The steps required for this workflow are almost exactly the same as the one I created in the beta workflow. I could go through all the same steps, like creating the start condition, archiving the app and so on. Instead, I want to direct you to an Xcode Cloud feature that will allow us to duplicate the beta workflow. First, I'm going to right-click on the beta workflow, select duplicate, then rename the workflow from Beta to Release.
Then, I'm going to add a new start condition. So I will click on the plus sign in the start conditions section and select "Tag Changes".
Similar to the branch changes, I don't want to create builds every time a tag is pushed, but only when the name of the tag starts with the word "release." I'm going to select "Custom Tags" in the "tag" section. Enter "release/"...
...and select "tags beginning with release/" in the menu. With this start condition created, I will go back to the existing "branch changes" start condition and delete it. Now, let's move on to the existing Archive action. The beta workflow was created to deploy builds internally, specifically to the QA team. Here, the team wants to prepare a release for external testing and the App Store. In the Deployment Preparation section, I'm going to select the "Testflight and App Store" option. That said, we still want to deploy the build to an internal team of stakeholders. I'm going to select the existing post build action and remove the QA team Group.
Then, I'm going to click on the plus sign and select the "Executive Stakeholders" group. As a last step, I'm going to add another post action, but this time select TestFlight External Testing. I will click on the plus sign in the Post Actions section and select TestFlight External Testing. Then, I will click on the plus sign in the Groups section, and select the Early Adopters group.
Now, the release workflow is almost ready. We mentioned earlier that this team uses Slack to communicate and collaborate with each other. For this team, getting updates about their builds in Slack will match perfectly their development process. This is especially important if the build failed and cannot be released. Let's add a final step to our workflow. In the release workflow, I will click on the plus sign in the post actions section and select Notify. Xcode Cloud supports sending notifications via email and Slack. Here, I'm going to click on the plus sign under Slack and select the “Releases Feed" channel, then press OK. That concludes our second use case. Those three workflows cover all of the team's development process. They build the app and run tests continuously, allowing developers to contribute with confidence. They archive and distribute the app frequently, making sure that various groups of people are able to provide feedback. This is a fairly common situation, where teams can release apps of great quality with the help of tools that adapt to any processes. Let's further support this statement by looking at a third and final use case, in which a bigger team wants to migrate to Xcode Cloud. For our final case study, say we have a large team of developers. This team shares a lot of similarities with the medium-sized team we just looked at, with some twists. The team is bigger and the code base, much more complex. They have an app on iOS and iPadOS, which has been around since the beginning of the App Store. It has been redesigned and updated many times since then, and developers are dealing with a lot of legacy code and complexity, especially when doing QA. They have a lot of tests. Recently, they adopted a test-driven development approach and lots of new tests are being added with every new code change.
A lot of people are involved in successful updates to the app, so they often distribute new builds to various TestFlight groups, both internal and external, to gather feedback. The team includes many developers working around the world, using Slack to communicate and collaborate. But here is the interesting twist. They already rely on continuous integration and continuous deployment to get their work done. Currently, they use an in-house solution that one of the team member maintains and operates. Access to and knowledge of this system is limited, which makes issues hard to investigate and even harder to resolve. For these reasons, and more, they're considering switching to Xcode Cloud to replace this in-house system. Additionally, they use a project management tool, to track, coordinate, and prioritize the work they're doing. They have also created various dashboards and status pages. That way, people not directly involved in the development of the app can track the progress of the project. Xcode Cloud is a great fit for this kind of team, but migrating a project of this complexity onto a new CI system is hard and can feel overwhelming. In this situation, my recommendation is to break this migration down into different milestones. Each milestone involves moving a workload from the existing system into Xcode Cloud over a period of time. The main focus here is to allow a successful migration, while keeping the team productive and happy. Instead of looking at workflow configurations, let's look at what those milestones might be. My recommendation is to split this migration into distinct milestones. The first step is creating a workflow that builds a version of the app that can be released to the App Store. The second is to get tests working reliably. The third is establishing the remaining workflows that match and improve the team's development process. We'll look at each of these steps in details, beginning with creating a release workflow.
When migrating to Xcode Cloud, my recommendation is to start by creating a workflow that archives and uploads an App Store-ready build of the app. This is just like some of the example workflows we've already created and it can be achieved with zero disruption for the rest of the team. By starting there, you'll be able to use the cloud code signing feature built right into Xcode Cloud. No need to mess with certificates and provisioning profiles to sign your build. This is also a good way to see what is needed in order to build the app successfully with respect to dependencies and other configuration changes. Once this workflow is ready, it can be included into the team's regular development process as the part that creates your App Store-ready build. This is the first piece of work to have moved off of the existing system and onto Xcode Cloud. Next, its time to focus on getting tests working reliably. Testing can be very tricky in a continuous integration system. Often, tests will have been tailored to run in the CI environment that was being used at the time they were created. When running in a new CI environment, they may not run as reliably, causing builds to fail. During the creation of Xcode Cloud, we thought about this specific problem, and built a feature we believe can really help teams get their tests running smoothly. This feature makes Xcode Cloud ignore failures in some of the actions in a workflow and let the build finish.
To activate this feature, select the "Not Required To Pass" option under "requirement" in the workflow's action. By specifying an action as Not Required To Pass, the result of this action won't affect the final result of the Xcode Cloud build. The tests could fail, but the build will succeed nonetheless. You will still see a green checkmark in Xcode Cloud, and in the commit status in your Source Code Management for your build.
This is useful because it means you can continually run your tests off of the critical path. That way, you get to aggregate data to assess how they are performing and if they're reliable enough. Let's look at how to use this feature to get tests working in Xcode Cloud.
The team has quite a few tests, covering many aspects of their app. In this situation, my recommendation is to start by creating a new workflow that runs for all pull requests. In this workflow, a build action will run all the tests but be marked as Not Required To Pass. Whether the tests pass or fail won't block the pull request from being merged just yet. Right now, the idea is to assess how reliable the tests are. Let's remember, the tests are still running in the existing solution, so the pull requests are still merged with confidence, after a week or so. The team can look at the test result data from their pull request builds and see which tests have been passing reliably in Xcode Cloud. These tests can be moved into a new Test Plan, called Reliable Tests. Then, the team can edit the existing pull request workflow and add a new test action that will run the tests from that specific test plan. This time, the test action will be required to pass before the pull request can be merged. For more informations about using test plans on Xcode Cloud, you can refer to the "Author fast and reliable tests for Xcode Cloud" from WWDC22. You can also refer to our documentation on improving code assessments using test plans. The remaining tests, the ones that are not currently performing reliably, can be further investigated to figure out what changes need to be made to make them reliable. As time goes on and changes are made, those tests can be trusted again. They can finally be moved into the reliable test plan and be used to validate changes again. This approach allows you to move your tests to the critical path, step by step, and provide validation and test coverage in your Xcode Cloud workflows.
Once you're happy the tests are running, you now have App Store-ready builds and tests, running reliably in Xcode Cloud. Those two workloads can be removed from the existing CI solution. We are now left with the third and final step: building out the rest of the workflows needed for the team's development process. Some of those workflows will be similar to what we've seen already in the case studies in this session. Through the various customizations you can make to start conditions and actions, you can create some really powerful workflows to help automating your CI and CD process. We also mentioned this team has created tools and dashboards outside their CI system. Those tools help them keep on top of their development process, and can also be integrated with Xcode Cloud. For example, you can use the webhook feature. After a webhook as been configured, whenever a build completes, a request will be sent to your server with information about the build, the workflow that started it, and so on. From there, if the build was created from the beta workflow and it succeeded, you could create a new ticket in your task management system, to track the QA process on this specific build.
If you wish to learn more about webhooks and specifically when those requests are sent and what information are available to you, you can refer to our documentation. Another approach is to use the Xcode Cloud public API. It allows you to fetch information about the recent builds, among other things, and display them on a dashboard or a status page.
Once again, you can refer to the documentation to learn how to use the Xcode Cloud's public API and integrate it into your workflows. Xcode Cloud's public API and the webhook mechanism are features that are extra useful for teams, no matter their size. When combining all the options available, the possibilities are endless. You can refer to the session from WWDC22, "Deep dive into Xcode Cloud for teams" for more examples. In this session, we looked at various types of simple but powerful workflows that can be created to help your team be more productive. We showed some examples on how to customize your build process using build scripts at various points in the build. Finally, we showed that some of the features allow you to build tools on top of Xcode Cloud and integrate with external tools. We hope that these three cases studies helped you realize how Xcode Cloud can fit your team and improve your day-to-day work. Thank you for watching. ♪ ♪