diff --git a/scripts/gitea_api.py b/scripts/gitea_api.py index be56423..166a945 100644 --- a/scripts/gitea_api.py +++ b/scripts/gitea_api.py @@ -97,7 +97,7 @@ def post_review(gitea_url, api_token, target_repo, pr_num, review): # ── Issue endpoints ───────────────────────────────────────────────────── _ISSUE_REF_RE = re.compile( - r"(?:fixe?s?|close?s?|resolve?s?|refs?|see)\s+" + r"(?:fixe?s?|close?s?|resolve?s?|refs?|see)[\s:]+" r"((?:[\w.-]+/[\w.-]+)?#\d+)", re.IGNORECASE, ) diff --git a/scripts/test_issue_api.py b/scripts/test_issue_api.py new file mode 100644 index 0000000..45f12ac --- /dev/null +++ b/scripts/test_issue_api.py @@ -0,0 +1,121 @@ +"""Smoke-tests for the issue-linking feature in gitea_api.py. + +Run:: + + python scripts/test_issue_api.py +""" + +import sys +import os + +sys.path.insert(0, os.path.dirname(__file__)) + +from gitea_api import ( + _extract_issue_refs, + format_issues_markdown, + fetch_issue, + fetch_linked_issues, +) + +# ── Test 1: _extract_issue_refs ──────────────────────────────────────── + +BODY = """ +This PR fixes bug in user login. + +Closes #42. + +Also see #99 and refs: org/other-repo#7 for related changes. +Not a ref: # 12 (space between). +""" + +refs = _extract_issue_refs(BODY) +print("=== Test 1: _extract_issue_refs ===") +print(f"Found {len(refs)} refs:") +for owner, repo, num in refs: + print(f" owner={owner!r} repo={repo!r} num={num}") +assert len(refs) == 3, f"Expected 3 refs, got {len(refs)}" +assert (None, None, 42) in refs, "Missing #42" +assert (None, None, 99) in refs, "Missing #99" +assert ("org", "other-repo", 7) in refs, "Missing org/other-repo#7" +print("PASS\n") + + +# ── Test 2: format_issues_markdown ───────────────────────────────────── + +issues = [ + { + "number": 42, + "title": "Login bug", + "state": "open", + "labels": ["bug", "high-priority"], + "body": "Users cannot log in with email.", + "html_url": "https://gitea.example.com/org/repo/issues/42", + }, + { + "number": 99, + "title": "Add rate limiting", + "state": "closed", + "labels": [], + "body": "Need to rate-limit login attempts.", + "html_url": "https://gitea.example.com/org/repo/issues/99", + }, +] + +md = format_issues_markdown(issues) +print("=== Test 2: format_issues_markdown ===") +print(md[:500]) +assert "Login bug" in md +assert "high-priority" in md +assert "Add rate limiting" in md +assert "closed" in md +print("PASS\n") + + +# ── Test 3: E2E with real API (optional) ─────────────────────────────── + +GITEA_URL = os.environ.get("GITEA_URL", "") +API_TOKEN = os.environ.get("GITEA_API_TOKEN", "") +TARGET_REPO = os.environ.get("GITEA_REPO", "") + +if GITEA_URL and API_TOKEN and TARGET_REPO: + print("=== Test 3: E2E with real API ===") + issues = fetch_linked_issues(GITEA_URL, API_TOKEN, TARGET_REPO, BODY) + print(f"Fetched {len(issues)} issue(s)") + for iss in issues: + print(f" #{iss['number']}: {iss['title']} [{iss['state']}]") + print(f" body: {iss['body'][:100]}...") + print("PASS\n") +else: + print("=== Test 3: E2E (skipped — set GITEA_URL, GITEA_API_TOKEN, GITEA_REPO) ===\n") + + +# ── Test 4: Edge cases ───────────────────────────────────────────────── + +print("=== Test 4: Edge cases ===") + +# Empty body +assert _extract_issue_refs("") == [], "Empty body should return empty list" +print(" empty body: PASS") + +# No issue refs +assert _extract_issue_refs("Just a regular description.") == [], \ + "No refs should return empty list" +print(" no refs: PASS") + +# Duplicate detection: "Fixes #1" + bare "#1" → only one entry +refs = _extract_issue_refs("Fixes #42. Also #42.") +nums = [r[2] for r in refs] +assert nums == [42], f"Duplicated #42 should appear once, got {nums}" +print(" duplicate dedup: PASS") + +# Mixed refs +refs = _extract_issue_refs("closes #10 FIXES #20 Resolves org/x#30") +assert len(refs) == 3 +print(" mixed keywords: PASS") + +# Empty issues markdown +assert format_issues_markdown([]) == "" +print(" empty markdown: PASS\n") + + +print("All tests passed!")