reCAPTCHA WAF Session Token

DocC Tutorial for Swift: Automating Publishing With GitHub Actions

In the software development routine, it’s common to perform repetitive tasks manually. But this comes with a price: It’s both tedious and error-prone. Fortunately, the industry has developed solutions that address the need to automate the repetitive processes a developer or a team must perform.

In a previous tutorial, Mina H. Gerges walked through using DocC and Xcode to generate documentation for an app and a Swift package and then export them in the DocC archive format.

In this follow-up tutorial, you’ll learn how to automate exporting a DocC archive file using DocC on GitHub Actions and then publish it on the internet using GitHub Pages as a static website host.

Along the way, you’ll learn:

  • How to generate the documentation in the DocC using Xcode and the command line.
  • How to configure a GitHub repo to host the generated documentation.
  • How to set up GitHub Actions to regenerate and republish the documentation when you push changes to the repo.
Note: This tutorial assumes you have a basic notion of how Git and GitHub work. To learn more about it, check out Open-Source Collaboration Using Git and GitHub.You’ll build documentation for a package that requires SwiftUI and the iOS SDK. For that reason, this tutorial uses DocC integration within Xcode, which requires a Mac host. If you’re willing to document a pure Swift package that can be built on Linux, you might use the Swift-DocC plugin directly, as explained in this page. Besides that difference, you can still follow along to understand how GitHub Actions works.

Getting Started

Start by clicking Download materials at the top or bottom of this tutorial. Open GivenWithLove.xcworkspace in the Starter directory in Xcode.

You’ll notice the workspace contains the app as well as a Swift package. For both, Xcode can build the documentation. While this tutorial is about calling DocC via command line, you can use the Xcode UI to build the documentation. To do so, select any simulator as a run destination rather than a device or Any iOS Device. Then, open the Product menu, and select Build Documentation.

After a few seconds, Xcode builds the documentation and then automatically opens it in the Developer Documentation window.

In this tutorial, you’ll learn how to execute this same Action from the command line, export it to HTML and host it using GitHub Pages — all powered by GitHub Actions. But before starting and getting your hands on the keyboard, here’s a quick review of what CI/CD and GitHub Actions mean.

Understanding CI/CD and GitHub Actions

If you work with mobile or web development, there’s a good chance you’re familiar with the terms continuous integration (CI), continuous delivery (CD) and GitHub Actions. If they’re new to you, no worries: You’re in the right place!

What Is CI/CD?

When adding new features or fixing bugs, you need to test your new code and verify you didn’t break anything else. Or you might work on an SDK and need to publish the updated documentation. But doing it manually — again and again — is far from ideal. To solve this issue, and to reduce human error, a good practice is automating these tasks.

Continuous integration is the automation of building and testing code whenever the version control system, such as Git, detects new changes. Usually, using webhooks, the Git remote repository updates the CI system about the changes. For example, when the main branch has a new commit, when someone creates a pull request or when a new tag is available, it updates the CI, which, in turn, runs specific workflows depending on the trigger.

Another term that frequently appears alongside CI is CD, which stands for “continuous delivery”. Besides compiling and running tests on the new code, developers often want to preview their changes without performing manual operations. A CD system (no, not those old sound systems from the ’90s) addresses this need by deploying a preview website or a beta app, or even fully releasing an app or a website.

Git operation update the CI, which tests or builds the code

In general, CI/CD runs on a remote, hosted computer, with the objective of offloading time and resources from a developer’s machine, in addition to the round-the-clock availability.

Meet GitHub Actions

Although Git and CI/CD aren’t interchangeable concepts, they’re essentially intertwined. By definition, CI/CD must have access to the source code and be alert for the events mentioned above. Because of the natural relationship between these tools, in 2018, GitHub launched its own workflow automation tool. By providing both Git and CI/CD, GitHub can centralize them in a single place, allowing for a faster, seamless developer experience.

A repository on GitHub might contain multiple workflows, each with a different goal. For instance, one workflow runs tests while another builds and uploads a new app version. They run based on triggered events: The tests’ workflow can run when there’s a new pull request, and the deploy workflow can start once a new Git tag is pushed. The workflow itself contains one or multiple jobs, which in turn consist of one or more steps.

A step can be a regular terminal command, such as running Swift, NodeJS or any other CLI tools and binaries. But to make its CI even more powerful, GitHub allows developers to create their own building blocks and share them with the open-source community. These building blocks are called actions, and your workflows can use these steps besides running one-off script commands. Here’s where GitHub’s platform makes a difference, and the GitHub Marketplace page enables you to search for actions that might fit your needs.

