At Decodable we migrated our docs platform onto Antora. I wrote previously about my escapades in getting cross-repository authentication working using Private Access Tokens (PAT). These are fine for just a single user, but they’re tied to that user, which isn’t a good practice for deployment in this case.
In this article I’ll show how to use GitHub Apps and Installation Access Tokens (IAT) instead, and go into some detail on how we’ve deployed Antora. Our GitHub repositories are private which makes it extra-gnarly.
Overview 🔗
The docs platform is built on Antora, which generates a static site. This is hosted on Cloudflare Pages.
-
The docs content is on our private
code_repoGitHub repo. -
The Antora platform configuration and build scripts is held on the private
docs-platformGitHub repo. -
The user interface of the documentation site is taken mostly from the vanilla antora-ui-default, with some small tweaks in this repo.
GitHub Actions is used to trigger, build, and deploy the docs site.
Why Two Repositories? 🔗
One of the brilliant things that Antora supports is the ability to pull in the docs content from a git repository. This can be the same as the one that is hosting the Antora configuration—or as in our case, the repository that holds the code for which the documentation is written.
This means that when a new feature is released the code and the docs can be kept in lock-step, both deploy and rollback if necessary.
You can also pull in code from multiple repositories—Antora is super-flexible like this, and supports various styles of code organisation and control.
Build and Deploy 🔗
The docs content lives in code_repo under /docs. The actual build and deploy happens on the docs-platform repository, and as a result the process is more complicated than it would be in a single repository.
-
For docs changes, when a change is pushed to
mainoncode_repothat includes a file under/docs/, thedocs-trigger-deploy.yamlworkflow runs. This in turn triggers thecloudflare.yamlworkflow on thedocs-platformrepository. -
For a platform change the
cloudflare.yamlworkflow on thedocs-platformrepository will run directly.
PR Preview builds 🔗
Not everyone writes perfect docs PRs. I has ben knowwn to right mistaks with speling and grammer, and that’s before you get onto the correctness of documentation which in software is particularly important to be precise and accurate.
By being able to create a preview of PRs as they are raised it’s easy to seek review from colleagues. However readable Asciidoc might be as a markup language, it’s not going to be more readable than the parsed and rendered web page with its links and images in all their glory. The same goes for PRs against the Antora platform configuration itself—whether customising the skin, tweaking a config—all these things benefit from being able to see them in action before hitting the deploy button.
Thus, when a PR is raised against main on the docs-platform or code_repo repos (and includes a file under /docs/ in the case of the code_repo repo) a preview docs site is built and deployed to a unique URL.
The build process does some additional things that the production one doesn’t:
-
The trigger action passes details about the source PR as inputs to the
docs-platformworkflow -
The preview-cloudflare.yaml workflow on the
docs-platformmodifies the Antora playbook to use the source branch of the PR on thecode-reporepository (instead ofmain)- name: If not a platform PR, set the branch of the source repo for antora content if: github.event_name != 'pull_request' id: override_antora_playbook_yml run: | sed -i '7s/main/${{ inputs.pr_branch }}/' antora-playbook.yml -
It overlays a message on the preview site indicating the PR with which that it is associated.
-
Once deployed, it updates the originating PR with the URL of the preview site.
Security and Configuration in GitHub Workflows 🔗
There are two areas of security that need to be correctly configured:
-
Cloudflare
-
GitHub Intra-Repository interactions
Cloudflare 🔗
This one is fairly simple. Store these in the docs-platform repository settings:
-
Repository secret:
CLOUDFLARE_API_TOKEN -
Repository variable:
CLOUDFLARE_ACCOUNT_ID
The GitHub Action then uses these when deploying the site to Cloudflare.
GitHub Intra-Repository Interactions 🔗
This is more complicated since the two repositories are private. The following interactions need authorisation beyond what happens by default within a GitHub Workflow:
-
Actions running in
code_reporepo-
Triggering a workflow in
docs-platformfromcode_repoworkflow
-
-
Actions running in
docs-platformrepo-
When Antora builds the docs site it needs to clone the
code_reporepository -
Updating the PR issue on
code_repothat triggered the preview build
-
How It Works 🔗
The auth for these is handled using a custom GitHub App (Antora Docs Build Bot) installation on each repository.
| The auth can also be done using Personal Access Tokens (PAT) but this would then be tied to a particular user’s account and is therefore not suitable for an organisation. |
When each workflow runs its first step is to use the create-github-app-token action to generate a GitHub App installation access token (IAT). This is valid for the session only, and then provides the authorisation for the intra-repository actions.
The IAT is used in two ways:
-
From the github-script action via the optional
github-tokenparameter. This is used for two different interactions:-
To trigger the
docs-platformbuild and deploy workflows from thecode_reporepository. -
When the Preview workflow adds a comment to the PR that triggered it. If this PR came from the
docs-platformrepository (i.e. local to the action) then no additional auth is needed, but to comment on thecode_reporepository it is.
-
-
When Antora builds the site it clones the
code_reporepository. Since this is run from a different repository the default authentication that would apply to an action running in the same repository doesn’t exist. Antora performs the authentication using the pre-specifiedGIT_CREDENTIALSenvironment variable. This must follow the following syntax:https://x-access-token:[email protected]
Setting up the GitHub App 🔗
This needs to be done by a user with Owner rights on the GitHub organisation. The App has to be created in the GitHub organisation, and from there is installed to the two repositories. The GitHub docs detail the process - below is a short set of notes covering the essential settings:
-
From your GitHub profile page set the
settings contextto that of your organisation, and then click onDeveloper settings(at the very bottom of the page) and thenGitHub Apps -
Click on
New GitHub App.-
Give the new app a name (e.g.
Antora Docs Build Bot) -
Set the
Homepage URLto that ofdocs-platformrepo -
Disable
Webhook
-
-
Under
Repository permissionsset the followingActions
Read/Write
Contents
Read
Issues
Read/Write
Metadata
Read
Pull Requests
Read/Write
-
Click
Create GitHub App -
Make a note of the App ID. You’ll store this later on as a repository secret.
-
Scroll down to
Private keysand click onGenerate a private key. Save the resulting.pemfile locally. -
Click
Install App-
Install it to the account under which the the
docs-platformandcode_reporepos are (i.e.decodeableco). -
When prompted which repositories it should be installed to, select
Only select repositoriesand choosedocs-platformandcode_repo
-
Configuring Repository Secrets and Variables 🔗
As a repo admin, on the code_repo repository add the following repository secrets:
| Key | Value |
|---|---|
|
GitHub App ID |
|
The full text of the .pem, including the |
As a repo admin, on the docs-platform add the following repository secrets
| Key | Value |
|---|---|
|
GitHub App ID |
|
The full text of the .pem, including the |
|
API token from Cloudflare |
and the following repository variable
| Key | Value |
|---|---|
|
Cloudflare Account ID |
Addendum: Deploying Antora using AWS Amplify and GitHub Workflows 🔗
For $REASONS we ended up using AWS Amplify. You can find the build scripts here. There are three scripts:
-
Preview deployment (triggered by a PR creation)
-
Live deployment (triggered by a merge to
main) -
Teardown preview (triggered by a PR being closed)
