Files
github-action/.gitea/workflows/quality-checks.yml
T
Tirsvad 45219a19f6
Validate workflows / validate (pull_request) Successful in 14s
Add the reusable quality-check workflow
quality-checks.yml implements the contract of ADR-0005: inputs for the
languages, the working directory and one pinned version per tool; ruff,
mypy --strict, shellcheck and shfmt installed from PyPI into a venv; every
tool runs and any failure fails the job; a language without files is skipped
with a notice. Offline tests run the shell steps with stub tools. Verified
live from another organisation with clean files, a seeded failure and an
empty language.

Task: MIL-003#3
2026-10-10 16:13:57 +08:00

154 lines
5.1 KiB
YAML

name: Quality checks
# Reusable workflow (ADR-0005). A repository calls it with
#
# jobs:
# quality:
# uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@main
#
# It checks the Python and shell files of the repository with pinned tools,
# changes no file and needs no secret.
on:
workflow_call:
inputs:
languages:
description: "Comma list of the languages to check: python, shell"
type: string
default: "python,shell"
working-directory:
description: "Directory, relative to the repository root, whose files are checked"
type: string
default: "."
ruff-version:
description: "Version of ruff (Python lint and format)"
type: string
default: "0.6.9"
mypy-version:
description: "Version of mypy (Python types, --strict)"
type: string
default: "1.11.2"
shellcheck-py-version:
description: "Version of the shellcheck-py package (ShellCheck 0.10.0)"
type: string
default: "0.10.0.1"
shfmt-py-version:
description: "Version of the shfmt-py package (shfmt 3.11.0)"
type: string
default: "3.11.0.2"
jobs:
quality-checks:
permissions:
contents: read
runs-on: ubuntu-latest
env:
LANGUAGES: ${{ inputs.languages }}
WORKING_DIRECTORY: ${{ inputs.working-directory }}
RUFF_VERSION: ${{ inputs.ruff-version }}
MYPY_VERSION: ${{ inputs.mypy-version }}
SHELLCHECK_PY_VERSION: ${{ inputs.shellcheck-py-version }}
SHFMT_PY_VERSION: ${{ inputs.shfmt-py-version }}
QC_VENV: /tmp/quality-tools
steps:
- name: Validate the inputs
run: |
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}"
- name: Check out the repository
uses: actions/checkout@v4
- name: Install the tools
run: |
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[@]}"
- name: Run the checks
run: |
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."