250 lines
7.0 KiB
Python
250 lines
7.0 KiB
Python
#!/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[""] 中的 version(lockfile 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()
|