mirror of
https://github.com/jpush/jpush-phonegap-plugin.git
synced 2026-05-27 00:00:12 +08:00
278 lines
9.7 KiB
Python
278 lines
9.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Update SDK version references in plugin files based on config.json."""
|
|
|
|
import sys
|
|
import json
|
|
import re
|
|
import argparse
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
CONFIG_PATH = ".claude/skills/update-sdk/scripts/config.json"
|
|
|
|
|
|
def load_config():
|
|
with open(CONFIG_PATH, "r", encoding="utf-8") as f:
|
|
return json.load(f)
|
|
|
|
|
|
def bump_patch(version: str) -> str:
|
|
"""Bump patch version. patch and minor cap at 9; carry over to next component at 10."""
|
|
parts = version.split(".")
|
|
major, minor, patch = int(parts[0]), int(parts[1]), int(parts[2])
|
|
patch += 1
|
|
if patch >= 10:
|
|
patch = 0
|
|
minor += 1
|
|
if minor >= 10:
|
|
minor = 0
|
|
major += 1
|
|
return f"{major}.{minor}.{patch}"
|
|
|
|
|
|
def get_current_version_from_ref(ref: dict) -> str | None:
|
|
"""Read the current version string from a file ref."""
|
|
path = Path(ref["path"])
|
|
if not path.exists():
|
|
return None
|
|
content = path.read_text(encoding="utf-8")
|
|
|
|
if "pattern" in ref:
|
|
regex = re.escape(ref["pattern"]).replace(r"\{VERSION\}", r"([\d.]+(?:-\w+)?)")
|
|
match = re.search(regex, content)
|
|
return match.group(1) if match else None
|
|
elif "key" in ref:
|
|
if path.suffix in (".yaml", ".yml"):
|
|
match = re.search(r"^version:\s*(.+)$", content, re.MULTILINE)
|
|
return match.group(1).strip() if match else None
|
|
elif path.suffix == ".xml":
|
|
key = ref["key"]
|
|
match = re.search(rf'{re.escape(key)}="([^"]+)"', content)
|
|
return match.group(1) if match else None
|
|
else: # JSON
|
|
try:
|
|
data = json.loads(content)
|
|
keys = ref["key"].split(".")
|
|
obj = data
|
|
for k in keys:
|
|
obj = obj[k]
|
|
return str(obj)
|
|
except (KeyError, json.JSONDecodeError):
|
|
return None
|
|
return None
|
|
|
|
|
|
def update_by_pattern(file_path: str, pattern: str, new_version: str) -> bool:
|
|
"""Replace version in file using a pattern with {VERSION} placeholder."""
|
|
path = Path(file_path)
|
|
if not path.exists():
|
|
print(f" WARNING: File not found: {file_path}")
|
|
return False
|
|
|
|
content = path.read_text(encoding="utf-8")
|
|
regex = re.escape(pattern).replace(r"\{VERSION\}", r"([\d.]+(?:-\w+)?)")
|
|
replacement = pattern.replace("{VERSION}", new_version)
|
|
|
|
match = re.search(regex, content)
|
|
if not match:
|
|
print(f" WARNING: Pattern not found in {file_path}")
|
|
print(f" Pattern: {pattern}")
|
|
return False
|
|
|
|
old_version = match.group(1)
|
|
if old_version == new_version:
|
|
print(f" SKIP: {file_path} already at {new_version}")
|
|
return True
|
|
|
|
new_content = content.replace(match.group(0), replacement, 1)
|
|
path.write_text(new_content, encoding="utf-8")
|
|
print(f" UPDATED: {file_path} {old_version} → {new_version}")
|
|
return True
|
|
|
|
|
|
def update_json_field(file_path: str, key: str, new_version: str) -> bool:
|
|
"""Update a field in a JSON file (supports dot-notation keys)."""
|
|
path = Path(file_path)
|
|
if not path.exists():
|
|
print(f" WARNING: File not found: {file_path}")
|
|
return False
|
|
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
data = json.load(f)
|
|
|
|
keys = key.split(".")
|
|
obj = data
|
|
for k in keys[:-1]:
|
|
obj = obj.setdefault(k, {})
|
|
|
|
old = obj.get(keys[-1], "unknown")
|
|
if old == new_version:
|
|
print(f" SKIP: {file_path} [{key}] already at {new_version}")
|
|
return True
|
|
|
|
obj[keys[-1]] = new_version
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
f.write("\n")
|
|
|
|
print(f" UPDATED: {file_path} [{key}] {old} → {new_version}")
|
|
return True
|
|
|
|
|
|
def update_yaml_version(file_path: str, new_version: str) -> bool:
|
|
"""Update 'version:' line in a YAML file."""
|
|
path = Path(file_path)
|
|
if not path.exists():
|
|
print(f" WARNING: File not found: {file_path}")
|
|
return False
|
|
|
|
content = path.read_text(encoding="utf-8")
|
|
match = re.search(r"^(version:\s*)(.+)$", content, re.MULTILINE)
|
|
if not match:
|
|
print(f" WARNING: No 'version:' field found in {file_path}")
|
|
return False
|
|
|
|
old_version = match.group(2).strip()
|
|
if old_version == new_version:
|
|
print(f" SKIP: {file_path} already at {new_version}")
|
|
return True
|
|
|
|
new_content = content.replace(match.group(0), f"{match.group(1)}{new_version}", 1)
|
|
path.write_text(new_content, encoding="utf-8")
|
|
print(f" UPDATED: {file_path} {old_version} → {new_version}")
|
|
return True
|
|
|
|
|
|
def update_xml_attribute(file_path: str, attribute: str, new_version: str) -> bool:
|
|
"""Update a version attribute in an XML file (e.g., plugin.xml version="X.X.X")."""
|
|
path = Path(file_path)
|
|
if not path.exists():
|
|
print(f" WARNING: File not found: {file_path}")
|
|
return False
|
|
|
|
content = path.read_text(encoding="utf-8")
|
|
pattern = rf'({re.escape(attribute)}=")([^"]+)(")'
|
|
match = re.search(pattern, content)
|
|
if not match:
|
|
print(f" WARNING: Attribute '{attribute}' not found in {file_path}")
|
|
return False
|
|
|
|
old_version = match.group(2)
|
|
if old_version == new_version:
|
|
print(f" SKIP: {file_path} [{attribute}] already at {new_version}")
|
|
return True
|
|
|
|
new_content = content.replace(match.group(0), f'{match.group(1)}{new_version}{match.group(3)}', 1)
|
|
path.write_text(new_content, encoding="utf-8")
|
|
print(f" UPDATED: {file_path} [{attribute}] {old_version} → {new_version}")
|
|
return True
|
|
|
|
|
|
def update_config_json_dep(file_path: str, dep_prefix: str, new_version: str) -> bool:
|
|
"""Update a maven dependency version in a UTS config.json dependencies array."""
|
|
path = Path(file_path)
|
|
if not path.exists():
|
|
print(f" WARNING: File not found: {file_path}")
|
|
return False
|
|
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
data = json.load(f)
|
|
|
|
deps = data.get("dependencies", [])
|
|
updated = False
|
|
for i, dep in enumerate(deps):
|
|
if isinstance(dep, str) and dep.startswith(dep_prefix):
|
|
old = dep
|
|
parts = dep.rsplit(":", 1)
|
|
deps[i] = f"{parts[0]}:{new_version}"
|
|
print(f" UPDATED: {file_path} dep {old} → {deps[i]}")
|
|
updated = True
|
|
|
|
if not updated:
|
|
print(f" WARNING: Dependency prefix '{dep_prefix}' not found in {file_path}")
|
|
return False
|
|
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
json.dump(data, f, indent="\t", ensure_ascii=False)
|
|
f.write("\n")
|
|
return True
|
|
|
|
|
|
def update_changelog(changelog_file: str, plugin_version: str, summary: str):
|
|
path = Path(changelog_file)
|
|
date_str = datetime.now().strftime("%Y-%m-%d")
|
|
entry = f"## {plugin_version} ({date_str})\n\n{summary}\n\n"
|
|
existing = path.read_text(encoding="utf-8") if path.exists() else "# Changelog\n\n"
|
|
path.write_text(entry + existing, encoding="utf-8")
|
|
print(f" UPDATED: {changelog_file} → added v{plugin_version} entry")
|
|
|
|
|
|
def process_file_ref(ref: dict, version: str) -> bool:
|
|
path = ref["path"]
|
|
if "pattern" in ref:
|
|
return update_by_pattern(path, ref["pattern"], version)
|
|
elif "key" in ref:
|
|
if path.endswith(".yaml") or path.endswith(".yml"):
|
|
return update_yaml_version(path, version)
|
|
elif path.endswith(".xml"):
|
|
return update_xml_attribute(path, ref["key"], version)
|
|
else:
|
|
return update_json_field(path, ref["key"], version)
|
|
elif "dep_prefix" in ref:
|
|
return update_config_json_dep(path, ref["dep_prefix"], version)
|
|
return False
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Update SDK version references")
|
|
parser.add_argument("--android", help="Android SDK version")
|
|
parser.add_argument("--ios", help="iOS SDK version")
|
|
parser.add_argument("--plugin-version", help="Explicit new plugin version")
|
|
parser.add_argument("--bump-patch", action="store_true",
|
|
help="Auto-bump patch (carry at 10: x.y.9→x.(y+1).0, x.9.9→(x+1).0.0)")
|
|
parser.add_argument("--changelog-summary", default="", help="Summary for CHANGELOG.md")
|
|
args = parser.parse_args()
|
|
|
|
config = load_config()
|
|
refs = config.get("version_refs", {})
|
|
|
|
print("\n=== Updating version references ===")
|
|
|
|
if args.android and "android_sdk" in refs:
|
|
print(f"\n[Android SDK → {args.android}]")
|
|
for ref in refs["android_sdk"].get("files", []):
|
|
process_file_ref(ref, args.android)
|
|
|
|
if args.ios and "ios_sdk" in refs:
|
|
print(f"\n[iOS SDK → {args.ios}]")
|
|
for ref in refs["ios_sdk"].get("files", []):
|
|
process_file_ref(ref, args.ios)
|
|
|
|
# Resolve plugin version
|
|
plugin_version = args.plugin_version
|
|
if args.bump_patch and not plugin_version and "plugin" in refs:
|
|
for ref in refs["plugin"].get("files", []):
|
|
current = get_current_version_from_ref(ref)
|
|
if current:
|
|
plugin_version = bump_patch(current)
|
|
print(f"\n[Auto bump-patch: {current} → {plugin_version}]")
|
|
break
|
|
if not plugin_version:
|
|
print(" ERROR: Could not read current plugin version for bump-patch")
|
|
sys.exit(1)
|
|
|
|
if plugin_version and "plugin" in refs:
|
|
print(f"\n[Plugin version → {plugin_version}]")
|
|
for ref in refs["plugin"].get("files", []):
|
|
process_file_ref(ref, plugin_version)
|
|
|
|
if plugin_version and args.changelog_summary:
|
|
changelog_file = config.get("changelog_file", "CHANGELOG.md")
|
|
update_changelog(changelog_file, plugin_version, args.changelog_summary)
|
|
|
|
print("\n=== Version update complete ===")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|