Several enhancements
This commit is contained in:
@@ -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)
|
||||||
@@ -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)
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
from types import ClassMethodDescriptorType
|
from types import ClassMethodDescriptorType
|
||||||
from jira import JIRA, Issue, Comment, exceptions
|
from jira import JIRA, Issue, Comment, exceptions
|
||||||
|
from datetime import date
|
||||||
import re
|
import re
|
||||||
import csv
|
import csv
|
||||||
import xlsxwriter
|
import xlsxwriter
|
||||||
@@ -16,10 +17,10 @@ logging.basicConfig(filename='sprint efforts.log',
|
|||||||
|
|
||||||
host = "https://jira.wien.gv.at/"
|
host = "https://jira.wien.gv.at/"
|
||||||
pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD"
|
pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD"
|
||||||
sprint = 2
|
#sprint = 2
|
||||||
|
|
||||||
row = 0; col = 0
|
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')
|
worksheet = workbook.add_worksheet('efforts')
|
||||||
|
|
||||||
cell_format = workbook.add_format()
|
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('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')
|
#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
|
xsp = lambda s: s or 0
|
||||||
|
|
||||||
issue: Issue
|
issue: Issue
|
||||||
|
|||||||
+64
-59
@@ -9,6 +9,7 @@ import csv
|
|||||||
import xlsxwriter
|
import xlsxwriter
|
||||||
import logging
|
import logging
|
||||||
from bisect import bisect_left
|
from bisect import bisect_left
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
def take_closest(myList, myNumber):
|
def take_closest(myList, myNumber):
|
||||||
"""
|
"""
|
||||||
@@ -29,15 +30,18 @@ def take_closest(myList, myNumber):
|
|||||||
return before
|
return before
|
||||||
|
|
||||||
def get_assignee(type, issue):
|
def get_assignee(type, issue):
|
||||||
isBuergerfrontend = False
|
# isBuergerfrontend = False
|
||||||
if type == 'Dev Backend':
|
if (type == 'Dev Backend' or type.startswith('Dev Unit')):
|
||||||
return 'reu9001'
|
# use assignee of story
|
||||||
|
return 'rab9001'
|
||||||
|
#return issue.fields.assignee.name
|
||||||
elif type == 'Dev Frontend':
|
elif type == 'Dev Frontend':
|
||||||
for component in issue.fields.components:
|
# for component in issue.fields.components:
|
||||||
isBuergerfrontend = component.name == "Bürgerfrontend"
|
# isBuergerfrontend = component.name == "Bürgerfrontend"
|
||||||
if isBuergerfrontend:
|
# if isBuergerfrontend:
|
||||||
return 'reu9001'
|
|
||||||
return 'thh9001'
|
return 'thh9001'
|
||||||
|
elif type == 'Dev Citizen-Frontend':
|
||||||
|
return 'reu9001'
|
||||||
elif type.startswith('Test-Anpassung'):
|
elif type.startswith('Test-Anpassung'):
|
||||||
return 'osm9005'
|
return 'osm9005'
|
||||||
|
|
||||||
@@ -99,18 +103,18 @@ logging.basicConfig(filename='sub_task_generator.log',
|
|||||||
|
|
||||||
host = "https://jira.wien.gv.at/"
|
host = "https://jira.wien.gv.at/"
|
||||||
pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD"
|
pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD"
|
||||||
sprint = 4
|
sprint = 6
|
||||||
|
|
||||||
headers = JIRA.DEFAULT_OPTIONS["headers"].copy()
|
headers = JIRA.DEFAULT_OPTIONS["headers"].copy()
|
||||||
headers["Authorization"] = f"Bearer {pat}"
|
headers["Authorization"] = f"Bearer {pat}"
|
||||||
jira_server = JIRA(server=host, options={"headers": headers})
|
jira_server = JIRA(server=host, options={"headers": headers})
|
||||||
|
|
||||||
# use filter or single issue
|
# use filter or single issue
|
||||||
issues_Jql = jira_server.search_issues('filter=25827') #, expand='changelog')
|
#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('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')
|
#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
|
xsp = lambda s: s or 0
|
||||||
|
|
||||||
issue: Issue
|
issue: Issue
|
||||||
@@ -123,63 +127,64 @@ for issue in issues_Jql:
|
|||||||
if hasattr(issue.fields, 'customfield_10022'):
|
if hasattr(issue.fields, 'customfield_10022'):
|
||||||
sp = xsp(issue.fields.customfield_10022)
|
sp = xsp(issue.fields.customfield_10022)
|
||||||
|
|
||||||
if sp != 0:
|
# if sp == 0:
|
||||||
logging.info('Ignoring issue {} as there are Story-Points already omitted'.format(issue))
|
# logging.info('Ignoring issue {} as there are Story-Points already omitted'.format(issue))
|
||||||
else:
|
# else:
|
||||||
single_issue = jira_server.issue(issue.key)
|
single_issue = jira_server.issue(issue.key)
|
||||||
comments = single_issue.fields.comment.comments
|
comments = single_issue.fields.comment.comments
|
||||||
|
|
||||||
# Find all comments made by me on this issue.
|
# Find all comments made by me on this issue.
|
||||||
for comment in comments:
|
for comment in comments:
|
||||||
comment_lines = comment.body.splitlines()
|
comment_lines = comment.body.splitlines()
|
||||||
|
|
||||||
if len(comment_lines) == 7:
|
if len(comment_lines) == 9:
|
||||||
if comment_lines[0][:5] == "Dev B":
|
if comment_lines[0][:5] == "Dev B":
|
||||||
for comment_line in comment_lines:
|
for comment_line in comment_lines:
|
||||||
if comment_line != "":
|
if comment_line != "":
|
||||||
# pos = comment_lines[2].find('NN')
|
# pos = comment_lines[2].find('NN')
|
||||||
comment_line_parts = comment_line.split(':')
|
comment_line_parts = comment_line.split(':')
|
||||||
|
|
||||||
# if 1. Test* != NN create a sub-task (if not existing)
|
# if 1. Test* != NN create a sub-task (if not existing)
|
||||||
if len(comment_line_parts) == 2:
|
if len(comment_line_parts) == 2:
|
||||||
if comment_line_parts[1] != u'\xa0': # empty string
|
if comment_line_parts[1] != u'\xa0': # empty string
|
||||||
if (comment_line_parts[1][-2:] != 'NN'): # NN means NotNecessary
|
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:] == '-'):
|
if (comment_line_parts[1][-1:] == '-'):
|
||||||
subtask_ph = 0
|
subtask_ph = 0
|
||||||
estimation_remark = "(not estimated yet)"
|
estimation_remark = "(not estimated yet)"
|
||||||
else:
|
else:
|
||||||
comment_line_sub_parts = comment_line_parts[1].split(' (')
|
comment_line_sub_parts = comment_line_parts[1].split(' (')
|
||||||
if len(comment_line_sub_parts)>1:
|
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
|
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:
|
else:
|
||||||
if comment_line_sub_parts[0].strip().isnumeric():
|
if comment_line_sub_parts[0].strip() == "tbd":
|
||||||
subtask_ph = float(comment_line_sub_parts[0]) * 0.5
|
subtask_ph = take_closest([1,2,3,5,8,13,21,42], sp_sum/3)
|
||||||
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":
|
if comment_line_parts[0][:15] != "Test-Ausführung":
|
||||||
create_subtask(issue,
|
create_subtask(issue,
|
||||||
issue.key,
|
issue.key,
|
||||||
comment_line_parts[0],
|
comment_line_parts[0],
|
||||||
subtask_ph,
|
subtask_ph,
|
||||||
estimation_remark)
|
estimation_remark)
|
||||||
sp_sum += subtask_ph / 0.5
|
sp_sum += subtask_ph / 0.5
|
||||||
|
|
||||||
# find corresponding sub-task
|
# find corresponding sub-task
|
||||||
# issuelinks.inwardIssue
|
# issuelinks.inwardIssue
|
||||||
try:
|
try:
|
||||||
if sp != sp_sum:
|
if sp != sp_sum:
|
||||||
issue.update(fields={'customfield_10022': 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))
|
logging.info("Estimated story-points changed to Sum(Sub-Tasks story-points): {}".format(sp_sum, sp_sum))
|
||||||
|
|
||||||
except exceptions.JIRAError:
|
except exceptions.JIRAError:
|
||||||
logging.error("Issue {} has no (visible) Story Points-attribute".format(issue.key))
|
logging.error("Issue {} has no (visible) Story Points-attribute".format(issue.key))
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
logging.info('Done {}'.format(issue.key))
|
logging.info('Done {}'.format(issue.key))
|
||||||
|
|
||||||
#print('{}: {}, SP: {}'.format(issue.key, issue.fields.summary, sp))
|
#print('{}: {}, SP: {}'.format(issue.key, issue.fields.summary, sp))
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user