Skip to content

Commit 14be180

Browse files
committed
Jira issues with worklogs
This finds Jira issues and their worklogs. This adds the `-worklog` option to the stats, next to `-commented`, `-resolved`, etc. Fixes #428
1 parent b35729b commit 14be180

File tree

1 file changed

+63
-9
lines changed

1 file changed

+63
-9
lines changed

did/plugins/jira.py

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Jira stats such as created, updated or resolved issues
2+
Jira stats such as created, updated or resolved issues, and worklogs
33
44
Configuration example (token)::
55
@@ -141,6 +141,9 @@ def __init__(self, issue=None, parent=None):
141141
self.key = issue["key"]
142142
self.summary = issue["fields"]["summary"]
143143
self.comments = issue["fields"]["comment"]["comments"]
144+
self.worklogs = []
145+
if "worklog" in issue["fields"]:
146+
self.worklogs = issue["fields"]["worklog"]["worklogs"]
144147
if "changelog" in issue:
145148
self.histories = issue["changelog"]["histories"]
146149
else:
@@ -154,32 +157,46 @@ def __init__(self, issue=None, parent=None):
154157

155158
def __str__(self):
156159
""" Jira key and summary for displaying """
160+
res = ""
157161
label = f"{self.prefix}-{self.identifier}"
162+
worklogs = ""
163+
for worklog in self.worklogs:
164+
created = dateutil.parser.parse(worklog["created"])
165+
worklogs += "\n\n"
166+
# TODO(kwk) Add time spent? ({worklog["timeSpent"]})
167+
worklogs += f" * Worklog: {created.strftime("%A, %B %d, %Y")}\n\n"
168+
worklogs += "\n".join(
169+
[f" {line}" for line in worklog["comment"].splitlines()])
158170
if self.options.format == "markdown":
159171
href = f"{self.parent.url}/browse/{self.issue['key']}"
160-
return f"[{label}]({href}) - {self.summary}"
161-
return f"{label} - {self.summary}"
172+
res = f"[{label}]({href}) - {self.summary}"
173+
else:
174+
res = f"{label} - {self.summary}"
175+
176+
return res + worklogs
162177

163178
def __eq__(self, other):
164179
""" Compare issues by key """
165180
return self.key == other.key
166181

167182
@staticmethod
168-
def search(query, stats, expand="", timeout=TIMEOUT):
183+
def search(query, stats, expand="", timeout=TIMEOUT, with_worklog=False):
169184
""" Perform issue search for given stats instance """
170185
log.debug("Search query: %s", query)
171186
issues = []
172187
# Fetch data from the server in batches of MAX_RESULTS issues
188+
fields = "summary,comment"
189+
if with_worklog:
190+
fields += ",worklog"
173191
for batch in range(MAX_BATCHES):
174192
encoded_query = urllib.parse.urlencode(
175193
{
176194
"jql": query,
177-
"fields": "summary,comment",
195+
"fields": fields,
178196
"maxResults": MAX_RESULTS,
179-
"startAt": batch * MAX_RESULTS,
180-
"expand": expand
181-
}
182-
)
197+
"startAt": batch *
198+
MAX_RESULTS,
199+
"expand": expand})
183200
current_url = f"{stats.parent.url}/rest/api/latest/search?{encoded_query}"
184201
log.debug("Fetching %s", current_url)
185202
while True:
@@ -425,6 +442,40 @@ def fetch(self):
425442
query = query + f" AND project in ({self.parent.project})"
426443
self.stats = Issue.search(query, stats=self)
427444

445+
446+
class JiraWorklog(Stats):
447+
""" Jira Issues for which a worklog entry was made """
448+
449+
def fetch(self):
450+
log.info(
451+
"[%s] Searching for issues for which work was logged by '%s'",
452+
self.option,
453+
self.user.login or self.user.email)
454+
query = (
455+
f"worklogAuthor = '{self.user.login or self.user.email}' "
456+
f"and worklogDate > {self.options.since} "
457+
f"and workLogDate < {self.options.until} "
458+
)
459+
if self.parent.project:
460+
query = query + f" AND project in ({self.parent.project})"
461+
issues = Issue.search(query, stats=self, with_worklog=True)
462+
# Now we have just the issues which have work logs but we
463+
# want to limit what worklogs we include in the report.
464+
# Filter out worklogs that were not done in the given
465+
# time frame.
466+
log.debug("Found issues: %d", len(issues))
467+
for issue in issues:
468+
log.debug("Found worklogs: %s", len(issue.worklogs))
469+
issue.worklogs = [wl for wl in issue.worklogs if
470+
(wl["author"]["name"] == self.user.login
471+
or wl["author"]["emailAddress"] == self.user.email)
472+
and dateutil.parser.parse(wl["created"]).date()
473+
> self.options.since.date
474+
and dateutil.parser.parse(wl["created"]).date()
475+
< self.options.until.date]
476+
log.debug("Num worklogs after filterting: %d", len(issue.worklogs))
477+
self.stats = issues
478+
428479
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
429480
# Stats Group
430481
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -570,6 +621,9 @@ def __init__(self, option, name=None, parent=None, user=None):
570621
JiraTransition(
571622
option=option + "-transitioned", parent=self,
572623
name=f"Issues transitioned in {option}"),
624+
JiraWorklog(
625+
option=f"{option}-worklog", parent=self,
626+
name=f"Issues with worklogs in {option}")
573627
]
574628

575629
def _basic_auth_session(self):

0 commit comments

Comments
 (0)