Validate workflows / validate (pull_request) Successful in 16s
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
106 lines
4.4 KiB
Markdown
106 lines
4.4 KiB
Markdown
# 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
|
|
|
|
```yaml
|
|
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
|
|
|
|
1. Open the status check on the pull request, then the job `quality-checks`.
|
|
2. 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.
|
|
3. A tool ends with `PASS <tool>` or `FAIL <tool>`. The last line of a failed
|
|
run names the tools that failed:
|
|
`Quality checks failed: ruff check shellcheck`.
|
|
4. A finding is written by the tool itself as `path:line:column: CODE message`.
|
|
Paths are relative to `working-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:
|
|
|
|
```bash
|
|
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](troubleshooting.md) |
|