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: 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: 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)"> Other options </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     </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 checking if the CI image is up to 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)"> Common options </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 </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 answer to 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 dry-run is set, 
[...]
-</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 verbose information
[...]
-</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   </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 this 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     </text><text
class="breeze-run-r1" x="414.8" y="1044.8" textLength="915"
clip-path="url(#breeze-run-line-42)">Whether to include mounting of the mypy volume (useful for 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 checking if the CI image is up to 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)"> Common options </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 </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 answer to 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 dry-run is set, 
[...]
+</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 verbose information
[...]
+</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   </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 this 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