Skip to content

Commit 266a7e2

Browse files
Merge pull request #31 from anttipalsola/add_update_and_delete_worklogs
Add update and delete worklogs
2 parents e46ac75 + 12c14c3 commit 266a7e2

File tree

4 files changed

+195
-1
lines changed

4 files changed

+195
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/tempo_api_python_client.egg-info
22
/dist
33
/build
4+
__pycache__/

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ You need an API token for communicating with tempo REST APIs.
5656
for i in worklogs:
5757
print(i)
5858

59+
There are also functions to retrieve `user` and `team`-specific worklogs.
60+
5961

6062
#### Create Worklog
6163

@@ -68,7 +70,20 @@ You need an API token for communicating with tempo REST APIs.
6870
startTime="17:00:00"
6971
)
7072

71-
There are also functions to retrieve `user` and `team`-specific worklogs.
73+
#### Update Worklog
74+
75+
logged_worklog = tempo.update_worklog(
76+
id="<id_of_the_worklog_to_be_updated>" # required
77+
accountId="<your_jira_account_id>", # required
78+
dateFrom="2019-11-11", # required
79+
timeSpentSeconds=3600, # required
80+
description="Something", # optional
81+
startTime="17:00:00" # optional
82+
)
83+
84+
#### Delete Worklog
85+
86+
delete_response = tempo.delete_worklog(<worklog_id>)
7287

7388

7489
## Code Format

