Files
meijiaka-zy/scripts/bump-version.py
T

250 lines
7.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""统一版本号管理脚本。
用法:
python scripts/bump-version.py # 读取 VERSION 文件并同步到所有配置
python scripts/bump-version.py 1.5.15 # 更新 VERSION 并同步(同时打 Git tag
覆盖文件:
- VERSION
- AGENTS.md
- tauri-app/AGENTS.md
- tauri-app/package.json
- tauri-app/src-tauri/Cargo.toml
- tauri-app/src-tauri/tauri.conf.json
- tauri-app/src-tauri/Cargo.lock
- tauri-app/package-lock.json
- tauri-app/src/store/authStore.ts
- python-api/pyproject.toml
- python-api/uv.lock
- python-api/app/config.py
- python-api/.env.example
"""
import json
import re
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).parent.parent
VERSION_FILE = ROOT / "VERSION"
def read_version() -> str:
return VERSION_FILE.read_text().strip()
def write_version(version: str) -> None:
VERSION_FILE.write_text(version + "\n")
def bump_agents_md(path: Path, version: str) -> None:
content = path.read_text()
content = re.sub(
r'\*\*版本\*\*: `[^`]+`',
f'**版本**: `{version}`',
content,
)
path.write_text(content)
def bump_cargo_toml(version: str) -> None:
path = ROOT / "tauri-app" / "src-tauri" / "Cargo.toml"
content = path.read_text()
content = re.sub(
r'^version = "[^"]+"',
f'version = "{version}"',
content,
flags=re.MULTILINE,
)
path.write_text(content)
def bump_cargo_lock(version: str) -> None:
path = ROOT / "tauri-app" / "src-tauri" / "Cargo.lock"
content = path.read_text()
# Cargo.lock 中 tauri-app 包的版本行
content = re.sub(
r'(\[\[package\]\]\nname = "tauri-app"\nversion = ")([^"]+)(")',
rf'\g<1>{version}\g<3>',
content,
)
path.write_text(content)
def bump_tauri_conf(version: str) -> None:
path = ROOT / "tauri-app" / "src-tauri" / "tauri.conf.json"
data = json.loads(path.read_text())
data["version"] = version
path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n")
def bump_package_json(version: str) -> None:
path = ROOT / "tauri-app" / "package.json"
data = json.loads(path.read_text())
data["version"] = version
path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n")
def bump_package_lock_json(version: str) -> None:
path = ROOT / "tauri-app" / "package-lock.json"
content = path.read_text()
# package-lock.json 顶层的 version
content = re.sub(
r'^\s+"version": "[^"]+"',
f' "version": "{version}"',
content,
count=1,
flags=re.MULTILINE,
)
# 顶层 packages[""] 中的 versionlockfile v3
content = re.sub(
r'("\": \{\n[^}]*"version": ")([^"]+)(")',
rf'\g<1>{version}\g<3>',
content,
count=1,
)
path.write_text(content)
def bump_auth_store(version: str) -> None:
path = ROOT / "tauri-app" / "src" / "store" / "authStore.ts"
content = path.read_text()
content = re.sub(
r"appVersion: '[^']+'",
f"appVersion: '{version}'",
content,
)
path.write_text(content)
def bump_pyproject_toml(version: str) -> None:
path = ROOT / "python-api" / "pyproject.toml"
content = path.read_text()
content = re.sub(
r'^version = "[^"]+"',
f'version = "{version}"',
content,
flags=re.MULTILINE,
)
path.write_text(content)
def bump_uv_lock(version: str) -> None:
path = ROOT / "python-api" / "uv.lock"
content = path.read_text()
# uv.lock 中当前包的版本(name = "meijiaka-ai-api" 后的 version
content = re.sub(
r'(name = "meijiaka-ai-api"\nversion = ")([^"]+)(")',
rf'\g<1>{version}\g<3>',
content,
)
path.write_text(content)
def bump_config_py(version: str) -> None:
path = ROOT / "python-api" / "app" / "config.py"
content = path.read_text()
content = re.sub(
r'APP_VERSION: str = Field\(default="[^"]+"',
f'APP_VERSION: str = Field(default="{version}"',
content,
)
path.write_text(content)
def bump_env_example(version: str) -> None:
path = ROOT / "python-api" / ".env.example"
content = path.read_text()
content = re.sub(
r'^APP_VERSION=[^\n]+',
f'APP_VERSION={version}',
content,
flags=re.MULTILINE,
)
path.write_text(content)
def create_git_tag(version: str) -> None:
tag = f"v{version}"
try:
subprocess.run(
["git", "tag", "-a", tag, "-m", f"Release {tag}"],
cwd=ROOT,
check=True,
capture_output=True,
text=True,
)
print(f"✅ Git tag 已创建: {tag}")
except subprocess.CalledProcessError as e:
if "already exists" in e.stderr:
print(f"⚠️ Git tag {tag} 已存在,跳过")
else:
print(f"❌ 创建 Git tag 失败: {e.stderr}")
raise
def main():
if len(sys.argv) > 1:
version = sys.argv[1]
write_version(version)
print(f"VERSION 已更新为: {version}")
else:
version = read_version()
print(f"读取 VERSION: {version}")
bump_agents_md(ROOT / "AGENTS.md", version)
bump_agents_md(ROOT / "tauri-app" / "AGENTS.md", version)
bump_cargo_toml(version)
bump_cargo_lock(version)
bump_tauri_conf(version)
bump_package_json(version)
bump_package_lock_json(version)
bump_auth_store(version)
bump_pyproject_toml(version)
bump_uv_lock(version)
bump_config_py(version)
bump_env_example(version)
print(f"\n✅ 版本号已统一更新为: {version}")
print("\n修改的文件列表:")
print(" - VERSION")
print(" - AGENTS.md")
print(" - tauri-app/AGENTS.md")
print(" - tauri-app/package.json")
print(" - tauri-app/package-lock.json")
print(" - tauri-app/src-tauri/Cargo.toml")
print(" - tauri-app/src-tauri/Cargo.lock")
print(" - tauri-app/src-tauri/tauri.conf.json")
print(" - tauri-app/src/store/authStore.ts")
print(" - python-api/pyproject.toml")
print(" - python-api/uv.lock")
print(" - python-api/app/config.py")
print(" - python-api/.env.example")
if len(sys.argv) > 1:
# 自动提交版本更新,确保 tag 落在正确的 commit 上
subprocess.run(
["git", "add", "-A"],
cwd=ROOT,
check=True,
capture_output=True,
)
subprocess.run(
["git", "commit", "-m", f"bump version to {version}"],
cwd=ROOT,
check=True,
capture_output=True,
)
print(f"✅ 已提交: bump version to {version}")
create_git_tag(version)
print("\n下一步:")
print(f" git push && git push origin v{version}")
print(f" # 如果使用 GitHub Actions,同时推送到 GitHub remote:")
print(f" git push github-new && git push github-new v{version}")
if __name__ == "__main__":
main()