mirror of
https://github.com/ironfox-oss/IronFox.git
synced 2026-07-31 01:46:33 -04:00
Add a blocking `lint` CI stage (runs first, on a lightweight Alpine image) plus a core.hooksPath pre-commit hook, with scripts/lint.sh as the shared runner for CI, the hook, and manual use. Checks are configured in .shellcheckrc and formatting in .editorconfig. bootstrap.sh installs shellcheck + shfmt per-OS and enables the pre-commit hook. The hook is a convenience (bypassable with --no-verify); the CI `lint-scripts` job enforces formatting. SC2086/SC2046 are disabled for now. SC2002 is disabled too, since shellcheck made it opt-in as of 0.11.0 while older versions (e.g. Alpine's in CI) still enable it by default.
81 lines
2.3 KiB
Bash
Executable File
81 lines
2.3 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Lints IronFox's shell scripts with shellcheck (static analysis) and shfmt
|
|
# (formatting). This is the single source of truth used by CI, the pre-commit
|
|
# hook, and manual runs.
|
|
#
|
|
# It is intentionally SELF-CONTAINED: it does NOT source env.sh (which performs
|
|
# full OS/path bootstrap), so it runs unchanged in a minimal CI container.
|
|
#
|
|
# Usage:
|
|
# scripts/lint.sh Lint all tracked shell scripts (CI + manual)
|
|
# scripts/lint.sh --staged Lint only staged shell scripts (pre-commit hook)
|
|
#
|
|
# Config lives in .shellcheckrc (checks) and .editorconfig (shfmt formatting),
|
|
# both read automatically from the repo root.
|
|
|
|
set -euo pipefail
|
|
|
|
# Resolve and move to the repo root so relative paths and config discovery
|
|
# (.shellcheckrc, .editorconfig) work regardless of the caller's cwd.
|
|
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
|
cd "${REPO_ROOT}"
|
|
|
|
mode='all'
|
|
if [[ "${1:-}" == '--staged' ]]; then
|
|
mode='staged'
|
|
fi
|
|
|
|
# Collect target scripts. `git ls-files` naturally excludes generated,
|
|
# gitignored files (e.g. scripts/env_local.sh, scripts/env_build.sh).
|
|
declare -a targets=()
|
|
if [[ "${mode}" == 'staged' ]]; then
|
|
while IFS= read -r file; do
|
|
[[ -n "${file}" ]] && targets+=("${file}")
|
|
done < <(git diff --cached --name-only --diff-filter=ACM -- 'scripts/*.sh')
|
|
else
|
|
while IFS= read -r file; do
|
|
targets+=("${file}")
|
|
done < <(git ls-files 'scripts/*.sh')
|
|
fi
|
|
|
|
if [[ ${#targets[@]} -eq 0 ]]; then
|
|
echo 'lint: no shell scripts to check.'
|
|
exit 0
|
|
fi
|
|
|
|
# Ensure the tools are available before running.
|
|
missing=0
|
|
for tool in shellcheck shfmt; do
|
|
if ! command -v "${tool}" > /dev/null 2>&1; then
|
|
echo "lint: required tool '${tool}' is not installed or not in PATH." >&2
|
|
missing=1
|
|
fi
|
|
done
|
|
if [[ "${missing}" -ne 0 ]]; then
|
|
echo 'lint: install the missing tool(s) (e.g. run scripts/bootstrap.sh) and retry.' >&2
|
|
exit 127
|
|
fi
|
|
|
|
status=0
|
|
|
|
echo "lint: shellcheck (${#targets[@]} file(s))..."
|
|
if ! shellcheck -x "${targets[@]}"; then
|
|
status=1
|
|
fi
|
|
|
|
echo 'lint: shfmt formatting check...'
|
|
if ! shfmt -d "${targets[@]}"; then
|
|
echo >&2
|
|
echo "lint: formatting issues found above. Fix with:" >&2
|
|
echo " git ls-files 'scripts/*.sh' | xargs shfmt -w" >&2
|
|
status=1
|
|
fi
|
|
|
|
if [[ "${status}" -eq 0 ]]; then
|
|
echo 'lint: OK'
|
|
else
|
|
echo 'lint: FAILED' >&2
|
|
fi
|
|
exit "${status}"
|