Skip to content

Commit 125f41e

Browse files
committed
Use latest known Core version as reference
Instead of using current date to determine if Core version is more than 2 years old, use the latest known Core version as reference point and check if current version is more than 24 releases behind. This is crucial because when update information refresh is disabled due to unsupported Core version, using date would create a permanent unsupported state. Even if users update to the last known version in 4+ years, the system would remain unsupported. By using latest known version as reference, updating Core to the last known version makes the system supported again, allowing update information refresh to resume. This ensures users can always escape the unsupported state by updating to the last known Core version, maintaining the update refresh cycle.
1 parent ed5b1b3 commit 125f41e

File tree

2 files changed

+56
-35
lines changed

2 files changed

+56
-35
lines changed

supervisor/resolution/evaluations/core_version.py

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Evaluation class for Core version."""
22

3-
from datetime import datetime, timedelta
43
import logging
54

65
from awesomeversion import (
@@ -43,25 +42,44 @@ def states(self) -> list[CoreState]:
4342

4443
async def evaluate(self) -> bool:
4544
"""Run evaluation."""
46-
if not (current := self.sys_homeassistant.version):
45+
if not (current := self.sys_homeassistant.version) or not (
46+
latest := self.sys_homeassistant.latest_version
47+
):
4748
return False
4849

4950
# Skip evaluation for landingpage version
5051
if current == LANDINGPAGE:
5152
return False
5253

5354
try:
54-
# Calculate if the current version was released more than 2 years ago
55-
# Home Assistant releases happen monthly, so approximately 24 versions per 2 years
56-
# However, we'll be more precise and check based on actual version numbers
57-
# Home Assistant uses CalVer versioning scheme like 2024.1, 2024.2, etc.
58-
59-
# Calculate 2 years ago from now
60-
two_years_ago = datetime.now() - timedelta(days=730) # 2 years = 730 days
61-
cutoff_year = two_years_ago.year
62-
cutoff_month = two_years_ago.month
63-
64-
# Create a cutoff version based on the date 2 years ago
55+
# We use the latest known version as reference instead of current date.
56+
# This is crucial because when update information refresh is disabled due to
57+
# unsupported Core version, using date would create a permanent unsupported state.
58+
# Even if the user updates to the last known version, the system would remain
59+
# unsupported in 4+ years. By using latest known version, updating Core to the
60+
# last known version makes the system supported again, allowing update refresh.
61+
#
62+
# Home Assistant uses CalVer versioning (2024.1, 2024.2, etc.) with monthly releases.
63+
# We consider versions more than 24 releases (approximately 2 years) behind as unsupported.
64+
65+
# Extract year and month from latest version to calculate cutoff
66+
latest_parts = str(latest).split(".")
67+
if len(latest_parts) < 2:
68+
return True # Invalid latest version format
69+
70+
latest_year = int(latest_parts[0])
71+
latest_month = int(latest_parts[1])
72+
73+
# Calculate 24 months back from latest version
74+
cutoff_month = latest_month - 24
75+
cutoff_year = latest_year
76+
77+
# Handle year rollover
78+
while cutoff_month <= 0:
79+
cutoff_month += 12
80+
cutoff_year -= 1
81+
82+
# Create cutoff version
6583
cutoff_version = AwesomeVersion(
6684
f"{cutoff_year}.{cutoff_month}",
6785
ensure_strategy=AwesomeVersionStrategy.CALVER,
@@ -70,12 +88,12 @@ async def evaluate(self) -> bool:
7088
# Compare current version with the cutoff
7189
return current < cutoff_version
7290

73-
except AwesomeVersionException as err:
91+
except (AwesomeVersionException, ValueError, IndexError) as err:
7492
# This is run regularly, avoid log spam by logging at debug level
7593
_LOGGER.debug(
76-
"Failed to parse Home Assistant version '%s' or cutoff version '%s': %s",
94+
"Failed to parse Home Assistant version '%s' or latest version '%s': %s",
7795
current,
78-
cutoff_version,
96+
latest,
7997
err,
8098
)
8199
# Consider non-parseable versions as unsupported

tests/resolution/evaluation/test_evaluate_core_version.py

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Test Core Version evaluation."""
22

