Fixed bugs and added last comment auto completion

This commit is contained in:
Fabian 2021-11-30 23:06:05 +01:00
parent 0a01146227
commit 3189d9a7a5
2 changed files with 79 additions and 49 deletions

View File

@ -96,7 +96,8 @@ class WorklogDialog(QtWidgets.QDialog):
def __init__(self, config: Config, worklog: Worklog, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.rest = WorklogRest(config)
self.config = config
self.rest = WorklogRest(self.config)
self._changing_items = False
self._worklog = worklog
@ -172,8 +173,10 @@ class WorklogDialog(QtWidgets.QDialog):
self.update_timer.timeout.connect(self.update_statuses)
def showEvent(self, _):
self.rest.purge_cache()
# reinitialize to purge caches
self.rest = WorklogRest(self.config)
self.update_all()
self.upload_button.setEnabled(False)
def update_all(self):
self.refresh_table()
@ -187,10 +190,13 @@ class WorklogDialog(QtWidgets.QDialog):
for row in self._worklog_data[:-1]:
issue_keys.append(row[0].split()[0])
old_statuses = self._statuses
self._statuses = self.rest.get_issues_state(issue_keys)
self._statuses = self.rest.get_issues_state(issue_keys, self._worklog.date)
for row, status in enumerate(self._statuses):
if len(old_statuses) != len(self._statuses) or old_statuses[row][0] != status[0]:
self.update_status_view(row)
if not self._worklog_data[row][1] and status[2]:
self._worklog_data[row][1] = status[2]
self.tableWidget.cellWidget(row, 1).setPlainText(status[2])
all_ok = reduce(lambda acc, it: acc and it[0] is Status.OK, self._statuses, True)
if all_ok:
self.upload_button.setEnabled(True)

View File

@ -6,7 +6,7 @@ from datetime import date, datetime, timedelta, time
from functools import partial
from textwrap import dedent
from threading import Lock
from typing import List, Dict, Tuple
from typing import List, Dict, Tuple, Optional
import requests
from requests_futures.sessions import FuturesSession
@ -25,9 +25,11 @@ class WorklogRest:
self.worklog_update_url = os.path.join(config.jira_url, "rest/api/2/issue/{issue_key}/worklog/{worklog_id}")
self.session = FuturesSession()
self._user = None
self._user_future = self._req_user()
self._issue_state: Dict[str, Tuple[Status, str]] = dict()
self._issue_state_lock = Lock()
self._req_user()
self._issue_previous_comments: Dict[str, str] = dict()
self._issue_worklog_id: Dict[str, str] = dict()
self._issues_lock = Lock()
def _req_user(self):
future = self.session.get(
@ -38,6 +40,7 @@ class WorklogRest:
},
)
future.add_done_callback(self._resp_user)
return future
def _resp_user(self, future):
try:
@ -46,20 +49,21 @@ class WorklogRest:
print("Could not get user key:\n", file=sys.stderr)
print(traceback.format_exc(), file=sys.stderr)
def get_issues_state(self, issue_keys: List[str]):
def get_issues_state(self, issue_keys: List[str], pdate: date) -> List[Tuple[Status, str, Optional[str]]]:
ret = []
with self._issue_state_lock:
with self._issues_lock:
for issue_key in issue_keys:
if issue_key not in self._issue_state:
self._issue_state[issue_key] = (Status.PROGRESS, "Working")
self._req_issue(issue_key)
ret.append(self._issue_state[issue_key])
self._req_issue(issue_key, pdate)
if issue_key in self._issue_previous_comments:
prev_comment = self._issue_previous_comments[issue_key]
else:
prev_comment = None
ret.append((*self._issue_state[issue_key], prev_comment))
return ret
def purge_cache(self):
self._issue_state = dict()
def _req_issue(self, issue_key: str):
def _req_issue(self, issue_key: str, pdate :date):
future = self.session.get(
self.issue_url.format(issue_key),
headers={
@ -67,22 +71,60 @@ class WorklogRest:
"Accept": "application/json",
},
)
future.add_done_callback(partial(self._resp_issue, issue_key))
future.add_done_callback(partial(self._resp_issue, issue_key, pdate))
def _resp_issue(self, issue_key: str, future: Future):
def _resp_issue(self, issue_key: str, pdate: date, future: Future):
resp: requests.Response = future.result()
with self._issue_state_lock:
with self._issues_lock:
if resp.status_code == 200:
hint = f'{issue_key} {resp.json()["fields"]["summary"]}'
self._issue_state[issue_key] = (Status.OK, hint)
issue_title = f'{issue_key} {resp.json()["fields"]["summary"]}'
self._req_worklog_check(issue_key, issue_title, pdate)
else:
self._issue_state[issue_key] = (Status.ERROR, "Could not find specified issue")
def _req_worklog_check(self, issue_key: str, issue_title: str, pdate: date):
future = self.session.get(
self.worklog_url.format(issue_key),
headers={
"Authorization": f"Bearer {self.config.jira_token}",
"Accept": "application/json",
},
)
future.add_done_callback(partial(self._resp_worklog_check, issue_key, issue_title, pdate))
def _resp_worklog_check(self, issue_key: str, issue_title: str, pdate: date, future: Future):
resp = future.result()
worklogs = resp.json()["worklogs"]
worklogs = sorted(
worklogs, key=lambda x: datetime.strptime(x["started"], "%Y-%m-%dT%H:%M:%S.%f%z"), reverse=True)
self._user_future.result()
if not self._user:
with self._issues_lock:
self._issue_state[issue_key] = (Status.OK, issue_title)
return
worklog_found = False
with self._issues_lock:
for log in worklogs:
if log["author"]["key"] == self._user:
if datetime.strptime(log["started"], "%Y-%m-%dT%H:%M:%S.%f%z").date() == pdate:
self._issue_worklog_id[issue_key] = log["id"]
worklog_found = True
else:
self._issue_previous_comments[issue_key] = log["comment"].strip()
worklog_found = True
break
if worklog_found:
print(f"Found existing worklog for issue {issue_key}")
else:
print(f"Did not find existing worklog for issue {issue_key}")
self._issue_state[issue_key] = (Status.OK, issue_title)
def _upload_sanity_check(self, issue_keys: List[str]):
if not self._user:
raise FimeException("Could not get user key")
# lock is held by caller
for issue_key in issue_keys:
if issue_key not in self._issue_state or self._issue_state[issue_key] is not Status.OK:
if issue_key not in self._issue_state or self._issue_state[issue_key][0] is not Status.OK:
raise FimeException(f"Issue with key {issue_key} in unexpected state")
def upload(self, issues: List[Tuple[str, str, timedelta]], pdate: date):
@ -92,33 +134,15 @@ class WorklogRest:
timedelta(seconds=300),
), ... ]
"""
self._upload_sanity_check(list(map(lambda x: x[0], issues)))
for issue in issues:
future = self.session.get(
self.worklog_url.format(issue[0]),
headers={
"Authorization": f"Bearer {self.config.jira_token}",
"Accept": "application/json",
}
)
future.add_done_callback(partial(self._worklog_check_resp, issue[0], issue[1], issue[2], pdate))
self._issue_state[issue[0]] = (Status.PROGRESS, "Working")
def _worklog_check_resp(self, issue_key: str, comment: str, time_spent: timedelta, pdate: date, future: Future):
resp = future.result()
worklogs = resp.json()["worklogs"]
worklog_id = None
for log in worklogs:
if log["author"]["key"] == self._user \
and datetime.strptime(log["started"], "%Y-%m-%dT%H:%M:%S.%f%z").date() == pdate:
worklog_id = log["id"]
break
if worklog_id:
print(f"Found existing worklog for issue {issue_key} with id {worklog_id}")
self._worklog_update(issue_key, worklog_id, comment, time_spent, pdate)
else:
print(f"Did not find existing worklog for issue {issue_key}")
self._worklog_create(issue_key, comment, time_spent, pdate)
with self._issues_lock:
self._upload_sanity_check(list(map(lambda x: x[0], issues)))
for issue in issues:
issue_key, comment, time_spent = issue
if issue_key in self._issue_worklog_id:
self._worklog_update(issue_key, self._issue_worklog_id[issue_key], comment, time_spent, pdate)
else:
self._worklog_create(issue_key, comment, time_spent, pdate)
self._issue_state[issue[0]] = (Status.PROGRESS, "Working")
def _worklog_create(self, issue_key: str, comment: str, time_spent: timedelta, pdate: date):
future = self.session.post(
@ -156,8 +180,8 @@ class WorklogRest:
def _worklog_resp(self, issue_key: str, future: Future):
resp: requests.Response = future.result()
with self._issue_state_lock:
if resp.status_code == 200:
with self._issues_lock:
if resp.status_code in (200, 201):
self._issue_state[issue_key] = (Status.OK, "Successfully uploaded")
print(f"Successfully uploaded issue {issue_key}")
else: