Skip to content

Leave the repo resumable mid BACKLOG 1a, at a green gate #141

Leave the repo resumable mid BACKLOG 1a, at a green gate

Leave the repo resumable mid BACKLOG 1a, at a green gate #141

Workflow file for this run

name: publishing
on:
push:
branches:
# `main` is the ONLY publishing branch. It declares everything it
# publishes in docs-version.yml, including the RIDDL 1.x maintenance
# line, which lives in sites/riddl-1x/ rather than on a branch of its own
# (TASK G, 2026-07-31). Work branches are deliberately absent: work in
# progress must not refresh the production site.
- main
permissions:
contents: write
# Kept even though only one branch publishes now. Two pushes to main in quick
# succession still start two runs, both committing to gh-pages, and the second
# would be rejected with "fetch first" -- its deploy silently lost. That
# happened for real when main and docs/1.x were pushed seconds apart.
#
# cancel-in-progress is deliberately FALSE: these runs publish, so cancelling
# one drops a deploy rather than deferring it.
#
# Do NOT reach for mike's --ignore-remote-status as a workaround. It does not
# serialise anything; it just overwrites whatever the other run published.
concurrency:
group: gh-pages-deploy
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# mike commits into the gh-pages branch, so its history must be
# present locally. The default shallow checkout does not fetch it.
fetch-depth: 0
- name: Configure Git Credentials
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- uses: actions/setup-python@v5
with:
python-version: 3.x
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache
restore-keys: |
mkdocs-material-
- run: pip install -r requirements.txt
- run: pip install -e .
# Shared logos and CSS live once in common/ and are copied into each
# sub-site's docs tree. The copies are gitignored, so this is required
# before any build -- without it every page loses its stylesheet.
- name: Sync shared assets
run: ./scripts/sync-shared-assets.sh
# Cross-site links are absolute, so MkDocs treats them as external and
# never checks them. --strict proves the intra-site links; this proves
# the rest. Run before deploying anything.
- name: Check cross-site links
run: python3 scripts/check-cross-site-links.py
- name: Deploy each versioned sub-site
run: |
python - <<'PY' > /tmp/deploy.sh
import yaml, shlex
cfg = yaml.safe_load(open("docs-version.yml"))
for s in cfg.get("sites") or []:
url = f"https://ossum.tech/{s['prefix']}/{s['version']}/"
args = " ".join(shlex.quote(a) for a in (s.get("aliases") or []))
# --alias-type copy is REQUIRED, not a preference. mike's default
# is `symlink`, and GitHub Pages does not serve symlinked content
# -- so /riddl/latest/... would 404 in production while working
# perfectly under a local `python -m http.server`, which DOES
# follow symlinks. A passing local rehearsal cannot catch it.
print(f"echo '--> {s['prefix']} {s['version']} [{args}]'")
print(f"DOCS_SITE_URL={shlex.quote(url)} mike deploy --push "
f"--update-aliases --alias-type copy "
f"--deploy-prefix {shlex.quote(s['prefix'])} "
f"-F {shlex.quote(s['config'])} "
f"{shlex.quote(s['version'])} {args}")
# Point <prefix>/index.html at this product's default alias.
# NEVER run set-default without --deploy-prefix: it would write a
# redirect over the shell's index.html at the site root.
# -F is required too -- set-default reads mkdocs.yml from the
# working directory to resolve the remote and branch, and there
# is no config at the repo root any more.
default = (s.get("aliases") or [s["version"]])[0]
print(f"mike set-default --push --deploy-prefix "
f"{shlex.quote(s['prefix'])} -F {shlex.quote(s['config'])} "
f"{shlex.quote(default)}")
PY
cat /tmp/deploy.sh
bash -euo pipefail /tmp/deploy.sh
# The shell is not versioned, so mike is not involved. It is built and
# committed to the gh-pages root, touching only the paths it owns --
# never the product prefixes or their versions.json.
- name: Deploy the shell and rebuild the search index
run: |
git fetch origin gh-pages
git worktree add /tmp/ghp origin/gh-pages
# The shell is only published by the branch that declares it. Every
# other branch skips this part but still reaches the indexing step
# below -- see the comment there for why that matters.
SHELL_CFG=$(python -c "import yaml;c=yaml.safe_load(open('docs-version.yml'));print((c.get('shell') or {}).get('config',''))")
if [ -n "$SHELL_CFG" ]; then
DOCS_SITE_URL=https://ossum.tech/ mkdocs build -f "$SHELL_CFG" -d /tmp/shell
# rsync --delete, NOT cp. `cp -r` only ever adds, so a page deleted
# from the shell stayed on gh-pages forever -- /coming-soon/ and
# /find/ both kept serving 200 after being removed from the source.
#
# The excludes are what make --delete safe at the site root: they
# cover everything the shell does NOT own -- the product prefixes
# published by mike, the generated search index and robots.txt, the
# 404 handler copied in below, and the worktree's own .git file.
# Getting this list wrong deletes another product's entire site,
# so add a new prefix here whenever one is added to docs-version.yml.
rsync -a --delete \
--exclude '/riddl/' --exclude '/riddlg/' --exclude '/synapify/' \
--exclude '/pagefind/' --exclude '/robots.txt' \
--exclude '/404.html' --exclude '/.nojekyll' --exclude '/.git' \
/tmp/shell/ /tmp/ghp/
# Copied after, deliberately: the shell build emits its own 404.html
# and this one -- which redirects legacy unversioned links -- wins.
cp scripts/gh-pages-404.html /tmp/ghp/404.html
else
echo "This branch does not publish the shell."
fi
# The cross-site index is rebuilt on EVERY publishing branch, not
# just the one that owns the shell. It indexes each product's
# `latest` alias, and docs/1.x owns riddl/latest -- so if this only
# ran where the shell is built, a docs/1.x push would update the
# published pages while search kept returning their old text, with
# nothing to indicate the index had gone stale.
"$GITHUB_WORKSPACE/scripts/build-search-index.sh" /tmp/ghp
# robots.txt is generated for the same reason: each build writes its
# own sitemap.xml inside its own version directory, and nothing at the
# root references them. A hand-written file would stop listing new
# versions the day after it was written.
"$GITHUB_WORKSPACE/scripts/build-robots-txt.sh" /tmp/ghp
cd /tmp/ghp
git add -A
if git diff --cached --quiet; then
echo "Shell and search index unchanged."
else
git commit -m "Deploy the shell and refresh the cross-site search index"
git push origin HEAD:gh-pages
fi