Versioned docs publishing¶
Every terok-* repo serves per-release documentation on GitHub Pages
with Material's version chooser: master merges refresh /dev/, and
each PyPI release adds a frozen /<minor>/ snapshot. The machinery
lives in this package — the
publish-versioned-docs.yml
reusable workflow and the
mkdocs_terok.versions assembler it runs.
The model: stateless assembly¶
There is no gh-pages branch and no stored site state. Each PyPI
release ships its built site as an immutable docs-site.tar.gz asset
on the GitHub release, and every deploy reassembles the whole served
tree from scratch: the newest final release of each served minor,
plus a fresh /dev/ build, with versions.json (the chooser contract)
derived from the release list. A deploy is a pure function of the
release set and master — a botched one is fixed by re-running, and
retention is just a parameter: the newest keep minors are served
(default 6), older versions stay downloadable from their release
assets forever. Alphas never reach PyPI, so they mint no snapshot and
never appear in the chooser.
Consumer wiring¶
A repo needs three pieces:
- docs.yml, build job — build the site exactly as before and
upload it as the
docs-siteartifact. -
docs.yml, publish job — hand it to the reusable workflow:
publish: if: github.repository == 'terok-ai/<repo>' && (github.ref == 'refs/heads/master' || inputs.release) needs: build permissions: contents: write pages: write id-token: write uses: terok-ai/mkdocs-terok/.github/workflows/publish-versioned-docs.yml@vX.Y.Z with: release: ${{ inputs.release == true }}with a
workflow_calltrigger exposing the booleanreleaseinput. On a release call the same job first ships the snapshot asset, so its own plan already sees the new release. -
release.yml — a
docs-versionjob withneeds: pypi-publishcalling docs.yml withrelease: true. Only what users canpip installmints a docs version; gh-only releases publish nothing.
Repo settings: Pages source GitHub Actions, and the github-pages
environment must allow deployments from v* tags (release deploys run
on the tag ref).
In properdocs.yml, enable the chooser with
extra.version.provider: mike — that names the versions.json
contract Material reads, not the tool.
One deployment per commit¶
GitHub Pages supports exactly one deployment per commit SHA: the API
404s any pages_build_version that is not a commit SHA, and a second
deployment of the same SHA is silently ignored (or not — the behaviour
is unspecified). See
actions/deploy-pages#383.
The workflow therefore makes sure each SHA's one deployment is the
right one. A final v*.*.* tag on a pushed commit means a PyPI
release is in flight and its versioned publish owns that SHA, so the
branch-push deploy yields; alpha and untagged pushes deploy /dev/ as
usual, which also covers gh-only releases. If a final tag ever lands
long after its merge (the release chain tags within seconds), the
snapshot simply appears with the next merge.