Initial Commit
This commit is contained in:
@@ -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)) """
|
||||
Reference in New Issue
Block a user