Skip to content

ci(docs): build & deploy Astro docs to gh-pages with PR previews #160

ci(docs): build & deploy Astro docs to gh-pages with PR previews

ci(docs): build & deploy Astro docs to gh-pages with PR previews #160

Workflow file for this run

name: Docs
# Deploy the Astro docs site at `docs/` to GitHub Pages.
#
# Behaviour:
# - Push to `main` → build with PPVM_BASE=/ and publish
# to the gh-pages branch root.
# - Pull request (opened / → build with PPVM_BASE=/pr-preview/pr-<N>
# synchronize / reopened) and let rossjrw/pr-preview-action publish
# the build to gh-pages under
# `pr-preview/pr-<N>/`. Triggered only when
# the diff actually touches inputs the
# site depends on.
# - Pull request closed → cleanup-preview job removes the
# `pr-preview/pr-<N>/` subdirectory.
#
# The Rust API site under `/rust-api/` is published by `rust-docs.yml`
# and survives our deploys via `keep_files: true`.
on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened]
paths:
# Site sources. Other paths (crates/, ppvm-python/) don't affect
# the build because the API JSON consumed by /api/ is committed
# under docs/src/data/ and regenerated manually.
- "docs/**"
- ".github/workflows/docs.yml"
pull_request_target:
types: [closed]
permissions:
contents: write
pull-requests: write
concurrency:
# Serialise per-PR (and main); a fresh build cancels any in-flight one
# for the same ref so PR comments don't pile up on rapid pushes.
group: docs-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
# Build the static site once, upload it as an artifact, and let the
# downstream jobs decide where (if anywhere) to publish it.
if: github.event.action != 'closed'
name: Build Astro site
runs-on: ubuntu-latest
outputs:
base: ${{ steps.compute-base.outputs.base }}
steps:
- uses: actions/checkout@v4
# Build inputs: nightly Rust for the rustdoc-JSON extractor,
# uv to run griffe for the Python extractor, Node 20 for Astro.
- uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
- uses: astral-sh/setup-uv@v5
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: docs/package-lock.json
- name: Install Astro deps
# `npm ci` is faster than `npm install` and asserts the
# lockfile is in sync; it fails loudly if package.json and
# package-lock.json have drifted.
run: npm ci
working-directory: docs
- name: Compute base path
id: compute-base
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "base=/pr-preview/pr-${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT"
else
echo "base=/" >> "$GITHUB_OUTPUT"
fi
- name: Generate API JSON
# The /api/ page reads docs/src/data/{rust,python}-api.json,
# which are .gitignore'd and produced by docs/scripts/. The
# Rust extractor needs nightly for `--output-format json`;
# the Python extractor uses griffe via `uv run --with griffe`.
working-directory: docs
env:
RUSTFLAGS: "-C target-feature=+aes,+sse2"
run: |
node scripts/extract-rust.mjs
node scripts/extract-python.mjs
- name: Build site
working-directory: docs
env:
PPVM_SITE: https://congenial-bassoon-l436wp3.pages.github.io
PPVM_BASE: ${{ steps.compute-base.outputs.base }}
run: npx astro build
- name: Upload built site
uses: actions/upload-artifact@v4
with:
name: docs-dist
path: docs/dist/
if-no-files-found: error
retention-days: 7
deploy-main:
name: Deploy to gh-pages
needs: build
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
concurrency:
group: deploy-gh-pages
cancel-in-progress: false
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: docs-dist
path: docs/dist/
- name: Publish to gh-pages root
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/dist
# Preserve /rust-api/ (managed by rust-docs.yml) and
# /pr-preview/* (managed by pr-preview-action below).
keep_files: true
commit_message: "docs: deploy ${{ github.sha }}"
deploy-preview:
name: Deploy PR preview
needs: build
if: github.event_name == 'pull_request' && github.event.action != 'closed'
runs-on: ubuntu-latest
concurrency:
group: deploy-gh-pages
cancel-in-progress: false
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: docs-dist
path: docs/dist/
- name: Deploy PR preview to gh-pages/pr-preview/pr-<N>
uses: rossjrw/pr-preview-action@v1
with:
source-dir: docs/dist/
preview-branch: gh-pages
umbrella-dir: pr-preview
cleanup-preview:
name: Clean up PR preview
if: github.event_name == 'pull_request_target' && github.event.action == 'closed'
runs-on: ubuntu-latest
concurrency:
group: deploy-gh-pages
cancel-in-progress: false
steps:
- uses: actions/checkout@v4
- uses: rossjrw/pr-preview-action@v1
with:
source-dir: docs/dist/
preview-branch: gh-pages
umbrella-dir: pr-preview
action: remove