-
Notifications
You must be signed in to change notification settings - Fork 29.2k
[SPARK-56415][INFRA] Simplify create_spark_jira.py for LLM-driven JIRA ticket creation #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
Open
cloud-fan
wants to merge
9
commits into
apache:master
Choose a base branch
from
cloud-fan:improve-create-jira-script
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+82
−103
Open
Changes from all commits
Commits
Show all changes
9 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 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,24 +40,52 @@ 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 get_jira_client(): | ||
| return jira.client.JIRA( | ||
| {"server": JIRA_API_BASE}, token_auth=JIRA_ACCESS_TOKEN, timeout=(3.05, 30) | ||
| ) | ||
|
|
||
|
|
||
| def create_jira_issue(title, parent_jira_id=None, issue_type=None, version=None, component=None): | ||
| 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 c in sorted(components, key=lambda x: x.name): | ||
| print(c.name) | ||
|
|
||
|
|
||
| def main(): | ||
| 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 to create a subtask (e.g. SPARK-12345).", | ||
| ) | ||
| parser.add_argument( | ||
| "-t", | ||
| "--type", | ||
| help="Issue type (e.g. Bug, Improvement)", | ||
| ) | ||
| 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 version: | ||
| affected_version = version | ||
| else: | ||
| 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") | ||
| # Consider only x.y.z, unreleased, unarchived versions | ||
| versions = [ | ||
| x | ||
| for x in versions | ||
|
|
@@ -67,111 +94,53 @@ def create_jira_issue(title, parent_jira_id=None, issue_type=None, version=None, | |
| and re.match(r"\d+\.\d+\.\d+", x.name) | ||
| ] | ||
| versions = sorted(versions, key=lambda x: x.name, reverse=True) | ||
| affected_version = versions[0].name | ||
| 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: | ||
| parser.error("-c/--component is required") | ||
|
|
||
| if args.parent and args.type: | ||
| parser.error("--parent and --type cannot be used together") | ||
|
|
||
| if not args.parent and not args.type: | ||
| parser.error("-t/--type is required when not creating a subtask") | ||
|
|
||
| asf_jira = check_jira_access() | ||
| affected_version = detect_affected_version(asf_jira) | ||
|
|
||
| issue_dict = { | ||
| "project": {"key": "SPARK"}, | ||
| "summary": title, | ||
| "summary": args.title, | ||
| "description": "", | ||
| "versions": [{"name": affected_version}], | ||
| } | ||
|
|
||
| if component: | ||
| issue_dict["components"] = [{"name": component}] | ||
| issue_dict["components"] = [{"name": args.component}] | ||
|
|
||
| if parent_jira_id: | ||
| if args.parent: | ||
| issue_dict["issuetype"] = {"name": "Sub-task"} | ||
| issue_dict["parent"] = {"key": parent_jira_id} | ||
| issue_dict["parent"] = {"key": args.parent} | ||
| else: | ||
| issue_dict["issuetype"] = {"name": issue_type if issue_type else "Improvement"} | ||
| issue_dict["issuetype"] = {"name": args.type} | ||
|
|
||
| try: | ||
| new_issue = asf_jira.create_issue(fields=issue_dict) | ||
| return new_issue.key | ||
| print(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) | ||
| ) | ||
| 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.") | ||
|
|
||
|
|
||
| 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.", | ||
| ) | ||
| parser.add_argument("-v", "--version", help="Version to use for the issue") | ||
| parser.add_argument("-c", "--component", help="Component for the issue") | ||
| 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) | ||
|
|
||
| if not args.title: | ||
| parser.error("the following arguments are required: title") | ||
|
|
||
| if not args.component: | ||
| args.component = choose_components() | ||
|
|
||
| jira_id = create_jira_issue(args.title, args.parent, args.type, args.version, args.component) | ||
| print("Created JIRA issue: %s" % jira_id) | ||
|
|
||
| create_and_checkout_branch(jira_id) | ||
|
|
||
| create_commit(jira_id, args.title) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| try: | ||
| 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.