From 53b36bcc61dd10fb25fdbbdd6e8ea74e335b736b Mon Sep 17 00:00:00 2001 From: Fiachra Corcoran Date: Tue, 12 May 2026 16:15:12 +0100 Subject: [PATCH] docs: add versioned docs build with tag-based snapshots - Add versions.json manifest to define which versions to build - Add build-versioned-docs.sh script that builds main (latest) and tagged versions into subdirectories (e.g. /v1.5/) - Update netlify.toml to use the versioned build script - Update config.toml: relative URLs, version dropdown entries, latestTag - Docsy's built-in version-banner and navbar-version-selector handle the archived banner and version switcher dropdown The script uses only standard tools (awk, git, hugo, npm) with no additional dependencies. Tagged versions are built with an archived overlay config so Docsy renders the 'no longer maintained' banner. Signed-off-by: Fiachra Corcoran --- docs/config.toml | 12 ++- docs/netlify.toml | 2 +- docs/versions.json | 12 +++ scripts/build-versioned-docs.sh | 162 ++++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 docs/versions.json create mode 100755 scripts/build-versioned-docs.sh diff --git a/docs/config.toml b/docs/config.toml index 101a1c9ab..53a13774a 100644 --- a/docs/config.toml +++ b/docs/config.toml @@ -89,7 +89,7 @@ archived_version = false version = "latest" # The version of the latest code build -latestTag = "1.5.7" +latestTag = "1.5.9" # latest tested versions version_docker = "v28.1.1" @@ -102,7 +102,7 @@ version_kpt = "v1.0.0-beta.62.1" # A link to latest version of the docs. Used in the "version-banner" partial to # point people to the main doc site. -url_latest_version = "https://docs.porch.nephio.org/docs/" +url_latest_version = "/docs/" # Repository configuration (URLs for in-page links to opening issues and suggesting changes) @@ -239,7 +239,13 @@ enable = false # desc = "Discuss development issues around the project" # Add your release versions here +# Each entry appears in the version selector dropdown in the navbar. +# The first entry should be the current/latest version. [[params.versions]] version = "latest" - url = "https://docs.porch.nephio.org/docs/" + url = "/" + +[[params.versions]] + version = "v1.5" + url = "/v1.5/" diff --git a/docs/netlify.toml b/docs/netlify.toml index 879098fe3..04e5def31 100644 --- a/docs/netlify.toml +++ b/docs/netlify.toml @@ -3,7 +3,7 @@ [build] base = "docs" - command = "hugo --environment $HUGO_ENV --config config.toml,config/$HUGO_ENV.toml" + command = "../scripts/build-versioned-docs.sh" publish = "public" ignore = "false" # Always build diff --git a/docs/versions.json b/docs/versions.json new file mode 100644 index 000000000..12db85185 --- /dev/null +++ b/docs/versions.json @@ -0,0 +1,12 @@ +[ + { + "version": "latest", + "tag": null, + "path": "/" + }, + { + "version": "v1.5", + "tag": "v1.5.9", + "path": "/v1.5/" + } +] diff --git a/scripts/build-versioned-docs.sh b/scripts/build-versioned-docs.sh new file mode 100755 index 000000000..b1f489b49 --- /dev/null +++ b/scripts/build-versioned-docs.sh @@ -0,0 +1,162 @@ +#!/usr/bin/env bash +# Copyright 2026 The kpt and Nephio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# build-versioned-docs.sh +# +# Builds versioned Hugo documentation from git tags. +# Reads docs/versions.json to determine which versions to build. +# Produces a combined output directory suitable for Netlify deployment. +# +# Usage: +# ./scripts/build-versioned-docs.sh [output-dir] +# +# Environment: +# HUGO_ENV - Hugo environment (default: production) + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" +DOCS_DIR="${REPO_ROOT}/docs" +OUTPUT_DIR="${1:-${DOCS_DIR}/public}" +HUGO_ENV="${HUGO_ENV:-production}" + +# Ensure required tools are available +for cmd in hugo git npm; do + if ! command -v "${cmd}" &> /dev/null; then + echo "ERROR: ${cmd} is required but not installed." >&2 + exit 1 + fi +done + +VERSIONS_FILE="${DOCS_DIR}/versions.json" +if [[ ! -f "${VERSIONS_FILE}" ]]; then + echo "ERROR: ${VERSIONS_FILE} not found." >&2 + exit 1 +fi + +echo "==> Building versioned docs" +echo " Output: ${OUTPUT_DIR}" +echo " Versions file: ${VERSIONS_FILE}" +echo "" + +# Ensure we have all tags (Netlify may do shallow clones) +echo "==> Fetching tags..." +git -C "${REPO_ROOT}" fetch --unshallow 2>/dev/null || true +git -C "${REPO_ROOT}" fetch --tags --force 2>/dev/null || true +echo "" + +# Clean output directory +rm -rf "${OUTPUT_DIR}" +mkdir -p "${OUTPUT_DIR}" + +# Build the main/latest version from the current working tree +echo "==> Building latest (main) docs..." +( + cd "${DOCS_DIR}" + + # Install npm dependencies (needed for PostCSS/autoprefixer) + if [[ -f "package.json" ]]; then + npm install --quiet 2>/dev/null || true + fi + + hugo --gc --minify \ + --environment "${HUGO_ENV}" \ + --destination "${OUTPUT_DIR}" \ + -b "/" +) +echo " Done: latest -> /" +echo "" + +# Parse versions.json and build each tagged version. +# Uses grep/sed to extract entries — versions.json has a known, simple structure. +# Outputs tab-separated lines: version\ttag\tpath (skipping entries with null tag) +TAGGED_VERSIONS=$(awk ' + /"version"/ { gsub(/[",]/, ""); version=$2 } + /"tag"/ { gsub(/[",]/, ""); tag=$2 } + /"path"/ { gsub(/[",]/, ""); path=$2; if (tag != "null" && tag != "") print version "\t" tag "\t" path } +' "${VERSIONS_FILE}") + +while IFS=$'\t' read -r VERSION TAG URL_PATH; do + [[ -z "${VERSION}" ]] && continue + + echo "==> Building ${VERSION} from tag ${TAG}..." + + # Verify tag exists + if ! git -C "${REPO_ROOT}" rev-parse "${TAG}" &>/dev/null; then + echo " WARNING: Tag ${TAG} not found, skipping." >&2 + continue + fi + + # Create a temporary directory for the tagged docs + TEMP_DIR=$(mktemp -d) + + # Extract the docs directory from the tag + git -C "${REPO_ROOT}" archive "${TAG}" -- docs/ | tar -x -C "${TEMP_DIR}" + + # Remove existing [[params.versions]] entries from the tagged config + # to prevent duplication when our override config is merged + sed -i '/^\[\[params\.versions\]\]/,/^$/d' "${TEMP_DIR}/docs/config.toml" + + # Fix hardcoded absolute paths in content files so they respect the versioned baseURL. + # Raw HTML links in Hugo shortcodes bypass baseURL processing. + find "${TEMP_DIR}/docs/content" -name "*.md" -exec \ + sed -i "s|href=\"/docs|href=\"${URL_PATH}docs|g" {} \; + + # Create a config overlay to mark this as an archived version + VERSION_OUTPUT="${OUTPUT_DIR}${URL_PATH}" + mkdir -p "${VERSION_OUTPUT}" + + # Generate the versions list for the override config from versions.json + VERSIONS_TOML=$(awk ' + /"version"/ { gsub(/[",]/, ""); ver=$2 } + /"path"/ { gsub(/[",]/, ""); path=$2; print "[[params.versions]]"; print " version = \"" ver "\""; print " url = \"" path "\""; print "" } + ' "${VERSIONS_FILE}") + + cat > "${TEMP_DIR}/docs/config-version-override.toml" </dev/null || true + fi + + hugo --gc --minify \ + --environment "${HUGO_ENV}" \ + --destination "${VERSION_OUTPUT}" \ + -b "${URL_PATH}" \ + --config config.toml,config-version-override.toml + ) + + echo " Done: ${VERSION} -> ${URL_PATH}" + echo "" + + # Clean up temp dir + rm -rf "${TEMP_DIR}" +done <<< "${TAGGED_VERSIONS}" + +echo "==> All versions built successfully." +echo " Output directory: ${OUTPUT_DIR}" +ls -la "${OUTPUT_DIR}"