Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add minor version to config entries #105479

Merged
merged 8 commits into from Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 11 additions & 1 deletion homeassistant/config_entries.py
Expand Up @@ -205,6 +205,7 @@ class ConfigEntry:
__slots__ = (
"entry_id",
"version",
"minor_version",
"domain",
"title",
"data",
Expand Down Expand Up @@ -233,7 +234,9 @@ class ConfigEntry:

def __init__(
self,
*,
version: int,
minor_version: int,
domain: str,
title: str,
data: Mapping[str, Any],
Expand All @@ -252,6 +255,7 @@ def __init__(

# Version of the configuration.
self.version = version
self.minor_version = minor_version

# Domain the configuration belongs to
self.domain = domain
Expand Down Expand Up @@ -631,14 +635,17 @@ async def async_migrate(self, hass: HomeAssistant) -> bool:
while isinstance(handler, functools.partial):
handler = handler.func # type: ignore[unreachable]

if self.version == handler.VERSION:
same_major_version = self.version == handler.VERSION
if same_major_version and self.minor_version == handler.MINOR_VERSION:
return True

if not (integration := self._integration_for_domain):
integration = await loader.async_get_integration(hass, self.domain)
component = integration.get_component()
supports_migrate = hasattr(component, "async_migrate_entry")
if not supports_migrate:
if same_major_version:
return True
_LOGGER.error(
"Migration handler not found for entry %s for %s",
self.title,
Expand Down Expand Up @@ -676,6 +683,7 @@ def as_dict(self) -> dict[str, Any]:
return {
"entry_id": self.entry_id,
"version": self.version,
"minor_version": self.minor_version,
"domain": self.domain,
"title": self.title,
"data": dict(self.data),
Expand Down Expand Up @@ -974,6 +982,7 @@ async def async_finish_flow(

entry = ConfigEntry(
version=result["version"],
minor_version=result["minor_version"],
domain=result["handler"],
title=result["title"],
data=result["data"],
Expand Down Expand Up @@ -1196,6 +1205,7 @@ async def async_initialize(self) -> None:

config_entry = ConfigEntry(
version=entry["version"],
minor_version=entry.get("minor_version", 1),
domain=domain,
entry_id=entry_id,
data=entry["data"],
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/data_entry_flow.py
Expand Up @@ -94,6 +94,7 @@ class FlowResult(TypedDict, total=False):
handler: Required[str]
last_step: bool | None
menu_options: list[str] | dict[str, str]
minor_version: int
options: Mapping[str, Any]
preview: str | None
progress_action: str
Expand Down Expand Up @@ -470,6 +471,7 @@ class FlowHandler:

# Set by developer
VERSION = 1
MINOR_VERSION = 1
joostlek marked this conversation as resolved.
Show resolved Hide resolved

@property
def source(self) -> str | None:
Expand Down Expand Up @@ -549,6 +551,7 @@ def async_create_entry(
"""Finish flow."""
flow_result = FlowResult(
version=self.VERSION,
minor_version=self.MINOR_VERSION,
type=FlowResultType.CREATE_ENTRY,
flow_id=self.flow_id,
handler=self.handler,
Expand Down
2 changes: 2 additions & 0 deletions tests/common.py
Expand Up @@ -890,6 +890,7 @@ def __init__(
domain="test",
data=None,
version=1,
minor_version=1,
entry_id=None,
source=config_entries.SOURCE_USER,
title="Mock Title",
Expand All @@ -910,6 +911,7 @@ def __init__(
"pref_disable_polling": pref_disable_polling,
"options": options,
"version": version,
"minor_version": minor_version,
"title": title,
"unique_id": unique_id,
"disabled_by": disabled_by,
Expand Down
1 change: 1 addition & 0 deletions tests/components/airly/snapshots/test_diagnostics.ambr
Expand Up @@ -11,6 +11,7 @@
'disabled_by': None,
'domain': 'airly',
'entry_id': '3bd2acb0e4f0476d40865546d0d91921',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
1 change: 1 addition & 0 deletions tests/components/airnow/snapshots/test_diagnostics.ambr
Expand Up @@ -26,6 +26,7 @@
'disabled_by': None,
'domain': 'airnow',
'entry_id': '3bd2acb0e4f0476d40865546d0d91921',
'minor_version': 1,
'options': dict({
'radius': 150,
}),
Expand Down
Expand Up @@ -38,6 +38,7 @@
'disabled_by': None,
'domain': 'airvisual',
'entry_id': '3bd2acb0e4f0476d40865546d0d91921',
'minor_version': 1,
'options': dict({
'show_on_map': True,
}),
Expand Down
Expand Up @@ -93,6 +93,7 @@
'disabled_by': None,
'domain': 'airvisual_pro',
'entry_id': '6a2b3770e53c28dc1eeb2515e906b0ce',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
1 change: 1 addition & 0 deletions tests/components/airzone/snapshots/test_diagnostics.ambr
Expand Up @@ -240,6 +240,7 @@
'disabled_by': None,
'domain': 'airzone',
'entry_id': '6e7a0798c1734ba81d26ced0e690eaec',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
Expand Up @@ -93,6 +93,7 @@
'disabled_by': None,
'domain': 'airzone_cloud',
'entry_id': 'd186e31edb46d64d14b9b2f11f1ebd9f',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
Expand Up @@ -9,6 +9,7 @@
'disabled_by': None,
'domain': 'ambient_station',
'entry_id': '382cf7643f016fd48b3fe52163fe8877',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
1 change: 1 addition & 0 deletions tests/components/axis/snapshots/test_diagnostics.ambr
Expand Up @@ -41,6 +41,7 @@
'disabled_by': None,
'domain': 'axis',
'entry_id': '676abe5b73621446e6550a2e86ffe3dd',
'minor_version': 1,
'options': dict({
'events': True,
}),
Expand Down
1 change: 1 addition & 0 deletions tests/components/blink/snapshots/test_diagnostics.ambr
Expand Up @@ -38,6 +38,7 @@
}),
'disabled_by': None,
'domain': 'blink',
'minor_version': 1,
'options': dict({
'scan_interval': 300,
}),
Expand Down
1 change: 1 addition & 0 deletions tests/components/cloud/test_repairs.py
Expand Up @@ -154,6 +154,7 @@ async def test_legacy_subscription_repair_flow(
"handler": DOMAIN,
"description": None,
"description_placeholders": None,
"minor_version": 1,
}

assert not issue_registry.async_get_issue(
Expand Down
Expand Up @@ -9,6 +9,7 @@
'disabled_by': None,
'domain': 'co2signal',
'entry_id': '904a74160aa6f335526706bee85dfb83',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
1 change: 1 addition & 0 deletions tests/components/coinbase/snapshots/test_diagnostics.ambr
Expand Up @@ -47,6 +47,7 @@
'disabled_by': None,
'domain': 'coinbase',
'entry_id': '080272b77a4f80c41b94d7cdc86fd826',
'minor_version': 1,
'options': dict({
'account_balance_currencies': list([
]),
Expand Down
3 changes: 3 additions & 0 deletions tests/components/config/test_config_entries.py
Expand Up @@ -532,6 +532,7 @@ async def async_step_user(self, user_input=None):
"description": None,
"description_placeholders": None,
"options": {},
"minor_version": 1,
}


Expand Down Expand Up @@ -609,6 +610,7 @@ async def async_step_account(self, user_input=None):
"description": None,
"description_placeholders": None,
"options": {},
"minor_version": 1,
}


Expand Down Expand Up @@ -942,6 +944,7 @@ async def async_step_finish(self, user_input=None):
"version": 1,
"description": None,
"description_placeholders": None,
"minor_version": 1,
}


Expand Down
1 change: 1 addition & 0 deletions tests/components/deconz/snapshots/test_diagnostics.ambr
Expand Up @@ -12,6 +12,7 @@
'disabled_by': None,
'domain': 'deconz',
'entry_id': '1',
'minor_version': 1,
'options': dict({
'master': True,
}),
Expand Down
Expand Up @@ -40,6 +40,7 @@
'disabled_by': None,
'domain': 'devolo_home_control',
'entry_id': '123456',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
Expand Up @@ -24,6 +24,7 @@
'disabled_by': None,
'domain': 'devolo_home_network',
'entry_id': '123456',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
6 changes: 6 additions & 0 deletions tests/components/elgato/snapshots/test_config_flow.ambr
Expand Up @@ -14,6 +14,7 @@
'description_placeholders': None,
'flow_id': <ANY>,
'handler': 'elgato',
'minor_version': 1,
'options': dict({
}),
'result': ConfigEntrySnapshot({
Expand All @@ -25,6 +26,7 @@
'disabled_by': None,
'domain': 'elgato',
'entry_id': <ANY>,
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down Expand Up @@ -55,6 +57,7 @@
'description_placeholders': None,
'flow_id': <ANY>,
'handler': 'elgato',
'minor_version': 1,
'options': dict({
}),
'result': ConfigEntrySnapshot({
Expand All @@ -66,6 +69,7 @@
'disabled_by': None,
'domain': 'elgato',
'entry_id': <ANY>,
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down Expand Up @@ -95,6 +99,7 @@
'description_placeholders': None,
'flow_id': <ANY>,
'handler': 'elgato',
'minor_version': 1,
'options': dict({
}),
'result': ConfigEntrySnapshot({
Expand All @@ -106,6 +111,7 @@
'disabled_by': None,
'domain': 'elgato',
'entry_id': <ANY>,
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
2 changes: 2 additions & 0 deletions tests/components/energyzero/snapshots/test_config_flow.ambr
Expand Up @@ -11,6 +11,7 @@
'description_placeholders': None,
'flow_id': <ANY>,
'handler': 'energyzero',
'minor_version': 1,
'options': dict({
}),
'result': ConfigEntrySnapshot({
Expand All @@ -19,6 +20,7 @@
'disabled_by': None,
'domain': 'energyzero',
'entry_id': <ANY>,
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
Expand Up @@ -15,6 +15,7 @@
'disabled_by': None,
'domain': 'enphase_envoy',
'entry_id': '45a36e55aaddb2007c5f6602e0c38e72',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
1 change: 1 addition & 0 deletions tests/components/esphome/snapshots/test_diagnostics.ambr
Expand Up @@ -12,6 +12,7 @@
'disabled_by': None,
'domain': 'esphome',
'entry_id': '08d821dc059cf4f645cb024d32c8e708',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
1 change: 1 addition & 0 deletions tests/components/forecast_solar/snapshots/test_init.ambr
Expand Up @@ -8,6 +8,7 @@
'disabled_by': None,
'domain': 'forecast_solar',
'entry_id': <ANY>,
'minor_version': 1,
'options': dict({
'api_key': 'abcdef12345',
'azimuth': 190,
Expand Down
Expand Up @@ -31,6 +31,7 @@
'description_placeholders': None,
'flow_id': <ANY>,
'handler': 'gardena_bluetooth',
'minor_version': 1,
'options': dict({
}),
'result': ConfigEntrySnapshot({
Expand All @@ -40,6 +41,7 @@
'disabled_by': None,
'domain': 'gardena_bluetooth',
'entry_id': <ANY>,
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down Expand Up @@ -238,6 +240,7 @@
'description_placeholders': None,
'flow_id': <ANY>,
'handler': 'gardena_bluetooth',
'minor_version': 1,
'options': dict({
}),
'result': ConfigEntrySnapshot({
Expand All @@ -247,6 +250,7 @@
'disabled_by': None,
'domain': 'gardena_bluetooth',
'entry_id': <ANY>,
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
1 change: 1 addition & 0 deletions tests/components/gios/snapshots/test_diagnostics.ambr
Expand Up @@ -9,6 +9,7 @@
'disabled_by': None,
'domain': 'gios',
'entry_id': '86129426118ae32020417a53712d6eef',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
Expand Up @@ -7,6 +7,7 @@
}),
'disabled_by': None,
'domain': 'google_assistant',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
Expand Down
1 change: 1 addition & 0 deletions tests/components/guardian/test_diagnostics.py
Expand Up @@ -23,6 +23,7 @@ async def test_entry_diagnostics(
"entry": {
"entry_id": config_entry.entry_id,
"version": 1,
"minor_version": 1,
"domain": "guardian",
"title": REDACTED,
"data": {
Expand Down