From 38d56e6c89bc3b9f806b5a91b7185c15415d4e8a Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Thu, 20 Aug 2026 22:27:29 +0200 Subject: [PATCH] fix(scripts): check links in tracked files, not everything on disk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prune list was wrong three times running: it walked the scratch worktrees under .claude/, then makepkg's vendored cargo registry under packaging/arch/src/, reporting a dependency's broken README as if it were ours. Every one of those directories is already git-ignored, so asking git for the file list makes the exclusion rule the same one the repo already maintains β€” and it cannot drift the way a hand-kept prune list did. It also makes the script do what its header always said it did: check tracked markdown. Untracked-but-unignored files are included on purpose, so a new doc is checked before it is committed rather than after. The find(1) path stays as a fallback for a non-git checkout. CI was unaffected β€” a fresh checkout has none of those directories β€” but the local gate cried wolf, which is how a gate stops being read. --- scripts/check-doc-links.sh | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/scripts/check-doc-links.sh b/scripts/check-doc-links.sh index a8a4a12b..0813f952 100755 --- a/scripts/check-doc-links.sh +++ b/scripts/check-doc-links.sh @@ -48,6 +48,9 @@ cd "$(dirname "$0")/.." # Generated, vendored or build-output trees. Their markdown is not authored here # and their link targets are not ours to fix. +# +# Only consulted when this is NOT a git checkout β€” inside one, the tracked-file +# list does this job and does not need maintaining. Kept for the tarball case. EXCLUDES=( "./node_modules/*" "./.svelte-kit/*" @@ -81,14 +84,33 @@ is_generated() { echo "πŸ”Ž Checking relative markdown links resolve to files on disk…" -# Build the find(1) prune expression from EXCLUDES. -find_args=(. ) -for pattern in "${EXCLUDES[@]}"; do - find_args+=(-path "$pattern" -prune -o) -done -find_args+=(-name "*.md" -type f -print) - -mapfile -t md_files < <(find "${find_args[@]}" | sort) +# Ask git which markdown files are ours, rather than walking the filesystem. +# +# This started as a find(1) with a hand-maintained prune list, and that list was +# wrong three times in a row: it walked the scratch worktrees under .claude/, +# then makepkg's vendored cargo registry under packaging/arch/src/ β€” each time +# reporting a dependency's broken README as if it were ours. Every one of those +# directories is already git-ignored, so the tracked-file list is the exclusion +# rule, and it cannot drift out of date the way EXCLUDES did. It also matches +# what this script always claimed to do. +# +# Untracked-but-not-ignored files are deliberately included: a new doc added in +# a working tree should be checked before it is committed, not after. +if git rev-parse --git-dir >/dev/null 2>&1; then + mapfile -t md_files < <( + { git ls-files -z --cached --others --exclude-standard -- '*.md' | tr '\0' '\n'; } \ + | sed 's|^|./|' | sort -u + ) +else + # Not a git checkout (an exported tarball, say): fall back to walking, with + # the prune list below as the only defence. + find_args=(. ) + for pattern in "${EXCLUDES[@]}"; do + find_args+=(-path "$pattern" -prune -o) + done + find_args+=(-name "*.md" -type f -print) + mapfile -t md_files < <(find "${find_args[@]}" | sort) +fi echo " ${#md_files[@]} markdown files"