76 lines
2.6 KiB
Python
76 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Auto-merge PR by extracting task ID from branch and validating PR title.
|
|
|
|
Usage:
|
|
GITEA_TOKEN=<token> python3 scripts/auto_merge.py <branch> <pr_title> <repo> <pr_number>
|
|
"""
|
|
import argparse
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
import requests
|
|
|
|
GITEA_API = "https://git.oblachno.oblachno.fyi/api/v1"
|
|
TASK_ID_RE = re.compile(r"GRM-\d+")
|
|
CONVENTIONAL_RE = re.compile(
|
|
r"^(feat|fix|chore|docs|style|refactor|perf|test|ci|build|revert|BREAKING CHANGE)(\(.+\))?: .+"
|
|
)
|
|
|
|
|
|
def extract_task_id(branch: str) -> str:
|
|
"""Extract GRM-N task identifier from branch name."""
|
|
match = TASK_ID_RE.search(branch)
|
|
return match.group(0) if match else ""
|
|
|
|
|
|
def validate_pr_title(pr_title: str) -> None:
|
|
"""Raise SystemExit if PR title does not follow conventional commits."""
|
|
if not CONVENTIONAL_RE.match(pr_title):
|
|
print("ERROR: PR title must follow conventional commit format.")
|
|
print(" Expected: <type>: <description>")
|
|
print(f" Got: {pr_title}")
|
|
sys.exit(1)
|
|
|
|
|
|
def merge_pr(token: str, repo: str, pr_number: str, merge_title: str) -> None:
|
|
"""Call Gitea API to squash-merge the PR."""
|
|
url = f"{GITEA_API}/repos/{repo}/pulls/{pr_number}/merge"
|
|
headers = {
|
|
"Authorization": f"token {token}",
|
|
"Content-Type": "application/json",
|
|
}
|
|
payload = {"Do": "squash", "MergeTitleField": merge_title}
|
|
response = requests.post(url, headers=headers, json=payload, timeout=30)
|
|
response.raise_for_status()
|
|
|
|
|
|
def main(args: list[str] | None = None) -> None: # pragma: no cover
|
|
argv = args if args is not None else sys.argv
|
|
parser = argparse.ArgumentParser(description="Auto-merge a PR with task ID")
|
|
parser.add_argument("branch", help="Source branch name")
|
|
parser.add_argument("pr_title", help="Pull request title")
|
|
parser.add_argument("repo", help="Repository full name (owner/repo)")
|
|
parser.add_argument("pr_number", help="Pull request number")
|
|
parsed = parser.parse_args(argv[1:])
|
|
|
|
token = os.environ.get("GITEA_TOKEN", "")
|
|
if not token:
|
|
print("ERROR: GITEA_TOKEN is not set.", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
task_id = extract_task_id(parsed.branch)
|
|
if not task_id:
|
|
print(f"ERROR: No task ID (GRM-N) found in branch name '{parsed.branch}'")
|
|
sys.exit(1)
|
|
|
|
validate_pr_title(parsed.pr_title)
|
|
|
|
merge_title = f"{task_id}: {parsed.pr_title}"
|
|
merge_pr(token, parsed.repo, parsed.pr_number, merge_title)
|
|
print(f"PR #{parsed.pr_number} squash-merged with title: {merge_title}")
|
|
|
|
|
|
if __name__ == "__main__": # pragma: no cover
|
|
main()
|