3-
from datetime import datetime
43
from unittest.mock import PropertyMock, patch
54

65
from awesomeversion import AwesomeVersion
@@ -14,23 +13,29 @@
1413

1514

1615
@pytest.mark.parametrize(
17-
"current,expected",
16+
"current,latest,expected",
1817
[
19-
("2022.1.0", True), # More than 2 years old, should be unsupported
20-
("2023.12.0", False), # Less than 2 years old, should be supported
21-
(f"{datetime.now().year}.1", False), # Current year, supported
22-
(f"{datetime.now().year - 1}.12", False), # 1 year old, supported
23-
(f"{datetime.now().year - 2}.1", True), # 2 years old, unsupported
24-
(f"{datetime.now().year - 3}.1", True), # 3 years old, unsupported
25-
("2021.6.0", True), # Very old version, unsupported
26-
("0.116.4", True), # Old version scheme, should be unsupported
27-
("0.118.1", True), # Old version scheme, should be unsupported
28-
("landingpage", False), # Landingpage version, should be supported
29-
(None, False), # No current version info, check skipped
18+
("2022.1.0", "2024.12.0", True), # More than 24 versions behind, unsupported
19+
("2023.1.0", "2024.12.0", False), # Less than 24 versions behind, supported
20+
("2024.1.0", "2024.12.0", False), # Recent version, supported
21+
("2024.12.0", "2024.12.0", False), # Same as latest, supported
22+
("2024.11.0", "2024.12.0", False), # 1 month behind, supported
23+
(
24+
"2022.12.0",
25+
"2024.12.0",
26+
False,
27+
), # Exactly 24 months behind, supported (boundary)
28+
("2022.11.0", "2024.12.0", True), # More than 24 months behind, unsupported
29+
("2021.6.0", "2024.12.0", True), # Very old version, unsupported
30+
("0.116.4", "2024.12.0", True), # Old version scheme, should be unsupported
31+
("0.118.1", "2024.12.0", True), # Old version scheme, should be unsupported
32+
("landingpage", "2024.12.0", False), # Landingpage version, should be supported
33+
(None, "2024.12.0", False), # No current version info, check skipped
34+
("2024.1.0", None, False), # No latest version info, check skipped
3035
],
3136
)
3237
async def test_core_version_evaluation(
33-
coresys: CoreSys, current: str | None, expected: bool
38+
coresys: CoreSys, current: str | None, latest: str | None, expected: bool
3439
):
3540
"""Test evaluation logic on Core versions."""
3641
evaluation = EvaluateCoreVersion(coresys)
@@ -45,9 +50,7 @@ async def test_core_version_evaluation(
4550
patch.object(
4651
HomeAssistant,
4752
"latest_version",
48-
new=PropertyMock(
49-
return_value=AwesomeVersion("2024.12.0")
50-
), # Mock latest version
53+
new=PropertyMock(return_value=latest and AwesomeVersion(latest)),
5154
),
5255
):
5356
assert evaluation.reason not in coresys.resolution.unsupported
@@ -74,8 +77,8 @@ async def test_core_version_evaluation_no_latest(coresys: CoreSys):
7477
):
7578
assert evaluation.reason not in coresys.resolution.unsupported
7679
await evaluation()
77-
# Without latest version info, old versions should be marked as unsupported
78-
assert evaluation.reason in coresys.resolution.unsupported
80+
# Without latest version info, evaluation should be skipped (not run)
81+
assert evaluation.reason not in coresys.resolution.unsupported
7982

8083

8184
async def test_core_version_invalid_format(coresys: CoreSys):

0 commit comments

Comments
 (0)