#!/usr/bin/env bash # # tests/shellcheck.sh — enforce shellcheck (via Docker) on all repo shell scripts # # Usage: # bash tests/shellcheck.sh # lint every .sh in the repo # bash tests/shellcheck.sh path/a.sh # lint specific files # # Uses the koalaman/shellcheck:stable image (no native binary required). # Exits non-zero if ANY script emits a diagnostic. # set -uo pipefail IMAGE="koalaman/shellcheck:stable" ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" mapfile -t FILES < <( if [ "$#" -gt 0 ]; then for f in "$@"; do f_abs="$(cd "$(dirname "$f")" && pwd)/$(basename "$f")" case "$f_abs" in "$ROOT"/legacy/*) ;; # 2018 Perl snapshot, verbatim, not maintained *) case "$f_abs" in *.sh) echo "$f_abs" ;; esac ;; esac done else while IFS= read -r f_abs; do case "$f_abs" in "$ROOT"/legacy/*) ;; # 2018 Perl snapshot, verbatim, not maintained *) echo "$f_abs" ;; esac done < <(find "$ROOT" -type f -name '*.sh' \ -not -path '*/.git/*' -not -path "$ROOT/.crush/*") fi ) if [ "${#FILES[@]}" -eq 0 ]; then echo "shellcheck.sh: no .sh files to check." >&2 exit 0 fi # --- Filter out non-bash scripts (e.g. PHP with a .sh extension) -------------- BASH_FILES=() for f in "${FILES[@]}"; do shebang=$(head -c 64 "$f" 2>/dev/null | head -n1) case "$shebang" in \#!/usr/bin/php* | \#!/usr/bin/env\ php*) ;; # PHP, skip *) BASH_FILES+=("$f") ;; esac done if [ "${#BASH_FILES[@]}" -eq 0 ]; then echo "shellcheck.sh: no bash scripts among targets." >&2 exit 0 fi # shellcheck disable=SC2012 # basename loop is intentional REL=() for f in "${BASH_FILES[@]}"; do REL+=("${f#"$ROOT"/}"); done # Intentional conventions of this codebase (not bugs): # SC1090/SC1091 — awk program paths & dynamic sourcing not followable DISABLES=(-e SC1090 -e SC1091) echo "Checking ${#BASH_FILES[@]} script(s) with $IMAGE:" printf ' %s\n' "${REL[@]}" docker run --rm \ -v "$ROOT:/mnt:ro" \ -w /mnt \ "$IMAGE" -x "${DISABLES[@]}" "${REL[@]}" rc=$? if [ "$rc" -eq 0 ]; then echo "shellcheck: PASS (${#BASH_FILES[@]} scripts clean)" else echo "shellcheck: FAIL (fix the findings above or add targeted disable directives)" >&2 fi exit "$rc"