Initial Commit

This commit is contained in:
Zimmerberger Markus
2022-01-21 17:39:39 +01:00
commit e03f3aae52
10 changed files with 602 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
*.log
+15
View File
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"python.pythonPath": "C:\\Python39\\python.exe"
}
+43
View File
@@ -0,0 +1,43 @@
from types import ClassMethodDescriptorType
from jira import JIRA
import csv
import xlsxwriter
# TODO: create excel!
host = "https://jira.wien.gv.at/"
pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD"
headers = JIRA.DEFAULT_OPTIONS["headers"].copy()
headers["Authorization"] = f"Bearer {pat}"
jira_server = JIRA(server=host, options={"headers": headers})
#jira_server = JIRA(basic_auth=("zim9003",""), options={'server': 'https://jira.wien.gv.at/'})
#jira_server = JIRA(basic_auth=("postman","OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD"), options={'server': 'https://jira.wien.gv.at/'})
#issues_Jql = jira_server.issue('WRGWR-828',expand='changelog')#pass one issue at the time
assignees = ["thh9001","krp9002","reu9001","und9001","krj0003","bln9001","ce39001","rab9001"]
for assignee in assignees:
issues_Jql = jira_server.search_issues('sprint = 1137 AND assignee = {} ORDER BY cf[10022] ASC'.format(assignee)) #, expand='changelog') # 1093
xsp = lambda s: s or 0
sp_sum = 0
for issue in issues_Jql:
sp = 0
if hasattr(issue.fields, 'customfield_10022'):
sp = xsp(issue.fields.customfield_10022)
sp_sum += sp
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)
+131
View File
@@ -0,0 +1,131 @@
# 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
def get_assignee(type):
if type == 'Dev Backend':
return 'rab9001'
elif type == 'Dev Frontend':
return 'reu9001'
elif type[:14] == 'Test-Anpassung':
return 'ada9001'
def create_subtask(issue, parent, type, subtask_sp):
escaped = issue.fields.summary.replace('"','\\"')
print('summary ~ \"{}\"'.format(escaped))
subtask = jira_server.search_issues('summary ~ \"{} {}\"'.format(type, escaped))
if len(subtask) == 0:
#right = (comment_line.find(':')+2)-len(comment_line)
#subtask_sp = float(comment_line[right:])
assignee = get_assignee(type)
issue_dict = {
'project': {'id': 12501},
'summary': "[{}] {}".format(type, escaped),
'description': issue.fields.description,
'issuetype': {'name': 'Sub-task'},
'parent': {'key': parent},
# todo - json
#'components': [{'name': issue.fields.components}],
#'labels': [{'name': issue.fields.labels}],
'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})
logging.info('Created Sub-Task {}'.format(new_issue))
else:
logging.info('Skip creating Sub-Task {} for {} as it already exists'.format(type, 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"
headers = JIRA.DEFAULT_OPTIONS["headers"].copy()
headers["Authorization"] = f"Bearer {pat}"
jira_server = JIRA(server=host, options={"headers": headers})
#issues_Jql = jira_server.search_issues('filter=19527') #, 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(38))
xsp = lambda s: s or 0
issue: Issue
for issue in issues_Jql:
logging.info('Working on {}'.format(issue))
sp_sum = 0
# sp = 0
# if hasattr(issue.fields, 'customfield_10022'):
# sp = xsp(issue.fields.customfield_10022)
# sp_sum += sp
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:
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
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:
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)
+60
View File
@@ -0,0 +1,60 @@
# recalculate historical estimations
# zisco 2021-10-05 15:54
import logging
from types import ClassMethodDescriptorType
from jira import JIRA, Issue, Comment, exceptions
import re
import csv
import xlsxwriter
logging.basicConfig(filename='jahe.log', filemode='a', format='%(asctime)s - %(message)s', level=logging.INFO)
host = "https://jira.wien.gv.at/"
pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD"
headers = JIRA.DEFAULT_OPTIONS["headers"].copy()
headers["Authorization"] = f"Bearer {pat}"
jira_server = JIRA(server=host, options={"headers": headers})
logging.info("Connection to JIRA established")
# issues_Jql = jira_server.search_issues('cf[10022] is not EMPTY AND labels not in (Refinement23092021, hotfix0921) AND status not in (Done) and key not in (wrgwr-929)', expand='changelog')
issues_Jql = jira_server.search_issues('key in (wrgwr-856, wrgwr-854, wrgwr-853)', expand='changelog')
xsp = lambda s: s or 0
sp_sum = 0
issue: Issue
for issue in issues_Jql:
logging.info("Working on {}".format(issue.key))
sp = 0
if hasattr(issue.fields, 'customfield_10022'):
sp = xsp(issue.fields.customfield_10022)
sp_sum += sp
# log old values
print(sp, sp/8)
originalEstimate = issue.fields.timeoriginalestimate
logging.info("Estimation-system change: Old Story Points {} -> new Story Points {}".format(sp, sp/8))
# probably already adapted? Search for activity 'updated the Story Points'
doChange = True
for history in issue.changelog.histories:
if doChange==False:
break
if (history.author.key=='JIRAUSER17211'):
for item in history.items:
if (item.field=='Story Points'):
doChange = False
break
if doChange:
# update story-points
try:
issue.update(fields={'customfield_10022': sp/8})
comment = jira_server.add_comment(issue, "Estimation-system change: Old Story Points {} -> new Story Points {}".format(sp, sp/8))
except exceptions.JIRAError:
logging.error("Issue {} has no (visible) Story Points-attribute".format(issue.key))
finally:
print('Done {}'.format(issue.key))
+64
View File
@@ -0,0 +1,64 @@
# suche alle issues, wo (original estimate * 2) != story points
# korrigiere story points auf original estimate * 2
# zisco 2021-10-05 15:54
import logging
from types import ClassMethodDescriptorType
from jira import JIRA, Issue, Comment, exceptions
import re
import csv
import xlsxwriter
logging.basicConfig(filename='jahe.log', filemode='a', format='%(asctime)s - %(message)s', level=logging.INFO)
host = "https://jira.wien.gv.at/"
pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD"
headers = JIRA.DEFAULT_OPTIONS["headers"].copy()
headers["Authorization"] = f"Bearer {pat}"
jira_server = JIRA(server=host, options={"headers": headers})
logging.info("Connection to JIRA established")
# issues_Jql = jira_server.search_issues('cf[10022] is not EMPTY AND labels not in (Refinement23092021, hotfix0921) AND status not in (Done) and key not in (wrgwr-929)', expand='changelog')
# issues_Jql = jira_server.search_issues('status not in (Done)', expand='changelog')
issues_Jql = jira_server.search_issues('key in (wrgwr-773)', expand='changelog')
xsp = lambda s: s or 0
sp_sum = 0
issue: Issue
for issue in issues_Jql:
logging.info("Working on {}".format(issue.key))
sp = 0
if hasattr(issue.fields, 'customfield_10022'):
sp = xsp(issue.fields.customfield_10022)
sp_sum += sp
# log old values
print(sp, sp/8)
originalEstimate = xsp(issue.fields.timeoriginalestimate)
logging.info("Estimation-system change: Old Story Points {} -> new Story Points {}".format(sp, sp/8))
if (originalEstimate != 0) and (originalEstimate / 14400) != sp:
# probably already adapted? Search for activity 'updated the Story Points'
doChange = True
for history in issue.changelog.histories:
if doChange==False:
break
if (history.author.key=='JIRAUSER17211'):
for item in history.items:
if (item.field=='Story Points'):
doChange = False
break
if doChange:
# update story-points
try:
issue.update(fields={'customfield_10022': originalEstimate / 14400})
comment = jira_server.add_comment(issue, "Estimation-system change: Old Story Points {} -> new Story Points {}".format(sp, sp/8))
except exceptions.JIRAError:
logging.error("Issue {} has no (visible) Story Points-attribute".format(issue.key))
finally:
print('Done {}'.format(issue.key))
+219
View File
@@ -0,0 +1,219 @@
#!/usr/bin/python3
# import work-log entries from elsap csv
# avoid multiple logging
# TODO: log completely
# zisco 2021-10-28 09:33
import os, shutil
import logging
from types import ClassMethodDescriptorType
from jira import JIRA, Issue, Comment, exceptions, JIRAError
import re
import csv
from numpy import single
# import xlsxwriter
import pandas as pd
from pandas.core.dtypes.missing import notnull
import json
from pandas.core.frame import DataFrame
from requests.sessions import codes
def process_elsap_file(filename):
data = pd.read_excel(filename)
df = pd.DataFrame(data, columns=['Mitarbeiter','Datum','Menge.1','Benutzerfeld']) # dtype={'Mitarbeiter': str, 'Menge.1': float, 'Benutzerfeld': str})
df = df.dropna()
#filtered_df = df.loc[(df['Datum'] >= '2021-10-01')
# & (df['Datum'] < '2021-11-02')]
df = df.loc[(df['Datum'] <= '2021-11-07')]
logging.info('Consider dates <= {}'.format('2021-11-07'))
df['doit'] = True
df['new'] = False
df['del'] = False
df['JIRA'] = ''
logging.info("Initial DataFrame size is {} rows".format(len(df.index)))
df = single_line_dataframe(df)
logging.info("Adapted DataFrame size is {} rows".format(len(df.index)))
real = False
for index, row in df.iterrows():
# search for corresponding JIRA-issue
issue_str = "WRGWR-{}".format(row['JIRA'])
print("Working on {}".format(issue_str))
logging.info("Working on {}".format(issue_str))
try:
worklogs = jira_server.worklogs(issue_str)
except JIRAError as e:
logging.error('JIRA-Iyssue {} not found! (status: {} text: {})'.format(issue_str, e.status_code, e.text))
continue
# probably work is already logged?
for worklog in worklogs:
# get corresponding user
jira_worklog_user = worklog.author.key
elsap_user = user_array[row['Mitarbeiter']]
if jira_worklog_user==elsap_user:
if not confirm_prompt("User {} has already logged, still add worklog?".format(row['Mitarbeiter'])):
df.at[index,'doit'] = False
logging.info("No worklog wanted!")
issue = jira_server.issue(issue_str)
originalEstimate = xsp(issue.fields.timeoriginalestimate)
# TODO: Check if original time estimated set? (and, if it set well!)
if hasattr(issue.fields, 'customfield_10022'):
storypoints = xsp(issue.fields.customfield_10022)
if (storypoints/2*28800) != originalEstimate:
# adjust
if confirm_prompt("Adjust original-estimate with storypoints? (old {}, new {})".format(originalEstimate, storypoints/2*28800)):
if real == True:
issue.fields.timeoriginalestimate = storypoints/2*28800 # is that needed?
issue.update(fields={'timetracking': {'originalEstimate': '{}d'.format(storypoints/2)}})
# print("Old {} new {}".format(storypoints, issue.fields.timeoriginalestimate))
# logging.info("Old estimation {} should be changed to {} days (based on {} storypoints)".format(originalEstimate, storypoints/2, storypoints))
logging.info("Old estimation {} changed to {} days (based on {} storypoints)".format(originalEstimate, storypoints/2, storypoints))
if row['doit'] == True:
if confirm_prompt("Add worklog for {}? ".format(issue_str)):
if real == True:
jira_server.add_worklog(issue_str, timeSpent="{}h".format(row['Menge.1']), user="{} worked on issue {} {} hours at {}".format(row['Mitarbeiter'], issue_str, row['Menge.1'], row['Datum']))
# print(row['Datum'],row['Mitarbeiter'],row['Menge.1'],row['Benutzerfeld'],row['JIRA'])
logging.info("{} worked {} hours at {}".format(row['Mitarbeiter'], row['Menge.1'], row['Datum']))
def confirm_prompt(question: str) -> bool:
reply = None
while reply not in ("", "y", "n"):
reply = input(f"{question} (Y/n): ").lower()
return (reply in ("", "y"))
def extract_jira_issues(comment):
if pd.notna(comment):
return re.findall(r'WRGWR-\d+', comment)
"""
# possible values: Refinement (2), 1000 (2,5), Jour Fixe(1)
# 819(1),798(2),888(2), Meeting (1.5)
commentSplit = comment.split('),')
bookedJira = {}
singleJira = []
for singleItem in commentSplit:
# a valid single item is a pair of two numerical values
singleJira = re.findall(r'\d+', singleItem)
if len(singleJira) == 2:
bookedJira[singleJira[0]] = singleJira[1] """
# return bookedJira
def single_line_dataframe(df) -> DataFrame:
for index, row in df.iterrows():
issue_number = extract_jira_issues(row['Benutzerfeld'])
if issue_number:
if len(issue_number) > 1:
time = xsp(row['Menge.1'])/len(issue_number) # TODO: Consider possibility of given notation: "758 (2), 759 (1)"
df.at[index, 'del'] = True
for single_issue in issue_number: # issue_number[1:]
new_rows = []
# fix time of first entry, add as much as needed new lines
row.loc['Menge.1'] = time
row.loc['JIRA'] = single_issue
row.loc['new'] = True
new_rows.append(row)
df = df.append(pd.DataFrame(new_rows, columns=df.columns), ignore_index=True) # .reset_index()
else:
df.at[index, 'JIRA'] = issue_number
else:
df.at[index, 'doit'] = False
# drop all to-be deleted rows
indexNames = df[df['del'] == True].index
df.drop(indexNames , inplace=True)
# drop all non-doit
indexNames = df[df['doit'] == False].index
df.drop(indexNames , inplace=True)
return df
# map elsap-users to jira-users
# input_file = open('elsap_to_jira_user.json', encoding="utf-8")
userjson = '{"Kratochvil Jakub":"JIRAUSER16603","Zimmerberger Markus":"JIRAUSER17211","Cervenka Raimund":"JIRAUSER14400","Reischitz Ulf":"reu9001","Kremser Peter":"krp9002","Thüringer Helfried":"JIRAUSER15724","Blagojevic Nikolina":"JIRAUSER17212","Unfried Daniel":"und9001","Stefan Ion-Christian":"JIRAUSER16518"}'
user_array = json.loads(userjson)
# print(type(user_array))
logging.basicConfig(filename='elsap_importer.log',
filemode='a',
format='%(asctime)s - %(levelname)s: %(message)s',
level=logging.INFO,
encoding='utf-8')
host = "https://jira.wien.gv.at/"
pat = "OTAyMTM3MjY0MjE0Ovz6bu0ti1TlEdSegmmiWiJ2wGeD"
headers = JIRA.DEFAULT_OPTIONS["headers"].copy()
headers["Authorization"] = f"Bearer {pat}"
jira_server = JIRA(server=host, options={"headers": headers})
logging.info("Connection to JIRA established")
xsp = lambda s: s or 0
# open elsap-xlsx
with os.scandir(r'C:\Users\zim9003\Documents\reports') as it:
for entry in it:
if entry.name.endswith(".xlsx") and entry.is_file():
logging.info('Processing file {}'.format(entry.path))
process_elsap_file(entry.path)
# move to done
logging.info('Moved file to done -> {}'.format(entry.name))
shutil.move(entry.path, r'C:\Users\zim9003\Documents\reports\done\{}'.format(entry.name))
# issues_Jql = jira_server.search_issues('cf[10022] is not EMPTY AND labels not in (Refinement23092021, hotfix0921) AND status not in (Done) and key not in (wrgwr-929)', expand='changelog')
# issues_Jql = jira_server.search_issues('status not in (Done)', expand='changelog')
""" issues_Jql = jira_server.search_issues('key in (wrgwr-773)', expand='changelog')
xsp = lambda s: s or 0
sp_sum = 0
issue: Issue
for issue in issues_Jql:
logging.info("Working on {}".format(issue.key))
sp = 0
if hasattr(issue.fields, 'customfield_10022'):
sp = xsp(issue.fields.customfield_10022)
sp_sum += sp
# log old values
print(sp, sp/8)
originalEstimate = xsp(issue.fields.timeoriginalestimate)
logging.info("Estimation-system change: Old Story Points {} -> new Story Points {}".format(sp, sp/8))
if (originalEstimate != 0) and (originalEstimate / 14400) != sp:
# probably already adapted? Search for activity 'updated the Story Points'
doChange = True
for history in issue.changelog.histories:
if doChange==False:
break
if (history.author.key=='JIRAUSER17211'):
for item in history.items:
if (item.field=='Story Points'):
doChange = False
break
if doChange:
# update story-points
try:
issue.update(fields={'customfield_10022': originalEstimate / 14400})
comment = jira_server.add_comment(issue, "Estimation-system change: Old Story Points {} -> new Story Points {}".format(sp, sp/8))
except exceptions.JIRAError:
logging.error("Issue {} has no (visible) Story Points-attribute".format(issue.key))
finally:
print('Done {}'.format(issue.key)) """
+25
View File
@@ -0,0 +1,25 @@
[{
"Kratochvil Jakub": "JIRAUSER16603", "games": ["Spiderman","God of War"]
},
{
"JIRAUSER17211": "Zimmerberger Markus"
},
{
"Cervenka Raimund": "JIRAUSER14400"
},
{
"Reischitz Ulf": "reu9001"
},
{
"Kremser Peter": "krp9002"
},
{
"Thüringer Helfried": "JIRAUSER15724"
},
{
"Blagojevic Nikolina": "JIRAUSER17212"
},
{
"Unfried Daniel": "und9001"
}
]
+41
View File
@@ -0,0 +1,41 @@
[{
"elsap": "Kratochvil Jakub",
"name": "krj0003",
"key": "JIRAUSER16603"
},
{
"elsap": "Zimmerberger Markus",
"name": "zim9003",
"key": "JIRAUSER17211"
},
{
"elsap": "Cervenka Raimund",
"name": "ce39001",
"key": "JIRAUSER14400"
},
{
"elsap": "Reischitz Ulf",
"name": "reu9001",
"key": "reu9001"
},
{
"elsap": "Kremser Peter",
"name": "krp9002",
"key": "krp9002"
},
{
"elsap": "Thüringer Helfried",
"name": "thh9001",
"key": "JIRAUSER15724"
},
{
"elsap": "Blagojevic Nikolina",
"name": "bln9001",
"key": "JIRAUSER17212"
},
{
"elsap": "Unfried Daniel",
"name": "und9001",
"key": "und9001"
}
]