You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by sz...@apache.org on 2026/08/26 20:34:06 UTC
(spark) branch master updated: [SPARK-59017][INFRA] Prevent merge script skipping or hanging at the Fix Version prompt when no version can be inferred
This is an automated email from the ASF dual-hosted git repository.
szehon-ho pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push:
new a0ce466faaed [SPARK-59017][INFRA] Prevent merge script skipping or hanging at the Fix Version prompt when no version can be inferred
a0ce466faaed is described below
commit a0ce466faaed64663efee442a108d4abb748a9ee
Author: Szehon Ho <sz...@gmail.com>
AuthorDate: Wed Aug 26 13:33:54 2026 -0700
[SPARK-59017][INFRA] Prevent merge script skipping or hanging at the Fix Version prompt when no version can be inferred
### What changes were proposed in this pull request?
Two fixes in `dev/merge_spark_pr.py`, both on the path where Fix Version inference produces nothing:
1. Blank input at the Fix Version prompt with no default now exits with a message instead of re-prompting forever.
2. On an already-resolved JIRA, `already contains all inferred fix versions` is printed only when something was in fact inferred. Otherwise the committer reaches the prompt.
### Why are the changes needed?
Take a backport PR opened directly against `branch-4.2`, merged at a moment when JIRA has no unreleased `4.2.x` version -- either the line is EOL, or `4.2.2` has not been created yet after `4.2.1` shipped. Inference finds nothing and warns the committer to enter a version manually. What follows is wrong in both directions.
**The linked JIRA is already resolved by the earlier master merge**, which is the normal state for a backport. Before:
```
JIRA issue SPARK-58880 already has status 'Resolved' (Fixed)
Check if the JIRA information is as expected (y/N): y
Target version for branch-4.2 is not found on JIRA, it may be archived or not created. Skipping it.
JIRA issue SPARK-58880 already contains all inferred fix versions; no update needed.
```
The ticket has `['5.0.0']` and nothing was inferred, so the last line is false and contradicts the warning above it. The prompt never appears, and the merge records no Fix Version. After:
```
Target version for branch-4.2 is not found on JIRA, it may be archived or not created. Skipping it.
JIRA issue SPARK-58880 has fix version(s) ['5.0.0']; no additional fix version could be inferred.
Enter comma-separated additional fix version(s) []:
No fix version entered; update SPARK-58880 manually.
```
**The JIRA is not yet resolved.** The committer reaches the prompt with an empty default, and pressing Enter never escapes, because `""` can never match a known version -- even though the retry message offers exactly that. Before:
```
Target version for branch-4.2 is not found on JIRA, it may be archived or not created. Skipping it.
Enter comma-separated fix version(s) []:
Specified version(s) [] not found in the available versions, try again (or leave blank and fix manually).
Enter comma-separated fix version(s) []:
Specified version(s) [] not found in the available versions, try again (or leave blank and fix manually).
Enter comma-separated fix version(s) []:
^C
```
Only Ctrl-C exits, and the merge to `branch-4.2` has already been pushed by then, since the JIRA step runs in a `finally` block. After:
```
Target version for branch-4.2 is not found on JIRA, it may be archived or not created. Skipping it.
Enter comma-separated fix version(s) []:
No fix version entered; update SPARK-58880 manually.
```
In both cases the committer still has to record the Fix Version by hand. The point of the change is that the script now says so, instead of claiming the ticket is already correct or trapping them in a loop.
### Does this PR introduce _any_ user-facing change?
No. Committer-facing only.
### How was this patch tested?
New doctests on two extracted helpers, `fix_version_additions` and `fix_versions_from_input`, which cover both failure modes directly. `fix_versions_from_input("", "")` returns `[]` where the previous inline expression produced `[""]` and looped, and `fix_version_additions` separates "nothing inferred" from "all inferred already present", which the old code could not distinguish:
```
master : "".replace(" ","").split(",") -> [''] never a known version -> loops
patched : fix_versions_from_input("", "") -> []
master : additional_fix_versions([], ["5.0.0"]) -> [] identical to the up-to-date case
patched : fix_version_additions([], ["5.0.0"]) -> ([], False)
patched : fix_version_additions(["5.0.0"], ["5.0.0"]) -> ([], True)
```
Doctests go from 80 to 88, and they run on every invocation of the script since `__main__` calls `doctest.testmod()` before `main()`. I also drove `resolve_jira_issue` with a stubbed JIRA client to produce the transcripts above and to confirm that the cases where a version is inferable are unchanged, including the resolved-ticket path that proposes additions and asks for confirmation.
### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Cursor (Claude Opus 5)
Closes #58300 from szehon-ho/SPARK-59017.
Authored-by: Szehon Ho <sz...@gmail.com>
Signed-off-by: Szehon Ho <sz...@gmail.com>
---
dev/merge_spark_pr.py | 78 +++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 66 insertions(+), 12 deletions(-)
diff --git a/dev/merge_spark_pr.py b/dev/merge_spark_pr.py
index 366181a4b380..08441aa8cc08 100755
--- a/dev/merge_spark_pr.py
+++ b/dev/merge_spark_pr.py
@@ -350,6 +350,49 @@ def additional_fix_versions(inferred_versions, existing_versions):
return [version for version in inferred_versions if version not in existing]
+def fix_version_additions(inferred_versions, existing_versions):
+ """Return (additions, all_inferred_present).
+
+ An empty ``additions`` list is ambiguous on its own: either the issue already carries
+ every inferred version, or nothing was inferred. Only the first means there is nothing
+ to do; the second still needs the committer prompted.
+
+ >>> fix_version_additions(["4.3.0"], ["5.0.0"])
+ (['4.3.0'], False)
+ >>> fix_version_additions(["5.0.0"], ["5.0.0"])
+ ([], True)
+ >>> fix_version_additions([], ["5.0.0"])
+ ([], False)
+ """
+ additions = additional_fix_versions(inferred_versions, existing_versions)
+ return additions, bool(inferred_versions) and not additions
+
+
+def fix_versions_from_input(raw_input, default_fix_versions):
+ """Resolve the Fix Version prompt's raw input into a list of version names.
+
+ Blank falls back to the inferred default. With no default to fall back on, blank means
+ skip: the empty list, not [""], which no known version can match.
+
+ >>> fix_versions_from_input("4.2.2", "")
+ ['4.2.2']
+ >>> fix_versions_from_input("", "5.0.0")
+ ['5.0.0']
+ >>> fix_versions_from_input("5.0.0, 4.3.0", "")
+ ['5.0.0', '4.3.0']
+ >>> fix_versions_from_input("", "")
+ []
+ >>> fix_versions_from_input(" ", "")
+ []
+ """
+ if raw_input == "":
+ raw_input = default_fix_versions
+ stripped = raw_input.replace(" ", "")
+ if stripped == "":
+ return []
+ return stripped.split(",")
+
+
def red(text):
return "\033[91m%s\033[0m" % text
@@ -1252,19 +1295,28 @@ def resolve_jira_issue(
if is_resolved:
# A later backport run must preserve the versions recorded by the original merge and
# only add versions inferred from the newly discovered branches.
- default_fix_list = additional_fix_versions(default_fix_list, existing_fix_version_names)
- if not default_fix_list:
+ default_fix_list, all_inferred_present = fix_version_additions(
+ default_fix_list, existing_fix_version_names
+ )
+ if all_inferred_present:
print(
"JIRA issue %s already contains all inferred fix versions; no update needed."
% issue.key
)
return
- print(
- "JIRA issue %s has fix version(s) %s; inferred addition(s): %s"
- % (issue.key, existing_fix_version_names, default_fix_list)
- )
- if get_input("Add these fix version(s)? (y/N): ", ["y", "n", ""]) != "y":
- return
+ if default_fix_list:
+ print(
+ "JIRA issue %s has fix version(s) %s; inferred addition(s): %s"
+ % (issue.key, existing_fix_version_names, default_fix_list)
+ )
+ if get_input("Add these fix version(s)? (y/N): ", ["y", "n", ""]) != "y":
+ return
+ else:
+ # Nothing inferred, so there is nothing to confirm; fall through to the prompt.
+ print(
+ "JIRA issue %s has fix version(s) %s; no additional fix version could be "
+ "inferred." % (issue.key, existing_fix_version_names)
+ )
default_fix_versions = ",".join(default_fix_list)
available_versions = set(list(map(lambda v: v.name, versions)))
@@ -1273,10 +1325,12 @@ def resolve_jira_issue(
prompt = "Enter comma-separated fix version(s) [%s]: "
if is_resolved:
prompt = "Enter comma-separated additional fix version(s) [%s]: "
- fix_versions = bold_input(prompt % default_fix_versions)
- if fix_versions == "":
- fix_versions = default_fix_versions
- fix_versions = fix_versions.replace(" ", "").split(",")
+ fix_versions = fix_versions_from_input(
+ bold_input(prompt % default_fix_versions), default_fix_versions
+ )
+ if not fix_versions:
+ print("No fix version entered; update %s manually." % issue.key)
+ return
if set(fix_versions).issubset(available_versions):
break
else:
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org