From 2bb7714e528ce64181d838afb48fb2af69fabdd4 Mon Sep 17 00:00:00 2001 From: Dusan Fodor Date: Wed, 4 Oct 2023 11:17:07 +0200 Subject: [PATCH 1/3] added script to clone feature with child epics --- jira-automation/README.md | 17 ++++ jira-automation/clone-feature-w-epics.py | 119 +++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 jira-automation/README.md create mode 100755 jira-automation/clone-feature-w-epics.py diff --git a/jira-automation/README.md b/jira-automation/README.md new file mode 100644 index 0000000..84da5d7 --- /dev/null +++ b/jira-automation/README.md @@ -0,0 +1,17 @@ +# Installation + +```bash +$ python3 -m venv virtualenv +$ source virtualenv/bin/activate +$ pip install jira +$ deactivate +``` + +# Usage + +```bash +$ source virtualenv/bin/activate +$ export JIRA_TOKEN=... +$ python clone-feature.py --feature RHTAP-383 --summary "New Team Enablement" --dry-run +$ deactivate +``` diff --git a/jira-automation/clone-feature-w-epics.py b/jira-automation/clone-feature-w-epics.py new file mode 100755 index 0000000..fdccc88 --- /dev/null +++ b/jira-automation/clone-feature-w-epics.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python +""" +Description: Clone a feature and its child epics. +Author: rbean +""" + +import argparse +import os +import pprint +import sys + +import jira + + +def get_args(): + """ + Parse args from the command-line. + """ + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--feature", + required=True, + help="Key of the feature id the epic should be attached to", + ) + parser.add_argument( + "--summary", + required=True, + help="Summary of the new feature", + ) + parser.add_argument( + "--dry-run", + action="store_true", + default=False, + help="Whether or not to take action on JIRA", + ) + return parser.parse_args() + + +args = get_args() + +url = os.environ.get("JIRA_URL", "https://issues.redhat.com") +token = os.environ.get("JIRA_TOKEN") +if not token: + print("Set JIRA_TOKEN environment variable to your JIRA personal access token") + sys.exit(1) + +JIRA = jira.client.JIRA(server=url, token_auth=token) + +print("Inspecting JIRA API.") +all_fields = JIRA.fields() +jira_name_map = {field["name"]: field["id"] for field in all_fields} +parent_key = jira_name_map["Parent Link"] +epic_name_key = jira_name_map["Epic Name"] + +query = f"key={args.feature} and type=Feature" +print("Confirming the Feature exists:") +print(" > " + query) +results = JIRA.search_issues(query) +if not results: + print(f"Feature not found via query: {query}") + sys.exit(1) +origin_feature = results[0] + + +query = f"'Parent Link'={args.feature}" +print("Gathering child epics:") +print(" > " + query) +epics = JIRA.search_issues(query) +if not epics: + print(f"No child epics found via query: {query}") + sys.exit(1) + +kwargs = { + "project": origin_feature.fields.project.key, + "summary": args.summary, + "issuetype": origin_feature.fields.issuetype.name, + "description": origin_feature.fields.description, +} +if not args.dry_run: + new_feature = JIRA.create_issue(**kwargs) + new_feature_key = new_feature.key + print(f"Created feature {new_feature}, as a copy of {origin_feature}") + print(f"https://issues.redhat.com/browse/{new_feature}") + if origin_feature.fields.labels: + new_feature.update( + { + "labels": origin_feature.fields.labels, + } + ) +else: + print(f"Skipped creating clone of {origin_feature}") + print(f" Would have created:") + pprint.pprint(kwargs) + new_feature_key = "" + +for origin_epic in epics: + kwargs = { + "project": origin_epic.fields.project.key, + "summary": origin_epic.fields.summary, + "issuetype": origin_epic.fields.issuetype.name, + "description": origin_epic.fields.description or "", + epic_name_key: getattr(origin_epic.fields, epic_name_key), + parent_key: new_feature_key, + } + if not args.dry_run: + new_epic = JIRA.create_issue(**kwargs) + print(f"Created epic {new_epic}, as a copy of {origin_epic}") + if origin_epic.fields.labels: + new_epic.update( + { + "labels": origin_epic.fields.labels, + } + ) + else: + print(f"Skipped creating clone of {origin_epic}") + print(f" Would have created:") + pprint.pprint(kwargs) + +print("Done.") From ea7f5f67842f3a8ce742fb4621d70974b56413e6 Mon Sep 17 00:00:00 2001 From: dfodorRH Date: Tue, 10 Oct 2023 10:31:22 +0200 Subject: [PATCH 2/3] Update README.md --- jira-automation/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jira-automation/README.md b/jira-automation/README.md index 84da5d7..e3ae428 100644 --- a/jira-automation/README.md +++ b/jira-automation/README.md @@ -11,6 +11,8 @@ $ deactivate ```bash $ source virtualenv/bin/activate +# obtain your personal Jira access token here: +# https://issues.redhat.com/secure/ViewProfile.jspa?selectedTab=com.atlassian.pats.pats-plugin:jira-user-personal-access-tokens $ export JIRA_TOKEN=... $ python clone-feature.py --feature RHTAP-383 --summary "New Team Enablement" --dry-run $ deactivate From 35773f185692335ec71956dd8a2d0aacbbd8bfaf Mon Sep 17 00:00:00 2001 From: dfodorRH Date: Tue, 10 Oct 2023 10:49:21 +0200 Subject: [PATCH 3/3] Update README.md with correct filename --- jira-automation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jira-automation/README.md b/jira-automation/README.md index e3ae428..2203b89 100644 --- a/jira-automation/README.md +++ b/jira-automation/README.md @@ -14,6 +14,6 @@ $ source virtualenv/bin/activate # obtain your personal Jira access token here: # https://issues.redhat.com/secure/ViewProfile.jspa?selectedTab=com.atlassian.pats.pats-plugin:jira-user-personal-access-tokens $ export JIRA_TOKEN=... -$ python clone-feature.py --feature RHTAP-383 --summary "New Team Enablement" --dry-run +$ python clone-feature-w-epics.py --feature RHTAP-383 --summary "New Team Enablement" --dry-run $ deactivate ```