mirror of
https://github.com/TagStudioDev/TagStudio.git
synced 2026-05-09 22:03:51 +00:00
fix: catch update notification exceptions (#1278)
* feat: add test for failing GitHub API call. * fix: don't raise exceptions in get_most_recent_release_version. * style: apply ruff. * That not should not have been there.
This commit is contained in:
@@ -46,6 +46,7 @@ pyinstaller = ["Pyinstaller~=6.13"]
|
||||
pytest = [
|
||||
"pytest==8.3.5",
|
||||
"pytest-cov==6.1.1",
|
||||
"pytest-mock==3.15.1",
|
||||
"pytest-qt==4.4.0",
|
||||
"syrupy==4.9.1",
|
||||
]
|
||||
|
||||
@@ -193,18 +193,31 @@ class TagStudioCore:
|
||||
|
||||
@staticmethod
|
||||
@lru_cache(maxsize=1)
|
||||
def get_most_recent_release_version() -> str:
|
||||
"""Get the version of the most recent Github release."""
|
||||
resp = requests.get("https://api.github.com/repos/TagStudioDev/TagStudio/releases/latest")
|
||||
assert resp.status_code == 200, "Could not fetch information on latest release."
|
||||
def get_most_recent_release_version() -> str | None:
|
||||
"""Get the version of the most recent GitHub release."""
|
||||
try:
|
||||
resp = requests.get(
|
||||
"https://api.github.com/repos/TagStudioDev/TagStudio/releases/latest"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Error getting most recent GitHub release.", error=e)
|
||||
return None
|
||||
|
||||
if resp.status_code != 200:
|
||||
logger.error("Error getting most recent GitHub release.", status_code=resp.status_code)
|
||||
return None
|
||||
|
||||
data = resp.json()
|
||||
tag: str = data["tag_name"]
|
||||
assert tag.startswith("v")
|
||||
if not tag.startswith("v"):
|
||||
logger.error("Unexpected tag format.", tag=tag)
|
||||
return None
|
||||
|
||||
version = tag[1:]
|
||||
# the assert does not allow for prerelease/build,
|
||||
# the assertion does not allow for prerelease/build,
|
||||
# because the latest release should never have them
|
||||
assert re.match(r"^\d+\.\d+\.\d+$", version) is not None, "Invalid version format."
|
||||
if re.match(r"^\d+\.\d+\.\d+$", version) is None:
|
||||
logger.error("Invalid version format.", version=version)
|
||||
return None
|
||||
|
||||
return version
|
||||
|
||||
@@ -4,6 +4,7 @@ from PySide6.QtWidgets import QMessageBox
|
||||
|
||||
from tagstudio.core.constants import VERSION
|
||||
from tagstudio.core.ts_core import TagStudioCore
|
||||
from tagstudio.core.utils.types import unwrap
|
||||
from tagstudio.qt.models.palette import ColorType, UiColor, get_ui_color
|
||||
from tagstudio.qt.translations import Translations
|
||||
|
||||
@@ -30,7 +31,7 @@ class OutOfDateMessageBox(QMessageBox):
|
||||
|
||||
red = get_ui_color(ColorType.PRIMARY, UiColor.RED)
|
||||
green = get_ui_color(ColorType.PRIMARY, UiColor.GREEN)
|
||||
latest_release_version = TagStudioCore.get_most_recent_release_version()
|
||||
latest_release_version = unwrap(TagStudioCore.get_most_recent_release_version())
|
||||
status = Translations.format(
|
||||
"version_modal.status",
|
||||
installed_version=f"<span style='color:{red}'>{VERSION}</span>",
|
||||
|
||||
@@ -21,6 +21,7 @@ from PySide6.QtWidgets import (
|
||||
from tagstudio.core.constants import VERSION, VERSION_BRANCH
|
||||
from tagstudio.core.enums import Theme
|
||||
from tagstudio.core.ts_core import TagStudioCore
|
||||
from tagstudio.core.utils.types import unwrap
|
||||
from tagstudio.qt.models.palette import ColorType, UiColor, get_ui_color
|
||||
from tagstudio.qt.previews.vendored import ffmpeg
|
||||
from tagstudio.qt.resource_manager import ResourceManager
|
||||
@@ -106,7 +107,7 @@ class AboutModal(QWidget):
|
||||
|
||||
# Version
|
||||
version_title = QLabel("Version")
|
||||
most_recent_release = TagStudioCore.get_most_recent_release_version()
|
||||
most_recent_release = unwrap(TagStudioCore.get_most_recent_release_version(), "UNKNOWN")
|
||||
version_content_style = self.form_content_style
|
||||
if most_recent_release == VERSION:
|
||||
version_content = QLabel(f"{VERSION}")
|
||||
|
||||
@@ -613,7 +613,8 @@ class QtDriver(DriverMixin, QObject):
|
||||
if not which(FFMPEG_CMD) or not which(FFPROBE_CMD):
|
||||
FfmpegMissingMessageBox().show()
|
||||
|
||||
if is_version_outdated(VERSION, TagStudioCore.get_most_recent_release_version()):
|
||||
latest_version = TagStudioCore.get_most_recent_release_version()
|
||||
if latest_version and is_version_outdated(VERSION, latest_version):
|
||||
OutOfDateMessageBox().exec()
|
||||
|
||||
self.app.exec()
|
||||
|
||||
14
tests/qt/test_about_modal.py
Normal file
14
tests/qt/test_about_modal.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from pytestqt.qtbot import QtBot
|
||||
|
||||
from tagstudio.qt.mixed.about_modal import AboutModal
|
||||
|
||||
|
||||
def test_github_api_unavailable(qtbot: QtBot, mocker) -> None:
|
||||
mocker.patch(
|
||||
"requests.get",
|
||||
side_effect=ConnectionError(
|
||||
"Failed to resolve 'api.github.com' ([Errno -3] Temporary failure in name resolution)"
|
||||
),
|
||||
)
|
||||
modal = AboutModal("/tmp")
|
||||
qtbot.addWidget(modal)
|
||||
Reference in New Issue
Block a user