Files
holocron/tests/run-tests.sh
Defame1297 73393b9d01 fix(scripts): correct shellcheck source directives that resolved to nothing
`tests/run-tests.sh` declared `source=lib/batch-run.sh`, which resolves
to neither the repo root nor the script's own directory. A directive
that does not resolve is silent: it blinds test-vale-wrap.sh's
`sourced_files()` seeding exemption, and shellcheck's own SC1091 is
`info` while .pre-commit-config.yaml pins `--severity=warning`.

Issue #97 names run-bats.sh's `../scripts/lib/batch-run.sh` as the
correct spelling. It is not. Directives resolve against the source-path,
which under pre-commit is the repo root, so `../scripts/...` escapes the
repo and trips SC1091 exactly as `lib/...` does -- verified directly.
The spelling satisfying both shellcheck and `sourced_files()`'s
two-candidate rule is repo-root-relative, matching scripts/install.sh.

Fixes all three: run-tests.sh, run-bats.sh, and check-manifests.sh,
the last unmentioned by the issue. Every directive in the repo now
resolves, which the previous commit's case 27 asserts.

Refs #97

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7GvKuJfy2WrdBmUttV4DT
2026-08-14 08:03:30 +00:00

116 lines
3.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Run all test-*.sh files in the repo (including plugins) and the bats suite.
# Usage: bash tests/run-tests.sh [--bats-only]
#
# A script exiting 77 (the automake convention) is reported as SKIPPED, not
# passed — a suite that can't run for lack of a binary must not read as green.
#
# TEST_DIR — override root to search for test-*.sh (default: REPO_ROOT); used by tests.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
BATS="$REPO_ROOT/tests/run-bats.sh"
BATS_ONLY=false
[[ "${1:-}" == "--bats-only" ]] && BATS_ONLY=true
SEARCH_ROOT="${TEST_DIR:-$REPO_ROOT}"
FAILED=()
SKIPPED=()
PASSED=0
SKIP_EXIT=77
run_bats() {
if [[ -x "$BATS" ]]; then
echo "=== bats ==="
bash "$BATS"
echo ""
fi
}
if $BATS_ONLY; then
run_bats
exit 0
fi
run_bats
# Collected with a `while read` loop rather than `mapfile` — macOS ships
# /bin/bash 3.2, which has no `mapfile`. Process substitution (not a pipe)
# keeps the loop in this shell so the appends survive. `sort` is still fed
# newline-delimited output, exactly as before.
SCRIPTS=()
while IFS= read -r script; do
SCRIPTS+=("$script")
done < <(
find "$SEARCH_ROOT" -name "test-*.sh" \
-not -path "*/.git/*" \
-not -path "*/.claude/worktrees/*" \
| sort
)
# Each test-*.sh is independent (fixtures live under its own mktemp dir, none
# write back into the live repo tree -- verified before adding this), so they
# run concurrently in fixed-size batches instead of one at a time. Dispatch and
# throttling is scripts/lib/batch-run.sh's batch_run -- shared with
# scripts/sync-plugin-content.sh and tests/run-bats.sh so a batching bug fix
# only needs to land once; see that file for why this is batched rather than a
# rolling `wait -n` pool.
SCRATCH_ROOT="$(mktemp -d)"
trap 'rm -rf "$SCRATCH_ROOT"' EXIT
# The source= path below is repo-root-relative, matching scripts/install.sh:5 --
# NOT script-dir-relative. The source-path used to resolve it is the cwd
# pre-commit invokes the linter from, which is the repo root, so `lib/...`
# (resolving to a nonexistent tests/lib/) and `../scripts/...` (escaping the repo
# entirely) both fail. Both spellings were live until issue #97, and neither was
# visible: the resulting SC1091 is `info` while .pre-commit-config.yaml pins
# `--severity=warning`. A directive that does not resolve also blinds
# test-vale-wrap.sh's `sourced_files()` exemption, which reads these same
# directives to find array seeding that lives in the sourced file.
#
# Do not start a comment line here with the linter's name -- it is parsed as a
# directive and errors out (SC1073).
# shellcheck source=scripts/lib/batch-run.sh
source "$REPO_ROOT/scripts/lib/batch-run.sh"
declare -a batch_args=()
idx=0
for script in ${SCRIPTS[@]+"${SCRIPTS[@]}"}; do
idx=$((idx + 1))
cmd="$(printf 'rc=0; bash %q || rc=$?; echo "$rc" >%q' "$script" "$SCRATCH_ROOT/$idx.status")"
batch_args+=("$idx" "$cmd")
done
batch_run "$SCRATCH_ROOT" ${batch_args[@]+"${batch_args[@]}"}
idx=0
for script in ${SCRIPTS[@]+"${SCRIPTS[@]}"}; do
idx=$((idx + 1))
rel="${script#"$SEARCH_ROOT/"}"
echo "=== $rel ==="
cat "$SCRATCH_ROOT/$idx.log"
rc="$(cat "$SCRATCH_ROOT/$idx.status" 2>/dev/null || echo 1)"
if [[ $rc -eq 0 ]]; then
PASSED=$((PASSED + 1))
elif [[ $rc -eq $SKIP_EXIT ]]; then
SKIPPED+=("$rel")
else
FAILED+=("$rel")
fi
echo ""
done
echo "=== Summary: $PASSED passed, ${#SKIPPED[@]} skipped, ${#FAILED[@]} failed ==="
if [[ ${#SKIPPED[@]} -gt 0 ]]; then
echo "Skipped scripts:"
for s in ${SKIPPED[@]+"${SKIPPED[@]}"}; do
echo " $s"
done
fi
if [[ ${#FAILED[@]} -gt 0 ]]; then
echo "Failed scripts:"
for s in ${FAILED[@]+"${FAILED[@]}"}; do
echo " $s"
done
exit 1
fi