CI's shellcheck step set `globstar` and globbed `bin/* **/*.sh`. Globs do not match dot-prefixed names without `dotglob`, so `**/` never descended into `.github/` and two tracked scripts were linted by nothing: `.github/scripts/labels-reconcile.sh` and `.github/scripts/release-lib.sh`. release-lib.sh is the one that matters: it holds `changelog_section`, which release.yml sources to build the published release body and which test/release.sh's `changelog_armed` guard calls to decide whether main is armed. The script that decides both what ships and whether the changelog is safe was the script CI never read. Measured rather than assumed: `dotglob` adds exactly those two files to rig's line and nothing else, and `**` descending into `.git/` matches no `.sh` on a checkout. Both files already pass `shellcheck -x`, so this closes a hole in the net rather than fixing a defect behind it. Paired with a class check — `comm` against `git ls-files '*.sh'` — that fails the step naming any tracked script outside the globbed set, so the gap cannot reopen quietly. It also covers an escape `dotglob` does not: `globstar` declines to traverse symlinked directories. Refs #70
48 lines
2.1 KiB
YAML
48 lines
2.1 KiB
YAML
name: ci
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
jobs:
|
|
check:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: shellcheck
|
|
# -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.
|
|
# 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 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
|
|
- name: release-flow tests
|
|
run: bash test/release.sh
|
|
|
|
# Kept SEPARATE from `check` on purpose: this job pulls a Postgres image and
|
|
# stands up throwaway containers, and a slow image pull must never delay the
|
|
# fast shellcheck + cli.sh feedback above. ubuntu-latest ships Docker running
|
|
# and passwordless sudo, so test/db-integration.sh EXECUTES here (it only
|
|
# skips where Docker is absent). It is the automated proof that dump/restore
|
|
# actually round-trips, not just that the args parse.
|
|
db-integration:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: db dump/restore round-trip
|
|
run: bash test/db-integration.sh
|