This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch v3-3-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-3-test by this push:
     new 1df08159035 [v3-3-test] Fix breeze --include-mypy-volume not mounting 
the mypy cache volume (#72569) (#72692)
1df08159035 is described below

commit 1df08159035ce0c9010d6307f5429be757a2aa49
Author: Jarek Potiuk <[email protected]>
AuthorDate: Tue Sep 8 12:29:29 2026 +0200

    [v3-3-test] Fix breeze --include-mypy-volume not mounting the mypy cache 
volume (#72569) (#72692)
    
    * 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.
    (cherry picked from commit a88aaff419)
    
    Co-authored-by: Andrew Chang <[email protected]>
---
 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 34b755851a5..2377e996799 100644
--- a/dev/breeze/src/airflow_breeze/commands/developer_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/developer_commands.py
@@ -1291,6 +1291,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
@@ -1311,6 +1312,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,
@@ -1378,6 +1380,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 17d32146110..b79b9d0c4ae 100644
--- a/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
+++ b/dev/breeze/src/airflow_breeze/commands/developer_commands_config.py
@@ -334,6 +334,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 0d67d51e017..41f3dfdaf4c 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")
 
@@ -218,3 +221,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