lllin000_PaperForge/scripts/bump.py
Research Assistant ece6c9b2ba feat: complete i18n refactor + automated release script
- i18n.js: zh/en language pack with auto-detect from Obsidian config
- main.js: all UI strings use t() calls (settings tab, wizard, pre-check)
- scripts/bump.py: --release flag: bump + commit + tag + push + gh release
- AGENTS.md: developer guide section (bump, release, i18n, pre-commit)
2026-04-30 13:55:54 +08:00

130 lines
4.3 KiB
Python

#!/usr/bin/env python
"""Bump version across all PaperForge files and optionally create a release.
Usage:
python scripts/bump.py 1.4.12 # specific version, commit + tag only
python scripts/bump.py patch # bump patch, commit + tag
python scripts/bump.py patch --release # bump, commit, tag, push, create GitHub release
python scripts/bump.py minor --release -m "New feature X" # release with custom notes
python scripts/bump.py 2.0.0 --dry-run # preview only
python scripts/bump.py patch --no-git # skip git entirely
"""
import argparse
import json
import os
import re
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
FILES_TO_UPDATE = {
"__init__": ROOT / "paperforge" / "__init__.py",
"manifest": ROOT / "paperforge" / "plugin" / "manifest.json",
"versions": ROOT / "paperforge" / "plugin" / "versions.json",
}
PLUGIN_FILES = [
ROOT / "paperforge" / "plugin" / "main.js",
ROOT / "paperforge" / "plugin" / "styles.css",
ROOT / "paperforge" / "plugin" / "manifest.json",
ROOT / "paperforge" / "plugin" / "versions.json",
]
def read_current_version() -> str:
content = FILES_TO_UPDATE["__init__"].read_text(encoding="utf-8")
m = re.search(r'__version__\s*=\s*"([^"]+)"', content)
if not m:
sys.exit("Cannot find __version__ in __init__.py")
return m.group(1)
def bump_part(version: str, part: str) -> str:
parts = [int(x) for x in version.split(".")]
if part == "major":
return f"{parts[0] + 1}.0.0"
elif part == "minor":
return f"{parts[0]}.{parts[1] + 1}.0"
else:
return f"{parts[0]}.{parts[1]}.{parts[2] + 1}"
def update_file(path: Path, old_ver: str, new_ver: str, dry: bool) -> bool:
content = path.read_text(encoding="utf-8")
if old_ver not in content:
print(f" SKIP {path.name}: version {old_ver} not found")
return False
if dry:
print(f" WOULD update {path.name}: {old_ver}{new_ver}")
return True
new_content = content.replace(old_ver, new_ver)
if path.name == "versions.json" and f'"{new_ver}"' not in new_content:
data = json.loads(new_content)
data[new_ver] = "1.0.0"
new_content = json.dumps(data, indent=2, ensure_ascii=False) + "\n"
path.write_text(new_content, encoding="utf-8")
print(f" {path.name}: {old_ver}{new_ver}")
return True
def run(cmd, **kwargs):
subprocess.run(cmd, cwd=ROOT, check=True, **kwargs)
def main():
parser = argparse.ArgumentParser(description="Bump PaperForge version")
parser.add_argument("version", help="New version or bump part (major/minor/patch)")
parser.add_argument("--dry-run", action="store_true", help="Preview only")
parser.add_argument("--no-git", action="store_true", help="Skip git commit/tag")
parser.add_argument("--release", action="store_true", help="Push and create GitHub release")
parser.add_argument("-m", "--message", default="", help="Release notes (one-line summary)")
args = parser.parse_args()
old_ver = read_current_version()
new_ver = args.version if "." in args.version else bump_part(old_ver, args.version)
print(f"Bump: {old_ver}{new_ver}")
for key, path in FILES_TO_UPDATE.items():
update_file(path, old_ver, new_ver, args.dry_run)
if args.dry_run:
print("\nDry run — no changes made.")
return
if args.no_git:
print("\nSkipping git — files updated on disk only.")
return
# Git commit + tag
run(["git", "add", "-u"])
run(["git", "commit", "-m", f"chore: bump version to v{new_ver}"])
run(["git", "tag", f"v{new_ver}"])
print(f"Committed and tagged v{new_ver}")
if not args.release:
print("Run: git push && git push --tags")
return
# Push
run(["git", "push"])
run(["git", "push", "--tags"])
print("Pushed to remote")
# Create GitHub release
notes = args.message or f"v{new_ver}"
release_args = [
"gh", "release", "create", f"v{new_ver}",
"--title", f"v{new_ver}",
"--notes", notes,
]
for pf in PLUGIN_FILES:
release_args.append(str(pf))
run(release_args)
print(f"GitHub release v{new_ver} created with plugin assets")
if __name__ == "__main__":
main()