mirror of
https://github.com/gastownhall/beads.git
synced 2026-09-14 20:17:24 +08:00
d2f87d50de
* docs(pipeline): pin the generated CLI docs to the released bd; repair main's CLI reference The #4874 squash-merge raced the docs-autofix bot: the bot had pushed a regeneration from main's source onto the PR branch, so the squash landed a contradictory mix — the release-aligned hand-written docs plus a CLI reference re-documenting unreleased commands and flags, with docs.json referencing four pages (heartbeat, migrate-personal, reclaim, unclaim) whose files do not exist. That broken nav fails the docsync guard on main and on every branch cut from it. This restores the intended end state of #4874 and lands the pin that prevents the race from recurring. - Regenerate the CLI reference from a bd built from the v1.1.0 tag (CI's canonical pure-Go build), removing the unreleased commands/flags and fixing the dangling nav entries. - docs/cli-docs.pin names the release tag; scripts/resolve-docs-bd.sh builds and caches a canonical pure-Go bd from that tag, fetching the tag first in shallow CI checkouts. - generate-cli-docs.sh, check-doc-flags.sh, and check-cli-docs-drift.sh resolve bd through the pin and ignore a supplied binary while pinned (BD_DOCS_IGNORE_PIN=1 bypasses), so the drift gates and the autofix bot now enforce docs-match-release instead of docs-match-main. - tools/docsmint detects the pre-overhaul Docusaurus staging layout that bd <= v1.1.0 emits and converts it to the generic form before its normal Mintlify transform (tested); removable once the pin reaches a release whose emitter writes build/cli-docs. - check-doc-flags.sh: run without timeout(1) on macOS instead of failing Check 4. - Decision record: engdocs/decisions/2026-07-17-docs-release-pin.md; the beads-docs skill §8 updated to match. * lint: annotate gosec G705 false positive in the docsmint legacy bridge Same class as the existing nav-splice annotation: a developer tool writing repo Markdown, not a web-output sink.
192 lines
7.9 KiB
Bash
Executable File
192 lines
7.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# generate-cli-docs.sh — Generate CLI reference docs from the live bd command tree.
|
|
#
|
|
# Two stages:
|
|
# 1. `bd help --docs-root <root>` emits vendor-neutral output only:
|
|
# docs/CLI_REFERENCE.md plus a generic per-command tree at
|
|
# build/cli-docs/ (uncommitted staging).
|
|
# 2. `go run ./tools/docsmint <root>` post-processes the staging tree into
|
|
# the committed Mintlify pages at docs/cli-reference/ and splices the
|
|
# CLI Reference pages array in docs/docs.json.
|
|
# bd never emits site-generator-specific formats; all Mintlify targeting
|
|
# lives in tools/docsmint.
|
|
|
|
set -euo pipefail
|
|
export LC_ALL=C
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
|
|
CHECK_MODE=0
|
|
BD_ARG=""
|
|
TMP_BUILD_DIR=""
|
|
TMP_OUTPUT_DIR=""
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
--check)
|
|
CHECK_MODE=1
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
cat <<'EOF'
|
|
Usage: scripts/generate-cli-docs.sh [--check] [path-to-bd]
|
|
|
|
Generate the committed CLI docs (docs/CLI_REFERENCE.md, docs/cli-reference/,
|
|
and the CLI pages array in docs/docs.json) from one bd process plus the
|
|
tools/docsmint post-processor. --check regenerates into a scratch root and
|
|
fails if the committed copies are stale.
|
|
|
|
When docs/cli-docs.pin names a release tag, bd is built from that tag
|
|
(the published docs describe the pinned release, not this checkout) and a
|
|
supplied binary is ignored; set BD_DOCS_IGNORE_PIN=1 to bypass the pin.
|
|
|
|
If the resolved bd binary is CGO-enabled it emits the full `bd federation`
|
|
help tree that CI (CGO_ENABLED=0) stubs out; the script rebuilds a pinned
|
|
pure-go binary to keep committed docs in sync. Set BD_DOCS_ALLOW_CGO=1 to
|
|
bypass that rebuild and trust the supplied binary as-is.
|
|
EOF
|
|
exit 0
|
|
;;
|
|
*)
|
|
if [ -n "$BD_ARG" ]; then
|
|
echo "Error: multiple bd binaries supplied: $BD_ARG and $1" >&2
|
|
exit 2
|
|
fi
|
|
BD_ARG="$1"
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
cleanup() {
|
|
if [ -n "$TMP_BUILD_DIR" ]; then
|
|
rm -rf "$TMP_BUILD_DIR"
|
|
fi
|
|
if [ -n "$TMP_OUTPUT_DIR" ]; then
|
|
rm -rf "$TMP_OUTPUT_DIR"
|
|
fi
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
# Release pin (docs/cli-docs.pin): the published docs describe the pinned
|
|
# release, so the pipeline builds bd from that tag and ignores any supplied
|
|
# binary. Set BD_DOCS_IGNORE_PIN=1 to bypass (e.g. to preview docs for an
|
|
# unreleased emitter).
|
|
PINNED_BD=""
|
|
if [ "${BD_DOCS_IGNORE_PIN:-0}" != "1" ]; then
|
|
PINNED_BD="$("$SCRIPT_DIR/resolve-docs-bd.sh")"
|
|
fi
|
|
|
|
if [ -n "$PINNED_BD" ]; then
|
|
if [ -n "$BD_ARG" ] && [ "$BD_ARG" != "$PINNED_BD" ]; then
|
|
echo "Note: docs are pinned via docs/cli-docs.pin; ignoring supplied binary $BD_ARG." >&2
|
|
fi
|
|
BD="$PINNED_BD"
|
|
elif [ -n "$BD_ARG" ]; then
|
|
BD="$BD_ARG"
|
|
elif [ "$CHECK_MODE" -eq 0 ] && [ -x "$PROJECT_ROOT/bd" ]; then
|
|
# Convenience for regeneration only. --check never trusts a repo-root
|
|
# ./bd it wasn't explicitly given: the guard below detects CGO-ness, not
|
|
# staleness, so a stale pure-go ./bd would produce a false "fresh".
|
|
BD="$PROJECT_ROOT/bd"
|
|
else
|
|
TMP_BUILD_DIR="$(mktemp -d)"
|
|
BD="$TMP_BUILD_DIR/bd"
|
|
echo "Building temporary bd for docs generation..."
|
|
(cd "$PROJECT_ROOT" && CGO_ENABLED=0 go build -tags gms_pure_go -o "$BD" ./cmd/bd/)
|
|
fi
|
|
|
|
# Guard against a CGO-enabled bd: it exposes the full `bd federation` subcommand tree
|
|
# that CI never produces (scripts/ci/pr-policy.sh build_docs_binary uses env
|
|
# CGO_ENABLED=0 go build). A CGO build therefore emits ~hundreds of lines of federation
|
|
# help that the committed, CI-built docs stub out ("built without CGO support"), so a
|
|
# naive regen on a machine with a C compiler produces spurious federation churn.
|
|
#
|
|
# The pure-go federation stub prints "Federation commands require CGO" (see
|
|
# cmd/bd/federation_nocgo.go); a CGO build does not. If the resolved binary is missing
|
|
# that stub marker, warn and rebuild a pinned CGO_ENABLED=0 -tags gms_pure_go binary so
|
|
# the committed docs always match CI. Set BD_DOCS_ALLOW_CGO=1 to bypass the rebuild and
|
|
# trust the supplied binary as-is (e.g. to deliberately regenerate the full federation
|
|
# tree); you then own any federation churn the diff introduces.
|
|
if [ -z "$PINNED_BD" ] && [ -x "$BD" ] && ! "$BD" federation --help 2>&1 | grep -q "Federation commands require CGO"; then
|
|
if [ "${BD_DOCS_ALLOW_CGO:-0}" = "1" ]; then
|
|
echo "WARNING: $BD looks CGO-enabled and emits the full 'bd federation' help tree," >&2
|
|
echo " which CI's pure-go docs build stubs out. BD_DOCS_ALLOW_CGO=1 is set," >&2
|
|
echo " using it anyway; expect federation doc churn unless that is intended." >&2
|
|
else
|
|
echo "WARNING: $BD looks CGO-enabled; its 'bd federation' help differs from CI's" >&2
|
|
echo " pure-go build and would add spurious federation doc churn." >&2
|
|
echo " Rebuilding a pinned pure-go (CGO_ENABLED=0 -tags gms_pure_go) binary" >&2
|
|
echo " for CI-consistent docs. Set BD_DOCS_ALLOW_CGO=1 to use it as-is." >&2
|
|
if [ -z "$TMP_BUILD_DIR" ]; then
|
|
TMP_BUILD_DIR="$(mktemp -d)"
|
|
fi
|
|
BD="$TMP_BUILD_DIR/bd-pure"
|
|
(cd "$PROJECT_ROOT" && CGO_ENABLED=0 go build -tags gms_pure_go -o "$BD" ./cmd/bd/)
|
|
fi
|
|
fi
|
|
|
|
if [ ! -x "$BD" ]; then
|
|
echo "Error: bd binary not found or not executable: $BD" >&2
|
|
echo "Usage: $0 [--check] [path-to-bd]" >&2
|
|
exit 1
|
|
fi
|
|
|
|
generate_all() {
|
|
local root="$1"
|
|
local had_website=0
|
|
[ -d "$root/website" ] && had_website=1
|
|
# Clear stale staging so docsmint can only consume what this bd emitted
|
|
# (a pinned legacy bd stages under website/, not build/cli-docs).
|
|
rm -rf "$root/build/cli-docs"
|
|
"$BD" help --docs-root "$root"
|
|
(cd "$PROJECT_ROOT" && go run -tags=gms_pure_go ./tools/docsmint "$root")
|
|
# A pinned legacy emitter (bd <= v1.1.0) stages Docusaurus pages under
|
|
# website/; docsmint has consumed them, so drop the scaffolding.
|
|
if [ "$had_website" -eq 0 ] && [ -d "$root/website" ]; then
|
|
rm -rf "$root/website"
|
|
fi
|
|
}
|
|
|
|
if [ "$CHECK_MODE" -eq 1 ]; then
|
|
TMP_OUTPUT_DIR="$(mktemp -d)"
|
|
mkdir -p "$TMP_OUTPUT_DIR/docs"
|
|
# Seed the committed artifacts the pipeline rewrites, then regenerate and diff.
|
|
cp -f "$PROJECT_ROOT/docs/docs.json" "$TMP_OUTPUT_DIR/docs/docs.json"
|
|
if [ -d "$PROJECT_ROOT/docs/cli-reference" ]; then
|
|
cp -Rf "$PROJECT_ROOT/docs/cli-reference" "$TMP_OUTPUT_DIR/docs/cli-reference"
|
|
fi
|
|
|
|
generate_all "$TMP_OUTPUT_DIR"
|
|
|
|
if ! diff -q \
|
|
"$PROJECT_ROOT/docs/CLI_REFERENCE.md" \
|
|
"$TMP_OUTPUT_DIR/docs/CLI_REFERENCE.md" >/dev/null; then
|
|
echo "FAIL: docs/CLI_REFERENCE.md is out of sync with live CLI help."
|
|
echo "Run: ./scripts/generate-cli-docs.sh ${BD_ARG:-}"
|
|
diff -u "$PROJECT_ROOT/docs/CLI_REFERENCE.md" "$TMP_OUTPUT_DIR/docs/CLI_REFERENCE.md" | sed -n '1,120p' || true
|
|
exit 1
|
|
fi
|
|
|
|
if ! diff -q "$PROJECT_ROOT/docs/docs.json" "$TMP_OUTPUT_DIR/docs/docs.json" >/dev/null; then
|
|
echo "FAIL: docs/docs.json CLI Reference navigation is out of sync with live CLI help."
|
|
echo "Run: ./scripts/generate-cli-docs.sh ${BD_ARG:-}"
|
|
diff -u "$PROJECT_ROOT/docs/docs.json" "$TMP_OUTPUT_DIR/docs/docs.json" | sed -n '1,80p' || true
|
|
exit 1
|
|
fi
|
|
|
|
if ! diff -qr "$PROJECT_ROOT/docs/cli-reference" "$TMP_OUTPUT_DIR/docs/cli-reference" >/dev/null; then
|
|
echo "FAIL: docs/cli-reference is out of sync with live CLI help."
|
|
echo "Run: ./scripts/generate-cli-docs.sh ${BD_ARG:-}"
|
|
diff -ur "$PROJECT_ROOT/docs/cli-reference" "$TMP_OUTPUT_DIR/docs/cli-reference" | sed -n '1,160p' || true
|
|
exit 1
|
|
fi
|
|
|
|
echo "PASS: generated CLI docs are fresh"
|
|
else
|
|
generate_all "$PROJECT_ROOT"
|
|
echo "Generated CLI docs from: $($BD version 2>/dev/null | head -1 || echo "$BD")"
|
|
echo "Updated docs/CLI_REFERENCE.md, docs/cli-reference/, and the docs.json CLI nav"
|
|
fi
|