Runners are another important component of GitHub Actions. A runner is a server hosted by GitHub that executes a job of a workflow. Upon execution of a job, a fresh, clean virtual machine is created, running the platform of your choice: Linux, Windows or macOS.

Basic components of GitHub Actions

The Workflow YAML File

GitHub Actions allows multiple workflows per repository, and each workflow describes its jobs and their steps using a YAML file. If you aren’t familiar with the syntax, YAML is a data serialization language widely adopted in the industry, mostly for describing configuration files. Here’s a short example of how it works:

# Key-value pairs are separated by a colon and a space
name: Jane Appleseed
age: 30
city: Cupertino

# Maps/Dictionaries use indentation to show nested key-value pairs
  street: 19400 Homestead Road
  city: Cupertino
  state: CA
  zip: 95014

# Arrays are denoted by a hyphen and a space, and can contain any type of data, including nested dictionaries or arrays
  - apple
  - orange
  - banana

As some people find the syntax confusing, you can visit Learn YAML in Y minutes if you want to learn more or have further doubts. Online linter tools, such as YAML Lint, are also valuable when validating a YAML file.

One must place all workflow files in the .github/workflows directory of a repository. A later section will instruct you on how to configure a workflow file for this tutorial’s purpose, but here are some of the most important and frequent properties:

  • name: The name GitHub displays for actions that ran a workflow under the “Actions” tab. It’s optional, defaulting to the workflow file name.
  • on: A list of events that trigger a workflow, such as pushes, new pull requests, webhooks and many more. You can see the full list of events in this link.
  • jobs: A workflow consists of one or more jobs. Although they run in parallel, a job can have a dependency on another job, meaning it waits for another’s completion before starting.
  • runs-on: Every job in a workflow can run in a different runner. The job must declare which operating system and machine to run on. Some of the options are macos-latest, macos-13, ubuntu-latest, ubuntu-18.04 and any other runner image present in this list.

The full list of options and parameters is available in the Workflow syntax for GitHub Actions page.

Building the Documentation Locally

Before moving straight to GitHub Actions, you should verify that you can build the documentation locally. To achieve that — and to prepare the next steps of the automation — you’ll create a bash script to consolidate the commands.

Creating the Script

First, open Terminal in the root directory of the sample project to create the script file. Enter the following command:


This creates a file named Before editing it, make the script executable by adding the appropriate permission to the file so you can run it later:

chmod +x

Now, open it with your text editor of choice, and add the following command:


xcrun xcodebuild docbuild \
    -scheme GivenWithLove \
    -destination 'generic/platform=iOS Simulator' \
    -derivedDataPath "$PWD/.derivedData"

Although it’s spread across four lines, this is a single command. Here’s what it does:

  1. xcrun is a tool that allows interaction with Xcode via command line, and xcodebuild is the part of it responsible for building Xcode projects. docbuild is the subcommand that builds the documentation for a given target.
  2. Choose the scheme you want to build documentation for. In this case, it’s the GivenWithLove app.
  3. Both the app and package were built for iOS and import SwiftUI, so set the destination to iOS. Some xcodebuild actions don’t require a specific device or simulator to run on, so prefix the destination with generic/. And because you don’t want to deal with code signing, choose iOS Simulator instead of an actual device.
  4. By default, xcodebuild generates its products and places them in the default derived data folder. Because you’ll need to find the documentation it generates, use a custom derived data location, with a known path, for easy access.

Running the Script Locally

Now, it’s time to use the script and generate the documentation locally. Back in Terminal, run the following command:


After a few moments, the command should succeed. Once the xcodebuild output ends its explosion of characters, you’re ready to explore the generated documentation.

To find the DocC archives, open the .derivedData folder. Because it’s a hidden folder, you might not see it right away in Finder. To display hidden files and directories, press Command-Shift-.. Once you find it, open it and go to the Build folder, followed by the Products and the Debug-iphonesimulator directories. There, you’ll find the GivenWithLove.doccarchive file. If you can’t find the hidden folder or want to jump right into the final directory, run the following command:

open .derivedData/Build/Products/Debug-iphonesimulator

This is what you’ll see in that folder:

The fresh Docc archive

Double-click GivenWithLove.doccarchive, and Xcode will open the Developer Documentation window again. Notice how Xcode now displays it under the Imported Documentation section, as xcrun built it:

Xcode displaying the documentation created via command line

Congrats! You just generated your package’s documentation completely via Terminal commands — without interacting with the Xcode UI. In the upcoming sections, you’ll learn how to generate the same files on GitHub Actions, transform them into a website-compatible format and publish them to GitHub Pages.

