Files
computer-playbook/scripts/lint/autoformat.sh
T
kevinveenbirkenbach 837d0c5335 test(suppression): unify # noqa / # nocheck marker grammar
Introduce a single grammar for per-line, per-block, and per-file
suppression markers across the test suite, replacing seven ad-hoc
syntaxes that had drifted apart.

Helper
  utils/annotations/suppress.py exposes is_suppressed_at,
  is_suppressed_in_head, is_suppressed_anywhere, line_has_rule, and
  suppressed_line_numbers. Markers may use either `noqa` or `nocheck`
  (case-insensitive synonyms), live inside `#`, `//`, `{# ... #}`, or
  `<\!-- ... -->` comments, and combine multiple kebab-case rules
  comma-separated. 17 unit tests cover the grammar in isolation.

Refactored consumers
  - tests/external/repository/test_urls_reachable.py (rule: url)
  - tests/external/docker/test_image_versions.py via
    utils/docker/version_updater.py (rule: docker-version)
  - tests/lint/repository/test_no_direct_yaml_calls.py (rule:
    direct-yaml)
  - tests/lint/ansible/test_service_shared_consistency.py (rule:
    shared)
  - tests/lint/ansible/roles/test_web_app_email_integration.py (rule:
    email)
  - tests/lint/repository/test_python_file_size.py (rule: file-size)
  - tests/lint/ansible/test_run_once_tags.py +
    tests/integration/roles/run_once/test_schema.py (rules: run-once,
    run-once-suffix)

Marker migration
  12 role tasks/main.yml files: `# run_once_<key>: deactivated`
  -> `# nocheck: run-once`. roles/web-app-suitecrm/meta/services.yml
  drops a malformed inline `noqa: intentional legacy pin` from a TODO
  comment so the new parser does not pick it up as a stray rule.

Caching wins
  Test files that previously loaded YAML / read files via raw
  yaml.safe_load + Path.read_text now route through utils.cache.yaml
  (load_yaml_any / load_yaml_str) and utils.cache.files.read_text:
    - test_service_shared_consistency.py
    - test_web_app_email_integration.py
    - tests/integration/roles/run_once/test_schema.py
    - utils/docker/version_updater.py
  This both speeds up repeated reads and stays consistent with the
  direct-yaml lint policy.

Documentation
  New SPOT page at docs/contributing/actions/testing/suppression.md
  with grammar, position semantics, the catalog of rules, examples,
  and an "adding a new rule" checklist. lint.md and external.md drop
  their per-rule tables and link to the new page. All touched docs
  conform to docs/contributing/documentation.md (no em-dash thought
  breaks, no SPOT self-labels, RFC-2119 keywords used consistently).

Settings sort tooling
  scripts/lint/sort_claude_settings.sh wraps utils/claude/settings_sort.py
  and is wired into scripts/lint/autoformat.sh. The tooling fixes the
  ASCII-ascending requirement enforced by
  tests/lint/repository/test_claude_settings_sorted.py; the test's
  failure message now points operators at the script. .claude/settings.json
  is committed in sorted form.
2026-04-30 11:54:46 +02:00

74 lines
2.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# shellcheck shell=bash
# Auto-format all source files using available tools.
# Missing tools are reported and skipped rather than aborting the run.
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)"
cd "${REPO_ROOT}"
skipped=()
ran=()
# ── ruff (Python formatter + auto-fixer) ─────────────────────────────────────
if command -v ruff &>/dev/null; then
ruff format .
ruff check . --fix
ran+=("ruff")
else
skipped+=("ruff")
fi
# ── sort .claude/settings.json (curated arrays) ──────────────────────────────
if command -v python3 &>/dev/null; then
bash "${SCRIPT_DIR}/sort_claude_settings.sh"
ran+=("sort-claude-settings")
else
skipped+=("sort-claude-settings")
fi
# ── shfmt (shell script formatter) ───────────────────────────────────────────
if command -v shfmt &>/dev/null; then
shfmt -w scripts
ran+=("shfmt")
else
skipped+=("shfmt")
fi
# ── shellcheck (shell script linter with autofix via diff) ───────────────────
if command -v shellcheck &>/dev/null; then
mapfile -t shellcheck_files < <(find . -type f -name '*.sh' 2>/dev/null | sort)
if [[ "${#shellcheck_files[@]}" -gt 0 ]]; then
diff_file="$(mktemp)"
cleanup() { rm -f "${diff_file}"; }
trap cleanup EXIT
set +e
shellcheck -f diff -x "${shellcheck_files[@]}" >"${diff_file}" 2>/dev/null
set -e
if [[ -s "${diff_file}" ]]; then
printf 'Applying ShellCheck autofixes.\n'
git apply --whitespace=nowarn "${diff_file}"
fi
fi
ran+=("shellcheck")
else
skipped+=("shellcheck")
fi
# ── summary ──────────────────────────────────────────────────────────────────
if [[ "${#ran[@]}" -gt 0 ]]; then
printf 'autoformat: ran %s\n' "$(
IFS=', '
echo "${ran[*]}"
)"
fi
if [[ "${#skipped[@]}" -gt 0 ]]; then
printf 'autoformat: skipped (not installed) %s\n' "$(
IFS=', '
echo "${skipped[*]}"
)"
fi