mirror of
https://github.com/home-assistant/core.git
synced 2025-07-14 08:47:10 +00:00
Mealie min version check (#121677)
This commit is contained in:
parent
71e5ffb2bd
commit
a9c9963f0f
@ -12,7 +12,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|||||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN, MIN_REQUIRED_MEALIE_VERSION
|
||||||
from .coordinator import (
|
from .coordinator import (
|
||||||
MealieConfigEntry,
|
MealieConfigEntry,
|
||||||
MealieData,
|
MealieData,
|
||||||
@ -20,6 +20,7 @@ from .coordinator import (
|
|||||||
MealieShoppingListCoordinator,
|
MealieShoppingListCoordinator,
|
||||||
)
|
)
|
||||||
from .services import setup_services
|
from .services import setup_services
|
||||||
|
from .utils import create_version
|
||||||
|
|
||||||
PLATFORMS: list[Platform] = [Platform.CALENDAR, Platform.TODO]
|
PLATFORMS: list[Platform] = [Platform.CALENDAR, Platform.TODO]
|
||||||
|
|
||||||
@ -41,11 +42,22 @@ async def async_setup_entry(hass: HomeAssistant, entry: MealieConfigEntry) -> bo
|
|||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
about = await client.get_about()
|
about = await client.get_about()
|
||||||
|
version = create_version(about.version)
|
||||||
except MealieAuthenticationError as error:
|
except MealieAuthenticationError as error:
|
||||||
raise ConfigEntryError("Authentication failed") from error
|
raise ConfigEntryError("Authentication failed") from error
|
||||||
except MealieConnectionError as error:
|
except MealieConnectionError as error:
|
||||||
raise ConfigEntryNotReady(error) from error
|
raise ConfigEntryNotReady(error) from error
|
||||||
|
|
||||||
|
if not version.valid or version < MIN_REQUIRED_MEALIE_VERSION:
|
||||||
|
raise ConfigEntryError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="version_error",
|
||||||
|
translation_placeholders={
|
||||||
|
"mealie_version": about.version,
|
||||||
|
"min_version": MIN_REQUIRED_MEALIE_VERSION,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
assert entry.unique_id
|
assert entry.unique_id
|
||||||
device_registry = dr.async_get(hass)
|
device_registry = dr.async_get(hass)
|
||||||
device_registry.async_get_or_create(
|
device_registry.async_get_or_create(
|
||||||
|
@ -9,7 +9,8 @@ from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
|||||||
from homeassistant.const import CONF_API_TOKEN, CONF_HOST
|
from homeassistant.const import CONF_API_TOKEN, CONF_HOST
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
|
||||||
from .const import DOMAIN, LOGGER
|
from .const import DOMAIN, LOGGER, MIN_REQUIRED_MEALIE_VERSION
|
||||||
|
from .utils import create_version
|
||||||
|
|
||||||
SCHEMA = vol.Schema(
|
SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
@ -35,6 +36,8 @@ class MealieConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
info = await client.get_user_info()
|
info = await client.get_user_info()
|
||||||
|
about = await client.get_about()
|
||||||
|
version = create_version(about.version)
|
||||||
except MealieConnectionError:
|
except MealieConnectionError:
|
||||||
errors["base"] = "cannot_connect"
|
errors["base"] = "cannot_connect"
|
||||||
except MealieAuthenticationError:
|
except MealieAuthenticationError:
|
||||||
@ -43,12 +46,15 @@ class MealieConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
LOGGER.exception("Unexpected error")
|
LOGGER.exception("Unexpected error")
|
||||||
errors["base"] = "unknown"
|
errors["base"] = "unknown"
|
||||||
else:
|
else:
|
||||||
await self.async_set_unique_id(info.user_id)
|
if not version.valid or version < MIN_REQUIRED_MEALIE_VERSION:
|
||||||
self._abort_if_unique_id_configured()
|
errors["base"] = "mealie_version"
|
||||||
return self.async_create_entry(
|
else:
|
||||||
title="Mealie",
|
await self.async_set_unique_id(info.user_id)
|
||||||
data=user_input,
|
self._abort_if_unique_id_configured()
|
||||||
)
|
return self.async_create_entry(
|
||||||
|
title="Mealie",
|
||||||
|
data=user_input,
|
||||||
|
)
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="user",
|
step_id="user",
|
||||||
data_schema=SCHEMA,
|
data_schema=SCHEMA,
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from awesomeversion import AwesomeVersion
|
||||||
|
|
||||||
DOMAIN = "mealie"
|
DOMAIN = "mealie"
|
||||||
|
|
||||||
LOGGER = logging.getLogger(__package__)
|
LOGGER = logging.getLogger(__package__)
|
||||||
@ -12,3 +14,5 @@ ATTR_END_DATE = "end_date"
|
|||||||
ATTR_RECIPE_ID = "recipe_id"
|
ATTR_RECIPE_ID = "recipe_id"
|
||||||
ATTR_URL = "url"
|
ATTR_URL = "url"
|
||||||
ATTR_INCLUDE_TAGS = "include_tags"
|
ATTR_INCLUDE_TAGS = "include_tags"
|
||||||
|
|
||||||
|
MIN_REQUIRED_MEALIE_VERSION = AwesomeVersion("v1.0.0")
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
"error": {
|
"error": {
|
||||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
"unknown": "[%key:common::config_flow::error::unknown%]",
|
||||||
|
"mealie_version": "Minimum required version is v1.0.0. Please upgrade Mealie and then retry."
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
|
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
|
||||||
@ -66,6 +67,9 @@
|
|||||||
},
|
},
|
||||||
"item_not_found_error": {
|
"item_not_found_error": {
|
||||||
"message": "Item {shopping_list_item} not found."
|
"message": "Item {shopping_list_item} not found."
|
||||||
|
},
|
||||||
|
"version_error": {
|
||||||
|
"message": "You are running {mealie_version} of Mealie. Minimum required version is {min_version}. Please upgrade Mealie and then retry."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
10
homeassistant/components/mealie/utils.py
Normal file
10
homeassistant/components/mealie/utils.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
"""Mealie util functions."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from awesomeversion import AwesomeVersion
|
||||||
|
|
||||||
|
|
||||||
|
def create_version(version: str) -> AwesomeVersion:
|
||||||
|
"""Convert beta versions to PEP440."""
|
||||||
|
return AwesomeVersion(version.replace("beta-", "b"))
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from unittest.mock import AsyncMock
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
from aiomealie import MealieAuthenticationError, MealieConnectionError
|
from aiomealie import About, MealieAuthenticationError, MealieConnectionError
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.mealie.const import DOMAIN
|
from homeassistant.components.mealie.const import DOMAIN
|
||||||
@ -83,6 +83,40 @@ async def test_flow_errors(
|
|||||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("version"),
|
||||||
|
[
|
||||||
|
("v1.0.0beta-5"),
|
||||||
|
("v1.0.0-RC2"),
|
||||||
|
("v0.1.0"),
|
||||||
|
("something"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_flow_version_error(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_mealie_client: AsyncMock,
|
||||||
|
mock_setup_entry: AsyncMock,
|
||||||
|
version,
|
||||||
|
) -> None:
|
||||||
|
"""Test flow version error."""
|
||||||
|
mock_mealie_client.get_about.return_value = About(version=version)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": SOURCE_USER},
|
||||||
|
)
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{CONF_HOST: "demo.mealie.io", CONF_API_TOKEN: "token"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["errors"] == {"base": "mealie_version"}
|
||||||
|
|
||||||
|
|
||||||
async def test_duplicate(
|
async def test_duplicate(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_mealie_client: AsyncMock,
|
mock_mealie_client: AsyncMock,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from unittest.mock import AsyncMock
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
from aiomealie import MealieAuthenticationError, MealieConnectionError
|
from aiomealie import About, MealieAuthenticationError, MealieConnectionError
|
||||||
import pytest
|
import pytest
|
||||||
from syrupy import SnapshotAssertion
|
from syrupy import SnapshotAssertion
|
||||||
|
|
||||||
@ -32,6 +32,51 @@ async def test_device_info(
|
|||||||
assert device_entry == snapshot
|
assert device_entry == snapshot
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("exc", "state"),
|
||||||
|
[
|
||||||
|
(MealieConnectionError, ConfigEntryState.SETUP_RETRY),
|
||||||
|
(MealieAuthenticationError, ConfigEntryState.SETUP_ERROR),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_setup_failure(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_mealie_client: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
exc: Exception,
|
||||||
|
state: ConfigEntryState,
|
||||||
|
) -> None:
|
||||||
|
"""Test setup failure."""
|
||||||
|
mock_mealie_client.get_about.side_effect = exc
|
||||||
|
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
assert mock_config_entry.state is state
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("version"),
|
||||||
|
[
|
||||||
|
("v1.0.0beta-5"),
|
||||||
|
("v1.0.0-RC2"),
|
||||||
|
("v0.1.0"),
|
||||||
|
("something"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_setup_too_old(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_mealie_client: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
version,
|
||||||
|
) -> None:
|
||||||
|
"""Test setup of Mealie entry with too old version of Mealie."""
|
||||||
|
mock_mealie_client.get_about.return_value = About(version=version)
|
||||||
|
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR
|
||||||
|
|
||||||
|
|
||||||
async def test_load_unload_entry(
|
async def test_load_unload_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_mealie_client: AsyncMock,
|
mock_mealie_client: AsyncMock,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user