diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index df7c1e6..7716954 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -49,6 +49,44 @@ repos: pass_filenames: false stages: [pre-commit] + - id: checkmake + name: checkmake Makefile linter + entry: make checkmake + language: system + files: (Makefile|\.mak)$ + pass_filenames: false + stages: [pre-commit] + + - id: check-test-speed + name: unit test speed check + entry: .venv/bin/python -m devx.tools.check_test_speed --max-seconds 6 --max-single-seconds 0.5 + language: system + types: [python] + pass_filenames: false + stages: [pre-commit] + + - id: check-translations + name: translation completeness check + entry: env PYTHONPATH=src .venv/bin/python -m devx.ci.check_translations + language: system + files: ^src/devx/translations\.json$ + pass_filenames: false + stages: [pre-commit] + + - id: doc-coverage + name: documentation coverage check + entry: env PYTHONPATH=src .venv/bin/python -m devx.ci.doc_coverage --fail-on-missing + language: system + pass_filenames: false + stages: [pre-commit] + + - id: lint-docs + name: documentation lint check + entry: env PYTHONPATH=src .venv/bin/python -m devx.ci.lint_docs --root . + language: system + pass_filenames: false + stages: [pre-commit] + - id: pytest-cov name: pytest with 100% coverage entry: make pytest-cov diff --git a/Makefile b/Makefile index 599cdb9..770fb62 100644 --- a/Makefile +++ b/Makefile @@ -115,10 +115,7 @@ lint-all: lint workflow-lint lint-dockerfiles # devx's own CI images may have an older devx.mak. Consumer repos can safely alias. lint-dockerfiles: @echo "[lint-dockerfiles] Linting Dockerfiles with hadolint..." - @if ! command -v hadolint >/dev/null 2>&1; then \ - echo "[lint-dockerfiles] ERROR: hadolint not found. Install from https://github.com/hadolint/hadolint/releases" >&2; \ - exit 1; \ - fi + @command -v hadolint >/dev/null 2>&1 || { echo "hadolint not found" >&2; exit 1; } @find docker -name 'Dockerfile*' -exec hadolint {} + @echo "[lint-dockerfiles] All Dockerfiles passed." diff --git a/src/devx/tools/check_deps.py b/src/devx/tools/check_deps.py index af533e8..208ca5e 100644 --- a/src/devx/tools/check_deps.py +++ b/src/devx/tools/check_deps.py @@ -80,7 +80,7 @@ def _check_python_version(venv_bin: Path) -> None: @click.option("--checkmake-bin", default=None, help="Path to checkmake binary (fallback if not on PATH).") def cli(venv: str, checkmake_bin: str | None) -> None: """Verify that required development tools are present.""" - click.echo("[check-deps] Verifying tools...") + click.echo(_("[check-deps] Verifying tools...")) all_required = True for tool in REQUIRED_TOOLS: @@ -90,15 +90,15 @@ def cli(venv: str, checkmake_bin: str | None) -> None: for tool in OPTIONAL_TOOLS: if not _check_tool(tool, optional=True): if checkmake_bin and Path(checkmake_bin).exists(): - click.echo(f" {tool}: found at {checkmake_bin}") + click.echo(_(" {tool}: found at {path}", tool=tool, path=checkmake_bin)) else: - click.echo(" Run 'make install-checkmake' to install the Makefile linter.") + click.echo(_(" Run 'make install-checkmake' to install the Makefile linter.")) _check_python_version(Path(venv) / "bin") if not all_required: - raise click.ClickException("Required tools missing.") - click.echo("[check-deps] All core tools present.") + raise click.ClickException(_("Required tools missing.")) + click.echo(_("[check-deps] All core tools present.")) if __name__ == "__main__": # pragma: no cover diff --git a/src/devx/tools/tofu_ops.py b/src/devx/tools/tofu_ops.py index ccbbd34..daa2966 100644 --- a/src/devx/tools/tofu_ops.py +++ b/src/devx/tools/tofu_ops.py @@ -33,7 +33,7 @@ DEFAULT_VALIDATE_DIRS = [ def _run_tofu(cmd: list[str], cwd: Path) -> None: """Run a tofu command in the given directory, raising on failure.""" - click.echo(f" -> {cwd}") + click.echo(_(" -> {dir}", dir=cwd)) result = subprocess.run( # nosec B603, B607 cmd, cwd=str(cwd), @@ -60,9 +60,9 @@ def tofu_init(env: str, root: str = ".", extra_dirs: list[str] | None = None) -> for dir_pattern in dirs: dir_path = root_path / dir_pattern if dir_path.is_dir(): - click.echo(f"[tofu-init] Initializing {dir_path}...") + click.echo(_("[tofu-init] Initializing {dir}...", dir=dir_path)) _run_tofu(["tofu", "init"], dir_path) - click.echo("[tofu-init] Done.") + click.echo(_("[tofu-init] Done.")) def tofu_validate( @@ -83,7 +83,7 @@ def tofu_validate( root_path = Path(root) target_dirs = dirs or DEFAULT_VALIDATE_DIRS mode = "ci" if ci else "validate" - click.echo(f"[tofu-{mode}] Validating OpenTofu configurations...") + click.echo(_("[tofu-{mode}] Validating OpenTofu configurations...", mode=mode)) for dir_rel in target_dirs: dir_path = root_path / dir_rel if not dir_path.is_dir(): @@ -91,7 +91,7 @@ def tofu_validate( if ci: _run_tofu(["tofu", "init", "-backend=false", "-input=false"], dir_path) _run_tofu(["tofu", "validate"], dir_path) - click.echo(f"[tofu-{mode}] All configurations valid.") + click.echo(_("[tofu-{mode}] All configurations valid.", mode=mode)) @click.group() diff --git a/src/devx/translations.json b/src/devx/translations.json index a43ee19..263e2bf 100644 --- a/src/devx/translations.json +++ b/src/devx/translations.json @@ -3198,5 +3198,85 @@ "pl": "OSTRZEŻENIE: .venv ma Python {version}, ale wymagane jest >={req}.", "ru": "ПРЕДУПРЕЖДЕНИЕ: в .venv установлен Python {version}, но требуется >={req}.", "zh": "警告: .venv 的 Python 版本为 {version},但要求 >={req}。" + }, + " -> {dir}": { + "en": " -> {dir}", + "bg": " -> {dir}", + "de": " -> {dir}", + "pl": " -> {dir}", + "ru": " -> {dir}", + "zh": " -> {dir}" + }, + "[tofu-init] Initializing {dir}...": { + "en": "[tofu-init] Initializing {dir}...", + "bg": "[tofu-init] Инициализиране на {dir}...", + "de": "[tofu-init] Initialisiere {dir}...", + "pl": "[tofu-init] Inicjalizacja {dir}...", + "ru": "[tofu-init] Инициализация {dir}...", + "zh": "[tofu-init] 正在初始化 {dir}..." + }, + "[tofu-init] Done.": { + "en": "[tofu-init] Done.", + "bg": "[tofu-init] Готово.", + "de": "[tofu-init] Fertig.", + "pl": "[tofu-init] Gotowe.", + "ru": "[tofu-init] Готово.", + "zh": "[tofu-init] 完成。" + }, + "[tofu-{mode}] Validating OpenTofu configurations...": { + "en": "[tofu-{mode}] Validating OpenTofu configurations...", + "bg": "[tofu-{mode}] Проверка на OpenTofu конфигурациите...", + "de": "[tofu-{mode}] Validiere OpenTofu-Konfigurationen...", + "pl": "[tofu-{mode}] Sprawdzanie konfiguracji OpenTofu...", + "ru": "[tofu-{mode}] Проверка конфигураций OpenTofu...", + "zh": "[tofu-{mode}] 正在验证 OpenTofu 配置..." + }, + "[tofu-{mode}] All configurations valid.": { + "en": "[tofu-{mode}] All configurations valid.", + "bg": "[tofu-{mode}] Всички конфигурации са валидни.", + "de": "[tofu-{mode}] Alle Konfigurationen gültig.", + "pl": "[tofu-{mode}] Wszystkie konfiguracje są poprawne.", + "ru": "[tofu-{mode}] Все конфигурации валидны.", + "zh": "[tofu-{mode}] 所有配置有效。" + }, + "[check-deps] Verifying tools...": { + "en": "[check-deps] Verifying tools...", + "bg": "[check-deps] Проверка на инструментите...", + "de": "[check-deps] Werkzeuge werden überprüft...", + "pl": "[check-deps] Sprawdzanie narzędzi...", + "ru": "[check-deps] Проверка инструментов...", + "zh": "[check-deps] 正在验证工具..." + }, + " {tool}: found at {path}": { + "en": " {tool}: found at {path}", + "bg": " {tool}: намерен на {path}", + "de": " {tool}: gefunden unter {path}", + "pl": " {tool}: znaleziono w {path}", + "ru": " {tool}: найден в {path}", + "zh": " {tool}: 在 {path} 找到" + }, + " Run 'make install-checkmake' to install the Makefile linter.": { + "en": " Run 'make install-checkmake' to install the Makefile linter.", + "bg": " Изпълнете 'make install-checkmake' за инсталиране на Makefile линтера.", + "de": " Führen Sie 'make install-checkmake' aus, um den Makefile-Linter zu installieren.", + "pl": " Uruchom 'make install-checkmake', aby zainstalować linter Makefile.", + "ru": " Выполните 'make install-checkmake' для установки линтера Makefile.", + "zh": " 运行 'make install-checkmake' 来安装 Makefile 检查器。" + }, + "Required tools missing.": { + "en": "Required tools missing.", + "bg": "Липсват задължителни инструменти.", + "de": "Erforderliche Werkzeuge fehlen.", + "pl": "Brak wymaganych narzędzi.", + "ru": "Отсутствуют обязательные инструменты.", + "zh": "缺少必需的工具。" + }, + "[check-deps] All core tools present.": { + "en": "[check-deps] All core tools present.", + "bg": "[check-deps] Всички основни инструменти са налични.", + "de": "[check-deps] Alle Kernwerkzeuge vorhanden.", + "pl": "[check-deps] Wszystkie podstawowe narzędzia są dostępne.", + "ru": "[check-deps] Все основные инструменты доступны.", + "zh": "[check-deps] 所有核心工具均已就绪。" } }