123 lines
3.6 KiB
Bash
123 lines
3.6 KiB
Bash
#!/usr/bin/env bash
|
|
# Steps of the reusable workflow .gitea/workflows/quality-checks.yml (ADR-0005).
|
|
# The workflow checks out the calling repository, fetches this file into
|
|
# shared-scripts/ and runs one command per step:
|
|
#
|
|
# quality-checks.sh validate check the inputs, before anything is installed
|
|
# quality-checks.sh install install the pinned tools into a virtual environment
|
|
# quality-checks.sh run run every selected tool on the tracked files
|
|
#
|
|
# Settings come from the environment, never from interpolated expressions:
|
|
# LANGUAGES, WORKING_DIRECTORY, RUFF_VERSION, MYPY_VERSION,
|
|
# SHELLCHECK_PY_VERSION, SHFMT_PY_VERSION, QC_VENV (and QC_BIN for tests).
|
|
# Every failure is printed as ::error::[category] message.
|
|
|
|
validate_inputs() {
|
|
set -u
|
|
IFS=',' read -ra langs <<< "${LANGUAGES// /}"
|
|
if [ "${#langs[@]}" -eq 0 ]; then
|
|
echo "::error::[configuration] languages is empty; use python, shell or both, comma separated."
|
|
exit 1
|
|
fi
|
|
for lang in "${langs[@]}"; do
|
|
case "$lang" in
|
|
python | shell) ;;
|
|
*)
|
|
echo "::error::[configuration] Unknown language '$lang'; use python and shell, comma separated."
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
case "$WORKING_DIRECTORY" in
|
|
"" | /* | .. | ../* | */.. | */../*)
|
|
echo "::error::[configuration] working-directory must be a relative path inside the repository."
|
|
exit 1
|
|
;;
|
|
esac
|
|
echo "Checking ${LANGUAGES} in ${WORKING_DIRECTORY}"
|
|
}
|
|
|
|
install_tools() {
|
|
set -eu
|
|
IFS=',' read -ra langs <<< "${LANGUAGES// /}"
|
|
packages=()
|
|
for lang in "${langs[@]}"; do
|
|
case "$lang" in
|
|
python) packages+=("ruff==${RUFF_VERSION}" "mypy==${MYPY_VERSION}") ;;
|
|
shell) packages+=("shellcheck-py==${SHELLCHECK_PY_VERSION}" "shfmt-py==${SHFMT_PY_VERSION}") ;;
|
|
esac
|
|
done
|
|
python3 -m venv "$QC_VENV"
|
|
"$QC_VENV/bin/pip" install --quiet "${packages[@]}"
|
|
}
|
|
|
|
run_checks() {
|
|
set -u
|
|
QC_BIN="${QC_BIN:-$QC_VENV/bin}"
|
|
if [ ! -d "$WORKING_DIRECTORY" ]; then
|
|
echo "::error::[configuration] working-directory '$WORKING_DIRECTORY' does not exist."
|
|
exit 1
|
|
fi
|
|
cd "$WORKING_DIRECTORY"
|
|
|
|
failed=()
|
|
run_tool() {
|
|
local name="$1"
|
|
shift
|
|
echo "::group::$name"
|
|
if "$@"; then
|
|
echo "::endgroup::"
|
|
echo "PASS $name"
|
|
else
|
|
echo "::endgroup::"
|
|
echo "FAIL $name"
|
|
failed+=("$name")
|
|
fi
|
|
}
|
|
wanted() {
|
|
local lang
|
|
IFS=',' read -ra langs <<< "${LANGUAGES// /}"
|
|
for lang in "${langs[@]}"; do
|
|
[ "$lang" = "$1" ] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
if wanted python; then
|
|
mapfile -t files < <(git ls-files -- '*.py')
|
|
if [ "${#files[@]}" -eq 0 ]; then
|
|
echo "::notice::No python files in '$WORKING_DIRECTORY'; nothing was checked."
|
|
else
|
|
run_tool "ruff check" "$QC_BIN/ruff" check "${files[@]}"
|
|
run_tool "ruff format --check" "$QC_BIN/ruff" format --check "${files[@]}"
|
|
run_tool "mypy --strict" "$QC_BIN/mypy" --strict "${files[@]}"
|
|
fi
|
|
fi
|
|
|
|
if wanted shell; then
|
|
mapfile -t files < <(git ls-files -- '*.sh')
|
|
if [ "${#files[@]}" -eq 0 ]; then
|
|
echo "::notice::No shell files in '$WORKING_DIRECTORY'; nothing was checked."
|
|
else
|
|
run_tool "shellcheck" "$QC_BIN/shellcheck" "${files[@]}"
|
|
run_tool "shfmt -d" "$QC_BIN/shfmt" -d "${files[@]}"
|
|
fi
|
|
fi
|
|
|
|
if [ "${#failed[@]}" -gt 0 ]; then
|
|
echo "::error::Quality checks failed: ${failed[*]}"
|
|
exit 1
|
|
fi
|
|
echo "All selected checks passed."
|
|
}
|
|
|
|
case "${1:-}" in
|
|
validate) validate_inputs ;;
|
|
install) install_tools ;;
|
|
run) run_checks ;;
|
|
*)
|
|
echo "::error::[configuration] usage: quality-checks.sh validate|install|run" >&2
|
|
exit 2
|
|
;;
|
|
esac
|