From d2bacc9167a859603f197744e8c651b3e7b84604 Mon Sep 17 00:00:00 2001 From: Alexander Kuzmenkov <36882414+akuzm@users.noreply.github.com> Date: Thu, 11 Apr 2024 11:28:19 +0200 Subject: [PATCH 1/3] Fix backport script when PR references an issue from another repo We were always looking at the referenced issue number in the timescaledb repo, which is incorrect. --- scripts/backport.py | 53 ++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/scripts/backport.py b/scripts/backport.py index 569647923b9..bd53aac37cc 100755 --- a/scripts/backport.py +++ b/scripts/backport.py @@ -48,10 +48,9 @@ def get_referenced_issue(pr_number): repository(owner: "timescale", name: "timescaledb") { pullRequest(number: $pr_number) { closingIssuesReferences(first: 1) { - edges { - node { - number - } + nodes { + number, title, + labels (first: 30) { nodes { name } } } } } @@ -61,16 +60,26 @@ def get_referenced_issue(pr_number): ).substitute({"pr_number": pr_number}) ) - # The above returns {'data': {'repository': {'pullRequest': {'closingIssuesReferences': {'edges': [{'node': {'number': 4944}}]}}}}} + # The above returns: + # {'data': {'repository': {'pullRequest': {'closingIssuesReferences': {'nodes': [{'number': 6819, + # 'title': '[Bug]: Segfault when `ts_insert_blocker` function is called', + # 'labels': {'nodes': [{'name': 'bug'}]}}]}}}}} + # + # We can have {'nodes': [None]} in case it references an inaccessble repository, + # just ignore it. - ref_edges = ref_result["data"]["repository"]["pullRequest"][ + ref_nodes = ref_result["data"]["repository"]["pullRequest"][ "closingIssuesReferences" - ]["edges"] + ]["nodes"] - if ref_edges and len(ref_edges) == 1: - return ref_edges[0]["node"]["number"] + if not ref_nodes or len(ref_nodes) != 1 or not ref_nodes[0]: + return None, None, None - return None + number = ref_nodes[0]["number"] + title = ref_nodes[0]["title"] + labels = {x["name"] for x in ref_nodes[0]["labels"]["nodes"]} + + return number, title, labels def set_auto_merge(pr_number): @@ -160,9 +169,9 @@ def git_returncode(command): # address. It is required so that the commits are recognized by Github as made # by the user. That is, if you use a wrong e-mail, there won't be a clickable # profile picture next to the commit in the Github interface. -os.environ[ - "GIT_COMMITTER_EMAIL" -] = f"{token_user.id}+{token_user.login}@users.noreply.github.com" +os.environ["GIT_COMMITTER_EMAIL"] = ( + f"{token_user.id}+{token_user.login}@users.noreply.github.com" +) print( f"Will commit as {os.environ['GIT_COMMITTER_NAME']} <{os.environ['GIT_COMMITTER_EMAIL']}>" ) @@ -242,26 +251,25 @@ def __init__(self, pygithub_pr_, issue_number_): self.issue_number = issue_number_ -def should_backport_by_labels(pygithub_object): +def should_backport_by_labels(number, title, labels): """Should we backport the given PR/issue, judging by the labels? Note that this works in ternary logic: True means we must, False means we must not (tags to disable backport take precedence), and None means weak no (no tags to either request or disable backport)""" - labels = {label.name for label in pygithub_object.labels} stopper_labels = labels.intersection( ["disable-auto-backport", "auto-backport-not-done"] ) if stopper_labels: print( - f"#{pygithub_object.number} '{pygithub_object.title}' is labeled as '{list(stopper_labels)[0]}' which prevents automated backporting." + f"#{number} '{title}' is labeled as '{list(stopper_labels)[0]}' which prevents automated backporting." ) return False force_labels = labels.intersection(["bug", "force-auto-backport"]) if force_labels: print( - f"#{pygithub_object.number} '{pygithub_object.title}' is labeled as '{list(force_labels)[0]}' which requests automated backporting." + f"#{number} '{title}' is labeled as '{list(force_labels)[0]}' which requests automated backporting." ) return True @@ -308,7 +316,7 @@ def should_backport_by_labels(pygithub_object): # labels to request backport like "bug", and labels to prevent backport # like "disable-auto-backport", on both issue and the PR. We're going to use # the ternary False/None/True logic to combine them properly. - issue_number = get_referenced_issue(pull.number) + issue_number, issue_title, issue_labels = get_referenced_issue(pull.number) if not issue_number: should_backport_issue_ternary = None print( @@ -316,12 +324,17 @@ def should_backport_by_labels(pygithub_object): ) else: issue = source_repo.get_issue(number=issue_number) - should_backport_issue_ternary = should_backport_by_labels(issue) + should_backport_issue_ternary = should_backport_by_labels( + issue_number, issue_title, issue_labels + ) print( f"{commit_sha[:9]} belongs to the PR #{pull.number} '{pull.title}' " f"that references the issue #{issue.number} '{issue.title}'." ) - should_backport_pr_ternary = should_backport_by_labels(pull) + pull_labels = {label.name for label in pull.labels} + should_backport_pr_ternary = should_backport_by_labels( + pull.number, pull.title, pull_labels + ) # We backport if either the PR or the issue labels request the backport, and # none of them prevent it. I'm writing it with `is True` because I don't From 9898d9fb939f35bad6751389a9fad2f6126d934f Mon Sep 17 00:00:00 2001 From: Alexander Kuzmenkov <36882414+akuzm@users.noreply.github.com> Date: Thu, 11 Apr 2024 11:32:27 +0200 Subject: [PATCH 2/3] format --- scripts/backport.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/backport.py b/scripts/backport.py index bd53aac37cc..32d3d60eae3 100755 --- a/scripts/backport.py +++ b/scripts/backport.py @@ -169,9 +169,9 @@ def git_returncode(command): # address. It is required so that the commits are recognized by Github as made # by the user. That is, if you use a wrong e-mail, there won't be a clickable # profile picture next to the commit in the Github interface. -os.environ["GIT_COMMITTER_EMAIL"] = ( - f"{token_user.id}+{token_user.login}@users.noreply.github.com" -) +os.environ[ + "GIT_COMMITTER_EMAIL" +] = f"{token_user.id}+{token_user.login}@users.noreply.github.com" print( f"Will commit as {os.environ['GIT_COMMITTER_NAME']} <{os.environ['GIT_COMMITTER_EMAIL']}>" ) From 689cdab2b00eec8de5364a51c38111b2d5ed9938 Mon Sep 17 00:00:00 2001 From: Alexander Kuzmenkov <36882414+akuzm@users.noreply.github.com> Date: Fri, 12 Apr 2024 11:04:46 +0200 Subject: [PATCH 3/3] comment --- scripts/backport.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/backport.py b/scripts/backport.py index 32d3d60eae3..e4d3c39176b 100755 --- a/scripts/backport.py +++ b/scripts/backport.py @@ -41,6 +41,9 @@ def get_referenced_issue(pr_number): """Get the number of issue fixed by the given pull request. Returns None if no issue is fixed, or more than one issue""" + # We only need the first issue here. We also request only the first 30 labels, + # because GitHub requires some small restriction there that is counted + # towards the GraphQL API usage quota. ref_result = run_query( string.Template( """