From eaae2e543b58c31db91f862f2d0fa24025e89f66 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 20 Aug 2026 06:30:07 -0500 Subject: [PATCH] Reject unsupported CLI toolchains on every platform and complete the native CI triggers --- esphome/components/esp32/__init__.py | 5 +++++ esphome/components/nrf52/__init__.py | 5 +++++ script/determine-jobs.py | 1 + tests/component_tests/esp32/test_esp32.py | 14 ++++++++++++++ tests/script/test_determine_jobs.py | 2 ++ tests/unit_tests/test_nrf52_framework.py | 11 +++++++++++ 6 files changed, 38 insertions(+) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 3065cdadad..b124725c06 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -1053,6 +1053,11 @@ def _resolve_toolchain(value: ConfigType) -> ConfigType: # CORE.toolchain instead of re-resolving it from the config dict. if CORE.toolchain is None: CORE.toolchain = value.get(CONF_TOOLCHAIN, Toolchain.ESP_IDF) + if CORE.toolchain not in (Toolchain.PLATFORMIO, Toolchain.ESP_IDF): + raise cv.Invalid( + f"Unsupported toolchain '{CORE.toolchain.value}' for ESP32. " + "Supported toolchains are 'platformio' and 'esp-idf'." + ) return value diff --git a/esphome/components/nrf52/__init__.py b/esphome/components/nrf52/__init__.py index 2d25558254..2328d444f7 100644 --- a/esphome/components/nrf52/__init__.py +++ b/esphome/components/nrf52/__init__.py @@ -128,6 +128,11 @@ def set_core_data(config: ConfigType) -> ConfigType: def _resolve_toolchain(config: ConfigType) -> ConfigType: if CORE.toolchain is None: CORE.toolchain = config.get(CONF_TOOLCHAIN, Toolchain.SDK_NRF) + if CORE.toolchain not in (Toolchain.PLATFORMIO, Toolchain.SDK_NRF): + raise cv.Invalid( + f"Unsupported toolchain '{CORE.toolchain.value}' for nRF52. " + "Supported toolchains are 'platformio' and 'sdk-nrf'." + ) return config diff --git a/script/determine-jobs.py b/script/determine-jobs.py index 6bc6d8a875..c94367f0ad 100755 --- a/script/determine-jobs.py +++ b/script/determine-jobs.py @@ -644,6 +644,7 @@ ESP8266_NATIVE_TRIGGER_FILES = frozenset( "esphome/components/esp8266/build_surgery.py", "esphome/components/esp8266/boards.py", "esphome/platformio/library.py", + "esphome/platformio/toolchain.py", "script/test_build_components.py", ".github/workflows/ci.yml", } diff --git a/tests/component_tests/esp32/test_esp32.py b/tests/component_tests/esp32/test_esp32.py index 1fd835076d..254036c430 100644 --- a/tests/component_tests/esp32/test_esp32.py +++ b/tests/component_tests/esp32/test_esp32.py @@ -131,6 +131,20 @@ def test_esp32_rejects_unsupported_toolchains( CONFIG_SCHEMA({"variant": VARIANT_ESP32, "toolchain": config_toolchain}) +def test_esp32_rejects_unsupported_cli_toolchain( + set_core_config: SetCoreConfigCallable, +) -> None: + """A --toolchain the platform cannot serve fails instead of silently + building with PlatformIO (the CLI path bypasses the YAML validator).""" + set_core_config(PlatformFramework.ESP32_IDF) + + from esphome.components.esp32 import CONFIG_SCHEMA + + CORE.toolchain = Toolchain.ARDUINO + with pytest.raises(cv.Invalid, match="Unsupported toolchain 'arduino'"): + CONFIG_SCHEMA({"variant": VARIANT_ESP32}) + + @pytest.mark.parametrize( ("config", "error_match"), [ diff --git a/tests/script/test_determine_jobs.py b/tests/script/test_determine_jobs.py index 5aa67af73c..fa16a155d4 100644 --- a/tests/script/test_determine_jobs.py +++ b/tests/script/test_determine_jobs.py @@ -3086,6 +3086,8 @@ def test_esp8266_native_components_full_list_on_infra_change() -> None: # Top-level esphome/*.py modules the backend imports directly ["esphome/framework_helpers.py"], ["esphome/writer.py"], + # ccache_path imports from platformio/toolchain.py + ["esphome/platformio/toolchain.py"], ): with ( patch.object(determine_jobs, "changed_files", return_value=changed), diff --git a/tests/unit_tests/test_nrf52_framework.py b/tests/unit_tests/test_nrf52_framework.py index 0a6bddc280..6b318e13a9 100644 --- a/tests/unit_tests/test_nrf52_framework.py +++ b/tests/unit_tests/test_nrf52_framework.py @@ -531,3 +531,14 @@ def testget_tools_path_default_is_global_cache( Path(platformdirs.user_cache_dir("esphome", appauthor=False)) / "sdk-nrf" ).resolve() assert get_sdk_nrf_tools_path() == expected + + +def test_resolve_toolchain_rejects_unsupported() -> None: + """A --toolchain nRF52 cannot serve fails instead of degrading silently.""" + from esphome.components.nrf52 import _resolve_toolchain + import esphome.config_validation as cv + from esphome.const import Toolchain + + CORE.toolchain = Toolchain.ARDUINO + with pytest.raises(cv.Invalid, match="Unsupported toolchain 'arduino'"): + _resolve_toolchain({})