# 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 from atlassian import Confluence from bs4 import BeautifulSoup import re import csv import xlsxwriter import logging import requests import pandas as pd def get_priority(priority): match priority: case "GreenMVP": return "Highest" case _: return "Medium" def get_assignee(): return 'raj9002' isBuergerfrontend = False if type == 'Dev Backend': #return 'rab9001' return 'reu9001' elif type == 'Dev Frontend': # consider verwaltungsfrontend or bürgerfrontend existingComponents = [] for component in issue.fields.components: if component.name == "Bürgerfrontend": isBuergerfrontend = True if isBuergerfrontend: return 'reu9001' else: return 'thh9001' elif type[:14] == 'Test-Anpassung': return 'ada9001' def create_epic(use_case, priority): escaped = use_case.replace('"','\\"') epic = jira_server.search_issues('project = 19404 AND summary ~ \"{}\"'.format(escaped)) if len(epic) == 0: issue_type = 'Epic' assignee = get_assignee() issue_dict = { 'project': {'id': 19404}, 'summary': escaped, 'description': escaped, 'issuetype': {'name': issue_type}, 'priority': {'name': get_priority(priority)}, 'customfield_10019': escaped, #'parent': {'key': parent}, #'labels': issue.fields.labels, #'customfield_10022' - Story Points #'timetracking': {'originalEstimate': "{}d".format(subtask_sp)}, 'assignee': {'name': assignee} } try: new_issue = jira_server.create_issue(fields=issue_dict) except: print("Something") # 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 Epic {}'.format(new_issue)) else: #update epic = jira_server.issue(epic[0]) logging.info('Skip creating Epic {} as it already exists'.format(epic.key)) logging.basicConfig(filename='epic_generator.log', filemode='a', format='%(asctime)s - %(levelname)s: %(message)s', level=logging.INFO, encoding='utf-8') jira_host = "https://jira.wien.gv.at/" confluence_host = "https://confluence.wien.gv.at/" jira_pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD" confluence_pat = "MDI3ODU2NzkzMTAyOsPz47kjJvVdJa1bLpen3W5sB6S5" sprint = 57 headers = JIRA.DEFAULT_OPTIONS["headers"].copy() headers["Authorization"] = f"Bearer {jira_pat}" jira_server = JIRA(server=jira_host, options={"headers": headers}) s = requests.Session() s.headers['Authorization'] = f"Bearer {confluence_pat}" confluence = Confluence(url=confluence_host, session=s) page_id = 215812836 page = confluence.get_page_by_id(page_id, expand="body.storage", status=None, version=None) body = page["body"]["storage"]["value"] tables_raw = [[[cell.text for cell in row("th") + row("td")] for row in table("tr")] for table in BeautifulSoup(body, features="lxml")("table")] logging.info('Creating epics out of confluence description') #xsp = lambda s: s or 0 tables_df = [pd.DataFrame(table) for table in tables_raw] for table_df in tables_df: for index in table_df.index: if index >= 11 and index <= 12: create_epic(use_case=table_df[1][index], priority=table_df[2][index]) 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) == 5: 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') and (comment_line_parts[1][-1:] != '-'): # NN means NotNecessary subtask_ph = float(comment_line_parts[1]) * 0.5 if comment_line_parts[0][:15] != "Test-Ausführung": create_subtask(issue, issue.key, comment_line_parts[0], subtask_ph) 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)