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

SteNicholas pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/celeborn.git


The following commit(s) were added to refs/heads/main by this push:
     new b356ccec0 [CELEBORN-2437][INFRA] Fix JIRA fix version suggestion in 
merge_pr.py
b356ccec0 is described below

commit b356ccec00dc63f9b6efaac88c26517eae61e042
Author: Cheng Pan <[email protected]>
AuthorDate: Mon Aug 24 00:03:11 2026 +0800

    [CELEBORN-2437][INFRA] Fix JIRA fix version suggestion in merge_pr.py
    
    ### What changes were proposed in this pull request?
    
    When resolving a JIRA after merging a PR, the suggested fix version for 
`main` was the first unreleased version returned by the JIRA API, which is 
ordered by creation time rather than version number. As a result, `main` could 
suggest an old unreleased version (e.g. `0.3.3`) instead of the next main 
release (e.g. `1.0.0`).
    
    This PR follows the version inference approach of SPARK-56865 in 
`dev/merge_spark_pr.py`: suggested fix versions are picked by semantic version, 
with `main` contributing the greatest unreleased `N.0.0` and `branch-M.N` 
contributing the greatest unreleased `M.N.x`. It also requires JIRA version 
names to be exactly `x.y.z`, excluding malformed entries such as the current 
`0.5.2, 0.4.3, 0.6.0`.
    
    ### Why are the changes needed?
    
    The default suggestion was wrong for PRs merged to `main`, requiring 
committers to correct it manually.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    `python3 -m py_compile dev/merge_pr.py`, plus manual checks of 
`compute_default_fix_versions` against the current unreleased CELEBORN 
versions: `main + branch-0.7` now suggests `1.0.0,0.7.1` instead of 
`0.3.3,0.7.1`.
    
    Assisted-by: deepseek-v4-pro
    
    Closes #3818 from pan3793/CELEBORN-2437.
    
    Authored-by: Cheng Pan <[email protected]>
    Signed-off-by: Nicholas Jiang <[email protected]>
---
 dev/merge_pr.py | 85 +++++++++++++++++++++++++++++++++------------------------
 1 file changed, 50 insertions(+), 35 deletions(-)

diff --git a/dev/merge_pr.py b/dev/merge_pr.py
index 4794e62aa..adbad4f54 100755
--- a/dev/merge_pr.py
+++ b/dev/merge_pr.py
@@ -242,6 +242,52 @@ def cherry_pick(pr_num, merge_hash, default_branch):
     return pick_ref
 
 
+def _semver_max_version(names):
+    if not names:
+        return None
+    names = [n for n in names if re.fullmatch(r"\d+\.\d+\.\d+", n)]
+    if not names:
+        return None
+    parsed = [(tuple(int(p) for p in n.split(".")), n) for n in names]
+    return max(parsed)[1]
+
+
+def compute_default_fix_versions(merge_branches, unreleased_version_names):
+    """
+    Compute the suggested fix versions for the merge branches.
+
+    main contributes the greatest unreleased N.0.0, and branch-M.N contributes
+    the greatest unreleased M.N.x version. Duplicate suggestions are collapsed.
+    """
+    default_fix_versions = []
+    for b in merge_branches:
+        if b == "main":
+            chosen = _semver_max_version(
+                [n for n in unreleased_version_names if 
re.fullmatch(r"\d+\.0\.0", n)]
+            )
+            if chosen:
+                default_fix_versions.append(chosen)
+            else:
+                print(
+                    "No unreleased N.0.0 fix version found on JIRA for main; "
+                    "enter fix version(s) manually when prompted."
+                )
+        else:
+            prefix = b.replace("branch-", "") + "."
+            chosen = _semver_max_version(
+                [n for n in unreleased_version_names if n.startswith(prefix)]
+            )
+            if chosen:
+                default_fix_versions.append(chosen)
+            else:
+                print(
+                    "Target version for %s is not found on JIRA, it may be 
archived or "
+                    "not created. Skipping it." % b
+                )
+
+    return list(dict.fromkeys(default_fix_versions))
+
+
 def resolve_jira_issue(merge_branches, comment, default_jira_id=""):
     jira_id = input("Enter a JIRA id [%s]: " % default_jira_id)
     if jira_id == "":
@@ -276,43 +322,12 @@ def resolve_jira_issue(merge_branches, comment, 
default_jira_id=""):
     versions = [
         x
         for x in versions
-        if not x.raw["released"] and not x.raw["archived"] and 
re.match(r"\d+\.\d+\.\d+", x.name)
+        if not x.raw["released"] and not x.raw["archived"] and 
re.fullmatch(r"\d+\.\d+\.\d+", x.name)
     ]
 
-    default_fix_versions = []
-    for b in merge_branches:
-        if b == "main":
-            default_fix_versions.append(versions[0].name)
-        else:
-            found = False
-            found_versions = []
-            for v in versions:
-                if v.name.startswith(b.replace("branch-", "")):
-                    found_versions.append(v.name)
-                    found = True
-            if found:
-                # There might be several unreleased versions for specific 
branches
-                # For example, assuming
-                # versions = ['4.0.0', '3.5.1', '3.5.0', '3.4.2', '3.3.4', 
'3.3.3']
-                # we've found two candidates for branch-3.5, we pick the 
last/smallest one
-                default_fix_versions.append(found_versions[-1])
-            else:
-                print(
-                    "Target version for %s is not found on JIRA, it may be 
archived or "
-                    "not created. Skipping it." % b
-                )
-
-    for v in default_fix_versions:
-        # Handles the case where we have forked a release branch but not yet 
made the release.
-        # In this case, if the PR is committed to the main branch and the 
release branch, we
-        # only consider the release branch to be the fix version. E.g. it is 
not valid to have
-        # both 1.1.0 and 1.0.0 as fix versions.
-        (major, minor, patch) = v.split(".")
-        if patch == "0":
-            previous = "%s.%s.%s" % (major, int(minor) - 1, 0)
-            if previous in default_fix_versions:
-                default_fix_versions = list(filter(lambda x: x != v, 
default_fix_versions))
-    default_fix_versions = ",".join(default_fix_versions)
+    default_fix_versions = ",".join(
+        compute_default_fix_versions(merge_branches, [v.name for v in 
versions])
+    )
 
     available_versions = set(list(map(lambda v: v.name, versions)))
     while True:

Reply via email to