Files
computer-playbook/utils/install/lint/README.md
kevinveenbirkenbachandClaude Opus 4.8 fc0799883f refactor(structure): move prefix-grouped files into named subfolders
Resolve every 3+-file same-prefix group flagged by the new prefix lint
by moving the files into a subfolder named after the shared prefix and
dropping the prefix from the file names, updating all references:

- utils/env/handlers/infinito_*.py -> infinito/ (dir/, package_cache/
  nested a second level); registry imports and the four handler-dir
  globs switched to iter_project_files
- utils/install/lint/ansible_*.py -> ansible/ (aliased imports)
- roles/sys-svc-compose/files/swarm_*.{py,sh} -> files/swarm/
- web-app-erpnext/web-app-zammad files/scripts/apply_*.{py,rb} -> apply/
- web-app-odoo files/sql/{select,update}-* and sql/oidc/{grant,insert,
  select,update}-* -> matching subfolders
- web-app-keycloak tasks/update/05_ldap*.yml -> 05_ldap/ (internal
  includes made role_path-absolute)
- plugins/filter/get_*.py -> plugins/filter/get/ (filter names are the
  filters() dict keys, so Jinja usage is unaffected; ansible discovers
  the one-level-deep subdir)

Ansible lookup dirs, addon dirs and .github/workflows keep their flat
layout (the filename is the public id / GitHub only discovers flat).
Unit tests mirror the new source layout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:00:03 +02:00

63 lines
2.7 KiB
Markdown

# utils/install/lint
Per-tool installer policy for the lint toolchain.
For the package's overall role see [README.md](../README.md).
For general README conventions see [documentation.md](../../../docs/contributing/documentation.md).
## Purpose
Each module in this directory owns exactly one lint tool and exposes a single `ensure()` function.
The CLI in [__main__.py](__main__.py) groups these ensure calls and applies the stamp-based skip for the default "all" invocation.
## File Naming
- A module name MUST match the lowercase snake_case of the tool it installs:
- `actionlint` -> `actionlint.py`
- `markdownlint-cli2` -> `markdownlint_cli2.py`
- `ansible-lint` -> `ansible/lint.py`
- Aggregate installers (one helper covers a tightly coupled command pair) take the topic name without a key suffix.
Example: `ansible/commands.py` installs both `ansible-playbook` and `ansible-galaxy` via the same system-package candidates.
## Module Shape
Every per-tool module MUST expose the same surface so the dispatcher can call it uniformly:
```python
"""<one-line docstring: what gets installed and via which channel>."""
from __future__ import annotations
def ensure() -> None:
"""Install <tool> if not present. Raises RuntimeError on failure."""
```
- `ensure()` MUST be idempotent: return immediately when the tool is already on PATH (or importable, for Python modules).
- `ensure()` MUST raise `RuntimeError` with a descriptive message on failure.
- A module MAY read tool-specific environment overrides (e.g. `ACTIONLINT_VERSION`, `RUFF_PIP_SPEC`) at call time.
## Import Rules
- A per-tool module MUST NOT import another per-tool module.
Shared logic flows through `utils.install.primitives`, `utils.install.pip`, `utils.install.npm`, `utils.install.github_release`, and `utils.install.system_pkg` only.
- A per-tool module MAY import from `utils.cache` (for `PROJECT_ROOT`) and from stdlib.
## Group Dispatch
[__main__.py](__main__.py) maps each CLI group to a fixed set of `ensure()` calls:
| Group | Modules called (in order) |
|---|---|
| `action` | `actionlint` |
| `ansible` | `ansible_commands`, `ansible_collections`, `ansible_lint` |
| `python` | `shfmt`, `ruff` |
| `shellcheck` | `shellcheck` |
| `markdown` | `markdownlint_cli2` |
| `makefile` | `mbake` |
| `javascript` | `eslint` |
| `all` (default) | every group above, in the order listed |
The `all` mode honors a per-interpreter stamp at `build/install-lint-<hash>.stamp` (the suffix is the first 8 chars of `sha256(sys.executable)`, so host and container track independently even though `build/` is bind-mounted).
Stamp dependencies are [lint.sh](../../../scripts/install/lint.sh) and [pyproject.toml](../../../pyproject.toml).
Group-targeted invocations always run and never touch the stamp.