nchammas commented on code in PR #58288:
URL: https://github.com/apache/spark/pull/58288#discussion_r3866816782


##########
dev/merge_spark_pr.py:
##########
@@ -350,6 +350,112 @@ def additional_fix_versions(inferred_versions, 
existing_versions):
     return [version for version in inferred_versions if version not in 
existing]
 
 
+def parse_affects_versions_input(raw, available_versions):

Review Comment:
   Could we add types to all the new function signatures? Makes them a bit 
easier to understand at a glance.



##########
dev/merge_spark_pr.py:
##########
@@ -1179,6 +1285,56 @@ def reconcile_jira_components(issue, title_components):
     jira_ops.update_components(issue, new_names)
 
 
+def reconcile_jira_affects_versions(issue, fix_version_names, 
affects_available):
+    """Prompt the committer to update the JIRA Affects Version/s during a 
merge.
+
+    Meant for the case the caller gates on with ``fix_precedes_affects``: the 
affected
+    floor sits above the earliest fix, so a fixed release is not admitted as 
affected.
+    Mirrors the Fix Version prompt but targets ``issue.fields.versions``: it 
shows the
+    current Affects Version/s and the fix version(s) being set, offers a 
default
+    inferred from the fix version(s) via ``suggest_affects_versions``, then 
reads a
+    comma-separated entry validated against ``affects_available`` (all 
unarchived
+    versions, since an affected version may be released) with a retry loop. A 
blank
+    entry accepts the suggested default; otherwise the parsed versions replace 
the
+    current ones (through ``jira_ops`` so a dry run only logs the intended 
write).
+    """
+    current_names = [v.name for v in issue.fields.versions]
+    suggested = [
+        n
+        for n in suggest_affects_versions(fix_version_names, current_names)
+        if n in affects_available
+    ]
+    if not suggested:
+        return
+    default_str = ",".join(suggested)
+    print()
+    print("=" * 80)
+    print(
+        "JIRA %s Affects Version/s %s do not cover the fix version(s) %s."
+        % (issue.key, current_names if current_names else "(none)", 
fix_version_names)
+    )
+    print("=" * 80)
+    while True:
+        try:
+            raw = bold_input("Enter comma-separated affects version(s) [%s]: " 
% default_str)
+            if raw.strip() == "":
+                raw = default_str
+            new_names, valid = parse_affects_versions_input(raw, 
affects_available)
+            if valid and new_names:
+                break
+            print(
+                "Specified version(s) [%s] not found in the available 
versions, try "
+                "again (or leave blank to accept the suggestion)." % ", 
".join(new_names)
+            )

Review Comment:
   Couldn't we simplify this by giving the user a list of potential versions to 
choose from? Like how we do with the Assignee. Then we avoid needing to loop, 
parse, or validate their manually inputted versions.



##########
dev/merge_spark_pr.py:
##########
@@ -1231,14 +1387,19 @@ def resolve_jira_issue(
 
         reconcile_jira_components(issue, title_components)
 
-    versions = asf_jira.project_versions("SPARK")
+    all_versions = asf_jira.project_versions("SPARK")
     # Consider only x.y.z, unreleased, unarchived versions
     versions = [
         x
-        for x in versions
+        for x in all_versions
         if not x.raw["released"] and not x.raw["archived"] and 
re.match(r"\d+\.\d+\.\d+", x.name)
     ]
     versions = sorted(versions, key=lambda x: x.name, reverse=True)
+    # Affects Version/s may legitimately name an already-released version, so 
validate the
+    # affects prompt against all unarchived x.y.z versions, not just the 
unreleased fix ones.
+    affects_available = {
+        x.name for x in all_versions if not x.raw["archived"] and 
re.match(r"\d+\.\d+\.\d+", x.name)

Review Comment:
   We repeat this pattern match in several places in this script. Perhaps we 
should capture it in a utility? The utility could even parse the string into a 
tuple so that we're always working with the structured object for comparisons 
and the like.



##########
dev/merge_spark_pr.py:
##########
@@ -1439,6 +1620,12 @@ class DryRunJira(Jira):
     def update_components(self, issue, new_names):
         print("DRY-RUN: would set JIRA %s components to: %s" % (issue.key, ", 
".join(new_names)))
 
+    def update_affects_versions(self, issue, new_names):
+        print(
+            "DRY-RUN: would set JIRA %s Affects Version/s to: %s"
+            % (issue.key, ", ".join(new_names))
+        )
+

Review Comment:
   Nit: For any new code we should generally use f-strings or `.format()`, not 
`%` substitutions. I didn't comment on this in the dry run PR because you were 
refactoring existing code.



##########
dev/merge_spark_pr.py:
##########
@@ -1179,6 +1285,56 @@ def reconcile_jira_components(issue, title_components):
     jira_ops.update_components(issue, new_names)
 
 
+def reconcile_jira_affects_versions(issue, fix_version_names, 
affects_available):
+    """Prompt the committer to update the JIRA Affects Version/s during a 
merge.
+
+    Meant for the case the caller gates on with ``fix_precedes_affects``: the 
affected
+    floor sits above the earliest fix, so a fixed release is not admitted as 
affected.
+    Mirrors the Fix Version prompt but targets ``issue.fields.versions``: it 
shows the
+    current Affects Version/s and the fix version(s) being set, offers a 
default
+    inferred from the fix version(s) via ``suggest_affects_versions``, then 
reads a
+    comma-separated entry validated against ``affects_available`` (all 
unarchived
+    versions, since an affected version may be released) with a retry loop. A 
blank
+    entry accepts the suggested default; otherwise the parsed versions replace 
the
+    current ones (through ``jira_ops`` so a dry run only logs the intended 
write).
+    """

Review Comment:
   Maybe it's just me, but this docstring is very difficult to parse. Does 
something like this still capture the essence?
   
   > The "Fix Version" must always be greater than the "Affects Version". If 
not, prompt the committer to adjust the latter until the versions make sense.
   
   The extra prose describing what the function does step by step does not seem 
that helpful to me, and couples the docstring more tightly to details that may 
easily change over time.
   
   (By the way, super nit but: Jira is not an acronym. So not "JIRA". I know, 
we use "JIRA" all over the place...)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to