b7e195e426
- New: mcp_server.py — FastMCP stdio server exposing 7 tools: gitea_create_issue, gitea_create_pr, gitea_close_issue, gitea_list_issues, gitea_view_issue, gitea_mark_issue, gitea_mirror_refs - New: auth.py — shared authentication and API helpers (get_credentials, get_auth_header, api_request, repo_api_url) - Refactored: create_pr.py, create_issue.py, manage_labels.py to use shared auth module (eliminates credential duplication) - New: tests/test_mcp_server.py — 17 tests for all MCP tools - Updated: tests/test_credentials.py — now tests auth.py directly - Updated: tests/test_create_issue.py — adapted for refactored imports - New: requirements.txt — frozen venv deps (mcp[cli], pytest) - Updated: README.md — MCP server as primary interface - Config: added gitea-tools to mcp_config.json Closes #1. Resolves #2, #5. Relates to #7.
68 lines
2.2 KiB
Python
68 lines
2.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Create a Gitea issue.
|
|
|
|
Parameterized over title/body and the target Gitea instance.
|
|
Two instances are known out of the box:
|
|
|
|
dadeschools -> gitea.dadeschools.net / Contractor / Timesheet
|
|
prgs -> gitea.prgs.cc / Scaled-Tech-Consulting / Timesheet
|
|
|
|
Auth is pulled from the macOS keychain via `git credential fill` for the
|
|
chosen host -- no tokens on the command line.
|
|
|
|
Examples:
|
|
create_issue.py --title "Bug: blank PDF" --body "Blank on Safari"
|
|
create_issue.py --remote prgs --title "Add tests" --body-file desc.md
|
|
create_issue.py --host gitea.example.com --org Foo --repo Bar --title "..."
|
|
"""
|
|
import sys
|
|
import argparse
|
|
|
|
from auth import (
|
|
get_credentials, resolve_remote, add_remote_args,
|
|
api_request, repo_api_url,
|
|
)
|
|
|
|
|
|
def main(argv=None):
|
|
parser = argparse.ArgumentParser(description="Create a Gitea issue.")
|
|
add_remote_args(parser)
|
|
parser.add_argument("--title", required=True, help="Issue title.")
|
|
parser.add_argument("--body", default="", help="Issue body text.")
|
|
parser.add_argument("--body-file",
|
|
help="Read issue body from this file ('-' for stdin).")
|
|
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()
|
|
|
|
user, password = get_credentials(host)
|
|
if not user or not password:
|
|
print(f"Could not get credentials for {host} "
|
|
f"(no keychain entry? try a manual `git credential fill`).",
|
|
file=sys.stderr)
|
|
return 1
|
|
|
|
import base64
|
|
auth = f"Basic {base64.b64encode(f'{user}:{password}'.encode()).decode()}"
|
|
url = f"{repo_api_url(host, org, repo)}/issues"
|
|
|
|
try:
|
|
data = api_request("POST", url, auth, {"title": args.title, "body": body})
|
|
print(f"Issue #{data.get('number')}: {data.get('html_url')}")
|
|
return 0
|
|
except RuntimeError as e:
|
|
print(f"Error: {e}", file=sys.stderr)
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|