Skip to content

Commit d08a509

Browse files
authored
Change Jira resolution field (fixes #200) (#228)
* Change Jira resolution field (fixes #200) * Update secrets baseline
1 parent 0b46eb9 commit d08a509

File tree

5 files changed

+94
-10
lines changed

5 files changed

+94
-10
lines changed

.secrets.baseline

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,9 @@
122122
"filename": "README.md",
123123
"hashed_secret": "04e78d6e804f2b59e6cb282cb9ed2c7bfd8a9737",
124124
"is_verified": false,
125-
"line_number": 211
125+
"line_number": 218
126126
}
127127
]
128128
},
129-
"generated_at": "2022-08-17T08:30:43Z"
129+
"generated_at": "2022-08-30T10:02:55Z"
130130
}

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ If configured, the action supports setting the Jira issues's status when the Bug
121121
- `status_map` (optional)
122122
- mapping [str, str]
123123
- If defined, map the Bugzilla bug status to Jira issue status
124+
- `resolution_map` (optional)
125+
- mapping [str, str]
126+
- If defined, map the Bugzilla bug resolution to Jira issue resolution
124127

125128
Example configuration:
126129
```yaml
@@ -134,6 +137,10 @@ Example configuration:
134137
status_map:
135138
NEW: "In Progress"
136139
FIXED: "Closed"
140+
resolution_map:
141+
FIXED: "Done"
142+
DUPLICATE: "Duplicate"
143+
WONTFIX: "Won't Do"
137144
```
138145

139146
In this case if the bug changes to the NEW status the action will attempt to set the linked Jira

jbi/actions/default_with_assignee_and_status.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,21 @@
2727
JIRA_REQUIRED_PERMISSIONS = DEFAULT_JIRA_REQUIRED_PERMISSIONS
2828

2929

30-
def init(status_map=None, **kwargs):
30+
def init(status_map=None, resolution_map=None, **kwargs):
3131
"""Function that takes required and optional params and returns a callable object"""
32-
return AssigneeAndStatusExecutor(status_map=status_map or {}, **kwargs)
32+
return AssigneeAndStatusExecutor(
33+
status_map=status_map or {}, resolution_map=resolution_map or {}, **kwargs
34+
)
3335

3436

3537
class AssigneeAndStatusExecutor(DefaultExecutor):
3638
"""Callable class that encapsulates the default_with_assignee_and_status action."""
3739

38-
def __init__(self, status_map, **kwargs):
40+
def __init__(self, status_map, resolution_map, **kwargs):
3941
"""Initialize AssigneeAndStatusExecutor Object"""
4042
super().__init__(**kwargs)
4143
self.status_map = status_map
44+
self.resolution_map = resolution_map
4245

4346
def jira_comments_for_update(
4447
self,
@@ -121,17 +124,43 @@ def clear_assignee():
121124
# If this is a new issue or if the bug's status or resolution has
122125
# changed then update the issue status.
123126
if is_new or "status" in changed_fields or "resolution" in changed_fields:
124-
# We use resolution if one exists or status otherwise.
125-
status = bug_obj.resolution or bug_obj.status
127+
# If action has configured mappings for the issue resolution field, update it.
128+
bz_resolution = bug_obj.resolution
129+
jira_resolution = self.resolution_map.get(bz_resolution)
130+
if jira_resolution:
131+
logger.debug(
132+
"Updating Jira resolution to %s",
133+
jira_resolution,
134+
extra=log_context.dict(),
135+
)
136+
self.jira_client.update_issue_field(
137+
key=linked_issue_key,
138+
fields={"resolution": jira_resolution},
139+
)
140+
else:
141+
logger.debug(
142+
"Bug resolution was not in the resolution map.",
143+
extra=log_context.update(
144+
operation=Operation.IGNORE,
145+
extra={
146+
**log_context.extra,
147+
"resolution_map": self.resolution_map,
148+
},
149+
).dict(),
150+
)
126151

127-
if status in self.status_map:
152+
# We use resolution if one exists or status otherwise.
153+
bz_status = bz_resolution or bug_obj.status
154+
jira_status = self.status_map.get(bz_status)
155+
if jira_status:
128156
logger.debug(
129157
"Updating Jira status to %s",
130-
self.status_map[status],
158+
jira_status,
131159
extra=log_context.dict(),
132160
)
133161
self.jira_client.set_issue_status(
134-
linked_issue_key, self.status_map[status]
162+
linked_issue_key,
163+
jira_status,
135164
)
136165
else:
137166
logger.debug(

tests/conftest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ def webhook_modify_example() -> BugzillaWebhookRequest:
105105
return webhook_payload
106106

107107

108+
@pytest.fixture
109+
def webhook_modify_resolution_example() -> BugzillaWebhookRequest:
110+
bug = bug_factory(see_also=["https://mozilla.atlassian.net/browse/JBI-234"])
111+
event = webhook_event_factory(action="modify", routing_key="bug.modify:resolution")
112+
webhook_payload = webhook_factory(bug=bug, event=event)
113+
return webhook_payload
114+
115+
108116
@pytest.fixture
109117
def webhook_change_status_assignee():
110118
changes = [

tests/unit/actions/test_default_with_assignee_and_status.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,3 +270,43 @@ def test_change_to_known_resolution(webhook_create_example, mocked_jira):
270270
},
271271
)
272272
mocked_jira.set_issue_status.assert_called_once_with("JBI-234", "Closed")
273+
274+
275+
def test_change_to_known_resolution_with_resolution_map(
276+
webhook_modify_resolution_example, mocked_jira
277+
):
278+
webhook_modify_resolution_example.bug.resolution = "DUPLICATE"
279+
280+
callable_object = action.init(
281+
jira_project_key="JBI",
282+
resolution_map={
283+
"DUPLICATE": "Duplicate",
284+
},
285+
)
286+
callable_object(payload=webhook_modify_resolution_example)
287+
288+
mocked_jira.update_issue_field.assert_called_with( # not once
289+
key="JBI-234",
290+
fields={
291+
"resolution": "Duplicate",
292+
},
293+
)
294+
295+
296+
def test_change_to_unknown_resolution_with_resolution_map(
297+
webhook_modify_resolution_example, mocked_jira
298+
):
299+
webhook_modify_resolution_example.bug.resolution = "WONTFIX"
300+
301+
callable_object = action.init(
302+
jira_project_key="JBI",
303+
resolution_map={
304+
"DUPLICATE": "Duplicate",
305+
},
306+
)
307+
callable_object(payload=webhook_modify_resolution_example)
308+
309+
mocked_jira.update_issue_field.assert_called_once_with(
310+
key="JBI-234",
311+
fields={"summary": "JBI Test", "labels": ["bugzilla", "devtest", "[devtest]"]},
312+
)

0 commit comments

Comments
 (0)