Skip to content

Merge branch 'feat/cloudflare-hosting' #194

Merge branch 'feat/cloudflare-hosting'

Merge branch 'feat/cloudflare-hosting' #194

Workflow file for this run

name: Deploy (Cloudflare)
# Both public sites are static assets served by a Worker with NO script, in the
# Cloudflare account that also holds the archlang.uk zone. `main` is absent from
# each wrangler.jsonc on purpose: with no code to invoke, every request is a
# static-asset request — free, unmetered, and exempt from the Workers free-plan
# request cap.
#
# We deploy from CI rather than from Cloudflare's Git integration because the
# build is a monorepo build: `npm run docs:build` / `npm run playground:build`
# build the CORE first and then the site (docs-site/sync-docs.mjs hard-exits if
# dist/ is missing), and because the smoke check below belongs welded to the
# deploy that produced it.
#
# Two repository secrets are required:
# CLOUDFLARE_API_TOKEN — Workers Scripts:Edit + Workers Routes:Edit on the
# account, DNS:Edit + Zone:Read on the archlang.uk zone.
# Create at https://dash.cloudflare.com/profile/api-tokens
# CLOUDFLARE_ACCOUNT_ID — the account the Workers live in (not a secret value,
# kept as one so the workflow reads the same way).
# Then push to main (or run this workflow manually) to deploy.
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: cloudflare-deploy-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
jobs:
deploy:
name: Deploy ${{ matrix.name }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- name: docs
dir: docs-site
build: docs:build
url: https://archlang.uk
- name: playground
dir: playground
build: playground:build
url: https://playground.archlang.uk
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
steps:
- name: Check Cloudflare credentials are set
run: |
if [ -z "$CLOUDFLARE_API_TOKEN" ] || [ -z "$CLOUDFLARE_ACCOUNT_ID" ]; then
echo "::error::CLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_ID are not set. Add them in Settings → Secrets and variables → Actions, then re-run this workflow."
exit 1
fi
# fetch-depth: 0 is load-bearing, not caution: docs-site/.vitepress/config.ts
# sets `lastUpdated: true`, which reads each page's git commit time at BUILD
# time. A depth-1 clone has no history, so every "Last updated" stamp would
# silently collapse to the deploy commit.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
# Builds the core, then the site. Run from the repo ROOT — both scripts are
# `npm run build && npm -w <workspace> run build`.
- name: Build
run: npm run ${{ matrix.build }}
- name: Install Wrangler
# pinned for reproducibility in a token-bearing job; bump deliberately
run: npm i -g wrangler@4.108.0
# Uploads the asset directory named by ${{ matrix.dir }}/wrangler.jsonc and
# attaches/keeps its custom domain. Idempotent: an unchanged asset set
# uploads nothing.
- name: Deploy to Cloudflare
working-directory: ${{ matrix.dir }}
run: wrangler deploy
- name: Smoke check (machine routes + assets; retries ~30s for propagation)
# A 200 on `/` proved almost nothing — the site's real contract is the machine
# routes (/llms-full.txt, the raw /<page>.md copies, the schemas, the GBNF grammar,
# the example SVGs) and, on the playground, the hashed JS bundle the shell loads.
# scripts/smoke.mjs checks those; it is zero-dep Node and derives the docs route
# list from docs-site/sync-docs.mjs, so a new page is covered automatically.
run: node scripts/smoke.mjs --site ${{ matrix.name }} --base ${{ matrix.url }}