From e5189f0d8cb7a26413da1edcfb9bf33563b5645f Mon Sep 17 00:00:00 2001 From: Zimmerberger Markus Date: Wed, 8 May 2024 08:54:58 +0200 Subject: [PATCH] Several enhancements --- BitBucket_connector.py | 17 ++++ Confluence Blog timestamp change.py | 101 +++++++++++++++++++++++ JIRA_EffortbySubTasks.py | 7 +- JIRA_SubTasks_byComments.py | 123 +++++++++++++++------------- efforts sprint 2.xlsx | Bin 5486 -> 5486 bytes 5 files changed, 186 insertions(+), 62 deletions(-) create mode 100644 BitBucket_connector.py create mode 100644 Confluence Blog timestamp change.py diff --git a/BitBucket_connector.py b/BitBucket_connector.py new file mode 100644 index 0000000..4537283 --- /dev/null +++ b/BitBucket_connector.py @@ -0,0 +1,17 @@ +from atlassian import Bitbucket +from jira import JIRA + +host = "https://bitbucket.wien.gv.at/" +pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD" + +# Initialize Bitbucket instance +#TODO Use token for authentication +bitbucket = Bitbucket( + url=host, + username='zim9003', # Assuming you need authentication + password='3S1punk08_113$', # Use token for authentication +) + +repos = bitbucket.repo_list('BAUWB') +for repo in repos: + print(repo) \ No newline at end of file diff --git a/Confluence Blog timestamp change.py b/Confluence Blog timestamp change.py new file mode 100644 index 0000000..9ffd429 --- /dev/null +++ b/Confluence Blog timestamp change.py @@ -0,0 +1,101 @@ +# make page-header of confluence-area unique (add WGWR2) +# zisco 2023-11-10 06:59 + +from distutils.log import INFO +from queue import Full +from sqlite3 import Timestamp +from atlassian import Confluence +import logging +import requests +import json +from datetime import date, datetime + +# Custom serializer function +def custom_serializer(obj): + if isinstance(obj, datetime): + #'2024-03-28T09:20:00.000+01:00' + #return obj.strftime('%Y-%m-%dT%H:%M:%S') + return obj.strftime('%Y-%m-%dT%H:%M:%S.000+01:00') + raise TypeError(f'Object of type {type(obj)} is not JSON serializable') + +logging.basicConfig(filename='confluence blog timestamp change.log', + filemode='a', + format='%(asctime)s - %(levelname)s: %(message)s', + level=logging.WARNING, + encoding='utf-8') +logger = logging.getLogger('myLogger') +logger.setLevel(level=logging.INFO) + +confluence_host = "https://confluence.wien.gv.at/" +confluence_pat = "MDI3ODU2NzkzMTAyOsPz47kjJvVdJa1bLpen3W5sB6S5" + +s = requests.Session() +s.headers['Authorization'] = f"Bearer {confluence_pat}" +confluence = Confluence(url=confluence_host, session=s) + +# Function to retrieve page content by page ID +def get_page_content(page_id): + blog_page = confluence.get_page_by_id(page_id, expand='body.storage') + space = confluence.get_page_by_id(page_id, expand='space') + return blog_page, space['space'] + +# Function to create a new page with specified creation date +def create_page_with_creation_date(space, title, body, creation_date): + #headers = {'Content-Type': 'application/json'} + data = { + "type": "page", + "title": title, + "body": { + "storage": { + "value": body, + "representation": "storage" + } + }, + "metadata": { + "createdDate": creation_date + } + } + status = confluence.create_page(space=space, title=title, body=body, type='blogpost') + return status + +# Function to delete a page by page ID +def delete_page(page_id): + response = confluence.remove_page(page_id=page_id) + return response.status_code == 204 + +""" +def change_blog_timestamp(page_id): + blog_page = confluence.get_page_by_id(page_id, expand=None, status=None, version=None) + #confluence.update_page(page_id=page_id, Timestamp=datetime.now()) + + data = { + "history": { + "createdDate": datetime.now() + } + } + json_data = json.dumps(data, default=custom_serializer) + + + confluence.update_page_property(page_id=page_id, data=json_data) + + # Get old page contents + page_content = confluence.get_page_by_id(page_id=page_id, expand='body') # Old page contents + + #Rename and move page, get updated content + #new_page_content = confluence.update_page(old_page_content['id'], title=new_title, body=old_page_content['body'], parent_id=parent_id, type="page", representation="storage") + confluence.update_page(page_id=page_id, title=page_title) #, body=page_content['body']) + logger.info(f"New page title '{page_title}'") """ + +# Example usage +page_id = 317036255 # Jenkins-Blog +new_creation_date = datetime.now() +page_content, space = get_page_content(page_id) +if page_content: + title = page_content["title"] + body = page_content["body"] + new_page_id = create_page_with_creation_date(space['key'], title, body, new_creation_date) + delete_page(page_id) +else: + print("Page not found.") + +#change_blog_timestamp(page_id=page_id) \ No newline at end of file diff --git a/JIRA_EffortbySubTasks.py b/JIRA_EffortbySubTasks.py index e0d4177..08c7c79 100644 --- a/JIRA_EffortbySubTasks.py +++ b/JIRA_EffortbySubTasks.py @@ -3,6 +3,7 @@ from types import ClassMethodDescriptorType from jira import JIRA, Issue, Comment, exceptions +from datetime import date import re import csv import xlsxwriter @@ -16,10 +17,10 @@ logging.basicConfig(filename='sprint efforts.log', host = "https://jira.wien.gv.at/" pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD" -sprint = 2 +#sprint = 2 row = 0; col = 0 -workbook = xlsxwriter.Workbook(f'efforts sprint {sprint}.xlsx') +workbook = xlsxwriter.Workbook(f'efforts as of preplanning {date.today()}.xlsx') worksheet = workbook.add_worksheet('efforts') cell_format = workbook.add_format() @@ -43,7 +44,7 @@ issues_Jql = jira_server.search_issues('filter=25827') #, 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)) +logging.info(f'Sum effort stored in issue-comments of pre-planning of {date.today()}') xsp = lambda s: s or 0 issue: Issue diff --git a/JIRA_SubTasks_byComments.py b/JIRA_SubTasks_byComments.py index a816907..315f2fa 100644 --- a/JIRA_SubTasks_byComments.py +++ b/JIRA_SubTasks_byComments.py @@ -9,6 +9,7 @@ import csv import xlsxwriter import logging from bisect import bisect_left +from datetime import date def take_closest(myList, myNumber): """ @@ -29,15 +30,18 @@ def take_closest(myList, myNumber): return before def get_assignee(type, issue): - isBuergerfrontend = False - if type == 'Dev Backend': - return 'reu9001' + # 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 'reu9001' + # 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'): return 'osm9005' @@ -99,18 +103,18 @@ logging.basicConfig(filename='sub_task_generator.log', host = "https://jira.wien.gv.at/" pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD" -sprint = 4 +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 (WRWGR-2885)') #, expand='changelog') +#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('Creating sub-tasks out of estimation of pre-planning sprint {}'.format(sprint)) +logging.info(f'Creating sub-tasks out of estimation of pre-planning of {date.today()}') xsp = lambda s: s or 0 issue: Issue @@ -123,63 +127,64 @@ for issue in issues_Jql: 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 + # 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() + # Find all comments made by me on this issue. + for comment in comments: + comment_lines = comment.body.splitlines() - if len(comment_lines) == 7: - 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 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 - 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 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] + 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().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_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 + 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)) + # 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)) + except exceptions.JIRAError: + logging.error("Issue {} has no (visible) Story Points-attribute".format(issue.key)) - finally: - logging.info('Done {}'.format(issue.key)) + finally: + logging.info('Done {}'.format(issue.key)) #print('{}: {}, SP: {}'.format(issue.key, issue.fields.summary, sp)) diff --git a/efforts sprint 2.xlsx b/efforts sprint 2.xlsx index 8d905d0154eeadd9cada492597c3a79fdad076c9..bd174fda97e72dddcb02b975bc7194540e1e460b 100644 GIT binary patch delta 326 zcmV-M0lEI}D()(<=nn)6=Hj%I><=G*%WA_g5JmTe{)5rpmhAK?YzNwsRRe`4v~(w= zi6d$~kkmT)`zm(gB#>1>8|mITb7xRF-KaMC1?Q#F70NS$642ZTshbKd7qj#MB|b1M zSZg#?XbT=q>+7qMTgr`tH)kxkAi*b*q&?-fLhBGL#n|&TDCV>1&{13&r&x%8SJz<6 z_%~|+7lhnl1%U|`7~TO>I}*_zDfo!AKd$Wof@5ewfes$$S&on108aUf1-)|OR5ENW zT(lm<(Y^6Z8*1>@=xpI+kPTIRz%?sz3Z zJZ+<=G*UrWO<6vf{KzeCA;o2Jttq3u9rPYwhpifw?W6l4!SYZ`y9%27B`H=A8Sx=U!4ScB)N&!Fg$Pg-Dj81T;57>ZU^P>t*_Y5+9fr ztTh@cvR@(w=f#p=}73V(j@A6!Teh=qPTCQ!K=P(lyvJ z{>>V|MV`;Gg1`g|4EMm)PDFG-3O*t2k81~j;22s^po7OGBlzSE;FQ1GFeqnECBxpr zRqIil+&eEPW7lM#0;@ YG56&ssQ&=7FcG^01QLh9jFayae|+YkWB>pF