This is an automated email from the ASF dual-hosted git repository.

zhengruifeng pushed a commit to branch branch-4.x
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/branch-4.x by this push:
     new fd62e1a873cb [SPARK-56963][INFRA] Auto-close non-default-branch PRs in 
merge_spark_pr.py
fd62e1a873cb is described below

commit fd62e1a873cb69157aa7da9a63faa383c0bb0d7f
Author: Ruifeng Zheng <[email protected]>
AuthorDate: Wed May 20 18:45:48 2026 +0800

    [SPARK-56963][INFRA] Auto-close non-default-branch PRs in merge_spark_pr.py
    
    ### What changes were proposed in this pull request?
    
    When `dev/merge_spark_pr.py` merges a PR whose target branch is not the 
repository's default (e.g. backport PRs against `branch-X.Y`), explicitly close 
the PR through the GitHub REST API after the push. Specifically:
    
    - Add a small `close_pr(pr_num)` helper that issues an authenticated `PATCH 
/pulls/{n}` with `{"state": "closed"}`.
    - After a successful `git push` in `merge_pr()`, fetch the PR via `GET 
/pulls/{n}` and, if the state is still `"open"`, call `close_pr(pr_num)`.
    
    ### Why are the changes needed?
    
    The squash-merge commit message already contains `Closes #N from ...`, 
which GitHub treats as a closing keyword. However, GitHub honors closing 
keywords **only when the commit lands on the repository's default branch**. 
Backport PRs that target `branch-X.Y` therefore got merged successfully but 
stayed open on GitHub, and the committer had to close them manually. #56004 was 
a recent example.
    
    Checking the PR state after the push (instead of comparing `target_ref` to 
the default branch up front) keeps the change small and self-correcting: it 
does the right thing whenever GitHub's auto-close did not fire, without having 
to encode the default-branch rule in the script.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    Compile-checked with `python3 -m py_compile dev/merge_spark_pr.py` and the 
existing doctests still pass via `python3 -m doctest dev/merge_spark_pr.py`. 
End-to-end merge behavior will be validated the next time a committer runs the 
script on a backport PR.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Claude Opus 4.7)
    
    Closes #56007 from zhengruifeng/merge-script-close-backport-pr.
    
    Authored-by: Ruifeng Zheng <[email protected]>
    Signed-off-by: Ruifeng Zheng <[email protected]>
    (cherry picked from commit 4988ef161a809cdf85bea1f143cc0be26a9dd68c)
    Signed-off-by: Ruifeng Zheng <[email protected]>
---
 dev/merge_spark_pr.py | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/dev/merge_spark_pr.py b/dev/merge_spark_pr.py
index 4b256d061715..8d50366550f5 100755
--- a/dev/merge_spark_pr.py
+++ b/dev/merge_spark_pr.py
@@ -107,6 +107,21 @@ def get_json(url):
         sys.exit(-1)
 
 
+def close_pr(pr_num):
+    url = "%s/pulls/%s" % (GITHUB_API_BASE, pr_num)
+    data = json.dumps({"state": "closed"}).encode("utf-8")
+    request = Request(url, data=data, method="PATCH")
+    request.add_header("Content-Type", "application/json")
+    request.add_header("Accept", "application/vnd.github+json")
+    if GITHUB_OAUTH_KEY:
+        request.add_header("Authorization", "token %s" % GITHUB_OAUTH_KEY)
+    try:
+        return json.load(urlopen(request))
+    except HTTPError as e:
+        print_error("Failed to close PR #%s: HTTP %s %s" % (pr_num, e.code, 
e.reason))
+        return None
+
+
 def fail(msg):
     print_error(msg)
     clean_up()
@@ -743,6 +758,14 @@ def main():
 
     merge_hash = merge_pr(pr_num, target_ref, title, body, pr_repo_desc, 
pr_author, co_authors)
 
+    # The "Closes #N" keyword in the commit message only auto-closes the PR 
when the commit
+    # lands on the default branch. For merges into other branches (e.g. 
branch-X.Y backport
+    # PRs), GitHub leaves the PR open, so close it explicitly through the API.
+    pr_state = get_json("%s/pulls/%s" % (GITHUB_API_BASE, pr_num)).get("state")
+    if pr_state != "closed":
+        print("PR #%s is still open after push; closing it explicitly." % 
pr_num)
+        close_pr(pr_num)
+
     pick_prompt = "Would you like to pick %s into another branch?" % merge_hash
     while bold_input("\n%s (y/N): " % pick_prompt).lower() == "y":
         merged_refs = merged_refs + [


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to