feat: add PR review and edit tools to CLI and MCP server
This commit is contained in:
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Review and sign-off on a Gitea pull request.
|
||||
|
||||
Supports submitting a review (APPROVE, COMMENT, REQUEST_CHANGES) and optionally
|
||||
merging the pull request in one command.
|
||||
|
||||
Usage:
|
||||
review_pr.py --pr-number 12 --event APPROVE --body "Approved and signed off" --merge
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import base64
|
||||
import argparse
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
# Auto-execute using the project's local virtual environment Python
|
||||
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
|
||||
venv_python = os.path.join(PROJECT_ROOT, "venv", "bin", "python3")
|
||||
if os.path.exists(venv_python) and sys.executable != venv_python:
|
||||
os.execv(venv_python, [venv_python] + sys.argv)
|
||||
|
||||
from gitea_auth import get_auth_header, resolve_remote, add_remote_args, api_request, repo_api_url
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
parser = argparse.ArgumentParser(description="Review and sign-off on a Gitea pull request.")
|
||||
add_remote_args(parser)
|
||||
parser.add_argument("--pr-number", type=int, required=True, help="PR number/index to review.")
|
||||
parser.add_argument("--event", choices=["APPROVE", "COMMENT", "REQUEST_CHANGES"], default="APPROVE",
|
||||
help="Review event/action type (default: APPROVE).")
|
||||
parser.add_argument("--body", default="", help="Review body/comment text.")
|
||||
parser.add_argument("--body-file", help="Read review body from this file ('-' for stdin).")
|
||||
parser.add_argument("--merge", action="store_true", help="Automatically merge the PR if approved.")
|
||||
parser.add_argument("--merge-method", choices=["merge", "squash", "rebase"], default="merge",
|
||||
help="Merge method/style to use if merging (default: merge).")
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
host, org, repo = resolve_remote(args)
|
||||
|
||||
body = args.body
|
||||
if args.body_file:
|
||||
if args.body_file == "-":
|
||||
body = sys.stdin.read()
|
||||
else:
|
||||
with open(args.body_file, "r", encoding="utf-8") as fh:
|
||||
body = fh.read()
|
||||
|
||||
auth = get_auth_header(host)
|
||||
if not auth:
|
||||
print(f"Could not get credentials or token for {host}.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# 1. Fetch PR to get the latest head commit SHA (required for review validation)
|
||||
pr_url = f"{repo_api_url(host, org, repo)}/pulls/{args.pr_number}"
|
||||
try:
|
||||
pr_data = api_request("GET", pr_url, auth)
|
||||
except Exception as e:
|
||||
print(f"Error fetching PR #{args.pr_number}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
commit_sha = pr_data.get("head", {}).get("sha")
|
||||
if not commit_sha:
|
||||
print(f"Could not find head commit SHA for PR #{args.pr_number}.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# 2. Submit the PR review
|
||||
review_url = f"{repo_api_url(host, org, repo)}/pulls/{args.pr_number}/reviews"
|
||||
payload = {
|
||||
"body": body,
|
||||
"event": args.event,
|
||||
"commit_id": commit_sha
|
||||
}
|
||||
|
||||
try:
|
||||
api_request("POST", review_url, auth, payload)
|
||||
print(f"Successfully submitted review for PR #{args.pr_number}: event={args.event}")
|
||||
except Exception as e:
|
||||
print(f"Error submitting review: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# 3. Merge PR if --merge is requested and event is APPROVE
|
||||
if args.merge:
|
||||
if args.event != "APPROVE":
|
||||
print("Warning: Skipping merge because review event is not 'APPROVE'.", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
merge_url = f"{repo_api_url(host, org, repo)}/pulls/{args.pr_number}/merge"
|
||||
merge_payload = {
|
||||
"Do": args.merge_method,
|
||||
"force_merge": False
|
||||
}
|
||||
|
||||
try:
|
||||
api_request("POST", merge_url, auth, merge_payload)
|
||||
print(f"Successfully merged PR #{args.pr_number} using '{args.merge_method}' method.")
|
||||
except Exception as e:
|
||||
print(f"Error merging PR: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user