Move version validation to resolver (#51311)

This commit is contained in:
Joakim Sørensen 2021-06-01 00:32:03 +02:00 committed by GitHub
parent 95362d4215
commit 5d6b6deed4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 58 additions and 68 deletions

View file

@ -47,7 +47,7 @@ DATA_CUSTOM_COMPONENTS = "custom_components"
PACKAGE_CUSTOM_COMPONENTS = "custom_components"
PACKAGE_BUILTIN = "homeassistant.components"
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 "
"cause stability problems, be sure to disable it if you "
"experience issues with Home Assistant"
@ -290,13 +290,39 @@ class Integration:
)
continue
return cls(
integration = cls(
hass,
f"{root_module.__name__}.{domain}",
manifest_path.parent,
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
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
# components to find the integration.
if integration := (await async_get_custom_components(hass)).get(domain):
validate_custom_integration_version(integration)
_LOGGER.warning(CUSTOM_WARNING, integration.domain)
return integration
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:
return [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

View file

@ -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."""
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")
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_integration1 = loader.Integration(
hass, "custom_components.test", None, {"domain": "test1", "version": "test"}
)
test_integration2 = loader.Integration(
hass, "custom_components.test", None, {"domain": "test2"}
with pytest.raises(loader.IntegrationNotFound):
await loader.async_get_integration(hass, "test_no_version")
assert (
"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:
mock_get.return_value = {"test1": test_integration1, "test2": test_integration2}
with pytest.raises(loader.IntegrationNotFound):
await loader.async_get_integration(hass, "test1")
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
)
with pytest.raises(loader.IntegrationNotFound):
await loader.async_get_integration(hass, "test2")
assert (
"The custom integration 'test_bad_version' does not have a valid version key (bad) in the manifest file and was blocked from loading."
in caplog.text
)
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):
"""Test trying to load a custom integration without a version twice does not deadlock."""
test_integration_1 = loader.Integration(
hass, "custom_components.test1", None, {"domain": "test1"}
)
with patch("homeassistant.loader.async_get_custom_components") as mock_get:
mock_get.return_value = {
"test1": test_integration_1,
}
with pytest.raises(loader.IntegrationNotFound):
await loader.async_get_integration(hass, "test_no_version")
with pytest.raises(loader.IntegrationNotFound):
await loader.async_get_integration(hass, "test1")
with pytest.raises(loader.IntegrationNotFound):
await loader.async_get_integration(hass, "test1")
with pytest.raises(loader.IntegrationNotFound):
await loader.async_get_integration(hass, "test_no_version")
async def test_custom_integration_missing(hass, caplog):

View file

@ -0,0 +1 @@
"""Provide a mock integration."""

View file

@ -0,0 +1,4 @@
{
"domain": "test_bad_version",
"version": "bad"
}

View file

@ -0,0 +1 @@
"""Provide a mock integration."""

View file

@ -0,0 +1,3 @@
{
"domain": "test_no_version"
}