diff --git a/esphome/__main__.py b/esphome/__main__.py index 8e6d88f26e..15e7ddc6c5 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -2774,7 +2774,11 @@ def run_esphome(argv): # against the previous substitution set. config: ConfigType | None = None cache_eligible = ( - args.command in ("upload", "logs") and not command_line_substitutions + args.command in ("upload", "logs") + and not command_line_substitutions + # An explicit CLI toolchain must run the per-platform validators; + # the cache was validated under whatever the last compile used + and args.toolchain is None ) if cache_eligible: from esphome.compiled_config import load_compiled_config diff --git a/tests/unit_tests/test_config_validation.py b/tests/unit_tests/test_config_validation.py index 78fc39430e..6f98de2642 100644 --- a/tests/unit_tests/test_config_validation.py +++ b/tests/unit_tests/test_config_validation.py @@ -3200,6 +3200,8 @@ def test_check_supported_toolchain_unresolved_is_an_ordering_bug() -> None: ("host", {}), ("rp2", {"board": "rpipicow"}), ("bk72xx", {"board": "generic-bk7231n-qfn32-tuya"}), + ("rtl87xx", {"board": "generic-rtl8710bn-2mb-788k"}), + ("ln882x", {"board": "generic-ln882h"}), # The legacy stub platform must reject too, not just the chip families ("libretiny", {}), ], diff --git a/tests/unit_tests/test_main.py b/tests/unit_tests/test_main.py index be8209b7c9..501e0545e7 100644 --- a/tests/unit_tests/test_main.py +++ b/tests/unit_tests/test_main.py @@ -7387,3 +7387,20 @@ def test_command_analyze_memory_unsupported_toolchain( assert result == 1 assert "analyze-memory is not supported" in caplog.text + + +def test_cli_toolchain_skips_the_validated_config_cache(tmp_path: Path) -> None: + """An explicit --toolchain must run the per-platform validators, so the + upload/logs fast path becomes a cache miss.""" + from esphome.__main__ import run_esphome + + conf = tmp_path / "device.yaml" + conf.write_text("esphome:\n name: t\n") + argv = ["esphome", "--toolchain", "arduino", "logs", str(conf)] + with ( + patch("esphome.compiled_config.load_compiled_config") as mock_cache, + patch("esphome.config.read_config", return_value=None) as mock_read, + ): + assert run_esphome(argv) == 2 + mock_cache.assert_not_called() + mock_read.assert_called_once()