From d36987dd19c322e7cbc137605961c5a3fb1f23e9 Mon Sep 17 00:00:00 2001 From: Weilong Liao <37870767+Soulter@users.noreply.github.com> Date: Sat, 20 Jun 2026 22:06:24 +0800 Subject: [PATCH] fix: restore static runtime version Fixes #8924 --- AGENTS.md | 3 +- astrbot/core/config/default.py | 30 +---------- astrbot/core/utils/toml_parser.py | 40 -------------- scripts/prepare_release.py | 45 +++++++++++++++- tests/test_toml_parser.py | 90 +------------------------------ 5 files changed, 47 insertions(+), 161 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 35168f415..ed58fe067 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -50,6 +50,7 @@ ruff check . 5. Use English for all new comments. 6. For path handling, use `pathlib.Path` instead of string paths, and use `astrbot.core.utils.path_utils` to get the AstrBot data and temp directory. 7. When backend API routes, request/response schemas, or OpenAPI definitions change, regenerate the frontend API client by running `cd dashboard && pnpm generate:api`. +8. When updating the project version, keep `[project].version` in `pyproject.toml` and `VERSION` in `astrbot/core/config/default.py` in sync. ### KISS and First Principles @@ -108,7 +109,7 @@ Prepare a release from a clean worktree with: uv run python scripts/prepare_release.py 4.25.0 ``` -The script updates `pyproject.toml`, creates `changelogs/v4.25.0.md`, runs the required Python checks, and prints the remaining steps. Use these flags when needed: +The script updates `pyproject.toml` and `astrbot/core/config/default.py`, creates `changelogs/v4.25.0.md`, runs the required Python checks, and prints the remaining steps. Use these flags when needed: ```bash uv run python scripts/prepare_release.py 4.25.0 --generate-api-client diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index d6348a383..b41167d1d 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -1,39 +1,11 @@ """如需修改配置,请在 `data/cmd_config.json` 中修改或者在管理面板中可视化修改。""" import os -import re -from importlib.metadata import PackageNotFoundError -from importlib.metadata import version as package_version -from pathlib import Path from astrbot.core.computer.booters.cua_defaults import CUA_DEFAULT_CONFIG from astrbot.core.utils.astrbot_path import get_astrbot_data_path -from astrbot.core.utils.toml_parser import read_pyproject_project_version - -try: - import tomllib -except ModuleNotFoundError: - # <= Python 3.10 compatibility - tomllib = None - -try: - pyproject_path = Path(__file__).resolve().parents[3] / "pyproject.toml" - if tomllib is None: - VERSION = read_pyproject_project_version(pyproject_path) - else: - with pyproject_path.open("rb") as f: - VERSION = tomllib.load(f)["project"]["version"] -except (FileNotFoundError, IndexError, KeyError, TypeError, ValueError): - try: - VERSION = package_version("astrbot") # PEP 440 version style, e.g. 1.2.3a4 - match = re.match(r"^(\d+(?:\.\d+)*)(a|b|rc)(\d+)$", VERSION) - if match: - release, prerelease, number = match.groups() - prerelease = {"a": "alpha", "b": "beta", "rc": "rc"}[prerelease] - VERSION = f"{release}-{prerelease}.{number}" - except PackageNotFoundError: - VERSION = "0.0.0" +VERSION = "4.26.0-beta.10" DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db") PERSONAL_WECHAT_CONFIG_METADATA = { "weixin_oc_base_url": { diff --git a/astrbot/core/utils/toml_parser.py b/astrbot/core/utils/toml_parser.py index 1b647846c..011f617b8 100644 --- a/astrbot/core/utils/toml_parser.py +++ b/astrbot/core/utils/toml_parser.py @@ -72,46 +72,6 @@ def _read_dependency_array(raw_value: str) -> list[str]: raise ValueError("Unterminated project.dependencies array") -def read_pyproject_project_version(pyproject_path: Path) -> str: - """Read the project version from a pyproject.toml file. - - Args: - pyproject_path: Path to the pyproject.toml file. - - Returns: - The value of the project.version field. - - Raises: - FileNotFoundError: The pyproject.toml file does not exist. - ValueError: The project.version field is missing or unsupported. - """ - in_project_section = False - for raw_line in pyproject_path.read_text(encoding="utf-8").splitlines(): - line = raw_line.strip() - if not line or line.startswith("#"): - continue - - if line.startswith("[") and line.endswith("]"): - in_project_section = line == "[project]" - continue - - if not in_project_section: - continue - - key, separator, raw_value = line.partition("=") - if key.strip() != "version": - continue - if not separator: - raise ValueError("Missing value separator for project.version") - - version, tail = _read_quoted_value(raw_value, "project.version") - if tail and not tail.startswith("#"): - raise ValueError("Unsupported content after project.version") - return version - - raise ValueError("Missing project.version") - - def read_pyproject_project_dependencies(pyproject_path: Path) -> list[str]: """Read project dependencies from a pyproject.toml file. diff --git a/scripts/prepare_release.py b/scripts/prepare_release.py index 5d1cff70d..6c89f1e3e 100644 --- a/scripts/prepare_release.py +++ b/scripts/prepare_release.py @@ -193,6 +193,37 @@ def update_pyproject_version(version: str) -> Path: raise ReleaseError("Missing [project].version in pyproject.toml") +def update_default_config_version(version: str) -> Path: + """Update the hard-coded runtime version in default.py. + + Args: + version: Release version to write. + + Returns: + Path to the modified default.py file. + + Raises: + ReleaseError: The runtime version constant cannot be found or parsed. + """ + default_config_path = REPO_ROOT / "astrbot" / "core" / "config" / "default.py" + lines = default_config_path.read_text(encoding="utf-8").splitlines(keepends=True) + + for index, line in enumerate(lines): + match = re.match( + r"^(\s*VERSION\s*=\s*)([\"'])(.*?)(\2)(\s*(?:#.*)?)(\n?)$", + line, + ) + if not match: + continue + + prefix, quote, _current, _closing_quote, suffix, newline = match.groups() + lines[index] = f"{prefix}{quote}{version}{quote}{suffix}{newline}" + default_config_path.write_text("".join(lines), encoding="utf-8") + return default_config_path + + raise ReleaseError("Missing VERSION in astrbot/core/config/default.py") + + def write_changelog(version: str, commits: list[str]) -> Path: """Write a changelog draft for the release. @@ -297,7 +328,14 @@ def commit_and_maybe_push( Raises: ReleaseError: Git add, commit, or push fails. """ - git(["add", "pyproject.toml", str(changelog_path.relative_to(REPO_ROOT))]) + git( + [ + "add", + "pyproject.toml", + "astrbot/core/config/default.py", + str(changelog_path.relative_to(REPO_ROOT)), + ] + ) if args.generate_api_client: git(["add", "dashboard/src/api/generated"]) @@ -331,7 +369,9 @@ def print_next_steps( else: print("Next:") print(f"1. Review and polish {changelog_rel}") - print(f"2. git add pyproject.toml {changelog_rel}") + print( + f"2. git add pyproject.toml astrbot/core/config/default.py {changelog_rel}" + ) print(f'3. git commit -m "chore: bump version to {version}"') print(f"4. git push -u {args.remote} {branch}") @@ -414,6 +454,7 @@ def main(argv: list[str] | None = None) -> int: commits = release_commits(tag) update_pyproject_version(version) + update_default_config_version(version) changelog_path = write_changelog(version, commits) run_validation(args) diff --git a/tests/test_toml_parser.py b/tests/test_toml_parser.py index b8ee88561..beb8beef1 100644 --- a/tests/test_toml_parser.py +++ b/tests/test_toml_parser.py @@ -2,87 +2,7 @@ from pathlib import Path import pytest -from astrbot.core.utils.toml_parser import ( - read_pyproject_project_dependencies, - read_pyproject_project_version, -) - - -def test_read_pyproject_project_version_reads_project_section(tmp_path: Path) -> None: - pyproject_path = tmp_path / "pyproject.toml" - pyproject_path.write_text( - "\n".join( - [ - 'version = "ignored"', - "[project]", - 'name = "AstrBot"', - 'version = "1.2.3-beta.4" # release version', - "[tool.example]", - 'version = "ignored-again"', - ] - ), - encoding="utf-8", - ) - - assert read_pyproject_project_version(pyproject_path) == "1.2.3-beta.4" - - -@pytest.mark.parametrize( - ("version_line", "expected"), - [ - ('version = "1.2.3"', "1.2.3"), - ("version='1.2.3-beta.4'", "1.2.3-beta.4"), - (' version = "1.2.3-rc.1" ', "1.2.3-rc.1"), - ], -) -def test_read_pyproject_project_version_accepts_simple_variants( - tmp_path: Path, - version_line: str, - expected: str, -) -> None: - pyproject_path = tmp_path / "pyproject.toml" - pyproject_path.write_text( - "\n".join( - [ - "[project]", - 'name = "AstrBot"', - version_line, - ] - ), - encoding="utf-8", - ) - - assert read_pyproject_project_version(pyproject_path) == expected - - -@pytest.mark.parametrize( - ("version_line", "message"), - [ - ("version", "Missing value separator for project.version"), - ('version = "1.2.3', "Unterminated project.version string"), - ('version = "1.2.3" extra', "Unsupported content after project.version"), - ('version = ""', "Empty project.version value"), - ], -) -def test_read_pyproject_project_version_rejects_invalid_values( - tmp_path: Path, - version_line: str, - message: str, -) -> None: - pyproject_path = tmp_path / "pyproject.toml" - pyproject_path.write_text( - "\n".join( - [ - "[project]", - 'name = "AstrBot"', - version_line, - ] - ), - encoding="utf-8", - ) - - with pytest.raises(ValueError, match=message): - read_pyproject_project_version(pyproject_path) +from astrbot.core.utils.toml_parser import read_pyproject_project_dependencies def test_read_pyproject_project_dependencies_reads_multiline_array( @@ -174,11 +94,3 @@ def test_read_pyproject_project_dependencies_rejects_invalid_values( with pytest.raises(ValueError, match=message): read_pyproject_project_dependencies(pyproject_path) - - -def test_read_pyproject_project_version_raises_when_missing(tmp_path: Path) -> None: - pyproject_path = tmp_path / "pyproject.toml" - pyproject_path.write_text('[project]\nname = "AstrBot"\n', encoding="utf-8") - - with pytest.raises(ValueError, match="Missing project.version"): - read_pyproject_project_version(pyproject_path)