Template
136 lines
4.3 KiB
Python
Executable File
136 lines
4.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import json
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(subprocess.check_output(["git", "rev-parse", "--show-toplevel"], text=True).strip())
|
|
PLUGIN_JSON_PATH = REPO_ROOT / "plugin.json"
|
|
|
|
STOP_PATTERNS = [
|
|
r"\[no[-_ ]?bump\]",
|
|
r"\[skip[-_ ]?bump\]",
|
|
r"\[no[-_ ]?version[-_ ]?bump\]",
|
|
r"\[skip[-_ ]?version\]",
|
|
r"\bno[-_ ]bump\b",
|
|
r"\bskip[-_ ]bump\b",
|
|
r"\bno[-_ ]version[-_ ]bump\b",
|
|
]
|
|
|
|
|
|
def increment_patch_version(version_str: str) -> str:
|
|
match = re.fullmatch(r"^(\d+)\.(\d+)\.(\d+)(.*)$", version_str.strip())
|
|
if not match:
|
|
raise ValueError(f"Version '{version_str}' does not match x.y.z format")
|
|
major, minor, patch, suffix = match.groups()
|
|
new_patch = int(patch) + 1
|
|
return f"{major}.{minor}.{new_patch}{suffix}"
|
|
|
|
|
|
def get_head_version() -> str | None:
|
|
res = subprocess.run(
|
|
["git", "rev-parse", "--verify", "HEAD"],
|
|
cwd=REPO_ROOT,
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
)
|
|
if res.returncode != 0:
|
|
return None
|
|
|
|
show_res = subprocess.run(
|
|
["git", "show", "HEAD:plugin.json"],
|
|
cwd=REPO_ROOT,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.DEVNULL,
|
|
text=True,
|
|
)
|
|
if show_res.returncode != 0:
|
|
return None
|
|
|
|
try:
|
|
head_data = json.loads(show_res.stdout)
|
|
return str(head_data.get("version")) if "version" in head_data else None
|
|
except json.JSONDecodeError:
|
|
return None
|
|
|
|
|
|
def should_skip_from_commit_msg() -> bool:
|
|
# 1. Check GIT_PARAMS / COMMIT_EDITMSG / MERGE_MSG
|
|
candidates = [
|
|
REPO_ROOT / ".git" / "COMMIT_EDITMSG",
|
|
REPO_ROOT / ".git" / "MERGE_MSG",
|
|
]
|
|
for p in candidates:
|
|
if p.exists():
|
|
content = p.read_text(encoding="utf-8", errors="replace")
|
|
lines = [line for line in content.splitlines() if not line.strip().startswith("#")]
|
|
text = " ".join(lines)
|
|
for pattern in STOP_PATTERNS:
|
|
if re.search(pattern, text, re.IGNORECASE):
|
|
return True
|
|
|
|
# 2. Check process command-line arguments (e.g. git commit -m "...")
|
|
try:
|
|
# On Linux, inspect parent process /proc cmdline
|
|
ppid = subprocess.check_output(["ps", "-o", "ppid=", "-p", str(Path("/proc/self").resolve().name)], text=True).strip()
|
|
cmdline_path = Path(f"/proc/{ppid}/cmdline")
|
|
if cmdline_path.exists():
|
|
cmd_args = cmdline_path.read_bytes().decode("utf-8", errors="replace")
|
|
for pattern in STOP_PATTERNS:
|
|
if re.search(pattern, cmd_args, re.IGNORECASE):
|
|
return True
|
|
except Exception:
|
|
pass
|
|
|
|
return False
|
|
|
|
|
|
def main() -> int:
|
|
# Don't auto-bump during merge/rebase in progress
|
|
if (REPO_ROOT / ".git" / "MERGE_HEAD").exists() or (REPO_ROOT / ".git" / "rebase-merge").exists():
|
|
return 0
|
|
|
|
if should_skip_from_commit_msg():
|
|
print("pre-commit: stop word detected in commit message, skipping version bump")
|
|
return 0
|
|
|
|
if not PLUGIN_JSON_PATH.exists():
|
|
return 0
|
|
|
|
try:
|
|
data = json.loads(PLUGIN_JSON_PATH.read_text(encoding="utf-8"))
|
|
current_version = str(data.get("version", ""))
|
|
except Exception as e:
|
|
print(f"pre-commit: failed to parse {PLUGIN_JSON_PATH}: {e}", file=sys.stderr)
|
|
return 1
|
|
|
|
head_version = get_head_version()
|
|
|
|
# Skip if version was manually changed (differs from HEAD)
|
|
if head_version is not None and current_version != head_version:
|
|
print(
|
|
f"pre-commit: version already modified ({head_version} -> {current_version}), skipping auto-increment"
|
|
)
|
|
return 0
|
|
|
|
try:
|
|
new_version = increment_patch_version(current_version)
|
|
data["version"] = new_version
|
|
PLUGIN_JSON_PATH.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
|
|
except Exception as e:
|
|
print(f"pre-commit: failed to bump version in {PLUGIN_JSON_PATH}: {e}", file=sys.stderr)
|
|
return 1
|
|
|
|
res = subprocess.run(["git", "add", str(PLUGIN_JSON_PATH)], cwd=REPO_ROOT)
|
|
if res.returncode != 0:
|
|
print("pre-commit: failed to stage plugin.json", file=sys.stderr)
|
|
return res.returncode
|
|
|
|
print(f"pre-commit: bumped version {current_version} -> {new_version}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|