Skip to content

Commit b549ea6

Browse files
committed
refactor: simplify updater target resolution and nightly handling
1 parent fec8415 commit b549ea6

6 files changed

Lines changed: 79 additions & 70 deletions

File tree

.github/workflows/release.yml

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ jobs:
3030
nightly_tag: ${{ steps.nightly-tag.outputs.nightly_tag }}
3131
repo_slug: ${{ steps.repo-slug.outputs.repo_slug }}
3232
steps:
33-
- name: Checkout repository for constants
33+
- name: Checkout repository
3434
uses: actions/checkout@v6
3535
with:
36-
fetch-depth: 1
36+
fetch-depth: 0
3737

3838
- name: Resolve nightly tag
3939
id: nightly-tag
@@ -88,11 +88,23 @@ jobs:
8888
8989
echo "ref=$ref" >> "$GITHUB_OUTPUT"
9090
91-
- name: Checkout repository at release ref
92-
uses: actions/checkout@v6
93-
with:
94-
fetch-depth: 0
95-
ref: ${{ steps.checkout-ref.outputs.ref }}
91+
- name: Switch repository to release ref
92+
shell: bash
93+
run: |
94+
target_ref="${{ steps.checkout-ref.outputs.ref }}"
95+
if [ -z "$target_ref" ]; then
96+
echo "Resolved checkout ref is empty." >&2
97+
exit 1
98+
fi
99+
100+
if ! git checkout --force "$target_ref" >/tmp/git_checkout_ref.log 2>&1; then
101+
if ! git fetch --force origin "$target_ref" >/tmp/git_fetch_ref.log 2>&1; then
102+
echo "Failed to fetch checkout ref: $target_ref" >&2
103+
cat /tmp/git_fetch_ref.log >&2 || true
104+
exit 1
105+
fi
106+
git checkout --force FETCH_HEAD
107+
fi
96108
97109
- name: Resolve tag
98110
id: tag

astrbot/core/release_constants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1+
import re
2+
13
NIGHTLY_TAG = "nightly"
24
GITHUB_REPO_SLUG = "AstrBotDevs/AstrBot"
35
GITHUB_RELEASE_API = f"https://api.github.com/repos/{GITHUB_REPO_SLUG}/releases"
46
GITHUB_ARCHIVE_BASE = f"https://github.com/{GITHUB_REPO_SLUG}/archive"
7+
PRERELEASE_TAG_REGEX = re.compile(
8+
rf"[\-_.]?(alpha|beta|rc|dev|{re.escape(NIGHTLY_TAG)}|pre|preview)[\-_.]?\d*$",
9+
re.IGNORECASE,
10+
)

astrbot/core/updator.py

Lines changed: 44 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010
GITHUB_ARCHIVE_BASE,
1111
GITHUB_RELEASE_API,
1212
NIGHTLY_TAG,
13+
PRERELEASE_TAG_REGEX,
1314
)
1415
from astrbot.core.utils.astrbot_path import get_astrbot_path
1516
from astrbot.core.utils.io import download_file
1617

