GitHub Actions workflows
Four workflows live under .github/workflows/. Two run on pull requests
(the docs check and the preview-environment lifecycle), one runs on
pushes to main (production deploy), and one is the cleanup partner of
the preview lifecycle.
At a glance
| File | Trigger | What it does | Required check? |
|---|---|---|---|
docs-checks.yml | pull_request (opened, sync, reopened, edited, labelled, unlabelled) | Runs the spec 003 path-overlap check + Jira-link check | Yes — docs-required |
pr-preview-create.yml | pull_request (labelled, sync) | Provisions a DO app + optional isolated DB when deploy-preview / deploy-preview-with-db is set | No — only runs when labelled |
pr-preview-cleanup.yml | pull_request (closed, unlabelled) | Tears down the DO app + drops the isolated DB | No |
do-deployment.yml | push to main | Production deploy to DigitalOcean | n/a — runs after merge |
docs-checks.yml
The seatbelt for the docs-update flow. On every PR event, it:
- Computes the diff between the PR branch and
main. - For each changed file, asks whether any
/business-logic/pageowns:it via frontmatter glob. - Checks whether any of those owning pages were also edited on the
branch, OR whether a
docs-update: not-neededsentinel is present in any commit message. - Reports the result as the
docs-requiredstatus check.
It also runs a jira-link check that warns (non-blocking) if the PR
title has no Jira ref. The warning is posted as a sticky comment, not a
blocking check.
Common failure mode — “docs-required: failed”. Open the workflow
log; it lists exactly which files changed and which /business-logic/
page should be updated. Either update that page, or add the sentinel.
pr-preview-create.yml
Runs only when a PR has the deploy-preview or deploy-preview-with-db
label. Concurrency-grouped per PR — a fresh push cancels the in-flight
deploy and re-runs from scratch.
Steps in order:
- Install
doctl— DigitalOcean’s CLI, used for everything else. - Sanitise the branch name to fit DO hostname rules: lowercase,
non-alphanumerics → hyphens, max 18 chars.
TUN-1234-suspend-logic→tun-1234-suspend-l. The DB name (if needed) replaces hyphens with underscores and appends_iba. - (With
-with-dbonly) Install MySQL client, fetch the runner’s public IP, add it to the production DB cluster’s firewall, wait 15s for propagation. - (With
-with-dbonly) Get connection details for the DO managed DB, restore the latest production S3 backup into an isolated DB named for the branch. - Provision the DO app pointing at the right database — isolated
if
-with-db, sharedIBA-DEVotherwise. - Post a sticky comment on the PR with the live URL.
Common failure modes:
- Firewall propagation race — the workflow waits 15s after adding the runner IP. On rare congested days that isn’t enough; the MySQL connection step fails with “host not allowed”. Re-run the workflow.
- DB restore taking >5 minutes — the production backup is sometimes large. The job has generous timeouts but if it’s stuck, check the DO managed-database dashboard for restore progress.
- DO app spec rejected — usually because the team’s DO account ran out of app slots. Tear down a stale preview from a closed PR.
pr-preview-cleanup.yml
The cleanup partner. Fires when:
- A PR is closed (merged or otherwise), OR
- The
deploy-previewordeploy-preview-with-dblabel is removed.
It:
- Deletes the DO app named after the branch.
- Drops the isolated DB (if there was one).
- Removes the runner-IP firewall rule.
You should never need to run this manually. If it fails, the DO
dashboard has a one-click delete for the app and a SQL DROP DATABASE
gets the DB.
do-deployment.yml
Production deploy. Triggered by every push to main — i.e. every PR
merge. Pushes the api/, www/, and admin/ apps to their DigitalOcean
App Platform slots; image rebuilds happen there, not in CI.
The docs site (docs/) is not deployed by this workflow — that’s
handled separately by Cloudflare Pages, which auto-builds from the
GitHub repo. See the Cloudflare Pages integration below.
Common failure modes:
- Out-of-date secrets — the workflow uses Infisical secrets stored as GitHub Actions secrets. If those rotate, the workflow fails at the deploy step.
- Image build timeout — DO App Platform has a build timeout. Large npm installs occasionally exceed it; the fix is usually pruning devDependencies that ended up in production.
Cloudflare Pages (separate)
The docs site has its own status check labelled Cloudflare Pages
on every PR — Cloudflare’s GitHub integration. It runs the docs build
(npm run prebuild && npm run build) against the PR branch and
auto-deploys a preview URL. On merge to main, the same Cloudflare
build promotes to production at docs.tunnelflight.com.
This is not a GitHub Actions workflow — it’s configured entirely in the Cloudflare dashboard. The repo has no YAML controlling it.
See also
- Labels — what each label triggers.
- Deploy previews — the user-facing walkthrough of the preview lifecycle.