tempoapiclient/client_v4.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,8 +640,50 @@ def create_worklog(self, accountId, issueId, dateFrom, timeSpentSeconds, billabl
640640

641641
return self.post(url, data=data)
642642

643+
def update_worklog(self, id, accountId, dateFrom, timeSpentSeconds, billableSeconds=None, description=None,
644+
remainingEstimateSeconds=None, startTime=None):
645+
"""
646+
Updates an existing Worklog using the provided input and returns the updated Worklog.
647+
:param id: The ID of the Worklog to be updated
648+
:param accountId: The Author account ID of the user author
649+
:param dateFrom: The start date of the Worklog
650+
:param timeSpentSeconds: The total amount of time spent in seconds
651+
:param billableSeconds: The amount of seconds billable
652+
:param description: The description of the Worklog
653+
:param remainingEstimateSeconds: The total amount of estimated remaining seconds
654+
:param startTime: The start time of the Worklog
655+
656+
See https://apidocs.tempo.io/#tag/Worklogs/operation/updateWorklog
657+
"""
658+
659+
url = f"/worklogs/{id}"
660+
661+
data = {
662+
"authorAccountId": str(accountId),
663+
"startDate": self._resolve_date(dateFrom).isoformat(),
664+
"timeSpentSeconds": int(timeSpentSeconds),
665+
}
666+
667+
if billableSeconds:
668+
data["billableSeconds"] = int(billableSeconds)
669+
if description:
670+
data["description"] = str(description)
671+
if remainingEstimateSeconds:
672+
data["remainingEstimateSeconds"] = int(remainingEstimateSeconds)
673+
if startTime:
674+
data["startTime"] = self._resolve_time(startTime).isoformat()
675+
676+
return self.put(url, data=data)
643677

678+
def delete_worklog(self, id):
679+
"""
680+
Deletes a Worklog
681+
:param id: The ID of the Worklog to be deleted
644682
683+
See https://apidocs.tempo.io/#tag/Worklogs/operation/deleteWorklog
684+
"""
685+
url = f"/worklogs/{id}"
686+
return self.delete(url)
645687

646688
# Customer
647689

tests/test_client_v4.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
from unittest import TestCase, main
2+
import logging
23
import os
34
import sys
45

56
from tempoapiclient.client_v4 import Tempo
67

78
# please set TEMPO_AUTH_TOKEN to environment before running this test
89

10+
log = logging.getLogger()
11+
912

1013
class TestClient(TestCase):
1114

1215
def setUp(self):
1316
self.tempo = Tempo(auth_token=os.environ.get('TEMPO_AUTH_TOKEN'))
1417
self.dateFrom = "2020-09-01"
1518
self.dateTo = "2020-10-01"
19+
20+
self.accountId = os.environ.get('TEMPO_ACCOUNT_ID')
21+
self.issueId = os.environ.get('TEMPO_ISSUE_ID')
22+
1623

1724
def test_client_creation(self):
1825
self.assertTrue(isinstance(self.tempo, Tempo))
@@ -59,6 +66,135 @@ def test_get_team_members(self):
5966
self.assertIsInstance(team_members[0], dict)
6067
self.assertIsInstance(team_members[0]['member'], dict)
6168

69+
@staticmethod
70+
def _compare_worklog_to_parameters(worklog, parameters):
71+
"""
72+
Compares worklog values to parameters of create_worklog and update_worklog methods
73+
74+
:param worklog: Worklog returned from Tempo
75+
:param parameters: parameters for create_worklog and update_worklog methods
76+
"""
77+
return (
78+
all((
79+
worklog[keys[0]] == parameters[keys[1]] for keys in (
80+
("startDate", "dateFrom", ),
81+
("timeSpentSeconds", "timeSpentSeconds", ),
82+
("description", "description", ),
83+
)
84+
))
85+
and
86+
worklog["author"]["accountId"] == parameters["accountId"]
87+
)
88+
89+
@staticmethod
90+
def _compare_worklogs(worklog_a, worklog_b):
91+
"""
92+
Compares values of two worklogs together
93+
"""
94+
return all((
95+
worklog_a[key] == worklog_b[key] for key in (
96+
"tempoWorklogId", "author", "issue", "startDate",
97+
"timeSpentSeconds", "description", )
98+
))
99+
100+
def test_worklog_cycle(self):
101+
"""
102+
Tests worklog creation, read, update and deletion
103+
104+
This test creates a new worklog, reads it, updated it and finally deletes it.
105+
Thus, you may not want to run this test in a production environment.
106+
107+
The following environments are required in order to run this test:
108+
* TEMPO_ACCOUNT_ID: the Jira account id to be set as the author of the worklog
109+
* TEMPO_ISSUE_ID: the Jira issue id the Worklog is created
110+
"""
111+
112+
# Test worklog creation (and read)
113+
create_parameters = {
114+
"accountId": self.accountId,
115+
"issueId": self.issueId,
116+
"dateFrom": self.dateFrom,
117+
"timeSpentSeconds": 7200,
118+
"description": "TEST worklog",
119+
}
120+
121+
created_worklog = self.tempo.create_worklog(**create_parameters)
122+
123+
log.debug("created_worklog: %r", created_worklog)
124+
print(f"test_worklog_cycle: created worklog with ID: "
125+
f"{created_worklog.get('tempoWorklogId')}")
126+
127+
self.assertIsInstance(created_worklog, dict)
128+
self.assertEqual(created_worklog["issue"]["id"], int(create_parameters["issueId"]))
129+
self.assertTrue(self._compare_worklog_to_parameters(created_worklog,
130+
create_parameters))
131+
132+
read_created_worklog = self.tempo.get_worklogs(
133+
self.dateFrom, self.dateFrom,
134+
worklogId=created_worklog.get('tempoWorklogId')
135+
)
136+
log.debug("read_created_worklog: %r", read_created_worklog)
137+
138+
self.assertIsInstance(read_created_worklog, dict)
139+
self.assertTrue(self._compare_worklogs(created_worklog, read_created_worklog))
140+
141+
# Test worklog update (and read)
142+
update_parameters = {
143+
"id": created_worklog["tempoWorklogId"],
144+
"accountId": self.accountId,
145+
"dateFrom": self.dateFrom,
146+
"timeSpentSeconds": 10800,
147+
"description": "Updated TEST worklog",
148+
}
149+
150+
updated_worklog = self.tempo.update_worklog(**update_parameters)
151+
152+
log.debug("updated_worklog: %r", updated_worklog)
153+
print(f"test_worklog_cycle: updated worklog with ID: "
154+
f"{updated_worklog.get('tempoWorklogId')}")
155+
156+
self.assertIsInstance(updated_worklog, dict)
157+
self.assertEqual(created_worklog["tempoWorklogId"], updated_worklog["tempoWorklogId"])
158+
self.assertTrue(self._compare_worklog_to_parameters(updated_worklog,
159+
update_parameters))
160+
161+
read_updated_worklog = self.tempo.get_worklogs(
162+
self.dateFrom, self.dateFrom,
163+
worklogId=created_worklog.get('tempoWorklogId')
164+
)
165+
log.debug("read_updated_worklog: %r", read_updated_worklog)
166+
167+
self.assertIsInstance(read_updated_worklog, dict)
168+
self.assertTrue(self._compare_worklogs(updated_worklog, read_updated_worklog))
169+
170+
# Test worklog deletion
171+
deleted_worklog = self.tempo.delete_worklog(created_worklog['tempoWorklogId'])
172+
173+
log.debug("deleted_worklog: %r", deleted_worklog)
174+
175+
self.assertIsInstance(deleted_worklog, dict)
176+
self.assertFalse(deleted_worklog)
177+
178+
# The worklog should not exist anymore
179+
with self.assertRaises(SystemExit) as exc:
180+
read_deleted_worklog = self.tempo.get_worklogs(
181+
self.dateFrom, self.dateFrom,
182+
worklogId=created_worklog.get('tempoWorklogId')
183+
)
184+
185+
print(f"test_worklog_cycle: deleted worklog with ID: {created_worklog.get('tempoWorklogId')}")
186+
187+
def test_get_worklogs(self):
188+
"""
189+
Tests reading worklogs
190+
"""
191+
worklogs = self.tempo.get_worklogs(self.dateFrom, self.dateTo)
192+
193+
log.debug("worklogs: %r", worklogs)
194+
print(f"get_worklogs: {len(worklogs)}")
195+
196+
self.assertIsInstance(worklogs, list)
197+
62198
#def test_get_team_memberships(self):
63199
# l = self.tempo.get_team_memberships(membershipId=)
64200
# display(l)

0 commit comments

Comments
 (0)