saqut-compiler/scripts/gitea.py

170 lines
6.1 KiB
Python
Executable File

#!/usr/bin/env python3
import sys
import json
import base64
import urllib.request
import urllib.parse
import argparse
GITEA_API_URL = "https://git.saqut.com/api/v1"
REPO_PATH = "repos/saqut/saqut-compiler"
def get_credentials():
try:
import os
cred_path = os.path.expanduser("~/.git-credentials")
if os.path.exists(cred_path):
with open(cred_path, "r") as f:
for line in f:
if "git.saqut.com" in line:
# Format: https://username:password@git.saqut.com
url_part = line.strip().split("@")[0]
auth_part = url_part.split("://")[1]
username, password = auth_part.split(":")
# URL decode password
password = urllib.parse.unquote(password)
return username, password
except Exception as e:
sys.stderr.write(f"Credentials load warning: {e}\n")
return "saqut", "<Cloud2022>"
def make_request(endpoint, method="GET", data=None):
username, password = get_credentials()
url = f"{GITEA_API_URL}/{endpoint}"
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
auth_str = f"{username}:{password}"
auth_b64 = base64.b64encode(auth_str.encode('utf-8')).decode('utf-8')
headers["Authorization"] = f"Basic {auth_b64}"
req_data = None
if data is not None:
req_data = json.dumps(data).encode('utf-8')
req = urllib.request.Request(url, data=req_data, headers=headers, method=method)
try:
with urllib.request.urlopen(req) as response:
res_data = response.read()
if response.status in (200, 201):
return json.loads(res_data.decode('utf-8'))
elif response.status == 204:
return {"success": True}
return res_data.decode('utf-8')
except urllib.error.HTTPError as e:
sys.stderr.write(f"HTTP Error: {e.code} - {e.reason}\n")
try:
err_body = e.read().decode('utf-8')
sys.stderr.write(f"Details: {err_body}\n")
except Exception:
pass
sys.exit(1)
except Exception as e:
sys.stderr.write(f"Connection Error: {e}\n")
sys.exit(1)
def list_issues(state="open"):
endpoint = f"{REPO_PATH}/issues?state={state}&limit=100"
issues = make_request(endpoint)
print(f"\n--- Gitea {state.upper()} Issues ---")
for issue in issues:
print(f"#{issue['number']} - {issue['title']} ({issue['state']})")
if issue.get('assignee'):
print(f" Assignee: {issue['assignee']['login']}")
def get_issue(number):
endpoint = f"{REPO_PATH}/issues/{number}"
issue = make_request(endpoint)
print(json.dumps(issue, indent=2, ensure_ascii=False))
def create_issue(title, body, assignee=None):
endpoint = f"{REPO_PATH}/issues"
data = {
"title": title,
"body": body
}
if assignee:
data["assignees"] = [assignee]
res = make_request(endpoint, method="POST", data=data)
print(f"Created issue #{res['number']}: {res['title']}")
def edit_issue(number, title=None, body=None, state=None, assignee=None):
endpoint = f"{REPO_PATH}/issues/{number}"
data = {}
if title is not None:
data["title"] = title
if body is not None:
data["body"] = body
if state is not None:
data["state"] = state
if assignee is not None:
data["assignees"] = [assignee] if assignee else []
res = make_request(endpoint, method="PATCH", data=data)
print(f"Updated issue #{res['number']} to state: {res['state']}")
def comment_issue(number, body):
endpoint = f"{REPO_PATH}/issues/{number}/comments"
data = {
"body": body
}
res = make_request(endpoint, method="POST", data=data)
print(f"Added comment to issue #{number} (Comment ID: {res['id']})")
def main():
parser = argparse.ArgumentParser(description="Gitea Issue Manager for saQut")
subparsers = parser.add_subparsers(dest="command", help="Subcommands")
# List
list_parser = subparsers.add_parser("list", help="List issues")
list_parser.add_argument("--state", choices=["open", "closed", "all"], default="open", help="State of issues")
# Get
get_parser = subparsers.add_parser("get", help="Get issue detail")
get_parser.add_argument("number", type=int, help="Issue number")
# Create
create_parser = subparsers.add_parser("create", help="Create a new issue")
create_parser.add_argument("--title", required=True, help="Issue title")
create_parser.add_argument("--body", default="", help="Issue body")
create_parser.add_argument("--assignee", help="Assignee username")
# Edit
edit_parser = subparsers.add_parser("edit", help="Edit an existing issue")
edit_parser.add_argument("number", type=int, help="Issue number")
edit_parser.add_argument("--title", help="New title")
edit_parser.add_argument("--body", help="New body")
edit_parser.add_argument("--state", choices=["open", "closed"], help="New state")
edit_parser.add_argument("--assignee", help="New assignee (empty string to unassign)")
# Comment
comment_parser = subparsers.add_parser("comment", help="Add a comment to an issue")
comment_parser.add_argument("number", type=int, help="Issue number")
comment_parser.add_argument("--body", required=True, help="Comment body")
args = parser.parse_args()
if not args.command:
parser.print_help()
sys.exit(0)
if args.command == "list":
list_issues(args.state)
elif args.command == "get":
get_issue(args.number)
elif args.command == "create":
create_issue(args.title, args.body, args.assignee)
elif args.command == "edit":
edit_issue(args.number, args.title, args.body, args.state, args.assignee)
elif args.command == "comment":
comment_issue(args.number, args.body)
if __name__ == "__main__":
main()