1718
from .zip_updator import (
18-
PRERELEASE_TAG_REGEX,
19+
FetchReleaseError,
1920
ReleaseInfo,
2021
RepoZipUpdator,
2122
)
@@ -169,7 +170,7 @@ async def get_releases_with_nightly(self) -> list[dict]:
169170
nightly_release_url = f"{self.GITHUB_RELEASE_API}/tags/{self.NIGHTLY_TAG}"
170171
try:
171172
nightly_releases = await self.fetch_release_info(nightly_release_url)
172-
except Exception as e:
173+
except (FetchReleaseError, TimeoutError, OSError) as e:
173174
logger.warning(
174175
"获取 nightly 发布信息失败,跳过 nightly。"
175176
f"url={nightly_release_url}, error_type={type(e).__name__}, detail={e}",
@@ -184,7 +185,29 @@ async def get_releases_with_nightly(self) -> list[dict]:
184185
releases.insert(0, nightly_release)
185186
return releases
186187

187-
def _parse_update_target(
188+
async def _resolve_nightly_target(self) -> tuple[str, str]:
189+
nightly_release_url = f"{self.GITHUB_RELEASE_API}/tags/{self.NIGHTLY_TAG}"
190+
fallback = (
191+
self.NIGHTLY_TAG,
192+
f"{self.GITHUB_ARCHIVE_BASE}/refs/tags/{self.NIGHTLY_TAG}.zip",
193+
)
194+
try:
195+
nightly_releases = await self.fetch_release_info(nightly_release_url)
196+
except (FetchReleaseError, TimeoutError, OSError) as e:
197+
logger.warning(
198+
"获取 nightly 发布信息失败,使用归档地址。"
199+
f"url={nightly_release_url}, error_type={type(e).__name__}, detail={e}",
200+
)
201+
return fallback
202+
203+
if not nightly_releases:
204+
return fallback
205+
206+
nightly_release = nightly_releases[0]
207+
zip_url = nightly_release.get("zipball_url", fallback[1])
208+
return self.NIGHTLY_TAG, zip_url
209+
210+
async def _resolve_update_target(
188211
self,
189212
latest: bool,
190213
version: str | None,
@@ -198,31 +221,6 @@ def _parse_update_target(
198221
)
199222

200223
if latest:
201-
return "latest", ""
202-
203-
if not version_str:
204-
raise AstrBotUpdateError("invalid_target", "未指定有效的更新目标。")
205-
206-
if version_str.lower() == self.NIGHTLY_TAG:
207-
return "nightly", self.NIGHTLY_TAG
208-
209-
if version_str.startswith("v"):
210-
return "tag", version_str
211-
212-
if len(version_str) != 40:
213-
raise AstrBotUpdateError(
214-
"invalid_target", "commit hash 长度不正确,应为 40"
215-
)
216-
return "commit", version_str
217-
218-
async def _resolve_update_target(
219-
self,
220-
latest: bool,
221-
version: str | None,
222-
) -> tuple[str, str]:
223-
kind, value = self._parse_update_target(latest, version)
224-
225-
if kind == "latest":
226224
releases = await self.get_releases()
227225
latest_release = next(
228226
(
@@ -240,38 +238,34 @@ async def _resolve_update_target(
240238
raise AstrBotUpdateError("up_to_date", "当前已经是最新版本。")
241239
return latest_version, latest_release["zipball_url"]
242240

243-
if kind == "nightly":
244-
releases = await self.get_releases_with_nightly()
245-
nightly_release = next(
246-
(
247-
item
248-
for item in releases
249-
if item.get("tag_name", "").lower() == self.NIGHTLY_TAG
250-
),
251-
None,
252-
)
253-
if nightly_release is not None:
254-
return self.NIGHTLY_TAG, nightly_release["zipball_url"]
255-
return self.NIGHTLY_TAG, (
256-
f"{self.GITHUB_ARCHIVE_BASE}/refs/tags/{self.NIGHTLY_TAG}.zip"
257-
)
241+
if not version_str:
242+
raise AstrBotUpdateError("invalid_target", "未指定有效的更新目标。")
243+
244+
if version_str.lower() == self.NIGHTLY_TAG:
245+
return await self._resolve_nightly_target()
258246

259-
if kind == "tag":
247+
if version_str.startswith("v"):
260248
releases = await self.get_releases()
261249
for data in releases:
262-
if data.get("tag_name") == value:
263-
return value, data["zipball_url"]
250+
if data.get("tag_name") == version_str:
251+
return version_str, data["zipball_url"]
264252
raise AstrBotUpdateError(
265253
"file_not_found",
266-
f"未找到版本号为 {value} 的更新文件。",
254+
f"未找到版本号为 {version_str} 的更新文件。",
267255
)
268256

269-
return value, f"{self.GITHUB_ARCHIVE_BASE}/{value}.zip"
257+
if len(version_str) != 40:
258+
raise AstrBotUpdateError(
259+
"invalid_target",
260+
"commit hash 长度不正确,应为 40",
261+
)
262+
return version_str, f"{self.GITHUB_ARCHIVE_BASE}/{version_str}.zip"
270263

271264
async def update(self, reboot=False, latest=True, version=None, proxy="") -> None:
272265
if os.environ.get("ASTRBOT_CLI") or os.environ.get("ASTRBOT_LAUNCHER"):
273-
raise Exception(
274-
"Error: You are running AstrBot via CLI, please use `pip` or `uv tool upgrade` to update AstrBot."
266+
raise AstrBotUpdateError(
267+
"invalid_environment",
268+
"Error: You are running AstrBot via CLI, please use `pip` or `uv tool upgrade` to update AstrBot.",
275269
) # 避免版本管理混乱
276270

277271
try:

astrbot/core/zip_updator.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,10 @@
1010
import certifi
1111

1212
from astrbot.core import logger
13-
from astrbot.core.release_constants import NIGHTLY_TAG
13+
from astrbot.core.release_constants import PRERELEASE_TAG_REGEX
1414
from astrbot.core.utils.io import download_file, on_error
1515
from astrbot.core.utils.version_comparator import VersionComparator
1616

17-
PRERELEASE_TAG_REGEX = re.compile(
18-
rf"[\-_.]?(alpha|beta|rc|dev|{re.escape(NIGHTLY_TAG)}|pre|preview)[\-_.]?\d*$",
19-
re.IGNORECASE,
20-
)
2117
# Keep this rule aligned with dashboard/src/layouts/full/vertical-header/VerticalHeader.vue.
2218

2319

tests/unit/test_prerelease_rule_sync.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import re
22
from pathlib import Path
33

4-
from astrbot.core.zip_updator import PRERELEASE_TAG_REGEX
4+
from astrbot.core.release_constants import PRERELEASE_TAG_REGEX
55

66

77
def test_prerelease_rule_is_synced_with_dashboard():

tests/unit/test_updator.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,12 @@ async def test_resolve_update_target_nightly_uses_archive_fallback(monkeypatch):
142142
updator = AstrBotUpdator()
143143
updator.GITHUB_ARCHIVE_BASE = "https://github.com/example-org/example-repo/archive"
144144

145-
async def mock_get_releases_with_nightly():
146-
return []
145+
async def mock_fetch_release_info(url: str):
146+
if url == f"{updator.GITHUB_RELEASE_API}/tags/{updator.NIGHTLY_TAG}":
147+
raise FetchReleaseError("请求失败")
148+
raise AssertionError(f"unexpected URL: {url}")
147149

148-
monkeypatch.setattr(updator, "get_releases_with_nightly", mock_get_releases_with_nightly)
150+
monkeypatch.setattr(updator, "fetch_release_info", mock_fetch_release_info)
149151

150152
target_version, file_url = await updator._resolve_update_target(
151153
latest=False,
@@ -341,7 +343,7 @@ async def mock_fetch_release_info(url: str):
341343

342344

343345
@pytest.mark.asyncio
344-
async def test_get_releases_with_nightly_falls_back_on_unexpected_nightly_error(
346+
async def test_get_releases_with_nightly_raises_for_unexpected_nightly_error(
345347
monkeypatch,
346348
):
347349
updator = AstrBotUpdator()
@@ -362,9 +364,8 @@ async def mock_fetch_release_info(url: str):
362364

363365
monkeypatch.setattr(updator, "fetch_release_info", mock_fetch_release_info)
364366

365-
releases = await updator.get_releases_with_nightly()
366-
assert len(releases) == 1
367-
assert releases[0]["tag_name"] == "v9.9.9"
367+
with pytest.raises(KeyError):
368+
await updator.get_releases_with_nightly()
368369

369370

370371
@pytest.mark.asyncio

0 commit comments

Comments
 (0)