-
Notifications
You must be signed in to change notification settings - Fork 29.2k
[SPARK-56415][INFRA] Refactor create_spark_jira.py for LLM use and extract shared utilities #55281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
+249
−130
Closed
Changes from 3 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
1b37e89
[SPARK-56415][INFRA] Simplify create_spark_jira.py for LLM-driven JIR…
cloud-fan b009722
[SPARK-56415][INFRA] Refine version handling and pre-flight checks
cloud-fan f6e589e
[SPARK-56415][INFRA] Remove --parent flag and simplify to top-level i…
cloud-fan e58deff
[SPARK-56415][INFRA] Revert PR template wording to original
cloud-fan 53cfe21
[SPARK-56415][INFRA] Use more explicit PR template instruction
cloud-fan 974bd46
[SPARK-56415][INFRA] Use placeholder syntax for title in example command
cloud-fan 753c63e
[SPARK-56415][INFRA] Add back --parent flag for creating subtasks
cloud-fan 0158dad
[SPARK-56415][INFRA] Validate that --parent and --type are mutually e…
cloud-fan 0cc3250
[SPARK-56415][INFRA] Simplify JIRA ticket title instruction in CLAUDE.md
cloud-fan 5429be3
[SPARK-56415][INFRA] Keep the original script as dev/start_jira_issue.py
cloud-fan efc4c2a
[SPARK-56415][INFRA] Rename start_jira_issue.py to create_jira_and_br…
cloud-fan deb19db
[SPARK-56415][INFRA] Extract shared JIRA utilities into spark_jira_ut…
cloud-fan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,6 @@ | |
| import argparse | ||
| import os | ||
| import re | ||
| import subprocess | ||
| import sys | ||
| import traceback | ||
|
|
||
|
|
@@ -41,135 +40,89 @@ def fail(msg): | |
| sys.exit(-1) | ||
|
|
||
|
|
||
| def run_cmd(cmd): | ||
| print(cmd) | ||
| if isinstance(cmd, list): | ||
| return subprocess.check_output(cmd).decode("utf-8") | ||
| else: | ||
| return subprocess.check_output(cmd.split(" ")).decode("utf-8") | ||
|
|
||
|
|
||
| def create_jira_issue(title, parent_jira_id=None, issue_type=None, version=None, component=None): | ||
| asf_jira = jira.client.JIRA( | ||
| def get_jira_client(): | ||
| return jira.client.JIRA( | ||
| {"server": JIRA_API_BASE}, token_auth=JIRA_ACCESS_TOKEN, timeout=(3.05, 30) | ||
| ) | ||
|
|
||
| if version: | ||
| affected_version = version | ||
| else: | ||
| versions = asf_jira.project_versions("SPARK") | ||
| # Consider only x.y.z, unreleased, unarchived versions | ||
| 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) | ||
| ] | ||
| versions = sorted(versions, key=lambda x: x.name, reverse=True) | ||
| affected_version = versions[0].name | ||
|
|
||
| issue_dict = { | ||
| "project": {"key": "SPARK"}, | ||
| "summary": title, | ||
| "description": "", | ||
| "versions": [{"name": affected_version}], | ||
| } | ||
|
|
||
| if component: | ||
| issue_dict["components"] = [{"name": component}] | ||
|
|
||
| if parent_jira_id: | ||
| issue_dict["issuetype"] = {"name": "Sub-task"} | ||
| issue_dict["parent"] = {"key": parent_jira_id} | ||
| else: | ||
| issue_dict["issuetype"] = {"name": issue_type if issue_type else "Improvement"} | ||
|
|
||
| try: | ||
| new_issue = asf_jira.create_issue(fields=issue_dict) | ||
| return new_issue.key | ||
| except Exception as e: | ||
| fail("Failed to create JIRA issue: %s" % e) | ||
|
|
||
|
|
||
| def create_and_checkout_branch(jira_id): | ||
| try: | ||
| run_cmd("git checkout -b %s" % jira_id) | ||
| print("Created and checked out branch: %s" % jira_id) | ||
| except subprocess.CalledProcessError as e: | ||
| fail("Failed to create branch %s: %s" % (jira_id, e)) | ||
|
|
||
|
|
||
| def create_commit(jira_id, title): | ||
| try: | ||
| run_cmd(["git", "commit", "-a", "-m", "[%s] %s" % (jira_id, title)]) | ||
| print("Created a commit with message: [%s] %s" % (jira_id, title)) | ||
| except subprocess.CalledProcessError as e: | ||
| fail("Failed to create commit: %s" % e) | ||
|
|
||
|
|
||
| def choose_components(): | ||
| asf_jira = jira.client.JIRA( | ||
| {"server": JIRA_API_BASE}, token_auth=JIRA_ACCESS_TOKEN, timeout=(3.05, 30) | ||
| ) | ||
| def list_components(asf_jira): | ||
| components = asf_jira.project_components("SPARK") | ||
| components = [c for c in components if not c.raw.get("archived", False)] | ||
| for i, c in enumerate(components): | ||
| print("%d. %s" % (i + 1, c.name)) | ||
|
|
||
| while True: | ||
| try: | ||
| choice = input("Please choose a component by number: ") | ||
| idx = int(choice) - 1 | ||
| if 0 <= idx < len(components): | ||
| return components[idx].name | ||
| else: | ||
| print("Invalid number. Please try again.") | ||
| except ValueError: | ||
| print("Invalid input. Please enter a number.") | ||
| for c in sorted(components, key=lambda x: x.name): | ||
| print(c.name) | ||
|
|
||
|
|
||
| def main(): | ||
| if not JIRA_IMPORTED: | ||
| fail("Could not find jira-python library. Run 'sudo pip3 install jira' to install.") | ||
|
|
||
| if not JIRA_ACCESS_TOKEN: | ||
| fail("The env-var JIRA_ACCESS_TOKEN is not set.") | ||
|
|
||
| parser = argparse.ArgumentParser(description="Create a Spark JIRA issue.") | ||
| parser.add_argument("title", nargs="?", help="Title of the JIRA issue") | ||
| parser.add_argument("-p", "--parent", help="Parent JIRA ID for subtasks") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm alway using this parent JIRA ID feature. Please recover this, @cloud-fan .
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
| parser.add_argument( | ||
| "-t", | ||
| "--type", | ||
| help="Issue type to create when no parent is specified (e.g. Bug). Defaults to Improvement.", | ||
| help="Issue type (e.g. Bug, Improvement). Defaults to Improvement.", | ||
| ) | ||
| parser.add_argument("-v", "--version", help="Version to use for the issue") | ||
| parser.add_argument("-c", "--component", help="Component for the issue") | ||
| parser.add_argument( | ||
| "--list-components", action="store_true", help="List available components and exit" | ||
| ) | ||
| args = parser.parse_args() | ||
|
|
||
| if args.parent: | ||
| asf_jira = jira.client.JIRA( | ||
| {"server": JIRA_API_BASE}, token_auth=JIRA_ACCESS_TOKEN, timeout=(3.05, 30) | ||
| ) | ||
| parent_issue = asf_jira.issue(args.parent) | ||
| print("Parent issue title: %s" % parent_issue.fields.summary) | ||
| print("Creating a subtask of %s with title: %s" % (args.parent, args.title)) | ||
| else: | ||
| print("Creating JIRA issue with title: %s" % args.title) | ||
| def check_jira_access(): | ||
| errors = [] | ||
| if not JIRA_IMPORTED: | ||
| errors.append("jira-python library not installed, run 'pip install jira'") | ||
| if not JIRA_ACCESS_TOKEN: | ||
| errors.append("JIRA_ACCESS_TOKEN env-var not set") | ||
| if errors: | ||
| fail("Cannot create JIRA ticket automatically (%s). " | ||
| "Please create the ticket manually at %s" | ||
| % ("; ".join(errors), JIRA_API_BASE)) | ||
| return get_jira_client() | ||
|
|
||
| def detect_affected_version(asf_jira): | ||
| versions = asf_jira.project_versions("SPARK") | ||
| 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) | ||
| ] | ||
| versions = sorted(versions, key=lambda x: x.name, reverse=True) | ||
| if not versions: | ||
| fail("Cannot detect affected version. " | ||
| "Please create the ticket manually at %s" % JIRA_API_BASE) | ||
| return versions[0].name | ||
|
|
||
| if args.list_components: | ||
| asf_jira = check_jira_access() | ||
| list_components(asf_jira) | ||
| return | ||
|
|
||
| if not args.title: | ||
| parser.error("the following arguments are required: title") | ||
|
|
||
| if not args.component: | ||
| args.component = choose_components() | ||
| parser.error("the following arguments are required: -c/--component") | ||
|
|
||
| jira_id = create_jira_issue(args.title, args.parent, args.type, args.version, args.component) | ||
| print("Created JIRA issue: %s" % jira_id) | ||
| asf_jira = check_jira_access() | ||
| affected_version = detect_affected_version(asf_jira) | ||
|
|
||
| issue_dict = { | ||
| "project": {"key": "SPARK"}, | ||
| "summary": args.title, | ||
| "description": "", | ||
| "versions": [{"name": affected_version}], | ||
| "components": [{"name": args.component}], | ||
| } | ||
|
|
||
| create_and_checkout_branch(jira_id) | ||
| issue_dict["issuetype"] = {"name": args.type if args.type else "Improvement"} | ||
|
|
||
| create_commit(jira_id, args.title) | ||
| try: | ||
| new_issue = asf_jira.create_issue(fields=issue_dict) | ||
| print(new_issue.key) | ||
| except Exception as e: | ||
| fail("Failed to create JIRA issue: %s" % e) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add back the old script if people still need it, but with a different name, as
create_spark_jira.pyshould only create ticket.