Converting the Documentation to HTML

While it’s possible to view the DocC archive on a Mac, it’s still not the ideal format for publishing on the web. For that, Apple has added a command to docc that converts a .doccarchive input into a directory. This directory will contain all the necessary files for publishing the documentation as a static website.

Open the file, and add the following lines after the existing command:

xcrun docc process-archive transform-for-static-hosting \
    "$PWD/.derivedData/Build/Products/Debug-iphonesimulator/GivenWithLove.doccarchive" \
    --output-path ".docs" \
    --hosting-base-path "" # add your repo name later

By running this command, you’ll tell docc where to find the input archive and where it should place the output files: in a folder named .docs. After creating your repository on GitHub, you’ll need to set the hosting-base-path argument, but you can leave it empty for now. Run the script again to check the result:


After this command finishes, navigate to the .docs folder to see its contents:

open .docs

Note: To view the documentation locally, you’ll need to run a local server to host the website. As running a local server isn’t in the scope of this tutorial and also isn’t essential to it, it’s only briefly mentioned. If you have Python 3 installed, you can run the command python3 -m http.server -d .docs. If your macOS doesn’t have Python, you can install it with homebrew — brew install python3 — first. Once you have the local server running, the documentation will be visible at http://localhost:8000/documentation/givenwithlove/.

Redirecting to the Documentation Page

If you were able to serve the docs locally, you might be wondering why the root page displays an error. This is because DocC organizes the files for static hosting in the following structure:

The documentation in a format that can be statically served on the web

As you can see, the givenwithlove directory is located under documentation. To view the documentation of an app or package, the address should be in the pattern instead of accessing the root page ( Accessing the root page results in an error.

To help your readers, you can replace the .docs/index.html file with a redirect, and the browser will lead them directly to the correct path.

Open the file again, and in a new line, add the following:

echo '<script>window.location.href += "/documentation/givenwithlove"</script>' > .docs/index.html

This will redirect the root page to the documentation. Rerun, restart your local server, and when you visit http://localhost:8000/, you’ll be redirected to the documentation page.

Now, it’s time to move on and get your hands on GitHub!

Setting Up GitHub Pages

So far, you’ve learned how to generate the .doccarchive file and convert it into a format suitable for static hosting. The next step is defining the workflow file for running the same script you ran locally and publishing the content to GitHub Pages.

GitHub Pages is another service — you guessed right, from GitHub — that allows developers to host static website content for a personal profile or specific projects. It even allows custom domains with HTTPS support!

Activating GitHub Pages in Your Repository

Create an empty repository on GitHub for this tutorial. GitHub Pages only works with private repos if you’re on the Pro plan. Otherwise, if you have a free GitHub account, make sure you create a public repository. To make pushing your commits smoother, don’t include a Readme or a .gitignore file.

In your browser, open your new repository, and go to the Settings tab. In the left pane, under the Code and automation section, click Pages. In the Build and deployment section, click the Source menu, and choose GitHub Actions. There are two ways of deploying to GitHub Pages, and although still in beta, publishing to Pages via Actions is the way GitHub recommends (instead of pushing to a specific branch).

The GitHub Pages section in the repository settings

The GitHub Pages URL Format

GitHub Pages can host two types of pages: personal and projects. Personal pages are intended to be your “home” on the web, while project pages can be an open-source project’s showcase.

While personal pages must belong to a repository named, and the page is accessible at, project pages work slightly differently. The repository can have any name, and users can find it at

To take that into account, the export command can receive a base path and adjust the routes accordingly. Open — for the last time today — the build script at In the second command, where you see the comment, set your repository name in the already present, but empty, hosting-base-path argument:

--hosting-base-path "<your-repository-name>"

This makes your documentation aware of the relative location in which it’s placed on the website when DocC transforms the documentation for publishing.

Moving forward, it’s time to set up your workflow.

Configuring GitHub Actions

All the GitHub Actions configuration you’ll need takes place in the workflow file, so there’s no need to change the Actions settings. All workflow files must reside under the .github/workflows directory. To create one, run the following command:

mkdir -p .github/workflows

Now, create the YAML file you’ll use to define your workflow:

touch .github/workflows/docc.yml

Defining the Workflow File

Open the file you just created with your text editor. Copy the lines below and paste them into this new file. Make sure your text editor keeps the space indentation instead of replacing them with tabs. YAML relies on the spaces and the indentation to validate the content and its structure.

name: docc

    branches: [main]

  pages: write
  id-token: write
  contents: read

Here’s what this file describes so far:

  1. The name of this workflow.
  2. The events that will trigger running this workflow. The push trigger will work when new commits are pushed to the main branch. Adding workflow_dispatch allows manually triggering the workflow from the GitHub Actions UI.
  3. Set permissions for the GitHub token running the Action to allow deployment to GitHub Pages, and read permissions for checking out the repository content.

A workflow contains one or more jobs. The first stage of the workflow is running the script you prepared above. To configure the job to do so, add the following code:

    runs-on: macos-12
      - name: Checkout Repository
        uses: actions/checkout@v3
          fetch-depth: 0
      - name: Run Build Docs
        run: ./
      - name: Setup Pages
        id: pages
        uses: actions/configure-pages@v3
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v1
          path: .docs

It might be a lot, but breaking it down piece by piece makes it easier to understand:

  1. Declare the jobs map, and start with the build job.
  2. Because the script relies on xcrun and Xcode, you’ll need a macOS runner. When using DocC as a Swift package plugin, you can use a Linux machine instead.
  3. One or more steps make up a job. Declare the list of steps, and start by checking out the repository taking only the last commit. Therefore, the fetch-depth option is set to 0.
  4. After checking out the repository, run the script.
  5. Use the actions that GitHub provides: one for configuring pages and another for uploading the contents that the script will generate and place under .docs. Notice how this is the same directory you set in the last line.

You’re almost done! Now, you need to define a job to deploy what the build job generated.

Publishing to GitHub Pages via Actions

Still in the docc.yml file, add the lines below. Pay attention to the fact that the deploy key should have the same indentation as the build key from the previous snippet.

    runs-on: ubuntu-latest
    needs: build
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v2 
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}

