1
0
mirror of https://github.com/openSUSE/osc.git synced 2025-11-26 22:49:49 +01:00

Another take on parsing pull request references

Parse only references that start with 'PR:'.
Parse both owner/repo#number and gitea_url/owner/repo/pulls/number
This commit is contained in:
2025-08-12 21:25:02 +02:00
parent 999c1a716f
commit fe9c535596
2 changed files with 38 additions and 46 deletions

View File

@@ -309,47 +309,18 @@ class PullRequestDumpCommand(osc.commandline_git.GitObsCommand):
with open(os.path.join(metadata_dir, "submodules-diff.json"), "w", encoding="utf-8") as f: with open(os.path.join(metadata_dir, "submodules-diff.json"), "w", encoding="utf-8") as f:
json.dump(submodule_diff, f, indent=4, sort_keys=True) json.dump(submodule_diff, f, indent=4, sort_keys=True)
linked_prs = {} referenced_pull_requests = {}
for ref_owner, ref_repo, ref_number in pr_obj.parse_pr_references():
# body may contain references with both https:// or without, which look indetical in UI. so we must handle both cases: ref_id = f"{ref_owner}/{ref_repo}#{ref_number}"
for url in re.findall(r"https?://[^\s]+/pulls/\d+", pr_obj.body): referenced_pr_obj = gitea_api.PullRequest.get(self.gitea_conn, ref_owner, ref_repo, ref_number)
if not self.gitea_conn.host in url: referenced_pull_requests[ref_id] = referenced_pr_obj.dict()
print(f"ignoring PR {url}")
linked_prs[url] = None
continue
print(f"Linking PR {url}...")
_, _, linked_id = url.partition(self.gitea_conn.host + "/")
try:
linked_owner, linked_repo, linked_number = gitea_api.PullRequest.split_id(linked_id)
linked_pr_obj = gitea_api.PullRequest.get(self.gitea_conn, linked_owner, linked_repo, linked_number)
if linked_pr_obj is None:
linked_prs[url] = None
else:
linked_prs[url] = linked_pr_obj.to_light_dict()
except:
linked_prs[url] = None
for m in re.findall(r"([^\s\/]+)\/([^\s\/]+)\#(\d+)", pr_obj.body):
uri = f"{m[0]}/{m[1]}#{m[2]}"
print(f"Linking PR {uri}...")
try:
linked_pr_obj = gitea_api.PullRequest.get(self.gitea_conn, m[0], m[1], m[2])
if linked_pr_obj is None:
linked_prs[uri] = None
else:
linked_prs[uri] = linked_pr_obj.to_light_dict()
except:
linked_prs[uri] = None
with open( with open(
os.path.join(metadata_dir, "referenced-pull-requests.json"), os.path.join(metadata_dir, "referenced-pull-requests.json"),
"w", "w",
encoding="utf-8", encoding="utf-8",
) as f: ) as f:
json.dump(linked_prs, f, indent=4, sort_keys=True) json.dump(referenced_pull_requests, f, indent=4, sort_keys=True)
if warnings: if warnings:
return 38 return 38

View File

@@ -10,11 +10,7 @@ from .connection import GiteaHTTPResponse
from .user import User from .user import User
class PullRequestReview: class PullRequestReview(GiteaModel):
def __init__(self, data: dict, *, response: Optional[GiteaHTTPResponse] = None):
self._data = data
self._response = response
@property @property
def state(self) -> str: def state(self) -> str:
return self._data["state"] return self._data["state"]
@@ -104,9 +100,34 @@ class PullRequest(GiteaModel):
parsed_url = urllib.parse.urlparse(url) parsed_url = urllib.parse.urlparse(url)
path = parsed_url.path path = parsed_url.path
owner, repo, pulls, number = path.strip("/").split("/") owner, repo, pulls, number = path.strip("/").split("/")
assert pulls in ("pulls", "issues") if pulls not in ("pulls", "issues"):
raise ValueError(f"URL doesn't point to a pull request or an issue: {url}")
return owner, repo, int(number) return owner, repo, int(number)
def parse_pr_references(self) -> List[Tuple[str, str, int]]:
refs = re.findall(r"^PR: *(.*)$", self.body, re.M)
result = []
for ref in refs:
# try owner/repo#number first
try:
result.append(PullRequest.split_id(ref))
continue
except ValueError:
pass
# parse owner, repo, number from a pull request url
if ref.startswith(f"{self._conn.login.url.rstrip('/')}/"):
try:
result.append(PullRequest.get_owner_repo_number(ref))
continue
except ValueError:
pass
raise ValueError(f"Unable to parse pull request reference: {ref}")
return result
@property @property
def is_pull_request(self): def is_pull_request(self):
# determine if we're working with a proper pull request or an issue without pull request details # determine if we're working with a proper pull request or an issue without pull request details
@@ -337,7 +358,7 @@ class PullRequest(GiteaModel):
"body": description, "body": description,
} }
response = conn.request("POST", url, json_data=data) response = conn.request("POST", url, json_data=data)
obj = cls(response.json(), response=response) obj = cls(response.json(), response=response, conn=conn)
return obj return obj
@classmethod @classmethod
@@ -358,7 +379,7 @@ class PullRequest(GiteaModel):
""" """
url = conn.makeurl("repos", owner, repo, "pulls", str(number)) url = conn.makeurl("repos", owner, repo, "pulls", str(number))
response = conn.request("GET", url) response = conn.request("GET", url)
obj = cls(response.json(), response=response) obj = cls(response.json(), response=response, conn=conn)
return obj return obj
@classmethod @classmethod
@@ -391,7 +412,7 @@ class PullRequest(GiteaModel):
} }
url = conn.makeurl("repos", owner, repo, "pulls", str(number)) url = conn.makeurl("repos", owner, repo, "pulls", str(number))
response = conn.request("PATCH", url, json_data=json_data) response = conn.request("PATCH", url, json_data=json_data)
obj = cls(response.json(), response=response) obj = cls(response.json(), response=response, conn=conn)
return obj return obj
@classmethod @classmethod
@@ -420,7 +441,7 @@ class PullRequest(GiteaModel):
} }
url = conn.makeurl("repos", owner, repo, "pulls", query=q) url = conn.makeurl("repos", owner, repo, "pulls", query=q)
response = conn.request("GET", url) response = conn.request("GET", url)
obj_list = [cls(i, response=response) for i in response.json()] obj_list = [cls(i, response=response, conn=conn) for i in response.json()]
return obj_list return obj_list
@classmethod @classmethod
@@ -464,7 +485,7 @@ class PullRequest(GiteaModel):
url = conn.makeurl("repos", "issues", "search", query=q) url = conn.makeurl("repos", "issues", "search", query=q)
obj_list = [] obj_list = []
for response in conn.request_all_pages("GET", url): for response in conn.request_all_pages("GET", url):
obj_list.extend([cls(i, response=response) for i in response.json()]) obj_list.extend([cls(i, response=response, conn=conn) for i in response.json()])
return obj_list return obj_list
@classmethod @classmethod