Skip to content

Commit 1bd99c1

Browse files
committed
Add an extended action that supports syncing assignee and status.
Separates out a couple of key parts of the default action to allow sub-classes to make minor changes before and after Jira is updated. This includes: * Allowing sub-classes to modify the comments generated for existing issues * Allowing sub-classes to make changes to the Jira issue after the default action is done processing. Then defines a new action that extends the default and syncs assignee and status.
1 parent ecd95dc commit 1bd99c1

File tree

4 files changed

+512
-2
lines changed

4 files changed

+512
-2
lines changed

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ testpaths = [
5656
ignore='third_party'
5757
ignore-patterns = "tests/*"
5858
extension-pkg-whitelist = "pydantic"
59+
[tool.pylint.SIMILARITIES]
60+
ignore-signatures = "yes"
5961

6062
[tool.isort]
6163
profile = "black"

src/jbi/whiteboard_actions/default.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"""
88

99
from src.app.environment import get_settings
10-
from src.jbi.bugzilla import BugzillaWebhookRequest
10+
from src.jbi.bugzilla import BugzillaBug, BugzillaWebhookRequest
1111
from src.jbi.errors import ActionError
1212
from src.jbi.services import get_bugzilla, get_jira, getbug_as_bugzilla_object
1313

@@ -56,6 +56,22 @@ def comment_create_or_noop(self, payload: BugzillaWebhookRequest):
5656
)
5757
return {"status": "comment", "jira_response": jira_response}
5858

59+
def jira_comments_for_update( # pylint: disable=no-self-use
60+
self,
61+
payload: BugzillaWebhookRequest,
62+
):
63+
"""Returns the comments to post to Jira for a changed bug"""
64+
return payload.map_as_comments()
65+
66+
def update_issue(
67+
self,
68+
payload: BugzillaWebhookRequest,
69+
bug_obj: BugzillaBug,
70+
linked_issue_key: str,
71+
is_new: bool,
72+
):
73+
"""Allows sub-classes to modify the Jira issue in response to a bug event"""
74+
5975
def bug_create_or_update(
6076
self, payload: BugzillaWebhookRequest
6177
): # pylint: disable=too-many-locals
@@ -64,7 +80,7 @@ def bug_create_or_update(
6480
linked_issue_key = bug_obj.extract_from_see_also() # type: ignore
6581
if linked_issue_key:
6682
# update
67-
comments = payload.map_as_comments()
83+
comments = self.jira_comments_for_update(payload)
6884
jira_response_update = self.jira_client.update_issue_field(
6985
key=linked_issue_key, fields=bug_obj.map_as_jira_issue()
7086
)
@@ -76,6 +92,7 @@ def bug_create_or_update(
7692
issue_key=linked_issue_key, comment=comment
7793
)
7894
)
95+
self.update_issue(payload, bug_obj, linked_issue_key, False)
7996
return {
8097
"status": "update",
8198
"jira_responses": [jira_response_update, jira_response_comments],
@@ -131,6 +148,9 @@ def create_and_link_issue(self, payload, bug_obj):
131148
link_url=bugzilla_url,
132149
title="Bugzilla Ticket",
133150
)
151+
152+
self.update_issue(payload, bug_obj, jira_key_in_response, True)
153+
134154
return {
135155
"status": "create",
136156
"bugzilla_response": bugzilla_response,
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
"""
2+
Extended action that provides some additional features over the default:
3+
* Updates the Jira assignee when the bug's assignee changes.
4+
* Optionally updates the Jira status when the bug's resolution or status changes.
5+
6+
`init` is required; and requires at minimum the
7+
`whiteboard_tag` and `jira_project_key`. `status_map` is optional.
8+
9+
`init` should return a __call__able
10+
"""
11+
12+
from src.jbi.bugzilla import BugzillaBug, BugzillaWebhookRequest
13+
from src.jbi.whiteboard_actions.default import DefaultExecutor
14+
15+
16+
def init(whiteboard_tag, jira_project_key, **kwargs):
17+
"""Function that takes required and optional params and returns a callable object"""
18+
return ExtendedExecutor(
19+
whiteboard_tag=whiteboard_tag, jira_project_key=jira_project_key, **kwargs
20+
)
21+
22+
23+
class ExtendedExecutor(DefaultExecutor):
24+
"""Callable class that encapsulates the extended action."""
25+
26+
def __init__(self, **kwargs):
27+
"""Initialize ExtendedExecutor Object"""
28+
super().__init__(**kwargs)
29+
self.status_map = kwargs.get("status_map", {})
30+
31+
def jira_comments_for_update(
32+
self,
33+
payload: BugzillaWebhookRequest,
34+
):
35+
"""Returns the comments to post to Jira for a changed bug"""
36+
return payload.map_as_comments(False, False)
37+
38+
def update_issue(
39+
self,
40+
payload: BugzillaWebhookRequest,
41+
bug_obj: BugzillaBug,
42+
linked_issue_key: str,
43+
is_new: bool,
44+
):
45+
def clear_assignee():
46+
# New tickets already have no assignee.
47+
if not is_new:
48+
self.jira_client.update_issue_field(
49+
key=linked_issue_key, fields={"assignee": None}
50+
)
51+
52+
changed_fields = payload.event.changed_fields() or []
53+
54+
# If this is a new issue or if the bug's assignee has changed then
55+
# update the assignee.
56+
if is_new or "assigned_to" in changed_fields:
57+
if bug_obj.assigned_to == "[email protected]":
58+
clear_assignee()
59+
else:
60+
# Look up this user in Jira
61+
users = self.jira_client.user_find_by_user_string(
62+
query=bug_obj.assigned_to
63+
)
64+
if len(users) == 1:
65+
try:
66+
# There doesn't appear to be an easy way to verify that
67+
# this user can be assigned to this issue, so just try
68+
# and do it.
69+
self.jira_client.update_issue_field(
70+
key=linked_issue_key,
71+
fields={"assignee": {"accountId": users[0]["accountId"]}},
72+
)
73+
except IOError:
74+
# If that failed then just fall back to clearing the
75+
# assignee.
76+
clear_assignee()
77+
78+
# If this is a new issue or if the bug's status or resolution has
79+
# changed then update the assignee.
80+
if is_new or "status" in changed_fields or "resolution" in changed_fields:
81+
# We use resolution if one exists or status otherwise.
82+
status = bug_obj.resolution
83+
if status == "":
84+
status = bug_obj.status
85+
86+
if status in self.status_map:
87+
self.jira_client.set_issue_status(
88+
linked_issue_key, self.status_map[status]
89+
)

0 commit comments

Comments
 (0)