From ba41b9c5efc65f62a69831871866c2146aa9649c Mon Sep 17 00:00:00 2001 From: Zimmerberger Markus Date: Wed, 18 Oct 2023 11:47:31 +0200 Subject: [PATCH] Several minor enhancements --- JIRA_EffortbyComments.py | 81 +++++++++++++++++++++++++++++++++++++ JIRA_SubTasks_byComments.py | 35 +++++++++++++--- 2 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 JIRA_EffortbyComments.py diff --git a/JIRA_EffortbyComments.py b/JIRA_EffortbyComments.py new file mode 100644 index 0000000..072d53d --- /dev/null +++ b/JIRA_EffortbyComments.py @@ -0,0 +1,81 @@ +# find comments with estimations out of pre-planning +# zisco 2021-09-30 19:50 + +from types import ClassMethodDescriptorType +from jira import JIRA, Issue, Comment, exceptions +import re +import csv +import xlsxwriter +import logging + +logging.basicConfig(filename='sprint efforts.log', + filemode='a', + format='%(asctime)s - %(levelname)s: %(message)s', + level=logging.INFO, + encoding='utf-8') + +host = "https://jira.wien.gv.at/" +pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD" +sprint = 9 + +headers = JIRA.DEFAULT_OPTIONS["headers"].copy() +headers["Authorization"] = f"Bearer {pat}" +jira_server = JIRA(server=host, options={"headers": headers}) + +# use filter or single issue +issues_Jql = jira_server.search_issues('filter=24707') #, expand='changelog') +#issues_Jql = jira_server.search_issues('key in (DKARB-140)') #, expand='changelog') +#issues_Jql = jira_server.search_issues('labels in (Refinement11012022) AND type not in (Bug) AND status not in (Done) and ("Story Points" is EMPTY or "Story Points" = 0)') #, expand='changelog') + +logging.info('Sum effort stored in issue-comments of pre-planning sprint {}'.format(sprint)) +xsp = lambda s: s or 0 + +issue: Issue +for issue in issues_Jql: + #logging.info('Working on {}'.format(issue)) + sp_sum = 0 + + # only Issues with empty (or 0) story-points + sp = 0 + if hasattr(issue.fields, 'customfield_10022'): + sp = xsp(issue.fields.customfield_10022) + + single_issue = jira_server.issue(issue.key) + comments = single_issue.fields.comment.comments + + # Find all comments made by me on this issue. + for comment in comments: + comment_lines = comment.body.splitlines() + + if len(comment_lines) == 5: + if comment_lines[0][:5] == "Dev B": + for comment_line in comment_lines: + if comment_line != "": + logging.info(f"{comment_line}") + # pos = comment_lines[2].find('NN') + comment_line_parts = comment_line.split(':') + + if len(comment_line_parts) == 2: + if comment_line_parts[1] != u'\xa0': # empty string + if (comment_line_parts[1][-2:] != 'NN') and (comment_line_parts[1][-1:] != '-'): # NN means NotNecessary + comment_line_sub_parts = comment_line_parts[1].split(' (') + if len(comment_line_sub_parts)>1: + if comment_line_sub_parts[0].isnumeric(): + subtask_ph = float(comment_line_sub_parts[0]) * 0.5 + estimation_remark = comment_line_sub_parts[1] + else: + subtask_ph = 0 + else: + if comment_line_sub_parts[1].isnumeric(): + subtask_ph = float(comment_line_parts[1]) * 0.5 + estimation_remark = "" + else: + subtask_ph = 0 + #logging.info(f"Effort {comment_line_sub_parts[0]}") + sp_sum += subtask_ph / 0.5 + try: + if sp != sp_sum: + logging.info(f"Estimated story-points changed to Sum(Sub-Tasks story-points): {sp_sum}") + + except exceptions.JIRAError: + logging.error("Issue {} has no (visible) Story Points-attribute".format(issue.key)) \ No newline at end of file diff --git a/JIRA_SubTasks_byComments.py b/JIRA_SubTasks_byComments.py index 019258b..f6a97c3 100644 --- a/JIRA_SubTasks_byComments.py +++ b/JIRA_SubTasks_byComments.py @@ -7,6 +7,25 @@ import re import csv import xlsxwriter import logging +from bisect import bisect_left + +def take_closest(myList, myNumber): + """ + Assumes myList is sorted. Returns closest value to myNumber. + + If two numbers are equally close, return the smallest number. + """ + pos = bisect_left(myList, myNumber) + if pos == 0: + return myList[0] + if pos == len(myList): + return myList[-1] + before = myList[pos - 1] + after = myList[pos] + if after - myNumber < myNumber - before: + return after + else: + return before def get_assignee(type, issue): isBuergerfrontend = False @@ -19,7 +38,7 @@ def get_assignee(type, issue): return 'reu9001' return 'thh9001' elif type.startswith('Test-Anpassung'): - return 'ada9001' + return 'osm9005' def create_subtask(issue, parent, type, subtask_sp, estimation_remark): escaped = issue.fields.summary.replace('"', r'\"') @@ -71,15 +90,15 @@ logging.basicConfig(filename='sub_task_generator.log', host = "https://jira.wien.gv.at/" pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD" -sprint = 4 +sprint = 9 headers = JIRA.DEFAULT_OPTIONS["headers"].copy() headers["Authorization"] = f"Bearer {pat}" jira_server = JIRA(server=host, options={"headers": headers}) # use filter or single issue -issues_Jql = jira_server.search_issues('filter=22140') #, expand='changelog') -#issues_Jql = jira_server.search_issues('key in (DKARB-34)') #, expand='changelog') +issues_Jql = jira_server.search_issues('filter=24707') #, expand='changelog') +#issues_Jql = jira_server.search_issues('key in (DKARB-140)') #, expand='changelog') #issues_Jql = jira_server.search_issues('labels in (Refinement11012022) AND type not in (Bug) AND status not in (Done) and ("Story Points" is EMPTY or "Story Points" = 0)') #, expand='changelog') logging.info('Creating sub-tasks out of estimation of pre-planning sprint {}'.format(sprint)) @@ -121,8 +140,12 @@ for issue in issues_Jql: subtask_ph = float(comment_line_sub_parts[0]) * 0.5 estimation_remark = comment_line_sub_parts[1] else: - subtask_ph = float(comment_line_parts[1]) * 0.5 - estimation_remark = "" + if comment_line_sub_parts[0].strip().isnumeric(): + subtask_ph = float(comment_line_sub_parts[0]) * 0.5 + estimation_remark = "" + else: + if comment_line_sub_parts[0].strip() == "tbd": + subtask_ph = take_closest([1,2,3,5,8,13,21,42], sp_sum/3) if comment_line_parts[0][:15] != "Test-Ausführung": create_subtask(issue,