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

Reply via email to