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 a88aaff4199 Fix breeze --include-mypy-volume not mounting the mypy 
cache volume (#72569)
a88aaff4199 is described below

commit a88aaff4199684e4313fe5a75d22ef4f1d9f8991
Author: Andrew Chang <[email protected]>
AuthorDate: Tue Sep 8 18:02:29 2026 +0800

    Fix breeze --include-mypy-volume not mounting the mypy cache volume (#72569)
    
    * Fix breeze --include-mypy-volume not mounting the mypy cache volume
    
    The compose constant for the mypy volume pointed at local.yml instead of
    mypy.yml since the path constants were extracted in #58732, so the
    mypy-cache-volume was created but never mounted and the cache was lost
    whenever the container was removed.
    
    * Add --include-mypy-volume to breeze run so provider mypy hooks keep their 
cache
    
    The provider mypy prek hooks pass INCLUDE_MYPY_VOLUME=true to breeze run,
    but only breeze shell had the option, so the env var was ignored and the
    mypy cache was rebuilt on every hook run. The mypy cache volume is
    external, so the per-run compose project teardown leaves it in place.
---
 dev/breeze/doc/images/output_run.svg               | 26 ++++++++++-------
 dev/breeze/doc/images/output_run.txt               |  2 +-
 .../airflow_breeze/commands/developer_commands.py  |  3 ++
 .../commands/developer_commands_config.py          |  1 +
 dev/breeze/src/airflow_breeze/utils/path_utils.py  |  2 +-
 dev/breeze/tests/test_developer_commands.py        | 34 +++++++++++++++++++++-
 dev/breeze/tests/test_shell_params.py              | 10 ++++++-
 7 files changed, 63 insertions(+), 15 deletions(-)

diff --git a/dev/breeze/doc/images/output_run.svg 
b/dev/breeze/doc/images/output_run.svg
index e155248e08c..1f663a97be3 100644
--- a/dev/breeze/doc/images/output_run.svg
+++ b/dev/breeze/doc/images/output_run.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 1270.0" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 1294.3999999999999" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath id="breeze-run-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="1219.0" />
+      <rect x="0" y="0" width="1463.0" height="1243.3999999999999" />
     </clipPath>
     <clipPath id="breeze-run-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -192,9 +192,12 @@
 <clipPath id="breeze-run-line-48">
     <rect x="0" y="1172.7" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-run-line-49">
+    <rect x="0" y="1197.1" width="1464" height="24.65"/>
+            </clipPath>
     </defs>
 
-    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="1268" rx="8"/><text class="breeze-run-title" 
fill="#c5c8c6" text-anchor="middle" x="740" y="27">Command:&#160;run</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="1292.4" rx="8"/><text class="breeze-run-title" 
fill="#c5c8c6" text-anchor="middle" x="740" y="27">Command:&#160;run</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -246,14 +249,15 @@
 </text><text class="breeze-run-r5" x="0" y="971.6" textLength="1464" 
clip-path="url(#breeze-run-line-39)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-run-r1" x="1464" y="971.6" textLength="12.2" 
clip-path="url(#breeze-run-line-39)">
 </text><text class="breeze-run-r5" x="0" y="996" textLength="24.4" 
clip-path="url(#breeze-run-line-40)">╭─</text><text class="breeze-run-r5" 
x="24.4" y="996" textLength="183" 
clip-path="url(#breeze-run-line-40)">&#160;Other&#160;options&#160;</text><text 
class="breeze-run-r5" x="207.4" y="996" textLength="1232.2" 
clip-path="url(#breeze-run-line-40)">─────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-run-r5" x="1 [...]
 </text><text class="breeze-run-r5" x="0" y="1020.4" textLength="12.2" 
clip-path="url(#breeze-run-line-41)">│</text><text class="breeze-run-r4" 
x="24.4" y="1020.4" textLength="317.2" 
clip-path="url(#breeze-run-line-41)">--forward-credentials&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-run-r6" x="366" y="1020.4" textLength="24.4" 
clip-path="url(#breeze-run-line-41)">-f</text><text class="breeze-run-r1" 
x="414.8" y="1020.4" textLength="634.4" clip-path="url(#breeze-run-line-41)" 
[...]
-</text><text class="breeze-run-r5" x="0" y="1044.8" textLength="12.2" 
clip-path="url(#breeze-run-line-42)">│</text><text class="breeze-run-r4" 
x="24.4" y="1044.8" textLength="317.2" 
clip-path="url(#breeze-run-line-42)">--skip-image-upgrade-check</text><text 
class="breeze-run-r1" x="414.8" y="1044.8" textLength="536.8" 
clip-path="url(#breeze-run-line-42)">Skip&#160;checking&#160;if&#160;the&#160;CI&#160;image&#160;is&#160;up&#160;to&#160;date.</text><text
 class="breeze-run-r5" x="1451.8"  [...]
-</text><text class="breeze-run-r5" x="0" y="1069.2" textLength="1464" 
clip-path="url(#breeze-run-line-43)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-run-r1" x="1464" y="1069.2" textLength="12.2" 
clip-path="url(#breeze-run-line-43)">
-</text><text class="breeze-run-r5" x="0" y="1093.6" textLength="24.4" 
clip-path="url(#breeze-run-line-44)">╭─</text><text class="breeze-run-r5" 
x="24.4" y="1093.6" textLength="195.2" 
clip-path="url(#breeze-run-line-44)">&#160;Common&#160;options&#160;</text><text
 class="breeze-run-r5" x="219.6" y="1093.6" textLength="1220" 
clip-path="url(#breeze-run-line-44)">────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-run [...]
-</text><text class="breeze-run-r5" x="0" y="1118" textLength="12.2" 
clip-path="url(#breeze-run-line-45)">│</text><text class="breeze-run-r4" 
x="24.4" y="1118" textLength="109.8" 
clip-path="url(#breeze-run-line-45)">--answer&#160;</text><text 
class="breeze-run-r6" x="158.6" y="1118" textLength="24.4" 
clip-path="url(#breeze-run-line-45)">-a</text><text class="breeze-run-r1" 
x="207.4" y="1118" textLength="329.4" 
clip-path="url(#breeze-run-line-45)">Force&#160;answer&#160;to&#160;questions.& 
[...]
-</text><text class="breeze-run-r5" x="0" y="1142.4" textLength="12.2" 
clip-path="url(#breeze-run-line-46)">│</text><text class="breeze-run-r4" 
x="24.4" y="1142.4" textLength="109.8" 
clip-path="url(#breeze-run-line-46)">--dry-run</text><text 
class="breeze-run-r6" x="158.6" y="1142.4" textLength="24.4" 
clip-path="url(#breeze-run-line-46)">-D</text><text class="breeze-run-r1" 
x="207.4" y="1142.4" textLength="719.8" 
clip-path="url(#breeze-run-line-46)">If&#160;dry-run&#160;is&#160;set,&#160; 
[...]
-</text><text class="breeze-run-r5" x="0" y="1166.8" textLength="12.2" 
clip-path="url(#breeze-run-line-47)">│</text><text class="breeze-run-r4" 
x="24.4" y="1166.8" textLength="109.8" 
clip-path="url(#breeze-run-line-47)">--verbose</text><text 
class="breeze-run-r6" x="158.6" y="1166.8" textLength="24.4" 
clip-path="url(#breeze-run-line-47)">-v</text><text class="breeze-run-r1" 
x="207.4" y="1166.8" textLength="585.6" 
clip-path="url(#breeze-run-line-47)">Print&#160;verbose&#160;information&#16 
[...]
-</text><text class="breeze-run-r5" x="0" y="1191.2" textLength="12.2" 
clip-path="url(#breeze-run-line-48)">│</text><text class="breeze-run-r4" 
x="24.4" y="1191.2" textLength="109.8" 
clip-path="url(#breeze-run-line-48)">--help&#160;&#160;&#160;</text><text 
class="breeze-run-r6" x="158.6" y="1191.2" textLength="24.4" 
clip-path="url(#breeze-run-line-48)">-h</text><text class="breeze-run-r1" 
x="207.4" y="1191.2" textLength="329.4" 
clip-path="url(#breeze-run-line-48)">Show&#160;this&#160;mess [...]
-</text><text class="breeze-run-r5" x="0" y="1215.6" textLength="1464" 
clip-path="url(#breeze-run-line-49)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-run-r1" x="1464" y="1215.6" textLength="12.2" 
clip-path="url(#breeze-run-line-49)">
+</text><text class="breeze-run-r5" x="0" y="1044.8" textLength="12.2" 
clip-path="url(#breeze-run-line-42)">│</text><text class="breeze-run-r4" 
x="24.4" y="1044.8" textLength="317.2" 
clip-path="url(#breeze-run-line-42)">--include-mypy-volume&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-run-r1" x="414.8" y="1044.8" textLength="915" 
clip-path="url(#breeze-run-line-42)">Whether&#160;to&#160;include&#160;mounting&#160;of&#160;the&#160;mypy&#160;volume&#160;(useful&#160;for&#160;deb
 [...]
+</text><text class="breeze-run-r5" x="0" y="1069.2" textLength="12.2" 
clip-path="url(#breeze-run-line-43)">│</text><text class="breeze-run-r4" 
x="24.4" y="1069.2" textLength="317.2" 
clip-path="url(#breeze-run-line-43)">--skip-image-upgrade-check</text><text 
class="breeze-run-r1" x="414.8" y="1069.2" textLength="536.8" 
clip-path="url(#breeze-run-line-43)">Skip&#160;checking&#160;if&#160;the&#160;CI&#160;image&#160;is&#160;up&#160;to&#160;date.</text><text
 class="breeze-run-r5" x="1451.8"  [...]
+</text><text class="breeze-run-r5" x="0" y="1093.6" textLength="1464" 
clip-path="url(#breeze-run-line-44)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-run-r1" x="1464" y="1093.6" textLength="12.2" 
clip-path="url(#breeze-run-line-44)">
+</text><text class="breeze-run-r5" x="0" y="1118" textLength="24.4" 
clip-path="url(#breeze-run-line-45)">╭─</text><text class="breeze-run-r5" 
x="24.4" y="1118" textLength="195.2" 
clip-path="url(#breeze-run-line-45)">&#160;Common&#160;options&#160;</text><text
 class="breeze-run-r5" x="219.6" y="1118" textLength="1220" 
clip-path="url(#breeze-run-line-45)">────────────────────────────────────────────────────────────────────────────────────────────────────</text><text
 class="breeze-run-r5" x [...]
+</text><text class="breeze-run-r5" x="0" y="1142.4" textLength="12.2" 
clip-path="url(#breeze-run-line-46)">│</text><text class="breeze-run-r4" 
x="24.4" y="1142.4" textLength="109.8" 
clip-path="url(#breeze-run-line-46)">--answer&#160;</text><text 
class="breeze-run-r6" x="158.6" y="1142.4" textLength="24.4" 
clip-path="url(#breeze-run-line-46)">-a</text><text class="breeze-run-r1" 
x="207.4" y="1142.4" textLength="329.4" 
clip-path="url(#breeze-run-line-46)">Force&#160;answer&#160;to&#160;que [...]
+</text><text class="breeze-run-r5" x="0" y="1166.8" textLength="12.2" 
clip-path="url(#breeze-run-line-47)">│</text><text class="breeze-run-r4" 
x="24.4" y="1166.8" textLength="109.8" 
clip-path="url(#breeze-run-line-47)">--dry-run</text><text 
class="breeze-run-r6" x="158.6" y="1166.8" textLength="24.4" 
clip-path="url(#breeze-run-line-47)">-D</text><text class="breeze-run-r1" 
x="207.4" y="1166.8" textLength="719.8" 
clip-path="url(#breeze-run-line-47)">If&#160;dry-run&#160;is&#160;set,&#160; 
[...]
+</text><text class="breeze-run-r5" x="0" y="1191.2" textLength="12.2" 
clip-path="url(#breeze-run-line-48)">│</text><text class="breeze-run-r4" 
x="24.4" y="1191.2" textLength="109.8" 
clip-path="url(#breeze-run-line-48)">--verbose</text><text 
class="breeze-run-r6" x="158.6" y="1191.2" textLength="24.4" 
clip-path="url(#breeze-run-line-48)">-v</text><text class="breeze-run-r1" 
x="207.4" y="1191.2" textLength="585.6" 
clip-path="url(#breeze-run-line-48)">Print&#160;verbose&#160;information&#16 
[...]
+</text><text class="breeze-run-r5" x="0" y="1215.6" textLength="12.2" 
clip-path="url(#breeze-run-line-49)">│</text><text class="breeze-run-r4" 
x="24.4" y="1215.6" textLength="109.8" 
clip-path="url(#breeze-run-line-49)">--help&#160;&#160;&#160;</text><text 
class="breeze-run-r6" x="158.6" y="1215.6" textLength="24.4" 
clip-path="url(#breeze-run-line-49)">-h</text><text class="breeze-run-r1" 
x="207.4" y="1215.6" textLength="329.4" 
clip-path="url(#breeze-run-line-49)">Show&#160;this&#160;mess [...]
+</text><text class="breeze-run-r5" x="0" y="1240" textLength="1464" 
clip-path="url(#breeze-run-line-50)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-run-r1" x="1464" y="1240" textLength="12.2" 
clip-path="url(#breeze-run-line-50)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_run.txt 
b/dev/breeze/doc/images/output_run.txt
index 4a274308775..6d88ea6dd56 100644
--- a/dev/breeze/doc/images/output_run.txt
+++ b/dev/breeze/doc/images/output_run.txt
@@ -1 +1 @@
-e850a14ddf66f700b2595d65d7511869
+8f60079b567a52620babed8a0ed01b2a
diff --git a/dev/breeze/src/airflow_breeze/commands/developer_commands.py 
b/dev/breeze/src/airflow_breeze/commands/developer_commands.py
index 617f06329fc..ce8d3293bf4 100644
--- a/dev/breeze/src/airflow_breeze/commands/developer_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/developer_commands.py
@@ -1357,6 +1357,7 @@ def doctor(ctx):
 @option_forward_credentials
 @option_forward_ports
 @option_github_repository
+@option_include_mypy_volume
 @option_mysql_version
 @option_platform_single
 @option_postgres_version
@@ -1377,6 +1378,7 @@ def run(
     forward_credentials: bool,
     forward_ports: bool,
     github_repository: str,
+    include_mypy_volume: bool,
     mysql_version: str,
     platform: str | None,
     postgres_version: str,
@@ -1444,6 +1446,7 @@ def run(
         force_build=force_build,
         forward_credentials=forward_credentials,
         github_repository=github_repository,
+        include_mypy_volume=include_mypy_volume,
         mysql_version=mysql_version,
         platform=platform,
         postgres_version=postgres_version,
diff --git 
a/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py 
b/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
index f55608ba4fc..54e1a296f2c 100644
--- a/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
+++ b/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
@@ -322,6 +322,7 @@ DEVELOPER_PARAMETERS: dict[str, list[dict[str, str | 
list[str]]]] = {
             "name": "Other options",
             "options": [
                 "--forward-credentials",
+                "--include-mypy-volume",
                 "--skip-image-upgrade-check",
             ],
         },
diff --git a/dev/breeze/src/airflow_breeze/utils/path_utils.py 
b/dev/breeze/src/airflow_breeze/utils/path_utils.py
index 716d7c2c7cc..611db564a5e 100644
--- a/dev/breeze/src/airflow_breeze/utils/path_utils.py
+++ b/dev/breeze/src/airflow_breeze/utils/path_utils.py
@@ -523,7 +523,7 @@ SCRIPTS_CI_DOCKER_COMPOSE_INTEGRATION_KERBEROS_PATH = (
 SCRIPTS_CI_DOCKER_COMPOSE_LOCAL_ALL_SOURCES_PATH = 
SCRIPTS_CI_DOCKER_COMPOSE_PATH / "local-all-sources.yml"
 SCRIPTS_CI_DOCKER_COMPOSE_LOCAL_YAML_PATH = SCRIPTS_CI_DOCKER_COMPOSE_PATH / 
"local.yml"
 SCRIPTS_CI_DOCKER_COMPOSE_MOUNT_UI_DIST_PATH = SCRIPTS_CI_DOCKER_COMPOSE_PATH 
/ "mount-ui-dist.yml"
-SCRIPTS_CI_DOCKER_COMPOSE_MYPY_PATH = SCRIPTS_CI_DOCKER_COMPOSE_PATH / 
"local.yml"
+SCRIPTS_CI_DOCKER_COMPOSE_MYPY_PATH = SCRIPTS_CI_DOCKER_COMPOSE_PATH / 
"mypy.yml"
 SCRIPTS_CI_DOCKER_COMPOSE_PROVIDERS_AND_TESTS_SOURCES_PATH = (
     SCRIPTS_CI_DOCKER_COMPOSE_PATH / "providers-and-tests-sources.yml"
 )
diff --git a/dev/breeze/tests/test_developer_commands.py 
b/dev/breeze/tests/test_developer_commands.py
index 9c4a3a8f2f4..a684ae196ad 100644
--- a/dev/breeze/tests/test_developer_commands.py
+++ b/dev/breeze/tests/test_developer_commands.py
@@ -22,7 +22,7 @@ from unittest.mock import patch
 import pytest
 from click.testing import CliRunner
 
-from airflow_breeze.commands.developer_commands import build_docs
+from airflow_breeze.commands.developer_commands import build_docs, run
 from airflow_breeze.global_constants import DEFAULT_PYTHON_MAJOR_MINOR_VERSION
 
 
@@ -73,3 +73,35 @@ class TestBuildDocsPythonVersion:
 
         assert result.exit_code != 0
         assert "no such option" in result.output.lower()
+
+
+class TestRunIncludeMypyVolume:
+    @pytest.fixture(autouse=True)
+    def _no_docker(self, monkeypatch):
+        monkeypatch.setenv("SKIP_SAVING_CHOICES", "true")
+        monkeypatch.delenv("INCLUDE_MYPY_VOLUME", raising=False)
+        monkeypatch.setattr(
+            
"airflow_breeze.commands.developer_commands.bring_compose_project_down", lambda 
*a, **kw: None
+        )
+        for name in ("fix_ownership_using_docker", "remove_docker_networks"):
+            
monkeypatch.setattr(f"airflow_breeze.utils.docker_command_utils.{name}", lambda 
*a, **kw: None)
+
+    def _invoke(self, runner: CliRunner, args: list[str], env: dict[str, str] 
| None = None):
+        with (
+            
patch("airflow_breeze.commands.ci_image_commands.build_ci_image_if_needed"),
+            
patch("airflow_breeze.utils.docker_command_utils.execute_command_in_shell") as 
mock_shell,
+        ):
+            mock_shell.return_value.returncode = 0
+            runner.invoke(run, [*args, "true"], env=env, 
catch_exceptions=False)
+        return mock_shell.call_args.kwargs["shell_params"]
+
+    @pytest.mark.parametrize(
+        ("args", "env", "expected"),
+        [
+            pytest.param([], None, False, id="default"),
+            pytest.param(["--include-mypy-volume"], None, True, id="flag"),
+            pytest.param([], {"INCLUDE_MYPY_VOLUME": "true"}, True, id="env"),
+        ],
+    )
+    def test_include_mypy_volume_is_passed_to_shell_params(self, runner, args, 
env, expected):
+        assert self._invoke(runner, args, env=env).include_mypy_volume is 
expected
diff --git a/dev/breeze/tests/test_shell_params.py 
b/dev/breeze/tests/test_shell_params.py
index d1d36413989..8dd642727e5 100644
--- a/dev/breeze/tests/test_shell_params.py
+++ b/dev/breeze/tests/test_shell_params.py
@@ -25,7 +25,10 @@ from rich.console import Console
 
 from airflow_breeze.branch_defaults import AIRFLOW_BRANCH
 from airflow_breeze.params.shell_params import ShellParams
-from airflow_breeze.utils.path_utils import SCRIPTS_CI_DOCKER_COMPOSE_BASE_PATH
+from airflow_breeze.utils.path_utils import (
+    SCRIPTS_CI_DOCKER_COMPOSE_BASE_PATH,
+    SCRIPTS_CI_DOCKER_COMPOSE_PATH,
+)
 
 console = Console(width=400, color_system="standard")
 
@@ -254,3 +257,8 @@ def 
test_generated_env_files_do_not_change_when_pythonwarnings_is_set(tmp_path,
 def test_pythonwarnings_is_forwarded_by_the_compose_base_file():
     base_compose_file = 
yaml.safe_load(SCRIPTS_CI_DOCKER_COMPOSE_BASE_PATH.read_text())
     assert "PYTHONWARNINGS" in 
base_compose_file["services"]["airflow"]["environment"]
+
+
+def test_include_mypy_volume_adds_mypy_compose_file():
+    compose_files = 
ShellParams(include_mypy_volume=True).compose_file.split(":")
+    assert str(SCRIPTS_CI_DOCKER_COMPOSE_PATH / "mypy.yml") in compose_files

Reply via email to