Split per O&M lane work order. Full history: KNEL/PFVCluster. shellcheck debt fixed in librenms-agent (quoting, arithmetic, backticks); fixes upstream ntp-server.sh bug: input_wakeups reported PACKETSENDFAILURES instead of INPUTWAKEUPS. mysql.sh (PHP-in-.sh) exempt per house rule. https://projects.knownelement.com/issues/769#note-4152
98 lines
3.5 KiB
Bash
98 lines
3.5 KiB
Bash
#!/usr/bin/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 path/b.sh # lint specific files
|
|
#
|
|
# Uses the koalaman/shellcheck:stable image (no native binary required).
|
|
# Exits non-zero if ANY script emits a diagnostic. Skips non-bash scripts
|
|
# (e.g. PHP files with a .sh extension) and the vendored/ trees.
|
|
#
|
|
set -uo pipefail
|
|
|
|
IMAGE="koalaman/shellcheck:stable"
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
|
# --- Gather target files -----------------------------------------------------
|
|
mapfile -t FILES < <(
|
|
if [ "$#" -gt 0 ]; then
|
|
# Explicit args: resolve to repo-root-relative paths, keep only .sh
|
|
for f in "$@"; do
|
|
f_abs="$(cd "$(dirname "$f")" && pwd)/$(basename "$f")"
|
|
case "$f_abs" in
|
|
"$ROOT"/vendor/*) ;; # skip vendored
|
|
"$ROOT"/archive/provisioning/Agents/librenms/*) ;; # upstream librenms-agent scripts
|
|
"$ROOT"/oam/librenms-agent/agent/*) ;; # upstream librenms-agent scripts (verbatim port [#474])
|
|
"$ROOT"/archive/KNELServerBuild/*) ;; # archived legacy code, not maintained [#474]
|
|
*) case "$f_abs" in *.sh) echo "$f_abs";; esac ;;
|
|
esac
|
|
done
|
|
else
|
|
# Default: every .sh under the repo, minus vendor/
|
|
while IFS= read -r f_abs; do
|
|
case "$f_abs" in
|
|
"$ROOT"/vendor/*) ;; # skip vendored
|
|
"$ROOT"/archive/provisioning/Agents/librenms/*) ;; # upstream librenms-agent scripts
|
|
"$ROOT"/oam/librenms-agent/agent/*) ;; # upstream librenms-agent scripts (verbatim port [#474])
|
|
"$ROOT"/archive/KNELServerBuild/*) ;; # archived legacy code, not maintained [#474]
|
|
*) echo "$f_abs" ;;
|
|
esac
|
|
done < <(find "$ROOT" -type f -name '*.sh' \
|
|
-not -path '*/.git/*' -not -path "$ROOT/vendor/*" \
|
|
-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") ;; # any other shebang → check
|
|
*) BASH_FILES+=("$f") ;; # no shebang → check anyway
|
|
esac
|
|
done
|
|
|
|
if [ "${#BASH_FILES[@]}" -eq 0 ]; then
|
|
echo "shellcheck.sh: no bash scripts among targets." >&2
|
|
exit 0
|
|
fi
|
|
|
|
# --- Run shellcheck in Docker (mount repo root, pass root-relative paths) -----
|
|
# shellcheck disable=SC2012 # basename loop is intentional
|
|
REL=()
|
|
for f in "${BASH_FILES[@]}"; do REL+=("${f#"$ROOT"/}"); done
|
|
|
|
# Disable checks that are intentional conventions of this codebase (not bugs):
|
|
# SC1090/SC1091 — cannot follow dynamically-computed `source` paths (KNEL framework)
|
|
# SC2029 — ssh orchestration deliberately expands the command client-side
|
|
DISABLES=(
|
|
-e SC1090
|
|
-e SC1091
|
|
-e SC2029
|
|
)
|
|
|
|
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"
|