Continuously Building and Hosting our Swift DocC Documentation using Github Actions and Netlify
Tags: ios, docc, githubactions, netlify
Published: 2022-02-16 08:38:45

---
title: Continuously Building and Hosting our Swift DocC Documentation using Github Actions and Netlify
published: true
description: In this post we'll see how to use Github Actions to continuously generate the DocC documentation for our Swift libraries and how to publish this documentation so that can be accessed online, using Netlify.
canonical_url: https://www.mongodb.com/developer/how-to/build-host-docc-documentation-using-github-actions-netlify/
tags: iOS, DocC, GithubActions, Netlify
cover_image: https://mongodb-devhub-cms.s3.us-west-1.amazonaws.com/og_virtual_presentation_8e8c59be27.png
---

In a [past post](https://www.mongodb.com/developer/quickstart/document-swift-powered-frameworks-using-docc/) of this series, we showed how easy it was to generate documentation for our frameworks and libraries using DocC and the benefits of doing it. We also saw the different content we can add, like articles, how-tos, and references for our functions, classes, and structs.

But once generated, you end up with an archived DocC folder that is not _that_ easy to share. You can compress it, email it, put it somewhere in the cloud so it can be downloaded, but this is not what we want. We want:

* Automatic (and continuous) generation of our DocC documentation bundle.
* Automatic (and continuous) posting of that documentation to the web, so it can be read online. 

## What’s in a DocC bundle?

A `.doccarchive` archive is, like many other things in macOS, a folder. [Clone the repository we created with our documentation](https://github.com/mongodb-developer/realm-binary-tree-docc) and look inside `BinaryTree.doccarchive` from a terminal. 

```bash
git clone https://github.com/mongodb-developer/realm-binary-tree-docc 
cd BinaryTree.doccarchive
```

You’ll see:

```
..
├── css
│   ├── …
│   └── tutorials-overview.7d1da3df.css
├── data
│   ├── documentation
│   │   ├── binarytree
│   │   │   ├── …
│   │   │   └── treetraversable-implementations.json
│   └── tutorials
│       ├── binarytree
│       │   ├── …
│       │   └── traversingtrees.json
│       └── toc.json
├── downloads
├── favicon.ico
├── favicon.svg
├── images
│   ├── …
│   └── tree.png
├── img
│   ├── …
│   └── modified-icon.5d49bcfe.svg
├── index
│   ├── availability.index
│   ├── data.mdb
│   ├── lock.mdb
│   └── navigator.index
├── index.html
├── js
│   ├── chunk-2d0d3105.459bf725.js
│   ├ …
│   └── tutorials-overview.db178ab9.js
├── metadata.json
├── theme-settings.json
└── videos
```

This is a single-page web application. Sadly, we can’t just open `index.html` and expect it to render correctly. As [Apple explains in the documentation](https://developer.apple.com/documentation/Xcode/distributing-documentation-to-external-developers), for this to work, it has to be served from a proper web server, with a few [rewrite rules](https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html#rewriterule) added: 

> To host a documentation archive on your website, do the following:
> 
> 1. Copy the documentation archive to the directory that your web server uses to serve files. In this example, the documentation archive is SlothCreator.doccarchive.
> 1. Add a rule on the server to rewrite incoming URLs that begin with /documentation or /tutorial to SlothCreator.doccarchive/index.html.
> 1. Add another rule for incoming requests to support bundled resources in the documentation archive, such as CSS files and image assets.

They even add a sample configuration to use with the Apache `httpd` server. So, to recap:

* We can manually generate our documentation and upload it to a web server.
* We need to add the rewrite rules described in Apple’s documentation for the DocC bundle to work properly.

Each time we update our documentation, we need to generate it and upload it. Let’s generate our docs automatically.


## Automating generation of our DocC archive using GitHub Actions

We’ll continue using our [Binary Tree Package](https://github.com/mongodb-developer/realm-binary-tree) as an example to generate the documentation. We’ll add a GitHub Action to generate docs on each new push to main. This way, we can automatically refresh our documentation with the latest changes introduced in our library.

To add the action, we’ll click on the `Actions` button in our repo. In this case, a Swift Action is offered as a template to start. We’ll choose that one:

![Get started with GitHub screen, showing a “Suggested for this repository” Action for Swift projects.](https://mongodb-devhub-cms.s3.us-west-1.amazonaws.com/hosting_docc_01_edc5a3fe4b.png)

After clicking on `Configure`, we can start tweaking our action. A GitHub action is just a set of steps that GitHub runs in a container for us. There are predefined steps, or we can just write commands that will work in our local terminal. What we need to do is:

* Get the latest version of our code.
* Build out our documentation archive.
* Find where the `doccarchive` has been generated.
* Copy that archive to a place where it can be served online.

We’ll call our action `docc.yml`. GitHub actions are YAML files, [as the documentation tells us](https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions). After adding them to our repository, they will be stored in `.github/workflows/`. So, they’re just text files we can edit locally and push to our repo.


### Getting the latest version of our code

This is the easy part. Every time a Github action starts, it creates a new, empty container and clones our repo. So, our code is there, ready to be compiled, pass all tests, and does everything we need to do with it.

Our action starts with:

```yaml

name: Generate DocC
on:
  push:
    branches: [ main ]
    
jobs:
  Build-Github-Actions:
    runs-on: macos-latest

    steps:
    - name: Git Checkout
      uses: actions/checkout@v2
```

So, here:

* We gave the action the name “Generate DocC”.
* Then we select when it’ll run, i.e., on any pushes to `main`.
* We run this on a macOS container, as we need Xcode.
* The first step is to clone our repo. We use a predefined action, `checkout`, that GitHub provides us with.


### Building out our documentation archive

Now that our code is in place, we can use `xcodebuild` to build the DocC archive. We can [build our projects from the command line](https://developer.apple.com/library/archive/technotes/tn2339/_index.html), run our tests, or in this case, build the documentation.

```bash
xcodebuild docbuild -scheme BinaryTree -derivedDataPath ./docbuild -destination 'platform=iOS Simulator,OS=latest,name=iPhone 13 mini'
```

Here we’re building to generate DocC (`docbuild` parameter), choosing the `BinaryTree` scheme in our project, putting all generated binaries in a folder at hand (`docbuild`), and using an iPhone 13 mini as Simulator. When we build our documentation, we need to compile our library too. That’s why we need to choose the Simulator (or device) used for building.


### Find where the `doccarchive` has been generated

If everything goes well, we’ll have our documentation built inside `docbuild`. We’ll search for it, as each build will generate a different hash to store the results of our build. And this is, on each run, a clean machine. To find the archive, we use:

```bash
find ./docbuild -type d -iname "BinaryTree.doccarchive"
```


### Copy our documentation to a place where it can be served online

Now that we know where our DocC archive is, it’s time to put it in a different repository. The idea is we’ll have one repository for our code and one for our generated DocC bundle. Netlify will read from this second repository and host it online.

So, we clone the repository that will hold our documentation with:

```bash
git clone https://github.com/mongodb-developer/realm-binary-tree-docc
```

So, yes, now we have two repositories, one cloned at the start of the action and now this one that holds only the documentation. We copy over the newly generated DocC archive:

          

```bash
cp -R "$DOCC_DIR" realm-binary-tree-docc
```

And we commit all changes:

```bash
cd realm-binary-tree-docc
git add .
git commit -m "$DOC_COMMIT_MESSAGE"
git status
```

Here, `$DOC_COMMIT_MESSAGE` is just a variable we populate with the last commit message from our repo and current date. But it can be any message.

After this, we need to push the changes to the documentation repository.

```bash
git config --get remote.origin.url
git remote set-url origin https://${{ secrets.API_TOKEN_GITHUB}}@github.com/mongodb-developer/realm-binary-tree-docc

git push origin
```

Here we first print our `origin` (the repo where we’ll be pushing our changes) with

```bash
git config --get remote.origin.url
```

This command will show the origin of a git repository. It will print the URL of our code repository. But this is not where we want to push. We want to push to the _documentation_ repository. So, we set the origin pointing to [https://github.com/mongodb-developer/realm-binary-tree-docc](https://github.com/mongodb-developer/realm-binary-tree-docc). As we will need permission to push changes, we authenticate using a Personal Access Token. From [Github Documentation on Personal Access Tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token):

> You should create a personal access token to use in place of a password with the command line or with the API.


![Github Settings page to add Personal Access Tokens](https://mongodb-devhub-cms.s3.us-west-1.amazonaws.com/hosting_docc_02_79756268e0.png)


Luckily, Github Actions [has a way to store these secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets), so they’re publicly accessible. Just go to your repository’s Settings and expand Secrets. You’ll see an “Actions” option. There you can give your secret a name to be used later in your actions.


![Repository Secrets, showing API_TOKEN_GITHUB](https://mongodb-devhub-cms.s3.us-west-1.amazonaws.com/hosting_docc_03_830c4af9aa.png)

For reference, [this is the complete action I’ve used](https://github.com/mongodb-developer/realm-binary-tree/blob/main/.github/workflows/main.yml).


## Hosting our DocC archives in Netlify

As shown in this [excellent post](https://josephduffy.co.uk/posts/hosting-docc-archives) by [Joseph Duffy](https://twitter.com/Joe_Duffy), we'll be hosting our documentation in [Netlify](https://www.netlify.com/). Creating a free account is super easy. In this case, I advise you to use your Github credentials to log in Netlify. This way, adding a new site that reads from a Github repo will be super easy. Just add a new site and select Import an existing project. You can then choose Github, and once authorized, you’ll be able to select one of your repositories. 

Now I set it to deploy with “Any pull request against your production branch / branch deploy branches.” So, every time your repo changes, Netlify will pick up the change and host it online (if it’s a web app, that is).

But we’re missing just one detail. Remember I mentioned before that we need to add some rewrite rules to our hosted documentation? We’ll add those in a file called [`netlify.toml`](https://github.com/mongodb-developer/realm-binary-tree-docc/blob/main/netlify.toml). This file looks like:

```toml
[build]
publish = "BinaryTree.doccarchive/"

[[redirects]]
from = "/documentation/*"
status = 200
to = "/index.html"

[[redirects]]
from = "/tutorials/*"
status = 200
to = "/index.html"

[[redirects]]
from = "/data/documentation.json"
status = 200
to = "/data/documentation/binarytree.json"

[[redirects]]
force = true
from = "/"
status = 302
to = "/documentation/"

[[redirects]]
force = true
from = "/documentation"
status = 302
to = "/documentation/"

[[redirects]]
force = true
from = "/tutorials"
status = 302
to = "/tutorials/"
```

To use it in your projects, just review the lines:

```toml
publish = "BinaryTree.doccarchive/"
…
to = "/data/documentation/binarytree.json"
```

And change them accordingly.


## Recap

In this post, we’ve seen how to:

* Add a Github Action to a [code repository](https://github.com/mongodb-developer/realm-binary-tree) that continuously builds a DocC documentation bundle every time we push a change to the code.
* That action will in turn push that newly built documentation to a [documentation repository](https://github.com/mongodb-developer/realm-binary-tree-docc) for our library.
* That documentation repository will be set up in Netlify and add some rewrite rules so we'll be able to [host it online](https://binary-tree-doc.netlify.app/documentation/).

Don’t wait and add continuous generation of your library’s documentation to your CI pipeline!