Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 46 additions & 19 deletions astrbot/core/zip_updator.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,36 +234,63 @@ def compare_version(self, v1: str, v2: str) -> int:
"""Semver 版本比较"""
return VersionComparator.compare_version(v1, v2)

def _is_prerelease_version(self, version: str) -> bool:
"""Check if a version string is a prerelease version."""
return bool(
re.search(
r"[\-_.]?(alpha|beta|rc|dev)[\-_.]?\d*$",
version,
re.IGNORECASE,
)
)

def _matches_prerelease_policy(
self,
release: dict,
consider_prerelease: bool,
) -> bool:
"""Return whether a release is allowed by the prerelease policy."""
return consider_prerelease or not self._is_prerelease_version(
release["tag_name"],
)

def _select_release_data(
self,
releases: list,
consider_prerelease: bool,
) -> dict | None:
"""Select the first release allowed by the prerelease policy."""
return next(
(
release
for release in releases
if self._matches_prerelease_policy(release, consider_prerelease)
),
None,
)

def _has_newer_version(self, current_version: str, release_version: str) -> bool:
"""Return whether the selected release is newer than current version."""
return self.compare_version(current_version, release_version) < 0

async def check_update(
self,
url: str,
current_version: str,
consider_prerelease: bool = True,
) -> ReleaseInfo | None:
update_data = await self.fetch_release_info(url)
if not update_data:
logger.error("未找到合适的发布版本")
return None

sel_release_data = None
if consider_prerelease:
tag_name = update_data[0]["tag_name"]
sel_release_data = update_data[0]
else:
for data in update_data:
# 跳过带有 alpha、beta 等预发布标签的版本
if re.search(
r"[\-_.]?(alpha|beta|rc|dev)[\-_.]?\d*$",
data["tag_name"],
re.IGNORECASE,
):
continue
tag_name = data["tag_name"]
sel_release_data = data
break

if not sel_release_data or not tag_name:
sel_release_data = self._select_release_data(update_data, consider_prerelease)
if not sel_release_data:
logger.error("未找到合适的发布版本")
return None

if self.compare_version(current_version, tag_name) >= 0:
tag_name = sel_release_data["tag_name"]
if not self._has_newer_version(current_version, tag_name):
return None
return ReleaseInfo(
version=tag_name,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_updator_socks.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,41 @@ async def fake_download_from_repo_url(
assert marker_path.read_text(encoding="utf-8") == "VALUE = 'old'\n"


@pytest.mark.asyncio
async def test_check_update_skips_stable_when_current_prerelease_is_newer(
monkeypatch: pytest.MonkeyPatch,
) -> None:
updator = RepoZipUpdator()

async def fake_fetch_release_info(url: str, latest: bool = True): # noqa: ARG001
return [
{
"version": "AstrBot v4.26.0-beta.1",
"published_at": "2026-06-20T00:00:00Z",
"body": "beta",
"tag_name": "v4.26.0-beta.1",
"zipball_url": "https://github.example/beta.zip",
},
{
"version": "AstrBot v4.25.6",
"published_at": "2026-06-19T00:00:00Z",
"body": "stable",
"tag_name": "v4.25.6",
"zipball_url": "https://github.example/stable.zip",
},
]

monkeypatch.setattr(updator, "fetch_release_info", fake_fetch_release_info)

result = await updator.check_update(
"https://example.invalid/releases",
current_version="v4.26.0-dev",
consider_prerelease=False,
)

assert result is None


@pytest.mark.asyncio
async def test_astrbot_updator_prefers_hosted_core_package(
monkeypatch: pytest.MonkeyPatch,
Expand Down
Loading