This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new eddc34c4b44 Fail the local yml mounts prek hook when synchronization
fails (#73785)
eddc34c4b44 is described below
commit eddc34c4b445f945cef9340ac2117a67e5ac39b9
Author: rjgoyln <[email protected]>
AuthorDate: Sun Oct 18 23:37:36 2026 +0800
Fail the local yml mounts prek hook when synchronization fails (#73785)
* Fail the local yml mounts prek hook when synchronization fails
The hook printed a red error and exited zero, so a failed synchronization
passed as green and left the generated mounts in local.yml stale. The
failure it is most likely to hide is a broken docker_command_utils.py,
which is one of the two files that trigger the hook in the first place.
* Run the real prek helper in the local yml mounts test
Stubbing common_prek_utils made the test carry a second copy of the
script's imports and a copy of the script itself, and left the helper
the hook actually runs untested. A fake breeze on PATH is enough.
---
scripts/ci/prek/local_yml_mounts.py | 2 +
scripts/tests/ci/prek/test_local_yml_mounts.py | 79 ++++++++++++++++++++++++++
2 files changed, 81 insertions(+)
diff --git a/scripts/ci/prek/local_yml_mounts.py
b/scripts/ci/prek/local_yml_mounts.py
index 5f699e56599..bb6694b4498 100755
--- a/scripts/ci/prek/local_yml_mounts.py
+++ b/scripts/ci/prek/local_yml_mounts.py
@@ -18,6 +18,7 @@
from __future__ import annotations
import subprocess
+import sys
from common_prek_utils import console, initialize_breeze_prek
@@ -29,3 +30,4 @@ res = subprocess.run(
)
if res.returncode != 0:
console.print("\n[red]Error when running local mounts synchronization.\n")
+ sys.exit(res.returncode)
diff --git a/scripts/tests/ci/prek/test_local_yml_mounts.py
b/scripts/tests/ci/prek/test_local_yml_mounts.py
new file mode 100644
index 00000000000..2918c5d7120
--- /dev/null
+++ b/scripts/tests/ci/prek/test_local_yml_mounts.py
@@ -0,0 +1,79 @@
+# 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.
+"""Tests for the exit code of local_yml_mounts.py."""
+
+from __future__ import annotations
+
+import os
+import subprocess
+import sys
+import textwrap
+from pathlib import Path
+
+import pytest
+
+SCRIPT_PATH = Path(__file__).resolve().parents[3] / "ci" / "prek" /
"local_yml_mounts.py"
+
+CALL_LOG_NAME = "breeze_calls.txt"
+
+BREEZE_STUB = textwrap.dedent(
+ """\
+ #!/usr/bin/env python3
+ import os
+ import sys
+
+ with open(os.environ["BREEZE_STUB_CALL_LOG"], "a") as call_log:
+ call_log.write(" ".join(sys.argv[1:]) + "\\n")
+
+ sys.exit(int(os.environ["BREEZE_STUB_RETURNCODE"]))
+ """
+)
+
+
+def run_script(tmp_path: Path, breeze_returncode: int) ->
subprocess.CompletedProcess:
+ bin_dir = tmp_path / "bin"
+ bin_dir.mkdir()
+ breeze_stub = bin_dir / "breeze"
+ breeze_stub.write_text(BREEZE_STUB)
+ breeze_stub.chmod(0o755)
+
+ env = {
+ **os.environ,
+ "PATH": f"{bin_dir}{os.pathsep}{os.environ['PATH']}",
+ "BREEZE_STUB_CALL_LOG": os.fspath(tmp_path / CALL_LOG_NAME),
+ "BREEZE_STUB_RETURNCODE": str(breeze_returncode),
+ }
+ # initialize_breeze_prek honours this by exiting 0 before it ever reaches
breeze.
+ env.pop("SKIP_BREEZE_PREK_HOOKS", None)
+
+ # The script exits when imported as a module, so it has to run as a
subprocess.
+ return subprocess.run(
+ [sys.executable, os.fspath(SCRIPT_PATH)],
+ env=env,
+ capture_output=True,
+ text=True,
+ check=False,
+ )
+
+
[email protected]("breeze_returncode", [0, 1, 2])
+def test_hook_exits_with_the_breeze_return_code(tmp_path, breeze_returncode):
+ result = run_script(tmp_path, breeze_returncode)
+
+ # Without this, an exit from initialize_breeze_prek's own preflight would
satisfy the next line.
+ assert (tmp_path / CALL_LOG_NAME).exists(), f"breeze was never invoked:
{result.stdout}{result.stderr}"
+ assert result.returncode == breeze_returncode