mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 23:27:37 +00:00
Move version validation to resolver (#51311)
This commit is contained in:
parent
95362d4215
commit
5d6b6deed4
@ -47,7 +47,7 @@ DATA_CUSTOM_COMPONENTS = "custom_components"
|
|||||||
PACKAGE_CUSTOM_COMPONENTS = "custom_components"
|
PACKAGE_CUSTOM_COMPONENTS = "custom_components"
|
||||||
PACKAGE_BUILTIN = "homeassistant.components"
|
PACKAGE_BUILTIN = "homeassistant.components"
|
||||||
CUSTOM_WARNING = (
|
CUSTOM_WARNING = (
|
||||||
"You are using a custom integration %s which has not "
|
"We found a custom integration %s which has not "
|
||||||
"been tested by Home Assistant. This component might "
|
"been tested by Home Assistant. This component might "
|
||||||
"cause stability problems, be sure to disable it if you "
|
"cause stability problems, be sure to disable it if you "
|
||||||
"experience issues with Home Assistant"
|
"experience issues with Home Assistant"
|
||||||
@ -290,13 +290,39 @@ class Integration:
|
|||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return cls(
|
integration = cls(
|
||||||
hass,
|
hass,
|
||||||
f"{root_module.__name__}.{domain}",
|
f"{root_module.__name__}.{domain}",
|
||||||
manifest_path.parent,
|
manifest_path.parent,
|
||||||
manifest,
|
manifest,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if integration.is_built_in:
|
||||||
|
return integration
|
||||||
|
|
||||||
|
_LOGGER.warning(CUSTOM_WARNING, integration.domain)
|
||||||
|
try:
|
||||||
|
AwesomeVersion(
|
||||||
|
integration.version,
|
||||||
|
[
|
||||||
|
AwesomeVersionStrategy.CALVER,
|
||||||
|
AwesomeVersionStrategy.SEMVER,
|
||||||
|
AwesomeVersionStrategy.SIMPLEVER,
|
||||||
|
AwesomeVersionStrategy.BUILDVER,
|
||||||
|
AwesomeVersionStrategy.PEP440,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
except AwesomeVersionException:
|
||||||
|
_LOGGER.error(
|
||||||
|
"The custom integration '%s' does not have a "
|
||||||
|
"valid version key (%s) in the manifest file and was blocked from loading. "
|
||||||
|
"See https://developers.home-assistant.io/blog/2021/01/29/custom-integration-changes#versions for more details",
|
||||||
|
integration.domain,
|
||||||
|
integration.version,
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
return integration
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -523,8 +549,6 @@ async def _async_get_integration(hass: HomeAssistant, domain: str) -> Integratio
|
|||||||
# Instead of using resolve_from_root we use the cache of custom
|
# Instead of using resolve_from_root we use the cache of custom
|
||||||
# components to find the integration.
|
# components to find the integration.
|
||||||
if integration := (await async_get_custom_components(hass)).get(domain):
|
if integration := (await async_get_custom_components(hass)).get(domain):
|
||||||
validate_custom_integration_version(integration)
|
|
||||||
_LOGGER.warning(CUSTOM_WARNING, integration.domain)
|
|
||||||
return integration
|
return integration
|
||||||
|
|
||||||
from homeassistant import components # pylint: disable=import-outside-toplevel
|
from homeassistant import components # pylint: disable=import-outside-toplevel
|
||||||
@ -744,31 +768,3 @@ def _lookup_path(hass: HomeAssistant) -> list[str]:
|
|||||||
if hass.config.safe_mode:
|
if hass.config.safe_mode:
|
||||||
return [PACKAGE_BUILTIN]
|
return [PACKAGE_BUILTIN]
|
||||||
return [PACKAGE_CUSTOM_COMPONENTS, PACKAGE_BUILTIN]
|
return [PACKAGE_CUSTOM_COMPONENTS, PACKAGE_BUILTIN]
|
||||||
|
|
||||||
|
|
||||||
def validate_custom_integration_version(integration: Integration) -> None:
|
|
||||||
"""
|
|
||||||
Validate the version of custom integrations.
|
|
||||||
|
|
||||||
Raises IntegrationNotFound when version is missing or not valid
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
AwesomeVersion(
|
|
||||||
integration.version,
|
|
||||||
[
|
|
||||||
AwesomeVersionStrategy.CALVER,
|
|
||||||
AwesomeVersionStrategy.SEMVER,
|
|
||||||
AwesomeVersionStrategy.SIMPLEVER,
|
|
||||||
AwesomeVersionStrategy.BUILDVER,
|
|
||||||
AwesomeVersionStrategy.PEP440,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
except AwesomeVersionException:
|
|
||||||
_LOGGER.error(
|
|
||||||
"The custom integration '%s' does not have a "
|
|
||||||
"valid version key (%s) in the manifest file and was blocked from loading. "
|
|
||||||
"See https://developers.home-assistant.io/blog/2021/01/29/custom-integration-changes#versions for more details",
|
|
||||||
integration.domain,
|
|
||||||
integration.version,
|
|
||||||
)
|
|
||||||
raise IntegrationNotFound(integration.domain) from None
|
|
||||||
|
@ -127,37 +127,30 @@ async def test_log_warning_custom_component(hass, caplog, enable_custom_integrat
|
|||||||
"""Test that we log a warning when loading a custom component."""
|
"""Test that we log a warning when loading a custom component."""
|
||||||
|
|
||||||
await loader.async_get_integration(hass, "test_package")
|
await loader.async_get_integration(hass, "test_package")
|
||||||
assert "You are using a custom integration test_package" in caplog.text
|
assert "We found a custom integration test_package" in caplog.text
|
||||||
|
|
||||||
await loader.async_get_integration(hass, "test")
|
await loader.async_get_integration(hass, "test")
|
||||||
assert "You are using a custom integration test " in caplog.text
|
assert "We found a custom integration test " in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_custom_integration_version_not_valid(hass, caplog):
|
async def test_custom_integration_version_not_valid(
|
||||||
|
hass, caplog, enable_custom_integrations
|
||||||
|
):
|
||||||
"""Test that we log a warning when custom integrations have a invalid version."""
|
"""Test that we log a warning when custom integrations have a invalid version."""
|
||||||
test_integration1 = loader.Integration(
|
with pytest.raises(loader.IntegrationNotFound):
|
||||||
hass, "custom_components.test", None, {"domain": "test1", "version": "test"}
|
await loader.async_get_integration(hass, "test_no_version")
|
||||||
)
|
|
||||||
test_integration2 = loader.Integration(
|
assert (
|
||||||
hass, "custom_components.test", None, {"domain": "test2"}
|
"The custom integration 'test_no_version' does not have a valid version key (None) in the manifest file and was blocked from loading."
|
||||||
|
in caplog.text
|
||||||
)
|
)
|
||||||
|
|
||||||
with patch("homeassistant.loader.async_get_custom_components") as mock_get:
|
with pytest.raises(loader.IntegrationNotFound):
|
||||||
mock_get.return_value = {"test1": test_integration1, "test2": test_integration2}
|
await loader.async_get_integration(hass, "test2")
|
||||||
|
assert (
|
||||||
with pytest.raises(loader.IntegrationNotFound):
|
"The custom integration 'test_bad_version' does not have a valid version key (bad) in the manifest file and was blocked from loading."
|
||||||
await loader.async_get_integration(hass, "test1")
|
in caplog.text
|
||||||
assert (
|
)
|
||||||
"The custom integration 'test1' does not have a valid version key (test) in the manifest file and was blocked from loading."
|
|
||||||
in caplog.text
|
|
||||||
)
|
|
||||||
|
|
||||||
with pytest.raises(loader.IntegrationNotFound):
|
|
||||||
await loader.async_get_integration(hass, "test2")
|
|
||||||
assert (
|
|
||||||
"The custom integration 'test2' does not have a valid version key (None) in the manifest file and was blocked from loading."
|
|
||||||
in caplog.text
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_get_integration(hass):
|
async def test_get_integration(hass):
|
||||||
@ -471,19 +464,11 @@ async def test_get_custom_components_safe_mode(hass):
|
|||||||
|
|
||||||
async def test_custom_integration_missing_version(hass, caplog):
|
async def test_custom_integration_missing_version(hass, caplog):
|
||||||
"""Test trying to load a custom integration without a version twice does not deadlock."""
|
"""Test trying to load a custom integration without a version twice does not deadlock."""
|
||||||
test_integration_1 = loader.Integration(
|
with pytest.raises(loader.IntegrationNotFound):
|
||||||
hass, "custom_components.test1", None, {"domain": "test1"}
|
await loader.async_get_integration(hass, "test_no_version")
|
||||||
)
|
|
||||||
with patch("homeassistant.loader.async_get_custom_components") as mock_get:
|
|
||||||
mock_get.return_value = {
|
|
||||||
"test1": test_integration_1,
|
|
||||||
}
|
|
||||||
|
|
||||||
with pytest.raises(loader.IntegrationNotFound):
|
with pytest.raises(loader.IntegrationNotFound):
|
||||||
await loader.async_get_integration(hass, "test1")
|
await loader.async_get_integration(hass, "test_no_version")
|
||||||
|
|
||||||
with pytest.raises(loader.IntegrationNotFound):
|
|
||||||
await loader.async_get_integration(hass, "test1")
|
|
||||||
|
|
||||||
|
|
||||||
async def test_custom_integration_missing(hass, caplog):
|
async def test_custom_integration_missing(hass, caplog):
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
"""Provide a mock integration."""
|
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"domain": "test_bad_version",
|
||||||
|
"version": "bad"
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
"""Provide a mock integration."""
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"domain": "test_no_version"
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user