diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0731ca..3ecbcee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,11 +12,22 @@ jobs: # -x follows the `source=SCRIPTDIR/...` directives into commands/lib/. # globstar so a script in a new subdirectory is linted without anyone # remembering to edit this list; bin/* covers the extensionless entrypoints. - # The file list is printed so under-coverage shows up in the log. + # dotglob because globs skip dot-prefixed names: without it `**/` never + # descends into `.github/`, so `.github/scripts/*.sh` — release-lib.sh + # among them — was swept up by nothing (#70). It also makes `**` + # descend into `.git/`, which holds no tracked `.sh` on a checkout. + # The file list is printed so under-coverage shows up in the log, and + # the comm below turns under-coverage into a failure rather than a + # thing someone has to notice: every tracked `.sh` must be in the set. run: | - shopt -s globstar + shopt -s globstar dotglob files=(bin/* **/*.sh) printf 'shellcheck: %s\n' "${files[@]}" + uncovered=$(comm -23 <(git ls-files '*.sh' | sort) <(printf '%s\n' "${files[@]}" | sort)) + if [ -n "$uncovered" ]; then + printf 'tracked .sh files the glob does not lint:\n%s\n' "$uncovered" >&2 + exit 1 + fi shellcheck -x "${files[@]}" - name: cli tests run: bash test/cli.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index b4a5fac..7beda3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -181,6 +181,24 @@ on the way to cutting its first release, and this file starts there. and retires it. It stayed a separate change because it reaches markers on live machines that guard root SSH, and so needed a compat read this rename did not. +### Fixed + +- **CI's shellcheck sweep now reaches `.github/scripts/`** (#70) — the step + ran `shopt -s globstar` and globbed `bin/* **/*.sh`, but globs skip + dot-prefixed names without `dotglob`, so `**/` never descended into + `.github/` and two tracked scripts were linted by nothing: + `labels-reconcile.sh` and `release-lib.sh`. The second is the one that + stings — it holds `changelog_section`, the extraction `release.yml` sources + to build the published release body and the same function `test/release.sh`'s + `changelog_armed` guard (#66) calls to decide whether main is armed. The + script deciding both what ships and whether the changelog is safe was the + script CI never read. Adding `dotglob` pulls in exactly those two files and + nothing else; both already pass, so this closes a hole in the net rather + than fixing a defect behind it. Paired with a class check that fails the + step when any tracked `.sh` falls outside the globbed set, so the gap + cannot reopen quietly — including via a symlinked directory, which + `globstar` declines to traverse. + ## 0.2.0 — 2026-07-19 ### Added