Files
homelab/scripts/ci/yaml-citations.sh
atlas-botandClaude Opus 5.5 21a7583523
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
ci: cite YAML by anchor instead of line number, and guard it (REN-183)
Comments that pointed at other YAML as `file.yaml:N` went stale on any
edit above the cited line; three drift fixes had been merged by hand
(REN-181). The cited block now carries `# anchor: <name>` and the
comment cites `path.yaml#<name>`.

- Sweep: all 32 line-number citations in YAML comments converted.
  Several were already stale at head and now point at the right block
  (see PR). Vendored files (Flux gotk-components, IMC CRD) get no
  anchor; those two citations name the object/schema path instead.
- Guard: scripts/ci/yaml-citations.sh in ci-manifests-test.yml; fails
  on a line-number citation or a path#name whose file/anchor is gone.
  Self-test in ci-scripts-test.yml.
- CONTRIBUTING.md: the convention in three lines.

Comment-only under kubernetes/: every file parses to identical objects
before and after, so Flux applies nothing and no ConfigMap data changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 08:44:54 +00:00

111 lines
4.0 KiB
Bash

#!/bin/sh
# Guard the citation convention in YAML comments (REN-183, see CONTRIBUTING.md).
#
# Run: sh scripts/ci/yaml-citations.sh [repo-root]
# Needs: sh, find, awk, grep (BusyBox is fine). Offline.
# Tests: scripts/ci/test-yaml-citations.sh
#
# A comment cites another block as `path.yaml#name`, and the cited block
# carries a marker line `# anchor: name`. `path` is relative to the citing
# file's directory or to the repo root. This fails when:
#
# * a comment cites by line number (`foo.yaml:12`). Line numbers go stale on
# the first unrelated edit above them, silently; three drift fixes were
# merged before this guard existed (REN-181).
# * a `path#name` citation names a file or an anchor that does not exist.
# * an anchor is not kebab-case, or is declared twice in one file.
#
# Existence only. It does not check that the anchored block still says what the
# citing comment claims — that stays a reviewer's job, and it is why this guard
# has no false positives from ordinary edits.
set -eu
ROOT="${1:-.}"
cd "$ROOT"
# Same loose-floor reasoning as ci-manifests-test.yml: catch discovery that
# silently returns nothing, not normal churn. ~650 YAML files exist today.
FLOOR="${YAML_CITATIONS_FLOOR:-50}"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT INT TERM
# Not `find -printf` (BusyBox lacks it).
find . -path ./.git -prune -o -type f \( -name '*.yaml' -o -name '*.yml' \) -print \
| sed 's|^\./||' | sort > "$TMP/files"
count=$(grep -c . "$TMP/files" || true)
if [ "$count" -lt "$FLOOR" ]; then
echo "FAIL: found only $count YAML files; floor is $FLOOR. Discovery is broken."
exit 1
fi
# One pass over every file. A YAML comment starts at a `#` that begins the line
# or follows whitespace, so a `#` inside a URL or a quoted value is not one.
# Emits tab-separated records:
# L file line text a line-number citation
# C file line path name a path#name citation
# A file line name an anchor declaration
# B file line text a malformed anchor declaration
while IFS= read -r f; do
awk -v f="$f" '
{
if (!match($0, /(^|[ \t])#/)) next
c = substr($0, RSTART)
if (c ~ /^[ \t]*# anchor:/) {
if (c ~ /^[ \t]*# anchor: [a-z0-9]+(-[a-z0-9]+)*[ \t]*$/) {
n = c; sub(/^[ \t]*# anchor: /, "", n); sub(/[ \t]*$/, "", n)
print "A\t" f "\t" NR "\t" n
} else {
print "B\t" f "\t" NR "\t" c
}
next
}
if (c ~ /\.ya?ml:[0-9]/) print "L\t" f "\t" NR "\t" c
while (match(c, /[A-Za-z0-9_.\/-]+\.ya?ml#[A-Za-z0-9_-]+/)) {
m = substr(c, RSTART, RLENGTH)
p = m; sub(/#.*/, "", p)
n = m; sub(/.*#/, "", n)
print "C\t" f "\t" NR "\t" p "\t" n
c = substr(c, RSTART + RLENGTH)
}
}' "$f"
done < "$TMP/files" > "$TMP/records"
fail=0
while IFS="$(printf '\t')" read -r kind f line a b; do
case "$kind" in
L)
echo "FAIL $f:$line cites by line number; use path.yaml#anchor instead"
echo " $a"
fail=1 ;;
B)
echo "FAIL $f:$line malformed anchor; want '# anchor: kebab-case-name'"
fail=1 ;;
C)
dir=$(dirname "$f")
if [ -f "$dir/$a" ]; then target="$dir/$a"
elif [ -f "$a" ]; then target="$a"
else
echo "FAIL $f:$line cites $a#$b, but no such file (tried $dir/$a and ./$a)"
fail=1; continue
fi
if ! grep -qE "^[[:space:]]*# anchor: $b[[:space:]]*\$" "$target"; then
echo "FAIL $f:$line cites $a#$b, but $target has no '# anchor: $b'"
fail=1
fi ;;
esac
done < "$TMP/records"
# Duplicate anchors in one file make a citation ambiguous.
awk -F '\t' '$1 == "A" { k = $2 "\t" $4; if (k in seen) print $2 ":" $3 " duplicate anchor " $4 " (first at line " seen[k] ")"; else seen[k] = $3 }' \
"$TMP/records" > "$TMP/dups"
if [ -s "$TMP/dups" ]; then
sed 's/^/FAIL /' "$TMP/dups"
fail=1
fi
anchors=$(grep -c '^A' "$TMP/records" || true)
cites=$(grep -c '^C' "$TMP/records" || true)
[ "$fail" -eq 0 ] && echo "ok $count YAML files, $anchors anchors, $cites path#anchor citations, 0 line-number citations"
exit $fail