GRM-20: feat: replace inline workflow scripts with tested Python modules
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user