Addon devs can block auto update for breaking versions (#4832)
This commit is contained in:
parent
d24543e103
commit
ddadbec7e3
|
@ -15,6 +15,7 @@ from tempfile import TemporaryDirectory
|
|||
from typing import Any, Final
|
||||
|
||||
import aiohttp
|
||||
from awesomeversion import AwesomeVersionCompareException
|
||||
from deepmerge import Merger
|
||||
from securetar import atomic_contents_add, secure_path
|
||||
import voluptuous as vol
|
||||
|
@ -279,6 +280,28 @@ class Addon(AddonModel):
|
|||
"""Set auto update."""
|
||||
self.persist[ATTR_AUTO_UPDATE] = value
|
||||
|
||||
@property
|
||||
def auto_update_available(self) -> bool:
|
||||
"""Return if it is safe to auto update addon."""
|
||||
if not self.need_update or not self.auto_update:
|
||||
return False
|
||||
|
||||
for version in self.breaking_versions:
|
||||
try:
|
||||
# Must update to latest so if true update crosses a breaking version
|
||||
if self.version < version:
|
||||
return False
|
||||
except AwesomeVersionCompareException:
|
||||
# If version scheme changed, we may get compare exception
|
||||
# If latest version >= breaking version then assume update will
|
||||
# cross it as the version scheme changes
|
||||
# If both versions have compare exception, ignore as its in the past
|
||||
with suppress(AwesomeVersionCompareException):
|
||||
if self.latest_version >= version:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@property
|
||||
def watchdog(self) -> bool:
|
||||
"""Return True if watchdog is enable."""
|
||||
|
|
|
@ -28,6 +28,7 @@ class MappingType(StrEnum):
|
|||
|
||||
|
||||
ATTR_BACKUP = "backup"
|
||||
ATTR_BREAKING_VERSIONS = "breaking_versions"
|
||||
ATTR_CODENOTARY = "codenotary"
|
||||
ATTR_READ_ONLY = "read_only"
|
||||
ATTR_PATH = "path"
|
||||
|
|
|
@ -90,6 +90,7 @@ from ..utils import version_is_new_enough
|
|||
from .configuration import FolderMapping
|
||||
from .const import (
|
||||
ATTR_BACKUP,
|
||||
ATTR_BREAKING_VERSIONS,
|
||||
ATTR_CODENOTARY,
|
||||
ATTR_PATH,
|
||||
ATTR_READ_ONLY,
|
||||
|
@ -620,6 +621,11 @@ class AddonModel(JobGroup, ABC):
|
|||
"""Return Signer email address for CAS."""
|
||||
return self.data.get(ATTR_CODENOTARY)
|
||||
|
||||
@property
|
||||
def breaking_versions(self) -> list[AwesomeVersion]:
|
||||
"""Return breaking versions of addon."""
|
||||
return self.data[ATTR_BREAKING_VERSIONS]
|
||||
|
||||
def validate_availability(self) -> None:
|
||||
"""Validate if addon is available for current system."""
|
||||
return self._validate_availability(self.data, logger=_LOGGER.error)
|
||||
|
|
|
@ -112,6 +112,7 @@ from ..validate import (
|
|||
)
|
||||
from .const import (
|
||||
ATTR_BACKUP,
|
||||
ATTR_BREAKING_VERSIONS,
|
||||
ATTR_CODENOTARY,
|
||||
ATTR_PATH,
|
||||
ATTR_READ_ONLY,
|
||||
|
@ -422,6 +423,7 @@ _SCHEMA_ADDON_CONFIG = vol.Schema(
|
|||
vol.Coerce(int), vol.Range(min=10, max=300)
|
||||
),
|
||||
vol.Optional(ATTR_JOURNALD, default=False): vol.Boolean(),
|
||||
vol.Optional(ATTR_BREAKING_VERSIONS, default=list): [version_tag],
|
||||
},
|
||||
extra=vol.REMOVE_EXTRA,
|
||||
)
|
||||
|
|
|
@ -95,6 +95,14 @@ class Tasks(CoreSysAttributes):
|
|||
# Evaluate available updates
|
||||
if not addon.need_update:
|
||||
continue
|
||||
if not addon.auto_update_available:
|
||||
_LOGGER.debug(
|
||||
"Not updating add-on %s from %s to %s as that would cross a known breaking version",
|
||||
addon.slug,
|
||||
addon.version,
|
||||
addon.latest_version,
|
||||
)
|
||||
continue
|
||||
if not addon.test_update_schema():
|
||||
_LOGGER.warning(
|
||||
"Add-on %s will be ignored, schema tests failed", addon.slug
|
||||
|
|
|
@ -6,6 +6,7 @@ import errno
|
|||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, PropertyMock, patch
|
||||
|
||||
from awesomeversion import AwesomeVersion
|
||||
from docker.errors import DockerException, NotFound
|
||||
import pytest
|
||||
from securetar import SecureTarFile
|
||||
|
@ -721,3 +722,29 @@ def test_addon_pulse_error(
|
|||
|
||||
assert "can't write pulse/client.config" in caplog.text
|
||||
assert coresys.core.healthy is False
|
||||
|
||||
|
||||
def test_auto_update_available(coresys: CoreSys, install_addon_example: Addon):
|
||||
"""Test auto update availability based on versions."""
|
||||
assert install_addon_example.auto_update is False
|
||||
assert install_addon_example.need_update is False
|
||||
assert install_addon_example.auto_update_available is False
|
||||
|
||||
with patch.object(
|
||||
Addon, "version", new=PropertyMock(return_value=AwesomeVersion("1.0"))
|
||||
):
|
||||
assert install_addon_example.need_update is True
|
||||
assert install_addon_example.auto_update_available is False
|
||||
|
||||
install_addon_example.auto_update = True
|
||||
assert install_addon_example.auto_update_available is True
|
||||
|
||||
with patch.object(
|
||||
Addon, "version", new=PropertyMock(return_value=AwesomeVersion("0.9"))
|
||||
):
|
||||
assert install_addon_example.auto_update_available is False
|
||||
|
||||
with patch.object(
|
||||
Addon, "version", new=PropertyMock(return_value=AwesomeVersion("test"))
|
||||
):
|
||||
assert install_addon_example.auto_update_available is False
|
||||
|
|
|
@ -20,3 +20,6 @@ schema:
|
|||
message: "str?"
|
||||
ingress: true
|
||||
ingress_port: 0
|
||||
breaking_versions:
|
||||
- test
|
||||
- 1.0
|
||||
|
|
Loading…
Reference in New Issue