Explain how to call the shared quality-checks workflow, read a failed run, fix the typical findings of ruff, mypy, shellcheck and shfmt, reproduce a run locally and configure the tools through the project's own files, including the shfmt .editorconfig route found in the RepoFoundry trial. Add the QualityChecks wiki page with its Danish and Bahasa Malaysia translations, update the capability row and teach build_wiki.py the page. Task: MIL-003#5
4.4 KiB
Reading quality-check results
How a software engineer calls the shared quality checks, reads a failed run and makes it pass. The workflow lints and format-checks the Python and shell files of a repository with pinned tools, changes no file and needs no secret. Its contract is ADR-0005 in this repository.
Calling the workflow
name: Quality
on:
pull_request:
push:
branches: [ main ]
jobs:
quality:
permissions:
contents: read
uses: TirSystem/github-action/.gitea/workflows/quality-checks.yml@main
with:
languages: python,shell
| Input | Default | Meaning |
|---|---|---|
languages |
python,shell |
Comma list of the languages to check |
working-directory |
. |
Directory, relative to the repository root, whose files are checked |
ruff-version |
0.6.9 |
Version of ruff |
mypy-version |
1.11.2 |
Version of mypy |
shellcheck-py-version |
0.10.0.1 |
Version of the shellcheck-py package (ShellCheck 0.10.0) |
shfmt-py-version |
3.11.0.2 |
Version of the shfmt-py package (shfmt 3.11.0) |
Reference the workflow at main or at a tag, never at the branch of a pull
request: that branch is deleted when the pull request is merged and the
reference stops working.
What is checked
| Language | Files | Tools |
|---|---|---|
| Python | tracked *.py under the working directory |
ruff check, ruff format --check, mypy --strict |
| Shell | tracked *.sh under the working directory |
shellcheck, shfmt -d |
Untracked files are not checked. A language without files is skipped with a notice and counts as a pass. Project tests are not run.
Reading a run
- Open the status check on the pull request, then the job
quality-checks. - Each tool has its own log group named after it. Every tool runs even when an earlier one failed, so one run shows all findings.
- A tool ends with
PASS <tool>orFAIL <tool>. The last line of a failed run names the tools that failed:Quality checks failed: ruff check shellcheck. - A finding is written by the tool itself as
path:line:column: CODE message. Paths are relative toworking-directory.
Typical failures and fixes
| Tool | What the log shows | Fix |
|---|---|---|
ruff check |
F401 ... imported but unused |
Remove the import, or use it |
ruff format --check |
Would reformat: <file> |
Run ruff format <file> and commit |
mypy --strict |
Function is missing a type annotation |
Add parameter and return types |
shellcheck |
SC2086 ... Double quote to prevent globbing |
Quote the expansion: "$1" |
shfmt -d |
a diff of <file>.orig and <file> |
Run shfmt -w <file> with the project's options and commit |
To reproduce a run on your machine, install the same versions and run the commands of the table:
python3 -m venv .qc
.qc/bin/pip install ruff==0.6.9 mypy==1.11.2 shellcheck-py==0.10.0.1 shfmt-py==3.11.0.2
.qc/bin/ruff check . && .qc/bin/ruff format --check .
Configuring the tools
The workflow adds no configuration; it runs from the repository root, so the files of the project apply:
| Tool | File | Example |
|---|---|---|
| ruff | pyproject.toml |
[tool.ruff] with line-length = 100 |
| mypy | pyproject.toml |
[tool.mypy] with per-module ignore_missing_imports |
| shellcheck | .shellcheckrc |
external-sources=true and source-path=SCRIPTDIR |
| shfmt | .editorconfig |
[*.sh] with indent_size = 2 and switch_case_indent = true |
shfmt follows a project's style only through .editorconfig. A shell project
that formats with its own flags (for example shfmt -i 2 -ci) should expect a
first formatting failure and express the flags there; in the first adoption
(RepoFoundry) one line, switch_case_indent = true, was enough and no script
changed.
When the workflow itself fails
| Message | Cause | Fix |
|---|---|---|
[configuration] Unknown language '<x>' |
languages has a value other than python or shell |
Correct the input |
[configuration] working-directory must be a relative path inside the repository. |
An absolute path or .. |
Use a path inside the repository |
[configuration] working-directory '<x>' does not exist. |
The directory is not in the repository | Correct the input |
| The install step fails | PyPI or the runner network is unreachable | Re-run the job; see troubleshooting.md |