feat(mdbook): multi-version site, mise-pinned tools, justfile
Three intertwined changes — split conceptually but landed together
because they share the same workflow rewrite:
1. MULTI-VERSION SITE. The published site now keeps every prior spec
version alongside the rolling latest build (docs.rs / readthedocs
pattern):
- .github/workflows/mdbook.yml builds latest from current HEAD and
each v* tag in a git worktree, placing each into _site/<ver>/.
Each per-version build gets MDBOOK_OUTPUT__HTML__SITE_URL set to
/meshcore-spec/<ver>/ so the sitemap/canonical links resolve
correctly per version.
- Workflow emits _site/versions.json (newest first) and a root
index.html that redirects to /latest/.
- theme/version-picker.js is a small client-side dropdown that
fetches /<base>/versions.json and lets the reader switch to the
same chapter in any other version. Slots into mdbook's menu bar
(.right-buttons); falls back to a fixed top-right widget if the
menu isn't found.
- theme/version-picker.css styles it to fit the navy theme.
- book.toml wires the picker files via additional-js /
additional-css; site-url defaults to /meshcore-spec/latest/ for
the main build (CI overrides per tag).
- Old tags built without these files render without a picker, which
is fine — users won't typically need to navigate AWAY from an
older version. v0.1.0 onward will all carry the picker.
Spec versions use independent semver and do NOT mirror MeshCore
firmware versions; each spec release records the upstream commit
hash it was validated against in CHANGELOG.md.
2. MISE-PINNED TOOLS. mise.toml pins cargo:mdbook so local dev and
CI use the same version. The workflow installs everything via
jdx/mise-action instead of peaceiris/actions-mdbook, making
mise.toml the single source of truth for tool versions.
3. JUSTFILE. justfile gives short names (build / serve / clean /
validate / setup) for the common tasks. Recipes run under
`mise exec -- sh -c …` so they always pick up the mise-pinned
tools (sh is intentional, keeping recipes POSIX-compatible).
Documentation: README's spec link now mentions the versioning model;
src/00-overview.md gets a "Spec Versions" subsection explaining the
URL layout and version-picker.
Verified locally: `just build` produces a clean book/ with the
version-picker JS/CSS injected (hashed filenames, slotted into
theme/). JS parses clean under `node --check`.
Note for first-time deploy: GitHub Pages source must be set to
"GitHub Actions" in repo settings (one-time, manual). After that,
push to main builds + deploys latest, and pushing a v* tag adds
the snapshot to the site.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
8 files changed
+294
-9
No files matched your search
@@ -3,6 +3,7 @@ name: mdBook
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags: ['v*']
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
@@ -16,26 +17,102 @@ concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
# Repo path on GitHub Pages — change here if the repo is renamed.
|
||||
SITE_BASE: /meshcore-spec
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install mdBook
|
||||
uses: peaceiris/actions-mdbook@v2
|
||||
- name: Checkout (with tags)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
mdbook-version: latest
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install mise + pinned tools (mdbook, etc.)
|
||||
uses: jdx/mise-action@v2
|
||||
with:
|
||||
install: true
|
||||
cache: true
|
||||
|
||||
- name: Configure Pages
|
||||
uses: actions/configure-pages@v5
|
||||
- name: Build book
|
||||
run: mdbook build
|
||||
|
||||
- name: Build all versions
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
mkdir -p _site
|
||||
WORKSPACE="$PWD"
|
||||
|
||||
# ---- latest (current ref) ----
|
||||
echo "::group::build latest"
|
||||
MDBOOK_OUTPUT__HTML__SITE_URL="${SITE_BASE}/latest/" \
|
||||
mdbook build "$WORKSPACE" -d "$WORKSPACE/_site/latest"
|
||||
echo "::endgroup::"
|
||||
|
||||
# ---- each v* tag ----
|
||||
# Tags are built in worktrees so the workflow's own files (this
|
||||
# file, the picker JS/CSS) don't bleed into older builds.
|
||||
mapfile -t TAGS < <(git tag --list 'v*' --sort=-v:refname)
|
||||
for tag in "${TAGS[@]:-}"; do
|
||||
[ -z "$tag" ] && continue
|
||||
echo "::group::build $tag"
|
||||
wt="$(mktemp -d -t "mdbook-${tag//\//-}-XXXXXX")"
|
||||
git worktree add --detach "$wt" "$tag"
|
||||
# If a very old tag lacks book.toml, skip it but don't fail.
|
||||
if [ -f "$wt/book.toml" ]; then
|
||||
MDBOOK_OUTPUT__HTML__SITE_URL="${SITE_BASE}/${tag}/" \
|
||||
mdbook build "$wt" -d "$WORKSPACE/_site/${tag}" || {
|
||||
echo "::warning::mdbook build failed for ${tag}; skipping"
|
||||
rm -rf "$WORKSPACE/_site/${tag}"
|
||||
}
|
||||
else
|
||||
echo "::warning::${tag} has no book.toml; skipping"
|
||||
fi
|
||||
git worktree remove --force "$wt"
|
||||
echo "::endgroup::"
|
||||
done
|
||||
|
||||
# ---- versions.json (consumed by theme/version-picker.js) ----
|
||||
# Newest first; "latest" always at the top.
|
||||
{
|
||||
printf '['
|
||||
printf '"latest"'
|
||||
for tag in "${TAGS[@]:-}"; do
|
||||
[ -z "$tag" ] && continue
|
||||
[ -d "_site/${tag}" ] || continue
|
||||
printf ',"%s"' "$tag"
|
||||
done
|
||||
printf ']\n'
|
||||
} > _site/versions.json
|
||||
echo "versions.json:"
|
||||
cat _site/versions.json
|
||||
|
||||
# ---- root redirect to /latest/ ----
|
||||
cat > _site/index.html <<'HTML'
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=./latest/">
|
||||
<link rel="canonical" href="./latest/">
|
||||
<title>MeshCore Protocol Specification</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Redirecting to the <a href="./latest/">latest version</a>…</p>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
- name: Upload Pages artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: ./book
|
||||
path: ./_site
|
||||
|
||||
deploy:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
|
||||
Reference in new issue
Block a user