Template
[nobump] Added plugin minor version auto-increment
This commit is contained in:
1 parent
1ef4e61334
commit
5e7f722bd9
1 file changed
+135
Executable
+135
@@ -0,0 +1,135 @@
|
|||||||
|
#!/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())
|
||||||
Reference in new issue
Block a user