ci(mdbook): drive CI through mise + just (no inline shell)
CI now mirrors the local dev path. The workflow installs mise,
trusts the config, installs all mise-pinned tools (mdbook, just),
and invokes `just build-site` for the whole multi-version build.
There is no longer any build logic inside the workflow YAML.
Changes:
- `mise.toml` now also pins `just = "1.50.0"` so `mise install`
brings in both mdbook and just.
- `scripts/build-site.sh` (new, POSIX sh, shellcheck-clean) takes
the multi-version build loop out of the workflow and parks it
next to the rest of the build tooling. Iterates v* tags via
`git worktree`, sets `MDBOOK_OUTPUT__HTML__SITE_URL` per
version, emits `_site/versions.json` and `_site/index.html`
(root redirect to /latest/).
- `justfile` gains a `build-site` recipe — `sh scripts/build-site.sh`.
- `.github/workflows/mdbook.yml` is now four short steps inside
the build job: jdx/mise-action (install: false) → `mise trust`
→ `mise install` → `just build-site`. The previous inline
multi-line bash block is gone.
- `.gitignore` adds `/_site/` alongside the existing `/book/`.
Local smoke test: `just build-site` with no v* tags produces
`_site/{latest/, versions.json=["latest"], index.html}` exactly as
CI will. Future `v0.1.0` tag will add `_site/v0.1.0/` and update
`versions.json` without any code changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
5 files changed
+108
-71
No files matched your search
@@ -18,7 +18,8 @@ concurrency:
|
|||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# Repo path on GitHub Pages — change here if the repo is renamed.
|
# Repo path on GitHub Pages. Forwarded to scripts/build-site.sh so
|
||||||
|
# per-version SITE_URLs are correct. Change here if the repo moves.
|
||||||
SITE_BASE: /meshcore-spec
|
SITE_BASE: /meshcore-spec
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -30,81 +31,23 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Install mise + pinned tools (mdbook, etc.)
|
- name: Install mise
|
||||||
uses: jdx/mise-action@v2
|
uses: jdx/mise-action@v2
|
||||||
with:
|
with:
|
||||||
install: true
|
install: false
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
|
- name: Trust mise config
|
||||||
|
run: mise trust
|
||||||
|
|
||||||
|
- name: Install pinned tools (mdbook, just)
|
||||||
|
run: mise install
|
||||||
|
|
||||||
- name: Configure Pages
|
- name: Configure Pages
|
||||||
uses: actions/configure-pages@v5
|
uses: actions/configure-pages@v5
|
||||||
|
|
||||||
- name: Build all versions
|
- name: Build full multi-version site
|
||||||
run: |
|
run: just build-site
|
||||||
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
|
- name: Upload Pages artifact
|
||||||
uses: actions/upload-pages-artifact@v3
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
|||||||
+2
-1
@@ -21,5 +21,6 @@ Thumbs.db
|
|||||||
/dist/
|
/dist/
|
||||||
/references/
|
/references/
|
||||||
|
|
||||||
# mdBook output
|
# mdBook output (single-version and multi-version)
|
||||||
/book/
|
/book/
|
||||||
|
/_site/
|
||||||
@@ -15,10 +15,15 @@ _default:
|
|||||||
setup:
|
setup:
|
||||||
mise install
|
mise install
|
||||||
|
|
||||||
# Build the spec into ./book/.
|
# Build the spec into ./book/ (single-version; for local dev).
|
||||||
build:
|
build:
|
||||||
mdbook build
|
mdbook build
|
||||||
|
|
||||||
|
# Build the full multi-version site into ./_site/ (latest + every v* tag).
|
||||||
|
# This is exactly what CI runs.
|
||||||
|
build-site:
|
||||||
|
sh scripts/build-site.sh
|
||||||
|
|
||||||
# Live-preview the spec at http://localhost:3000 with auto-reload.
|
# Live-preview the spec at http://localhost:3000 with auto-reload.
|
||||||
serve:
|
serve:
|
||||||
mdbook serve --open --port 3000
|
mdbook serve --open --port 3000
|
||||||
|
|||||||
@@ -6,3 +6,4 @@
|
|||||||
|
|
||||||
[tools]
|
[tools]
|
||||||
"cargo:mdbook" = "0.5.2"
|
"cargo:mdbook" = "0.5.2"
|
||||||
|
just = "1.50.0"
|
||||||
Executable
+87
@@ -0,0 +1,87 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# Build the full multi-version site into ./_site/:
|
||||||
|
# - "latest" from the current HEAD
|
||||||
|
# - one subtree per v* git tag
|
||||||
|
#
|
||||||
|
# Each per-version build gets MDBOOK_OUTPUT__HTML__SITE_URL set so its
|
||||||
|
# canonical URL and sitemap are correct for the deployed location.
|
||||||
|
# Emits _site/versions.json (newest first; consumed by
|
||||||
|
# theme/version-picker.js) and a root index.html that redirects to
|
||||||
|
# /latest/.
|
||||||
|
#
|
||||||
|
# Intended to be called via `just build-site`. SITE_BASE can be
|
||||||
|
# overridden to deploy under a different URL prefix; the default
|
||||||
|
# targets https://swaits.github.io/meshcore-spec/.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SITE_BASE="${SITE_BASE:-/meshcore-spec}"
|
||||||
|
WORKSPACE="$(pwd)"
|
||||||
|
SITE_DIR="$WORKSPACE/_site"
|
||||||
|
|
||||||
|
# Section grouping for GitHub Actions logs; noop locally.
|
||||||
|
group() { printf '::group::%s\n' "$1"; }
|
||||||
|
endgroup() { printf '::endgroup::\n'; }
|
||||||
|
warn() { printf '::warning::%s\n' "$1"; }
|
||||||
|
|
||||||
|
rm -rf "$SITE_DIR"
|
||||||
|
mkdir -p "$SITE_DIR"
|
||||||
|
|
||||||
|
# ---- latest (current HEAD) ----
|
||||||
|
group "build latest"
|
||||||
|
MDBOOK_OUTPUT__HTML__SITE_URL="${SITE_BASE}/latest/" \
|
||||||
|
mdbook build "$WORKSPACE" -d "$SITE_DIR/latest"
|
||||||
|
endgroup
|
||||||
|
|
||||||
|
# ---- each v* tag ----
|
||||||
|
# Each tag is built from its own git worktree so today's mdbook config
|
||||||
|
# / theme files don't bleed into older builds.
|
||||||
|
TAGS="$(git tag --list 'v*' --sort=-v:refname 2>/dev/null || true)"
|
||||||
|
for tag in $TAGS; do
|
||||||
|
[ -z "$tag" ] && continue
|
||||||
|
group "build $tag"
|
||||||
|
wt="$(mktemp -d -t mdbook-tag-XXXXXX)"
|
||||||
|
git worktree add --detach "$wt" "$tag"
|
||||||
|
if [ -f "$wt/book.toml" ]; then
|
||||||
|
if ! MDBOOK_OUTPUT__HTML__SITE_URL="${SITE_BASE}/${tag}/" \
|
||||||
|
mdbook build "$wt" -d "$SITE_DIR/${tag}"; then
|
||||||
|
warn "mdbook build failed for ${tag}; skipping"
|
||||||
|
rm -rf "${SITE_DIR:?}/${tag:?}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "${tag} has no book.toml; skipping"
|
||||||
|
fi
|
||||||
|
git worktree remove --force "$wt"
|
||||||
|
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_DIR/$tag" ] || continue
|
||||||
|
printf ',"%s"' "$tag"
|
||||||
|
done
|
||||||
|
printf ']\n'
|
||||||
|
} > "$SITE_DIR/versions.json"
|
||||||
|
echo "versions.json:"
|
||||||
|
cat "$SITE_DIR/versions.json"
|
||||||
|
|
||||||
|
# ---- root redirect to /latest/ ----
|
||||||
|
cat > "$SITE_DIR/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
|
||||||
Reference in new issue
Block a user