Here’s what these lines mean:

  1. Define the deploy job.
  2. Because Xcode isn’t necessary anymore, you can choose a Linux runner.
  3. The previous job, build, created and uploaded the artifacts. So, add a dependency on that job, meaning that this one will only run when the first has finished.
  4. Declare a single step for this job based on the official actions/deploy-pages Action. Set the environment variables it requires.

It’s finally time to test it all!

Running the Workflow on GitHub Actions

If you haven’t yet created your repository locally, run:

git init

As this is a new repository, all your changes are file additions. After staging them, create an initial commit. Then, add the GitHub remote. Replace your username and the repository name before running this command:

git remote add origin<your-username>/<your-repository-name>.git

Create the main branch, and push your changes:

git branch -M main && git push -u origin main

After pushing it to GitHub, open your repository page, and go to the Actions tab. In the list, you’ll see the Action you just created, within a few moments, in the queued state.

In some cases, the Action might get stuck in the queued state. If that’s the case, you’ve already defined the workflow_dispatch event in the workflow, which allows manually triggering the Action.

A GitHub workflow in the queued state, waiting to be started.

After moving from the queued to the running state, click the workflow run in the list to see more details:

A GitHub workflow while it's running

Notice how, in the image above, there’s a line between the build and deploy. It represents the dependency of the deploy job on the build job.

After a few minutes, both jobs should be complete:

A GitHub Action after all jobs completed successfully

As you can see, both jobs have green check marks, making the run itself a successful one. Under deploy, you’ll see a link. Clicking it will take you to, and the browser will display the documentation you worked so hard to publish:

The app documentation is live on GitHub Pages!

Where to Go From Here?

You can download the completed project files by clicking Download materials at the top or bottom of the tutorial.

Congratulations on reaching the end of this tutorial! It included many steps: writing a shell script, creating a repository, enabling GitHub Pages on it, defining your workflow file and running it. If you made it here, it means you learned and acquired new skills.

If you already feel the superpowers of automating your processes, you might want to expand your knowledge in the CI/CD space, deepen your expertise in GitHub Actions, and also in technologies or services that host static content and make its distribution even faster with content delivery networks (CDNs). Here’s what you could do next:

  • Wrap your frequently used steps into a shareable Action of your own.
  • Connect to the web: Automate calling your workflows via webhooks and also call external webhooks from your workflow steps.
  • Automate generation of Swift code that compiles on Linux, using the DocC Swift Package Manager plugin, instead of relying on Xcode and macOS. By doing so, you don’t need to use the macOS runners. The Linux runners will be enough, which is a positive factor since they consume fewer credits than the macOS ones.
  • Publish your documentation to other services, such as Netlify, which provides a CDN on top of hosting.

We hope you enjoyed this tutorial, and if you have any questions or comments, please join the forum discussion below!

Source link

Leave a Reply

Your email address will not be published. Required fields are marked *

WP Twitter Auto Publish Powered By :