2025-05-31 03:48:10 +08:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
"""
|
|
|
|
|
本地發布腳本
|
|
|
|
|
用法:
|
|
|
|
|
python scripts/release.py patch # 2.0.0 -> 2.0.1
|
2025-06-11 03:25:08 +08:00
|
|
|
|
python scripts/release.py minor # 2.0.0 -> 2.1.0
|
2025-05-31 03:48:10 +08:00
|
|
|
|
python scripts/release.py major # 2.0.0 -> 3.0.0
|
|
|
|
|
"""
|
|
|
|
|
|
2025-06-11 03:25:08 +08:00
|
|
|
|
import re
|
2025-05-31 03:48:10 +08:00
|
|
|
|
import subprocess
|
|
|
|
|
import sys
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
def run_cmd(cmd, check=True):
|
|
|
|
|
"""執行命令並返回結果"""
|
|
|
|
|
print(f"🔨 執行: {cmd}")
|
2025-06-11 03:25:08 +08:00
|
|
|
|
result = subprocess.run(
|
|
|
|
|
cmd, shell=True, capture_output=True, text=True, check=False
|
|
|
|
|
)
|
2025-05-31 03:48:10 +08:00
|
|
|
|
if check and result.returncode != 0:
|
|
|
|
|
print(f"❌ 錯誤: {result.stderr}")
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
return result
|
|
|
|
|
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
def get_current_version():
|
|
|
|
|
"""從 pyproject.toml 獲取當前版本"""
|
|
|
|
|
pyproject_path = Path("pyproject.toml")
|
|
|
|
|
content = pyproject_path.read_text(encoding="utf-8")
|
|
|
|
|
match = re.search(r'version = "([^"]+)"', content)
|
|
|
|
|
if match:
|
|
|
|
|
return match.group(1)
|
|
|
|
|
raise ValueError("無法找到版本號")
|
|
|
|
|
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
def bump_version(version_type):
|
|
|
|
|
"""更新版本號"""
|
2025-06-11 03:25:08 +08:00
|
|
|
|
if version_type not in ["patch", "minor", "major"]:
|
2025-05-31 03:48:10 +08:00
|
|
|
|
print("❌ 版本類型必須是: patch, minor, major")
|
|
|
|
|
sys.exit(1)
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
current = get_current_version()
|
|
|
|
|
print(f"📦 當前版本: {current}")
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:51:52 +08:00
|
|
|
|
# 使用 bump2version with allow-dirty
|
|
|
|
|
run_cmd(f"uv run bump2version --allow-dirty {version_type}")
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
new_version = get_current_version()
|
|
|
|
|
print(f"🎉 新版本: {new_version}")
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
return current, new_version
|
|
|
|
|
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
def main():
|
|
|
|
|
if len(sys.argv) != 2:
|
|
|
|
|
print(__doc__)
|
|
|
|
|
sys.exit(1)
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
version_type = sys.argv[1]
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
print("🚀 開始發布流程...")
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:51:52 +08:00
|
|
|
|
# 檢查 Git 狀態(僅提示,不阻止)
|
2025-05-31 03:48:10 +08:00
|
|
|
|
result = run_cmd("git status --porcelain", check=False)
|
|
|
|
|
if result.stdout.strip():
|
2025-05-31 03:51:52 +08:00
|
|
|
|
print("⚠️ 有未提交的變更:")
|
2025-05-31 03:48:10 +08:00
|
|
|
|
print(result.stdout)
|
2025-05-31 03:51:52 +08:00
|
|
|
|
print("💡 將繼續執行(使用 --allow-dirty 模式)")
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
# 更新版本
|
|
|
|
|
old_version, new_version = bump_version(version_type)
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
# 建置套件
|
|
|
|
|
print("📦 建置套件...")
|
|
|
|
|
run_cmd("uv build")
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
# 檢查套件
|
|
|
|
|
print("🔍 檢查套件...")
|
|
|
|
|
run_cmd("uv run twine check dist/*")
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:51:52 +08:00
|
|
|
|
# 提交所有變更(包括版本更新)
|
2025-05-31 03:48:10 +08:00
|
|
|
|
print("💾 提交版本更新...")
|
|
|
|
|
run_cmd("git add .")
|
|
|
|
|
run_cmd(f'git commit -m "🔖 Release v{new_version}"')
|
|
|
|
|
run_cmd(f'git tag "v{new_version}"')
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
# 詢問是否發布
|
|
|
|
|
print(f"\n✅ 準備發布版本 {old_version} -> {new_version}")
|
|
|
|
|
choice = input("是否發布到 PyPI? (y/N): ")
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
|
|
|
|
if choice.lower() == "y":
|
2025-05-31 03:48:10 +08:00
|
|
|
|
print("🚀 發布到 PyPI...")
|
|
|
|
|
run_cmd("uv run twine upload dist/*")
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
print("📤 推送到 GitHub...")
|
|
|
|
|
run_cmd("git push origin main")
|
|
|
|
|
run_cmd(f'git push origin "v{new_version}"')
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
print(f"🎉 發布完成!版本 v{new_version} 已上線")
|
2025-06-11 03:25:08 +08:00
|
|
|
|
print("📦 安裝命令: uvx mcp-feedback-enhanced")
|
2025-05-31 03:48:10 +08:00
|
|
|
|
else:
|
|
|
|
|
print("⏸️ 發布已取消,版本已更新但未發布")
|
|
|
|
|
print("💡 您可以稍後手動發布: uv run twine upload dist/*")
|
|
|
|
|
|
2025-06-11 03:25:08 +08:00
|
|
|
|
|
2025-05-31 03:48:10 +08:00
|
|
|
|
if __name__ == "__main__":
|
2025-06-11 03:25:08 +08:00
|
|
|
|
main()
|