Fixed bugs and added last comment auto completion
This commit is contained in:
parent
0a01146227
commit
3189d9a7a5
@ -96,7 +96,8 @@ class WorklogDialog(QtWidgets.QDialog):
|
|||||||
def __init__(self, config: Config, worklog: Worklog, parent, *args, **kwargs):
|
def __init__(self, config: Config, worklog: Worklog, parent, *args, **kwargs):
|
||||||
super().__init__(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._changing_items = False
|
||||||
self._worklog = worklog
|
self._worklog = worklog
|
||||||
@ -172,8 +173,10 @@ class WorklogDialog(QtWidgets.QDialog):
|
|||||||
self.update_timer.timeout.connect(self.update_statuses)
|
self.update_timer.timeout.connect(self.update_statuses)
|
||||||
|
|
||||||
def showEvent(self, _):
|
def showEvent(self, _):
|
||||||
self.rest.purge_cache()
|
# reinitialize to purge caches
|
||||||
|
self.rest = WorklogRest(self.config)
|
||||||
self.update_all()
|
self.update_all()
|
||||||
|
self.upload_button.setEnabled(False)
|
||||||
|
|
||||||
def update_all(self):
|
def update_all(self):
|
||||||
self.refresh_table()
|
self.refresh_table()
|
||||||
@ -187,10 +190,13 @@ class WorklogDialog(QtWidgets.QDialog):
|
|||||||
for row in self._worklog_data[:-1]:
|
for row in self._worklog_data[:-1]:
|
||||||
issue_keys.append(row[0].split()[0])
|
issue_keys.append(row[0].split()[0])
|
||||||
old_statuses = self._statuses
|
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):
|
for row, status in enumerate(self._statuses):
|
||||||
if len(old_statuses) != len(self._statuses) or old_statuses[row][0] != status[0]:
|
if len(old_statuses) != len(self._statuses) or old_statuses[row][0] != status[0]:
|
||||||
self.update_status_view(row)
|
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)
|
all_ok = reduce(lambda acc, it: acc and it[0] is Status.OK, self._statuses, True)
|
||||||
if all_ok:
|
if all_ok:
|
||||||
self.upload_button.setEnabled(True)
|
self.upload_button.setEnabled(True)
|
||||||
|
@ -6,7 +6,7 @@ from datetime import date, datetime, timedelta, time
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from typing import List, Dict, Tuple
|
from typing import List, Dict, Tuple, Optional
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from requests_futures.sessions import FuturesSession
|
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.worklog_update_url = os.path.join(config.jira_url, "rest/api/2/issue/{issue_key}/worklog/{worklog_id}")
|
||||||
self.session = FuturesSession()
|
self.session = FuturesSession()
|
||||||
self._user = None
|
self._user = None
|
||||||
|
self._user_future = self._req_user()
|
||||||
self._issue_state: Dict[str, Tuple[Status, str]] = dict()
|
self._issue_state: Dict[str, Tuple[Status, str]] = dict()
|
||||||
self._issue_state_lock = Lock()
|
self._issue_previous_comments: Dict[str, str] = dict()
|
||||||
self._req_user()
|
self._issue_worklog_id: Dict[str, str] = dict()
|
||||||
|
self._issues_lock = Lock()
|
||||||
|
|
||||||
def _req_user(self):
|
def _req_user(self):
|
||||||
future = self.session.get(
|
future = self.session.get(
|
||||||
@ -38,6 +40,7 @@ class WorklogRest:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
future.add_done_callback(self._resp_user)
|
future.add_done_callback(self._resp_user)
|
||||||
|
return future
|
||||||
|
|
||||||
def _resp_user(self, future):
|
def _resp_user(self, future):
|
||||||
try:
|
try:
|
||||||
@ -46,20 +49,21 @@ class WorklogRest:
|
|||||||
print("Could not get user key:\n", file=sys.stderr)
|
print("Could not get user key:\n", file=sys.stderr)
|
||||||
print(traceback.format_exc(), 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 = []
|
ret = []
|
||||||
with self._issue_state_lock:
|
with self._issues_lock:
|
||||||
for issue_key in issue_keys:
|
for issue_key in issue_keys:
|
||||||
if issue_key not in self._issue_state:
|
if issue_key not in self._issue_state:
|
||||||
self._issue_state[issue_key] = (Status.PROGRESS, "Working")
|
self._issue_state[issue_key] = (Status.PROGRESS, "Working")
|
||||||
self._req_issue(issue_key)
|
self._req_issue(issue_key, pdate)
|
||||||
ret.append(self._issue_state[issue_key])
|
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
|
return ret
|
||||||
|
|
||||||
def purge_cache(self):
|
def _req_issue(self, issue_key: str, pdate :date):
|
||||||
self._issue_state = dict()
|
|
||||||
|
|
||||||
def _req_issue(self, issue_key: str):
|
|
||||||
future = self.session.get(
|
future = self.session.get(
|
||||||
self.issue_url.format(issue_key),
|
self.issue_url.format(issue_key),
|
||||||
headers={
|
headers={
|
||||||
@ -67,22 +71,60 @@ class WorklogRest:
|
|||||||
"Accept": "application/json",
|
"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()
|
resp: requests.Response = future.result()
|
||||||
with self._issue_state_lock:
|
with self._issues_lock:
|
||||||
if resp.status_code == 200:
|
if resp.status_code == 200:
|
||||||
hint = f'{issue_key} {resp.json()["fields"]["summary"]}'
|
issue_title = f'{issue_key} {resp.json()["fields"]["summary"]}'
|
||||||
self._issue_state[issue_key] = (Status.OK, hint)
|
self._req_worklog_check(issue_key, issue_title, pdate)
|
||||||
else:
|
else:
|
||||||
self._issue_state[issue_key] = (Status.ERROR, "Could not find specified issue")
|
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]):
|
def _upload_sanity_check(self, issue_keys: List[str]):
|
||||||
if not self._user:
|
if not self._user:
|
||||||
raise FimeException("Could not get user key")
|
raise FimeException("Could not get user key")
|
||||||
|
# lock is held by caller
|
||||||
for issue_key in issue_keys:
|
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")
|
raise FimeException(f"Issue with key {issue_key} in unexpected state")
|
||||||
|
|
||||||
def upload(self, issues: List[Tuple[str, str, timedelta]], pdate: date):
|
def upload(self, issues: List[Tuple[str, str, timedelta]], pdate: date):
|
||||||
@ -92,33 +134,15 @@ class WorklogRest:
|
|||||||
timedelta(seconds=300),
|
timedelta(seconds=300),
|
||||||
), ... ]
|
), ... ]
|
||||||
"""
|
"""
|
||||||
self._upload_sanity_check(list(map(lambda x: x[0], issues)))
|
with self._issues_lock:
|
||||||
for issue in issues:
|
self._upload_sanity_check(list(map(lambda x: x[0], issues)))
|
||||||
future = self.session.get(
|
for issue in issues:
|
||||||
self.worklog_url.format(issue[0]),
|
issue_key, comment, time_spent = issue
|
||||||
headers={
|
if issue_key in self._issue_worklog_id:
|
||||||
"Authorization": f"Bearer {self.config.jira_token}",
|
self._worklog_update(issue_key, self._issue_worklog_id[issue_key], comment, time_spent, pdate)
|
||||||
"Accept": "application/json",
|
else:
|
||||||
}
|
self._worklog_create(issue_key, comment, time_spent, pdate)
|
||||||
)
|
self._issue_state[issue[0]] = (Status.PROGRESS, "Working")
|
||||||
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)
|
|
||||||
|
|
||||||
def _worklog_create(self, issue_key: str, comment: str, time_spent: timedelta, pdate: date):
|
def _worklog_create(self, issue_key: str, comment: str, time_spent: timedelta, pdate: date):
|
||||||
future = self.session.post(
|
future = self.session.post(
|
||||||
@ -156,8 +180,8 @@ class WorklogRest:
|
|||||||
|
|
||||||
def _worklog_resp(self, issue_key: str, future: Future):
|
def _worklog_resp(self, issue_key: str, future: Future):
|
||||||
resp: requests.Response = future.result()
|
resp: requests.Response = future.result()
|
||||||
with self._issue_state_lock:
|
with self._issues_lock:
|
||||||
if resp.status_code == 200:
|
if resp.status_code in (200, 201):
|
||||||
self._issue_state[issue_key] = (Status.OK, "Successfully uploaded")
|
self._issue_state[issue_key] = (Status.OK, "Successfully uploaded")
|
||||||
print(f"Successfully uploaded issue {issue_key}")
|
print(f"Successfully uploaded issue {issue_key}")
|
||||||
else:
|
else:
|
||||||
|
Loading…
Reference in New Issue
Block a user