.vale.ini's own comments named the issues that gated write-good.Passive, but the tracker-tag lint's extension list didn't cover .ini, so it never caught its own violation. Extend the scope and reword the comment to prose that stands on its own.
92 lines
4.3 KiB
Shell
Executable file
92 lines
4.3 KiB
Shell
Executable file
#!/bin/sh
|
|
# CI lint: flags tracker references — a `#N` tag or a full `.../issues/N`
|
|
# forge URL — anywhere in tracked text, source or docs. Prose, not tracker
|
|
# references: in code because tags rot; in markdown because the forge's
|
|
# public mirror carries no issue/PR data at all, so bare/qualified/glued
|
|
# `#N` and a full link are equally dead weight for a public reader — a
|
|
# full URL is the same problem spelled out longer, not a safer swap for a
|
|
# short tag. No markdown exemption: one used to exist, dropped once that
|
|
# read as still allowing exactly this.
|
|
#
|
|
# Emits a CI error annotation per hit, exits 1 if any hit is found. Its own
|
|
# required CI job (branch protection) — a hit blocks merge.
|
|
#
|
|
# Scope: every tracked `*.rs *.nix *.js *.mjs *.ts *.tsx *.css *.html *.md
|
|
# *.yml *.yaml *.ini`. CI workflow files (`.forgejo/workflows/*.yml`) are explicitly in
|
|
# scope: a step comment is still a comment. `.ini` covers `.vale.ini`, whose
|
|
# own inline comments are exactly the kind of prose this lint polices
|
|
# elsewhere — added after a `.vale.ini` comment named a tracker issue and
|
|
# nothing scanned the file to catch it. The pattern matches a hash,
|
|
# 2-5 digits, then a non-alphanumeric char or end-of-line (skips
|
|
# letter-bearing hex colours and digit-runs-then-letter, e.g. `#24h`;
|
|
# residual: a pure-numeric short hex trips it, write the six-digit form to
|
|
# dodge); or an `/issues/N` path segment, catching a full link via
|
|
# `$HIVE_FORGE_URL` or a literal domain alike.
|
|
#
|
|
# Escape hatch: a line with the marker `lint:allow` is exempt. Reserve it
|
|
# for a genuine non-tag hit (a `#123` heading example, test-input data) and
|
|
# keep a short reason next to it — not for a real reference of either
|
|
# form; rewrite those to prose that stands on its own instead.
|
|
set -eu
|
|
|
|
pattern='#[0-9]{2,5}([^0-9a-zA-Z]|$)|/issues/[0-9]+([^0-9a-zA-Z]|$)'
|
|
|
|
# A lint whose file-list matches nothing passes forever while checking not
|
|
# one file — mirrors the assertion in scripts/check-doc-refs.sh. If a rename
|
|
# or extension-list edit silences `git ls-files` here, that is a failure of
|
|
# this script, not a property of the tree.
|
|
file_count="$(git ls-files '*.rs' '*.nix' '*.js' '*.mjs' '*.ts' '*.tsx' '*.css' '*.html' '*.md' '*.yml' '*.yaml' '*.ini' | wc -l)"
|
|
if [ "$file_count" -eq 0 ]; then
|
|
echo 'check-issue-refs: file-list search matched nothing — pattern or tree changed' >&2
|
|
exit 1
|
|
fi
|
|
|
|
# git grep, not `git ls-files | xargs grep`: grep's exit code is the
|
|
# signal that distinguishes "no tracker refs" (1, clean) from a real
|
|
# scan failure (2+), but piping through xargs collapsed both into
|
|
# xargs(1)'s own 123 either way — indistinguishable, so a real failure
|
|
# (e.g. a file grep can't read) silently read as a clean tree. git grep
|
|
# runs once over the tracked set matching these globs and hands back its
|
|
# own exit status untouched: 0 = matched, 1 = no match, 2+/128 = error.
|
|
#
|
|
# The `if` guard (not `|| true`) is what's exempt from `set -e` here —
|
|
# capture the status, then branch on it explicitly rather than erasing it.
|
|
if matches="$(
|
|
git grep -nE "$pattern" -- '*.rs' '*.nix' '*.js' '*.mjs' '*.ts' '*.tsx' '*.css' '*.html' '*.md' \
|
|
'*.yml' '*.yaml' '*.ini'
|
|
)"; then
|
|
grep_status=0
|
|
else
|
|
grep_status=$?
|
|
fi
|
|
|
|
if [ "$grep_status" -gt 1 ]; then
|
|
printf 'check-issue-refs: git grep failed while scanning for tracker references (exit %s)\n' "$grep_status" >&2
|
|
exit 1
|
|
fi
|
|
|
|
hits=""
|
|
if [ "$grep_status" -eq 0 ]; then
|
|
# Lines carrying the `lint:allow` marker are dropped (legitimate
|
|
# non-tracker hit; see the header). Same exit-code split applies here:
|
|
# 1 means every match was exempted (clean), 2+ means grep itself broke.
|
|
if hits="$(printf '%s\n' "$matches" | grep -v 'lint:allow')"; then
|
|
filter_status=0
|
|
else
|
|
filter_status=$?
|
|
fi
|
|
if [ "$filter_status" -gt 1 ]; then
|
|
printf 'check-issue-refs: grep failed while filtering lint:allow markers (exit %s)\n' "$filter_status" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ -n "$hits" ]; then
|
|
echo "$hits" | while IFS=: read -r file lineno _; do
|
|
printf '::error file=%s,line=%s::tracker reference — write prose that stands on its own, not a hash-number tag or a full issue URL (see /knowledge/hive-rules.md)\n' "$file" "$lineno"
|
|
done
|
|
count="$(printf '%s\n' "$hits" | wc -l | tr -d ' ')"
|
|
printf 'check-issue-refs: %s tracker reference(s) found\n' "$count" >&2
|
|
exit 1
|
|
fi
|
|
exit 0
|