From 282aca50736206a18934d4ed549d69aab821b55c Mon Sep 17 00:00:00 2001 From: Amogh Desai Date: Fri, 17 Apr 2026 19:37:18 +0530 Subject: [PATCH 1/3] Add prek hook to ban caplog usage in test files --- airflow-core/.pre-commit-config.yaml | 9 +++++++++ providers/.pre-commit-config.yaml | 9 +++++++++ task-sdk/.pre-commit-config.yaml | 9 +++++++++ 3 files changed, 27 insertions(+) diff --git a/airflow-core/.pre-commit-config.yaml b/airflow-core/.pre-commit-config.yaml index 779f0bb2da5c0..cb85638a239d6 100644 --- a/airflow-core/.pre-commit-config.yaml +++ b/airflow-core/.pre-commit-config.yaml @@ -161,6 +161,15 @@ repos: language: python pass_filenames: true files: ^tests/.*\.py$ + - id: check-no-caplog-in-tests + language: pygrep + name: Tests do not use caplog fixture + description: > + Do not use caplog in tests — prefer checking logic and not log output. + See https://github.com/apache/airflow/blob/main/CLAUDE.md#testing-standards + entry: \bcaplog\b + pass_filenames: true + files: ^tests/.*\.py$ - id: check-no-fab-migrations language: pygrep name: Check no migration is done on FAB related table diff --git a/providers/.pre-commit-config.yaml b/providers/.pre-commit-config.yaml index 2cf29a4957e68..9b613632d2e82 100644 --- a/providers/.pre-commit-config.yaml +++ b/providers/.pre-commit-config.yaml @@ -64,6 +64,15 @@ repos: entry: ../scripts/ci/prek/check_airflow_v_imports_in_tests.py pass_filenames: true files: ^.*/tests/.+\.py$ + - id: check-no-caplog-in-tests + language: pygrep + name: Tests do not use caplog fixture + description: > + Do not use caplog in tests — prefer checking logic and not log output. + See https://github.com/apache/airflow/blob/main/CLAUDE.md#testing-standards + entry: \bcaplog\b + pass_filenames: true + files: ^.*/tests/.+\.py$ - id: check-sql-dependency-common-data-structure name: Check dependency of SQL providers description: Check dependency of SQL Providers with common data structure diff --git a/task-sdk/.pre-commit-config.yaml b/task-sdk/.pre-commit-config.yaml index 8966b40204489..a564c3615fc84 100644 --- a/task-sdk/.pre-commit-config.yaml +++ b/task-sdk/.pre-commit-config.yaml @@ -56,6 +56,15 @@ repos: entry: ../scripts/ci/prek/check_init_decorator_arguments.py pass_filenames: false files: ^src/airflow/sdk/definitions/dag\.py$|^src/airflow/sdk/definitions/decorators/task_group\.py$ + - id: check-no-caplog-in-tests + language: pygrep + name: Tests do not use caplog fixture + description: > + Do not use caplog in tests — prefer checking logic and not log output. + See https://github.com/apache/airflow/blob/main/CLAUDE.md#testing-standards + entry: \bcaplog\b + pass_filenames: true + files: ^tests/.*\.py$ - id: mypy-task-sdk name: Run mypy for task-sdk language: python From ac46319de58b20b892988e967f858074db16df60 Mon Sep 17 00:00:00 2001 From: Amogh Desai Date: Fri, 10 Jul 2026 12:13:28 +0530 Subject: [PATCH 2/3] back at it --- .pre-commit-config.yaml | 10 ++ airflow-core/.pre-commit-config.yaml | 9 -- providers/.pre-commit-config.yaml | 9 -- scripts/ci/prek/check_caplog_usage.py | 216 +++++++++++++++++++++++++ scripts/ci/prek/known_caplog_usage.txt | 116 +++++++++++++ task-sdk/.pre-commit-config.yaml | 9 -- 6 files changed, 342 insertions(+), 27 deletions(-) create mode 100755 scripts/ci/prek/check_caplog_usage.py create mode 100644 scripts/ci/prek/known_caplog_usage.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 50a49acb93adb..f51535035f18b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1221,6 +1221,16 @@ repos: language: python pass_filenames: true files: ^(airflow-core|providers)/.*\.py$|^scripts/ci/prek/known_provide_session_positional\.txt$|^scripts/ci/prek/check_provide_session_kwargs\.py$ + - id: check-no-new-caplog-usage + name: Check that no new caplog usage is added in tests + entry: ./scripts/ci/prek/check_caplog_usage.py + language: python + pass_filenames: true + files: > + (?x) + ^(airflow-core|task-sdk)/tests/.*\.py$| + ^providers/[^/]+/tests/.*\.py$| + ^scripts/ci/prek/known_caplog_usage\.txt$ - id: check-no-new-airflow-core-utils-modules name: Check that no new modules are added under airflow-core/src/airflow/utils entry: ./scripts/ci/prek/check_no_new_airflow_core_utils_modules.py diff --git a/airflow-core/.pre-commit-config.yaml b/airflow-core/.pre-commit-config.yaml index 2ac28e7b83352..949db83a81e63 100644 --- a/airflow-core/.pre-commit-config.yaml +++ b/airflow-core/.pre-commit-config.yaml @@ -172,15 +172,6 @@ repos: language: python pass_filenames: true files: ^tests/.*\.py$ - - id: check-no-caplog-in-tests - language: pygrep - name: Tests do not use caplog fixture - description: > - Do not use caplog in tests — prefer checking logic and not log output. - See https://github.com/apache/airflow/blob/main/CLAUDE.md#testing-standards - entry: \bcaplog\b - pass_filenames: true - files: ^tests/.*\.py$ - id: check-no-fab-migrations language: pygrep name: Check no migration is done on FAB related table diff --git a/providers/.pre-commit-config.yaml b/providers/.pre-commit-config.yaml index e52e3b85777f8..652477809de67 100644 --- a/providers/.pre-commit-config.yaml +++ b/providers/.pre-commit-config.yaml @@ -71,15 +71,6 @@ repos: entry: ../scripts/ci/prek/check_airflow_v_imports_in_tests.py pass_filenames: true files: ^.*/tests/.+\.py$ - - id: check-no-caplog-in-tests - language: pygrep - name: Tests do not use caplog fixture - description: > - Do not use caplog in tests — prefer checking logic and not log output. - See https://github.com/apache/airflow/blob/main/CLAUDE.md#testing-standards - entry: \bcaplog\b - pass_filenames: true - files: ^.*/tests/.+\.py$ - id: check-sql-dependency-common-data-structure name: Check dependency of SQL providers description: Check dependency of SQL Providers with common data structure diff --git a/scripts/ci/prek/check_caplog_usage.py b/scripts/ci/prek/check_caplog_usage.py new file mode 100755 index 0000000000000..4afc3c7dbb296 --- /dev/null +++ b/scripts/ci/prek/check_caplog_usage.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "rich>=13.0.0", +# ] +# /// +"""Check that no new ``caplog`` usage is added in test files. + +Existing usages are recorded in ``known_caplog_usage.txt``; a file's count may +not exceed its recorded limit. See ``CLAUDE.md#testing-standards``. +""" + +from __future__ import annotations + +import argparse +import re +import subprocess +from collections.abc import Iterable +from pathlib import Path + +from common_prek_utils import AIRFLOW_ROOT_PATH, AllowlistManager +from rich.console import Console +from rich.panel import Panel + +console = Console(color_system="standard", width=200) + +REPO_ROOT = AIRFLOW_ROOT_PATH + +_CAPLOG_RE = re.compile(r"\bcaplog\b") + +# Test directories scanned by ``--all-files`` / ``--generate``. Keep in sync with the +# ``files:`` pattern for this hook in ``.pre-commit-config.yaml``. +_TEST_ROOTS = ("airflow-core/tests", "task-sdk/tests") + + +def _iter_caplog_lines(path: Path) -> list[str]: + """Return stripped, non-comment lines in *path* that reference ``caplog``.""" + try: + text = path.read_text(encoding="utf-8", errors="replace") + except OSError: + return [] + + result = [] + for raw_line in text.splitlines(): + stripped = raw_line.strip() + if stripped.startswith("#"): + continue + if _CAPLOG_RE.search(raw_line): + result.append(stripped) + return result + + +def _count_violations(path: Path) -> int: + return len(_iter_caplog_lines(path)) + + +class CaplogAllowlistManager(AllowlistManager): + def __init__(self, allowlist_file: Path) -> None: + super().__init__(allowlist_file, repo_root=REPO_ROOT) + + def iter_files(self) -> Iterable[Path]: + return _iter_test_files() + + def count_occurrences(self, path: Path) -> int: + return _count_violations(path) + + def violation_panel_text(self) -> str: + return ( + "New [bold]caplog[/bold] usage in a test file — see CLAUDE.md#testing-standards.\n" + "If pre-existing, run [cyan]./scripts/ci/prek/check_caplog_usage.py --generate[/cyan] " + "and commit [cyan]known_caplog_usage.txt[/cyan]." + ) + + def format_violation_details(self, path: Path) -> list[str]: + return [f" [dim]{line}[/dim]" for line in _iter_caplog_lines(path)] + + +def _iter_test_files() -> list[Path]: + candidates: list[Path] = [] + for top in _TEST_ROOTS: + candidates.extend( + p.resolve() + for p in (REPO_ROOT / top).rglob("*.py") + if ".tox" not in p.parts and "__pycache__" not in p.parts + ) + for provider_tests_dir in (REPO_ROOT / "providers").glob("*/tests"): + candidates.extend( + p.resolve() + for p in provider_tests_dir.rglob("*.py") + if ".tox" not in p.parts and "__pycache__" not in p.parts + ) + return candidates + + +def _check_caplog_usage(files: list[Path], allowlist: dict[str, int], manager: CaplogAllowlistManager) -> int: + allowlist_file = manager.allowlist_file.resolve() + if any(p.resolve() == allowlist_file for p in files) and not allowlist_file.exists(): + console.print( + Panel.fit( + f"Allowlist file [cyan]{allowlist_file}[/cyan] is missing.\n" + "Restore it from git or regenerate with " + "[cyan]./scripts/ci/prek/check_caplog_usage.py --generate[/cyan].", + title="[red]Check failed[/red]", + border_style="red", + ) + ) + return 1 + return manager.check(files, allowlist) + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser( + description="Prevent new caplog usage in test files.", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=__doc__, + ) + parser.add_argument("files", nargs="*", metavar="FILE", help="Files to check (provided by prek)") + parser.add_argument( + "--all-files", + action="store_true", + help="Check every test file (airflow-core/tests, task-sdk/tests, providers/*/tests)", + ) + parser.add_argument( + "--cleanup", + action="store_true", + help="Remove stale entries from the allowlist and exit", + ) + parser.add_argument( + "--generate", + action="store_true", + help="Regenerate the allowlist from the current codebase and exit", + ) + args = parser.parse_args(argv) + + manager = CaplogAllowlistManager(Path(__file__).parent / "known_caplog_usage.txt") + + if args.generate: + return manager.generate() + + if args.cleanup: + return manager.cleanup() + + allowlist = manager.load() + + if args.all_files: + return _check_caplog_usage(_iter_test_files(), allowlist, manager) + + if not args.files: + console.print( + "[yellow]No files provided. Pass filenames or use --all-files to scan the whole repo.[/yellow]" + ) + return 0 + + paths = [Path(f).resolve() for f in args.files] + paths = _expand_for_allowlist_edits(paths, manager, allowlist) + return _check_caplog_usage(paths, allowlist, manager) + + +def _parse_tracked_allowlist(manager: CaplogAllowlistManager) -> dict[str, int]: + """Return the allowlist as recorded at ``HEAD``, so removed entries still get re-checked.""" + try: + rel = manager.allowlist_file.resolve().relative_to(REPO_ROOT.resolve()) + except ValueError: + return {} + try: + completed = subprocess.run( + ["git", "-C", str(REPO_ROOT), "show", f"HEAD:{rel.as_posix()}"], + capture_output=True, + text=True, + check=False, + ) + except (FileNotFoundError, OSError): + return {} + if completed.returncode != 0: + return {} + return manager.parse(completed.stdout) + + +def _expand_for_allowlist_edits( + paths: list[Path], manager: CaplogAllowlistManager, allowlist: dict[str, int] +) -> list[Path]: + """When the allowlist itself is edited, add its files so loosening it can't bypass the check.""" + allowlist_file = manager.allowlist_file.resolve() + if not any(p.resolve() == allowlist_file for p in paths): + return paths + + expanded = list(paths) + seen = {p.resolve() for p in paths if p.suffix == ".py"} + tracked = _parse_tracked_allowlist(manager) + for rel in {*allowlist, *tracked}: + candidate = (REPO_ROOT / rel).resolve() + if candidate.exists() and candidate not in seen: + seen.add(candidate) + expanded.append(candidate) + return expanded + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/ci/prek/known_caplog_usage.txt b/scripts/ci/prek/known_caplog_usage.txt new file mode 100644 index 0000000000000..9974e4f31caff --- /dev/null +++ b/scripts/ci/prek/known_caplog_usage.txt @@ -0,0 +1,116 @@ +airflow-core/tests/integration/security/test_kerberos.py::4 +airflow-core/tests/unit/always/test_providers_manager.py::2 +airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_plugins.py::3 +airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_variables.py::6 +airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_xcoms.py::6 +airflow-core/tests/unit/api_fastapi/test_app.py::2 +airflow-core/tests/unit/assets/test_manager.py::3 +airflow-core/tests/unit/cli/commands/test_config_command.py::2 +airflow-core/tests/unit/cli/commands/test_dag_command.py::3 +airflow-core/tests/unit/cli/commands/test_gunicorn_monitor.py::2 +airflow-core/tests/unit/cli/commands/test_task_command.py::5 +airflow-core/tests/unit/cli/conftest.py::2 +airflow-core/tests/unit/cli/test_cli_parser.py::10 +airflow-core/tests/unit/dag_processing/bundles/test_dag_bundle_manager.py::4 +airflow-core/tests/unit/dag_processing/test_collection.py::3 +airflow-core/tests/unit/dag_processing/test_dagbag.py::9 +airflow-core/tests/unit/dag_processing/test_manager.py::4 +airflow-core/tests/unit/dag_processing/test_processor.py::2 +airflow-core/tests/unit/decorators/test_task_group.py::6 +airflow-core/tests/unit/executors/test_base_executor.py::5 +airflow-core/tests/unit/jobs/test_base_job.py::3 +airflow-core/tests/unit/jobs/test_scheduler_job.py::45 +airflow-core/tests/unit/listeners/test_listeners.py::3 +airflow-core/tests/unit/models/test_dag.py::22 +airflow-core/tests/unit/models/test_dagrun.py::2 +airflow-core/tests/unit/models/test_mappedoperator.py::2 +airflow-core/tests/unit/models/test_pool.py::2 +airflow-core/tests/unit/models/test_variable.py::6 +airflow-core/tests/unit/plugins/test_plugins_manager.py::20 +airflow-core/tests/unit/security/test_kerberos.py::18 +airflow-core/tests/unit/serialization/test_serialized_objects.py::2 +airflow-core/tests/unit/utils/test_db_cleanup.py::12 +airflow-core/tests/unit/utils/test_db_manager.py::2 +airflow-core/tests/unit/utils/test_db_timeout.py::3 +airflow-core/tests/unit/utils/test_process_utils.py::12 +airflow-core/tests/unit/utils/test_retries.py::4 +providers/amazon/tests/unit/amazon/aws/executors/batch/test_batch_executor.py::22 +providers/amazon/tests/unit/amazon/aws/executors/ecs/test_ecs_executor.py::13 +providers/amazon/tests/unit/amazon/aws/executors/utils/test_exponential_backoff_retry.py::6 +providers/amazon/tests/unit/amazon/aws/hooks/test_athena.py::4 +providers/amazon/tests/unit/amazon/aws/hooks/test_base_aws.py::4 +providers/amazon/tests/unit/amazon/aws/hooks/test_batch_client.py::17 +providers/amazon/tests/unit/amazon/aws/hooks/test_emr.py::2 +providers/amazon/tests/unit/amazon/aws/hooks/test_glacier.py::12 +providers/amazon/tests/unit/amazon/aws/hooks/test_glue.py::22 +providers/amazon/tests/unit/amazon/aws/hooks/test_quicksight.py::2 +providers/amazon/tests/unit/amazon/aws/hooks/test_redshift_data.py::6 +providers/amazon/tests/unit/amazon/aws/hooks/test_s3.py::3 +providers/amazon/tests/unit/amazon/aws/log/test_s3_task_handler.py::12 +providers/amazon/tests/unit/amazon/aws/operators/test_ecs.py::2 +providers/amazon/tests/unit/amazon/aws/operators/test_eks.py::4 +providers/amazon/tests/unit/amazon/aws/operators/test_emr_serverless.py::4 +providers/amazon/tests/unit/amazon/aws/operators/test_lambda_function.py::8 +providers/amazon/tests/unit/amazon/aws/operators/test_rds.py::3 +providers/amazon/tests/unit/amazon/aws/sensors/test_glue_catalog_partition.py::2 +providers/amazon/tests/unit/amazon/aws/sensors/test_glue_data_quality.py::4 +providers/amazon/tests/unit/amazon/aws/utils/test_suppress.py::8 +providers/celery/tests/integration/celery/test_celery_executor.py::21 +providers/celery/tests/unit/celery/executors/test_celery_executor.py::19 +providers/docker/tests/unit/docker/decorators/test_docker.py::5 +providers/docker/tests/unit/docker/hooks/test_docker.py::10 +providers/docker/tests/unit/docker/operators/test_docker.py::4 +providers/docker/tests/unit/docker/operators/test_docker_swarm.py::4 +providers/edge3/tests/unit/edge3/cli/test_signalling.py::3 +providers/fab/tests/unit/fab/auth_manager/api_fastapi/test_parameters.py::3 +providers/fab/tests/unit/fab/auth_manager/models/test_db.py::1 +providers/fab/tests/unit/fab/auth_manager/test_security.py::2 +providers/google/tests/unit/google/cloud/hooks/test_compute_ssh.py::12 +providers/google/tests/unit/google/cloud/hooks/test_dataflow.py::5 +providers/google/tests/unit/google/cloud/hooks/test_dataform.py::3 +providers/google/tests/unit/google/cloud/hooks/test_datafusion.py::6 +providers/google/tests/unit/google/cloud/hooks/test_gcs.py::12 +providers/google/tests/unit/google/cloud/hooks/test_kubernetes_engine.py::2 +providers/google/tests/unit/google/cloud/log/test_gcs_task_handler.py::9 +providers/google/tests/unit/google/cloud/log/test_stackdriver_task_handler.py::2 +providers/google/tests/unit/google/cloud/operators/test_bigquery.py::10 +providers/google/tests/unit/google/cloud/operators/test_compute.py::3 +providers/google/tests/unit/google/cloud/secrets/test_secret_manager.py::6 +providers/google/tests/unit/google/cloud/transfers/test_gcs_to_bigquery.py::1 +providers/google/tests/unit/google/cloud/triggers/test_bigquery.py::24 +providers/google/tests/unit/google/cloud/triggers/test_bigquery_dts.py::5 +providers/google/tests/unit/google/cloud/triggers/test_cloud_build.py::6 +providers/google/tests/unit/google/cloud/triggers/test_cloud_sql.py::3 +providers/google/tests/unit/google/cloud/triggers/test_dataflow.py::8 +providers/google/tests/unit/google/cloud/triggers/test_datafusion.py::4 +providers/google/tests/unit/google/cloud/triggers/test_dataplex.py::3 +providers/google/tests/unit/google/cloud/triggers/test_dataproc.py::2 +providers/google/tests/unit/google/cloud/triggers/test_gen_ai.py::6 +providers/google/tests/unit/google/cloud/triggers/test_kubernetes_engine.py::20 +providers/google/tests/unit/google/cloud/utils/test_credentials_provider.py::40 +providers/google/tests/unit/google/common/hooks/test_base_google.py::2 +providers/google/tests/unit/google/marketing_platform/operators/test_bid_manager.py::7 +providers/http/tests/unit/http/hooks/test_http.py::3 +providers/jdbc/tests/unit/jdbc/hooks/test_jdbc.py::9 +providers/keycloak/tests/unit/keycloak/auth_manager/test_keycloak_auth_manager.py::7 +providers/odbc/tests/unit/odbc/hooks/test_odbc.py::6 +providers/openlineage/tests/unit/openlineage/api/test_datasets.py::3 +providers/openlineage/tests/unit/openlineage/api/test_sql.py::6 +providers/openlineage/tests/unit/openlineage/utils/test_sql_hook_lineage.py::3 +providers/openlineage/tests/unit/openlineage/utils/test_utils.py::3 +providers/sftp/tests/unit/sftp/hooks/test_sftp.py::3 +providers/sftp/tests/unit/sftp/operators/test_sftp.py::3 +providers/slack/tests/unit/slack/hooks/test_slack.py::1 +providers/standard/tests/unit/standard/decorators/test_bash.py::6 +providers/standard/tests/unit/standard/decorators/test_python.py::2 +providers/standard/tests/unit/standard/operators/test_python.py::22 +providers/standard/tests/unit/standard/operators/test_smooth.py::3 +providers/standard/tests/unit/standard/sensors/test_external_task_sensor.py::18 +providers/tableau/tests/unit/tableau/operators/test_tableau.py::3 +providers/yandex/tests/unit/yandex/utils/test_credentials.py::2 +task-sdk/tests/task_sdk/bases/test_notifier.py::4 +task-sdk/tests/task_sdk/bases/test_operator.py::13 +task-sdk/tests/task_sdk/definitions/_internal/test_templater.py::6 +task-sdk/tests/task_sdk/definitions/test_xcom_arg.py::5 +task-sdk/tests/task_sdk/execution_time/test_supervisor.py::6 +task-sdk/tests/task_sdk/test_providers_manager_runtime.py::2 diff --git a/task-sdk/.pre-commit-config.yaml b/task-sdk/.pre-commit-config.yaml index e084fbe3b0fa2..a44abd29c1566 100644 --- a/task-sdk/.pre-commit-config.yaml +++ b/task-sdk/.pre-commit-config.yaml @@ -58,15 +58,6 @@ repos: entry: ../scripts/ci/prek/check_init_decorator_arguments.py pass_filenames: false files: ^src/airflow/sdk/definitions/dag\.py$|^src/airflow/sdk/definitions/decorators/task_group\.py$ - - id: check-no-caplog-in-tests - language: pygrep - name: Tests do not use caplog fixture - description: > - Do not use caplog in tests — prefer checking logic and not log output. - See https://github.com/apache/airflow/blob/main/CLAUDE.md#testing-standards - entry: \bcaplog\b - pass_filenames: true - files: ^tests/.*\.py$ - id: mypy-task-sdk name: Run mypy for task-sdk language: python From 7d7e53e1da04750fd3270c882cc9b59fb2629711 Mon Sep 17 00:00:00 2001 From: Amogh Desai Date: Fri, 10 Jul 2026 14:47:51 +0530 Subject: [PATCH 3/3] fixing comemnts from jason --- .pre-commit-config.yaml | 2 +- {scripts/ci/prek => generated}/known_caplog_usage.txt | 0 scripts/ci/prek/check_caplog_usage.py | 8 ++++---- 3 files changed, 5 insertions(+), 5 deletions(-) rename {scripts/ci/prek => generated}/known_caplog_usage.txt (100%) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f51535035f18b..245b1e07fafb1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1230,7 +1230,7 @@ repos: (?x) ^(airflow-core|task-sdk)/tests/.*\.py$| ^providers/[^/]+/tests/.*\.py$| - ^scripts/ci/prek/known_caplog_usage\.txt$ + ^generated/known_caplog_usage\.txt$ - id: check-no-new-airflow-core-utils-modules name: Check that no new modules are added under airflow-core/src/airflow/utils entry: ./scripts/ci/prek/check_no_new_airflow_core_utils_modules.py diff --git a/scripts/ci/prek/known_caplog_usage.txt b/generated/known_caplog_usage.txt similarity index 100% rename from scripts/ci/prek/known_caplog_usage.txt rename to generated/known_caplog_usage.txt diff --git a/scripts/ci/prek/check_caplog_usage.py b/scripts/ci/prek/check_caplog_usage.py index 4afc3c7dbb296..c9f895a0d9578 100755 --- a/scripts/ci/prek/check_caplog_usage.py +++ b/scripts/ci/prek/check_caplog_usage.py @@ -23,8 +23,8 @@ # /// """Check that no new ``caplog`` usage is added in test files. -Existing usages are recorded in ``known_caplog_usage.txt``; a file's count may -not exceed its recorded limit. See ``CLAUDE.md#testing-standards``. +Existing usages are recorded in ``generated/known_caplog_usage.txt``; a file's +count may not exceed its recorded limit. See ``CLAUDE.md#testing-standards``. """ from __future__ import annotations @@ -85,7 +85,7 @@ def violation_panel_text(self) -> str: return ( "New [bold]caplog[/bold] usage in a test file — see CLAUDE.md#testing-standards.\n" "If pre-existing, run [cyan]./scripts/ci/prek/check_caplog_usage.py --generate[/cyan] " - "and commit [cyan]known_caplog_usage.txt[/cyan]." + "and commit [cyan]generated/known_caplog_usage.txt[/cyan]." ) def format_violation_details(self, path: Path) -> list[str]: @@ -149,7 +149,7 @@ def main(argv: list[str] | None = None) -> int: ) args = parser.parse_args(argv) - manager = CaplogAllowlistManager(Path(__file__).parent / "known_caplog_usage.txt") + manager = CaplogAllowlistManager(REPO_ROOT / "generated" / "known_caplog_usage.txt") if args.generate: return manager.generate()