diff --git a/.github/workflows/mdbook.yml b/.github/workflows/mdbook.yml index a2dc7c7..906fde5 100644 --- a/.github/workflows/mdbook.yml +++ b/.github/workflows/mdbook.yml @@ -3,7 +3,6 @@ name: mdBook on: push: branches: [main] - tags: ['v*'] pull_request: branches: [main] workflow_dispatch: @@ -26,10 +25,8 @@ jobs: build: runs-on: ubuntu-latest steps: - - name: Checkout (with tags) + - name: Checkout uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: Install mise uses: jdx/mise-action@v2 diff --git a/justfile b/justfile index 30a88fe..c716dfe 100644 --- a/justfile +++ b/justfile @@ -35,3 +35,24 @@ clean: # Run the corpus validator. validate: python3 tools/validate.py corpus/ + +# Cut a frozen spec version: copy ./src/ to ./versions//. +# Usage: just cut-version v0.2.0 +cut-version VERSION: + #!/usr/bin/env sh + set -eu + case "{{VERSION}}" in + v[0-9]*.[0-9]*.[0-9]*) ;; + *) echo "Version must look like vX.Y.Z (got '{{VERSION}}')" >&2; exit 1 ;; + esac + if [ -e "versions/{{VERSION}}" ]; then + echo "versions/{{VERSION}} already exists; not overwriting." >&2 + exit 1 + fi + mkdir -p versions + cp -R src "versions/{{VERSION}}" + echo "Snapshotted src/ -> versions/{{VERSION}}" + echo + echo "Next steps:" + echo " - git add versions/{{VERSION}} && commit (e.g. \"release {{VERSION}}\")" + echo " - optionally tag the commit: git tag {{VERSION}}" diff --git a/scripts/build-site.sh b/scripts/build-site.sh index 10dd600..aadf8fe 100755 --- a/scripts/build-site.sh +++ b/scripts/build-site.sh @@ -1,17 +1,19 @@ #!/usr/bin/env sh # Build the full multi-version site into ./_site/: -# - "latest" from the current HEAD -# - one subtree per v* git tag +# - "latest" from ./src/ +# - one subtree per ./versions/vX.Y.Z/ directory +# +# Each per-version build uses today's repo-root build infrastructure +# (book.toml, theme/, picker JS, scripts/), only swapping in the +# frozen content directory via MDBOOK_BOOK__SRC. This means every +# deploy gives every published version the current theme — site +# improvements never need backporting to old snapshots. # -# 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/. +# theme/version-picker.js) and _site/index.html (redirect 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/. +# Cut a new frozen version with `just cut-version vX.Y.Z`, which +# snapshots ./src/ into ./versions/vX.Y.Z/. set -eu @@ -19,7 +21,6 @@ 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"; } @@ -27,43 +28,45 @@ warn() { printf '::warning::%s\n' "$1"; } rm -rf "$SITE_DIR" mkdir -p "$SITE_DIR" -# ---- latest (current HEAD) ---- +# ---- latest (from src/) ---- 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" +# ---- frozen versions (./versions/v*) ---- +# Discover and sort by semver (newest first). The list is captured +# into a variable so we can iterate it twice — once to build, once to +# emit versions.json — without re-scanning. +list_versions() { + for d in versions/v*; do + [ -d "$d" ] || continue + basename "$d" + done | sort -V -r +} +VERSION_DIRS="$(list_versions)" + +for version in $VERSION_DIRS; do + vdir="versions/$version" + [ -d "$vdir" ] || continue + group "build $version" + if ! MDBOOK_BOOK__SRC="$vdir" \ + MDBOOK_OUTPUT__HTML__SITE_URL="${SITE_BASE}/${version}/" \ + mdbook build "$WORKSPACE" -d "$SITE_DIR/${version}"; then + warn "mdbook build failed for ${version}; skipping" + rm -rf "${SITE_DIR:?}/${version:?}" fi - git worktree remove --force "$wt" endgroup done # ---- versions.json (consumed by theme/version-picker.js) ---- -# Newest first; "latest" always at the top. +# "latest" always first; then each successfully-built frozen version. { printf '[' printf '"latest"' - for tag in $TAGS; do - [ -z "$tag" ] && continue - [ -d "$SITE_DIR/$tag" ] || continue - printf ',"%s"' "$tag" + for version in $VERSION_DIRS; do + [ -d "$SITE_DIR/$version" ] || continue + printf ',"%s"' "$version" done printf ']\n' } > "$SITE_DIR/versions.json" diff --git a/src/00-overview.md b/src/00-overview.md index 6227acb..39294af 100644 --- a/src/00-overview.md +++ b/src/00-overview.md @@ -42,8 +42,16 @@ The published site preserves prior spec versions alongside the rolling - `https://swaits.github.io/meshcore-spec/latest/` — built from the tip of `main`. May change between any two visits. - `https://swaits.github.io/meshcore-spec/v0.1.0/` (and likewise for any - future `vX.Y.Z`) — a frozen snapshot built from the matching git tag. - Suitable for citing or for certifying an implementation against. + future `vX.Y.Z`) — a frozen content snapshot. Suitable for citing or for + certifying an implementation against. + +Frozen versions live as their own directory in the repo +(`versions/vX.Y.Z/`) — a literal copy of `src/` taken at release time. +This deliberately separates **content** (versioned, frozen) from **site +infrastructure** (theme, picker, build pipeline; lives at the repo root +and is unversioned). Every deploy rebuilds every published version using +today's infrastructure, so site improvements show up everywhere without +backporting. The version-picker in the top-right of every page lists every published version; switching keeps you on the same chapter where it exists in the