1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
name: Docs
# Builds the Starlight docs site (docs-site/) and deploys it to Cloudflare
# Pages at murk.interrupted.sh. Runs on every push to main and on release tags,
# so a release redeploys the docs from the released tree.
#
# The Reference pages are mirrored from docs/cli-reference.md and
# docs/env-reference.md by docs-site/scripts/sync-generated-docs.mjs (invoked by
# the site's prebuild step). Those files are generated by gen-docs and their
# freshness is a required check on main (see ci.yaml: "gen-docs -- --check").
# This workflow only deploys tags that are ancestors of main (see the guard step
# below), so the committed references are always in sync with the released
# binary and we build straight from them — no need to recompile the crate to
# regenerate them inside this pipeline.
#
# One-time setup (Cloudflare side, not managed here):
# - Create a Cloudflare Pages project named "murk-docs".
# - Add the custom domain murk.interrupted.sh to that project.
# - Store repo secrets CLOUDFLARE_API_TOKEN (scoped to Pages:Edit for the
# account) and CLOUDFLARE_ACCOUNT_ID.
# Until the secrets exist the deploy step fails closed.
on:
push:
branches:
tags:
workflow_dispatch:
permissions:
contents: read
# Per-ref: successive pushes to the same ref supersede each other (latest main
# wins), but a release-tag deploy runs in its own group and is never canceled
# by a concurrent main push.
concurrency:
group: docs-deploy-${{ github.ref }}
cancel-in-progress: true
jobs:
deploy:
name: Build & deploy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Full history so the tag-on-main ancestor check below can resolve.
fetch-depth: 0
# A tag can be pushed anywhere; only deploy release docs from tags that
# are on main, mirroring release.yaml's preflight. Branch pushes to main
# and manual runs skip this.
- name: Verify tag is on main
if: startsWith(github.ref, 'refs/tags/')
run: |
set -euo pipefail
git fetch --no-tags origin main:refs/remotes/origin/main
# Dereference to the commit so annotated tags (a tag object, not a
# commit) resolve correctly for the ancestor check.
TAG_SHA=$(git rev-parse "${GITHUB_REF}^{commit}")
git merge-base --is-ancestor "$TAG_SHA" refs/remotes/origin/main \
|| { echo "::error::Tag ${GITHUB_REF_NAME} ($TAG_SHA) is not on main; refusing to deploy docs."; exit 1; }
echo "Tag ${GITHUB_REF_NAME} ($TAG_SHA) is on main."
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "22"
cache: npm
cache-dependency-path: docs-site/package-lock.json
- name: Install dependencies
working-directory: docs-site
run: npm ci
# prebuild runs sync-generated-docs.mjs, mirroring docs/cli-reference.md
# and docs/env-reference.md into the content collection before Astro builds.
- name: Build site
working-directory: docs-site
run: npm run build
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
workingDirectory: docs-site
command: pages deploy dist --project-name=murk-docs --branch=main --commit-dirty=true
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}