102 lines
2.9 KiB
Python
102 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
import stat
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
PROJECT_DIR = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description="安装提交后自动推送到 Gitea 的 Git hook")
|
|
parser.add_argument("--remote", default="origin", help="Gitea remote 名称,默认 origin")
|
|
parser.add_argument("--force", action="store_true", help="覆盖已有 post-commit hook")
|
|
parser.add_argument("--dry-run", action="store_true", help="只打印将要写入的 hook 内容")
|
|
return parser.parse_args()
|
|
|
|
|
|
def run_git(args: list[str]) -> str:
|
|
result = subprocess.run(
|
|
["git", *args],
|
|
cwd=PROJECT_DIR,
|
|
text=True,
|
|
capture_output=True,
|
|
check=False,
|
|
)
|
|
if result.returncode != 0:
|
|
raise RuntimeError(result.stderr.strip() or result.stdout.strip())
|
|
return result.stdout.strip()
|
|
|
|
|
|
def hook_text(remote: str) -> str:
|
|
return f"""#!/bin/sh
|
|
set -eu
|
|
|
|
remote={remote!r}
|
|
branch=$(git symbolic-ref --quiet --short HEAD || true)
|
|
|
|
if [ -z "$branch" ]; then
|
|
echo "[gitea-backup] detached HEAD,跳过自动推送" >&2
|
|
exit 0
|
|
fi
|
|
|
|
if ! git remote get-url "$remote" >/dev/null 2>&1; then
|
|
echo "[gitea-backup] remote '$remote' 不存在,跳过自动推送" >&2
|
|
exit 0
|
|
fi
|
|
|
|
echo "[gitea-backup] pushing $branch to $remote"
|
|
if ! git push "$remote" "HEAD:$branch"; then
|
|
echo "[gitea-backup] push 失败;本地提交已保留,请检查 SSH key 或远端权限" >&2
|
|
exit 0
|
|
fi
|
|
"""
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
git_dir = Path(run_git(["rev-parse", "--git-dir"]))
|
|
if not git_dir.is_absolute():
|
|
git_dir = PROJECT_DIR / git_dir
|
|
hook_path = git_dir / "hooks" / "post-commit"
|
|
|
|
try:
|
|
remote_url = run_git(["remote", "get-url", args.remote])
|
|
except RuntimeError:
|
|
remote_url = ""
|
|
|
|
content = hook_text(args.remote)
|
|
if args.dry_run:
|
|
print(content)
|
|
if remote_url:
|
|
print(f"# remote {args.remote}: {remote_url}")
|
|
else:
|
|
print(f"# remote {args.remote}: 未配置")
|
|
return 0
|
|
|
|
if hook_path.exists() and not args.force:
|
|
raise RuntimeError(f"{hook_path} 已存在;如需覆盖,请加 --force")
|
|
|
|
hook_path.parent.mkdir(parents=True, exist_ok=True)
|
|
hook_path.write_text(content, encoding="utf-8")
|
|
mode = hook_path.stat().st_mode
|
|
hook_path.chmod(mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
print(f"已安装 {hook_path}")
|
|
if remote_url:
|
|
print(f"提交后将自动推送到 {args.remote}: {remote_url}")
|
|
else:
|
|
print(f"注意:当前尚未配置 remote '{args.remote}',请先设置 Gitea SSH 地址")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
raise SystemExit(main())
|
|
except Exception as exc:
|
|
print(f"安装失败: {exc}", file=sys.stderr)
|
|
raise SystemExit(1)
|