fix(kvb-git-close-issues): drop false references found on a real PR
🧪 Test / 🧪 Lock + lint (push) Canceled after 0s
🧪 Test / 🧪 Lock + lint (push) Canceled after 0s
A read-only run of issues.py on infinito-nexus/core#1326 listed #0 and #1 from CI row names like WordPress#0 and docs#1, reported #1324 twice (plain and as infinito-nexus/core#1324 from the linked issue), and offered the pull request's own number. A bare # now needs no word character or slash before it and a number from 1, the required --repo maps the pull request's own repository to the plain form and merges the sources, and the pull request's number is skipped; the skill passes --repo and reads number. On #1326 only #1324 closing remains. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6865ae718a
commit
32f58712e5
3 files changed
+26
-14
No files matched your search
@@ -18,7 +18,7 @@ body and the commits, a trailing number in the branch name, and the issues
|
||||
GitHub already links:
|
||||
|
||||
```bash
|
||||
gh pr view <pr> --json body,headRefName,commits,closingIssuesReferences | issues.py
|
||||
gh pr view <pr> --json number,body,headRefName,commits,closingIssuesReferences | issues.py --repo <owner/name>
|
||||
```
|
||||
|
||||
## Step 2: verify
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
"""List the issues a pull request references, from `gh pr view --json` on stdin.
|
||||
|
||||
Args:
|
||||
stdin: JSON with body, headRefName, commits and closingIssuesReferences,
|
||||
as `gh pr view <pr> --json body,headRefName,commits,closingIssuesReferences`
|
||||
prints it.
|
||||
stdin: JSON with number, body, headRefName, commits and
|
||||
closingIssuesReferences, as `gh pr view <pr> --json
|
||||
number,body,headRefName,commits,closingIssuesReferences` prints it.
|
||||
--repo: owner/name of the pull request's repository; its own references
|
||||
are reported without a repository.
|
||||
--json: print the candidates as JSON instead of tab-separated lines.
|
||||
|
||||
Exit codes:
|
||||
@@ -19,7 +21,7 @@ import re
|
||||
import sys
|
||||
|
||||
KEYWORD = r"(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)"
|
||||
REF = r"(?:(?P<repo>[\w.-]+/[\w.-]+)#|https://github\.com/(?P<url>[\w.-]+/[\w.-]+)/issues/|#)(?P<num>\d+)"
|
||||
REF = r"(?:(?P<repo>[\w.-]+/[\w.-]+)#|https://github\.com/(?P<url>[\w.-]+/[\w.-]+)/issues/|(?<![\w/])#)(?P<num>[1-9]\d*)"
|
||||
PATTERN = re.compile(rf"(?P<kw>\b{KEYWORD}\b:?\s+)?{REF}", re.IGNORECASE)
|
||||
BRANCH = re.compile(r"[/-](\d+)$")
|
||||
|
||||
@@ -40,7 +42,7 @@ def scan(text: str, source: str, found: dict) -> None:
|
||||
entry["sources"].append(source)
|
||||
|
||||
|
||||
def candidates(pr: dict) -> list[dict]:
|
||||
def candidates(pr: dict, own: str) -> list[dict]:
|
||||
found: dict = {}
|
||||
scan(pr.get("body", ""), "body", found)
|
||||
for commit in pr.get("commits", []):
|
||||
@@ -57,14 +59,20 @@ def candidates(pr: dict) -> list[dict]:
|
||||
entry = found.setdefault(key, {"closing": False, "sources": []})
|
||||
entry["closing"] = True
|
||||
entry["sources"].append("linked")
|
||||
return [
|
||||
{"repo": repo, "issue": num, **entry}
|
||||
for (repo, num), entry in sorted(found.items())
|
||||
]
|
||||
merged: dict = {}
|
||||
for (repo, num), entry in found.items():
|
||||
key = ("" if repo.lower() == own.lower() else repo, num)
|
||||
if key == ("", pr.get("number")):
|
||||
continue
|
||||
target = merged.setdefault(key, {"closing": False, "sources": []})
|
||||
target["closing"] = target["closing"] or entry["closing"]
|
||||
target["sources"] += [s for s in entry["sources"] if s not in target["sources"]]
|
||||
return [{"repo": repo, "issue": num, **entry} for (repo, num), entry in sorted(merged.items())]
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
||||
parser.add_argument("--repo", required=True)
|
||||
parser.add_argument("--json", action="store_true")
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
@@ -73,7 +81,7 @@ def main() -> int:
|
||||
fail("stdin is not the JSON of gh pr view --json")
|
||||
if not isinstance(pr, dict):
|
||||
fail("stdin is not a pull request object")
|
||||
rows = candidates(pr)
|
||||
rows = candidates(pr, args.repo)
|
||||
if args.json:
|
||||
print(json.dumps(rows, indent=1))
|
||||
return 0
|
||||
|
||||
@@ -11,7 +11,11 @@ from pathlib import Path
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
SCRIPT = REPO_ROOT / "skills" / "kvb-git-close-issues" / "scripts" / "issues.py"
|
||||
PR = {
|
||||
"body": "Fixes #12 and touches #13.\nCloses: other/repo#7\nSee https://github.com/a/b/issues/9",
|
||||
"number": 40,
|
||||
"body": (
|
||||
"Fixes #12 and touches #13.\nCloses: other/repo#7\nSee https://github.com/a/b/issues/9\n"
|
||||
"Rows WordPress#0 and docs#1 are not issues; this is #40."
|
||||
),
|
||||
"headRefName": "fix/sys-ctl-hlth-runtime/vulnerability-engines/1324",
|
||||
"commits": [
|
||||
{"oid": "abcdef1234567", "messageHeadline": "fix: guard", "messageBody": "Resolved #13"},
|
||||
@@ -25,7 +29,7 @@ PR = {
|
||||
|
||||
def _run(payload: str) -> subprocess.CompletedProcess:
|
||||
return subprocess.run(
|
||||
[sys.executable, str(SCRIPT), "--json"],
|
||||
[sys.executable, str(SCRIPT), "--repo", "Owner/repo", "--json"],
|
||||
input=payload,
|
||||
check=False,
|
||||
capture_output=True,
|
||||
@@ -46,7 +50,7 @@ class TestIssues(unittest.TestCase):
|
||||
("other/repo", 7): (True, ["body"]),
|
||||
("a/b", 9): (False, ["body"]),
|
||||
("", 1324): (False, ["branch"]),
|
||||
("owner/repo", 21): (True, ["linked"]),
|
||||
("", 21): (True, ["linked"]),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
Reference in new issue
Block a user