Files
pyJira/JIRA_SubTasks_byComments.py
T

206 lines
8.5 KiB
Python

# find comments with estimations out of pre-planning
# zisco 2021-09-30 19:50
from multiprocessing.sharedctypes import Value
from types import ClassMethodDescriptorType
from jira import JIRA, Issue, Comment, exceptions
import re
import csv
import xlsxwriter
import logging
from bisect import bisect_left
from datetime import date
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
if (type == 'Dev Backend' or type.startswith('Dev Unit')):
# use assignee of story
return 'rab9001'
#return issue.fields.assignee.name
elif type == 'Dev Frontend':
# for component in issue.fields.components:
# isBuergerfrontend = component.name == "Bürgerfrontend"
# if isBuergerfrontend:
return 'thh9001'
elif type == 'Dev Citizen-Frontend':
return 'reu9001'
elif type.startswith('Test-Anpassung'):
if issue.key.startswith('WRGWR-'):
return 'ada9001'
else:
return 'osm9005'
def create_subtask(issue, parent, type, subtask_sp, estimation_remark):
escaped = issue.fields.summary.replace('"', r'\"')
logging.info(f'summary ~ \"{escaped}\"')
try:
subtask = jira_server.search_issues(f'summary ~ \"{type} {escaped}\"')
if subtask:
raise exceptions.JIRAError
except exceptions.JIRAError:
# correct estimation
#subtask.fields('timetracking': {'originalEstimate'}).Value() = subtask_sp
single_issue = jira_server.issue(subtask[0].key)
try:
single_issue.update(fields={'timetracking': {'originalEstimate': '{}d'.format(subtask_sp)}})
except Exception as e:
logging.info(e)
logging.info(f'Skip creating Sub-Task {type} for {issue} as it already exists')
return
issue_type = 'Sub-task'
assignee = get_assignee(type, issue)
description = 's. Story'
if estimation_remark != "":
description += "\nEstimation remark: {}".format(estimation_remark)
issue_dict = {
'project': {'id': issue.fields.project.id},
'summary': "[{}] {}".format(type, escaped),
'description': description, # issue.fields.description,
'issuetype': {'name': issue_type},
'priority': {'name': issue.fields.priority.name},
'parent': {'key': parent},
'labels': issue.fields.labels,
#'customfield_10022' - Story Points
'timetracking': {'originalEstimate': "{}d".format(subtask_sp)},
'assignee': {'name': assignee}
}
new_issue = jira_server.create_issue(fields=issue_dict)
# consider components
existingComponents = []
for component in issue.fields.components:
existingComponents.append({"name" : component.name})
new_issue.update(fields={"components": existingComponents})
#new_issue.update(priority={"name": issue.fields.priority.name})
logging.info('Created Sub-Task {}'.format(new_issue))
logging.basicConfig(filename='sub_task_generator.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 = 6
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=25827') #, expand='changelog')
#issues_Jql = jira_server.search_issues('key in (WRGWR-2932)') #, 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(f'Creating sub-tasks out of estimation of pre-planning of {date.today()}')
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)
# if sp == 0:
# logging.info('Ignoring issue {} as there are Story-Points already omitted'.format(issue))
# else:
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) == 9:
if comment_lines[0][:5] == "Dev B":
for comment_line in comment_lines:
if comment_line != "":
# pos = comment_lines[2].find('NN')
comment_line_parts = comment_line.split(':')
# if 1. Test* != NN create a sub-task (if not existing)
if len(comment_line_parts) == 2:
if comment_line_parts[1] != u'\xa0': # empty string
if (comment_line_parts[1][-2:] != 'NN'): # NN means NotNecessary, "-"" means we don't know yet (but subtask will be created)
if (comment_line_parts[1][-1:] == '-'):
subtask_ph = 0
estimation_remark = "(not estimated yet)"
else:
comment_line_sub_parts = comment_line_parts[1].split(' (')
if len(comment_line_sub_parts)>1:
if comment_line_sub_parts[0].strip().isnumeric():
subtask_ph = float(comment_line_sub_parts[0]) * 0.5
estimation_remark = comment_line_sub_parts[1]
else:
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,
issue.key,
comment_line_parts[0],
subtask_ph,
estimation_remark)
sp_sum += subtask_ph / 0.5
# find corresponding sub-task
# issuelinks.inwardIssue
try:
if sp != sp_sum:
issue.update(fields={'customfield_10022': sp_sum})
logging.info("Estimated story-points changed to Sum(Sub-Tasks story-points): {}".format(sp_sum, sp_sum))
except exceptions.JIRAError:
logging.error("Issue {} has no (visible) Story Points-attribute".format(issue.key))
finally:
logging.info('Done {}'.format(issue.key))
#print('{}: {}, SP: {}'.format(issue.key, issue.fields.summary, sp))
#print('Summe {}: {}'.format(assignee, sp_sum))
#print(issues_Jql)
# changelog = issues_Jql.
# count = 0
# for history in changelog.histories:
# for item in history.items:
# if item.field == 'status':
# if item.toString == "Reopened":
# count = count + 1
# print(count)