diff --git a/jipdate/jipsearch.py b/jipdate/jipsearch.py index 81c689b..648727f 100755 --- a/jipdate/jipsearch.py +++ b/jipdate/jipsearch.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 from argparse import ArgumentParser +from argparse import FileType import logging as log import re import os @@ -14,6 +15,23 @@ from jipdate import __version__ +jira_field_to_yaml = { + "issuetype": "IssueType", + "project": "Project", + "summary": "Summary", + "description": "Description", + "assignee": "AssigneeEmail", + "customfield_10014": "EpicLink", + "customfield_10104": "ClientStakeholder", + "timetracking": "OriginalEstimate", + "components": "Components", + "customfield_10020": "Sprint", + "duedate": "Due date", + "customfield_10011": "Epic Name", + "customfield_10034": "Share Visibility", +} + + ################################################################################ # Argument parser ################################################################################ @@ -31,6 +49,17 @@ def get_parser(): (first.last or first.last@linaro.org)""", ) + parser.add_argument( + "-o", + "--outputfile", + required=False, + action="store", + default=sys.stdout, + type=FileType("w"), + dest="output", + help="Directs the output to a name of your choice", + ) + parser.add_argument( "-j", "--jql", @@ -200,6 +229,14 @@ def get_parser(): help="""Do not make any changes to JIRA""", ) + parser.add_argument( + "--cloneformat", + required=False, + action="store_true", + default=False, + help="""Print all fields to enable creating a clone of the found issues.""", + ) + return parser @@ -217,14 +254,20 @@ def initialize_logger(args): ) +def print_output(s): + cfg.args.output.write(str(s)) + + def create_jql(jira, initial_jql): jql_parts = [] if initial_jql and initial_jql != "": jql_parts.append(initial_jql) if cfg.args.key: - for v in cfg.args.key: - jql_parts.append(f"key={v}") + jql_part = f"key in ({cfg.args.key[0]}" + for v in cfg.args.key[1:]: + jql_part += f", {v}" + jql_parts.append(f"{jql_part})") if cfg.args.project: jql_parts.append("project in (%s)" % cfg.args.project) @@ -271,7 +314,6 @@ def create_jql(jira, initial_jql): jql_parts.append("updated <= %s" % cfg.args.updated_before) jql_string = " AND ".join(jql_parts) - log.debug(f"{jql_string}") return jql_string @@ -292,6 +334,10 @@ def search_issues(jira, jql): "timetracking", ] + if cfg.args.cloneformat: + for key in jira_field_to_yaml: + fields.append(key) + if cfg.args.format: regex = r"\{(.+?)\}" for keys in re.findall(regex, cfg.args.format): @@ -309,7 +355,7 @@ def search_issues(jira, jql): json_result=True, ) except JIRAError as e: - print(f"{e.text}") + print_output(f"{e.text}") exit(1) issues += result["issues"] result["startAt"] += max_results @@ -325,9 +371,63 @@ def call_jqls(jira, jql): return issues +def jira_value_to_yaml(field, jira_value): + if jira_value: + if field == "issuetype": + return jira_value["name"] + if field == "project": + return jira_value["key"] + if field == "customfield_10020": + ret = jira_value[0]["name"] + for s in jira_value[1:]: + ret += f',{s["name"]}' + return ret + if field == "customfield_10104": + ret = jira_value[0]["value"] + for s in jira_value[1:]: + ret += f',{s["value"]}' + return ret + if field == "customfield_10034": + ret = f"[{jira_value[0]['emailAddress']}" + for s in jira_value[1:]: + ret += f', {s["emailAddress"]}' + ret += "]" + return ret + if field == "components": + ret = jira_value[0]["name"] + for s in jira_value[1:]: + ret += f',{s["name"]}' + return ret + if field == "assignee": + return jira_value["emailAddress"] + if field == "duedate": + return jira_value + if field == "description": + return jira_value + if field == "timetracking": + if "originalEstimate" in jira_value: + return jira_value["originalEstimate"] + else: + return None + return jira_value + else: + return None + + def print_issues(jira, issues): + cloneformat_issues = [] for issue in issues: jira_link = "https://linaro.atlassian.net/browse" + if cfg.args.cloneformat: + iss = {} + for field in issue["fields"]: + if field in jira_field_to_yaml: + value = jira_value_to_yaml(field, issue["fields"][field]) + if value is not None: + iss[jira_field_to_yaml[field]] = value + cloneformat_issues.append(iss) + continue + if cfg.args.format: regex = r"\{(.+?)\}" format_line = re.sub(regex, "{}", cfg.args.format) @@ -344,7 +444,7 @@ def print_issues(jira, issues): continue out.append(tmp_output) - print(format_line.format(*out)) + print_output(format_line.format(*out)) continue output = f"{jira_link}/{issue['key']} , Type: {issue['fields']['issuetype']['name'].strip()}, Summary: {issue['fields']['summary'].strip()} , Created: {str(parser.parse(issue['fields']['created'])).split(' ')[0]} , Status: {issue['fields']['status']['statusCategory']['name']}" if issue["fields"]["assignee"]: @@ -355,19 +455,19 @@ def print_issues(jira, issues): try: field = issue["fields"]["parent"] value = f" parent: {jira_link}/{field['key']}" - print(f"{output},{value}") + print_output(f"{output},{value}") except KeyError: - print(f"No key 'parent'.") + print_output(f"No key 'parent'.") continue - print(f"{output}") + print_output(f"{output}") if cfg.args.description: - print(f"# Description:") + print_output(f"# Description:") descriptions = issue["fields"]["description"] if descriptions: for line in descriptions.split("\n"): - print(f"# {line}") - print(f"#\n") + print_output(f"# {line}") + print_output(f"#\n") if cfg.args.comments: c = jira.comments(issue["key"]) @@ -382,16 +482,20 @@ def print_issues(jira, issues): ] except KeyError: originalestimate = "Not Set" - print( + print_output( f"# Assignee: {issue['fields']['assignee']['displayName']}, Original Estimate: {originalestimate}, Time Spent: {timespent}" ) - print(f"# Last comment, updated: {c[0].updated}, by: {c[0].author}") + print_output( + f"# Last comment, updated: {c[0].updated}, by: {c[0].author}" + ) comment = "# ---8<---\n# %s\n# --->8---\n" % "\n# ".join( c[-1].body.splitlines() ) - print(comment) + print_output(comment) - # print(f"{issue['key']}, status: {issue['fields']['status']['statusCategory']['name']}, created: {str(parser.parse(issue['fields']['created'])).split(' ')[0]}\n\t Summary: {issue['fields']['summary']}\n\t https://linaro.atlassian.net/browse/{issue['key']}") + # print_output(f"{issue['key']}, status: {issue['fields']['status']['statusCategory']['name']}, created: {str(parser.parse(issue['fields']['created'])).split(' ')[0]}\n\t Summary: {issue['fields']['summary']}\n\t https://linaro.atlassian.net/browse/{issue['key']}") + if cfg.args.cloneformat: + print_output(yaml.dump(cloneformat_issues)) ################################################################################