forked from heavy-duty/box
fix: lint the release path — globstar does not descend into dot-directories
CI's shellcheck sweep set globstar and globbed `bin/* **/*.sh`. globstar makes `**` descend into subdirectories, but a glob still does not MATCH a dot-prefixed name, so `**/` never entered `.github/` and three scripts were never linted: changelog-armed.sh (the #108/#110 guard that gates every PR), release-notes.sh (which produces the published release body), and labels-reconcile.sh (the label state machine). That is the entire release path, while the step's own comment promised the opposite — that a script in a new subdirectory is linted without anyone editing a list. Latent, not broken: all three pass shellcheck as-is, so this is a no-op on current code. What changes is that a regression in them would be caught. dotglob alongside globstar closes it, measured rather than assumed: it adds exactly those three and nothing else — a checkout's .git carries no *.sh, its hooks shipping as *.sample, so `**/*.sh` does not wander into it. The one-time fix is dotglob; what keeps the gap shut is the CLASS check, in the same shape as the eof_guard_sweep of #112. The sweep now compares the globbed set against `git ls-files '*.sh'` and fails naming any tracked script it does not cover, so a future dot-directory or shopt subtlety cannot silently lint a subset and pass. eof_guard_sweep carried the identical blind spot — it rebuilds the same glob — and is widened the same way. A no-op today: the three scripts set errexit, so they are in that class by construction, but none of them reads. Refs #116
This commit is contained in:
parent
4c34facefe
commit
0b7ad21eca
3 changed files with 55 additions and 2 deletions
27
.github/workflows/ci.yml
vendored
27
.github/workflows/ci.yml
vendored
|
|
@ -14,10 +14,35 @@ jobs:
|
|||
# globstar so a script in a new subdirectory is linted without anyone
|
||||
# remembering to edit this list; bin/* covers the extensionless entrypoint
|
||||
# (bin/box). The file list is printed so under-coverage shows up in the log.
|
||||
#
|
||||
# dotglob is not decoration (#116): globstar makes `**` descend, but a
|
||||
# glob still does not MATCH a dot-prefixed name, so `**/` never entered
|
||||
# `.github/` — and the whole release path (changelog-armed.sh, which
|
||||
# gates every PR, release-notes.sh, labels-reconcile.sh) went unlinted
|
||||
# while the comment above told the next author it was covered.
|
||||
# Measured on this tree: dotglob adds exactly those three and nothing
|
||||
# else — a checkout's `.git` carries no `*.sh` (its hooks ship as
|
||||
# `*.sample`), so `**/*.sh` does not wander into it.
|
||||
#
|
||||
# The sweep below is the CLASS check, same shape as the eof_guard_sweep
|
||||
# in test/cli.sh (#112): the one-time fix is `dotglob`, but what keeps
|
||||
# the gap from reopening is asserting that every TRACKED script is in
|
||||
# the set actually handed to shellcheck. `git ls-files` is the authority
|
||||
# on what the repo contains; if the glob ever drifts from it again —
|
||||
# another dot-directory, another shopt subtlety — CI says which files
|
||||
# escaped instead of quietly linting a subset and passing.
|
||||
run: |
|
||||
shopt -s globstar
|
||||
shopt -s globstar dotglob
|
||||
files=(bin/* **/*.sh)
|
||||
printf 'shellcheck: %s\n' "${files[@]}"
|
||||
missing="$(comm -13 \
|
||||
<(printf '%s\n' "${files[@]}" | sort -u) \
|
||||
<(git ls-files '*.sh' | sort -u))"
|
||||
if [ -n "$missing" ]; then
|
||||
echo "tracked scripts the shellcheck sweep does not cover (#116):"
|
||||
printf ' %s\n' $missing
|
||||
exit 1
|
||||
fi
|
||||
shellcheck -x "${files[@]}"
|
||||
- name: cli tests
|
||||
run: bash test/cli.sh
|
||||
|
|
|
|||
22
CHANGELOG.md
22
CHANGELOG.md
|
|
@ -61,6 +61,28 @@ which records not just what changed but what each drill run proved.
|
|||
|
||||
## 0.8.0 — 2026-07-19
|
||||
|
||||
### Fixed
|
||||
|
||||
- **CI's shellcheck sweep never lints `.github/scripts/*.sh`** (#116) —
|
||||
`globstar` makes `**` descend into subdirectories, but a glob still does
|
||||
not *match* a dot-prefixed name, so `**/` never entered `.github/`. The
|
||||
three scripts that escaped are the release path: `changelog-armed.sh` (the
|
||||
#108/#110 guard that gates every PR, and had never been linted),
|
||||
`release-notes.sh` (which produces the published release body), and
|
||||
`labels-reconcile.sh` (the label state machine) — while the step's own
|
||||
comment promised that "a script in a new subdirectory is linted without
|
||||
anyone remembering to edit this list". Latent, not broken: all three pass
|
||||
shellcheck as-is, so this lands as a no-op on current code and the fix is
|
||||
that a regression in them would now be caught. `dotglob` alongside
|
||||
`globstar` closes it, measured rather than assumed — it adds exactly those
|
||||
three and nothing else, a checkout's `.git` carrying no `*.sh` (its hooks
|
||||
ship as `*.sample`). Paired with a CLASS check in the same shape as the
|
||||
`eof_guard_sweep` of #112: the sweep now compares the globbed set against
|
||||
`git ls-files '*.sh'` and fails naming any tracked script it does not
|
||||
cover, so the gap cannot reopen silently the next time a dot-directory or
|
||||
a shopt subtlety hides one. `eof_guard_sweep` itself carried the identical
|
||||
blind spot — it rebuilds the same glob — and is widened the same way.
|
||||
|
||||
### Added
|
||||
|
||||
- **Merging the release PR IS the release — and the release re-arms main
|
||||
|
|
|
|||
|
|
@ -967,7 +967,13 @@ fi
|
|||
# guard is not.
|
||||
eof_guard_sweep() {
|
||||
local f n line bad=0 files
|
||||
files="$(cd "$ROOT" && shopt -s globstar && printf '%s\n' bin/* ./**/*.sh | sed 's|^\./||' | sort -u)"
|
||||
# dotglob alongside globstar for the same reason CI's shellcheck step carries
|
||||
# it (#116): globstar descends, but a glob does not MATCH a dot-prefixed name,
|
||||
# so this sweep skipped '.github/scripts/*.sh' — the release path — exactly as
|
||||
# the linter did. Those three set errexit, so they are in scope for this class
|
||||
# by construction; today none of them reads at all, which is why widening the
|
||||
# set is a no-op on current code rather than a bug fix.
|
||||
files="$(cd "$ROOT" && shopt -s globstar dotglob && printf '%s\n' bin/* ./**/*.sh | sed 's|^\./||' | sort -u)"
|
||||
while IFS= read -r f; do
|
||||
[ -f "$ROOT/$f" ] || continue
|
||||
grep -qE '^[[:space:]]*set[[:space:]]+-[a-zA-Z]*e' "$ROOT/$f" || continue
|
||||
|
|
|
|||
Loading…
Reference in a new issue