Skip to content

Commit 4595e60

Browse files
authored
Ref #984: Simple comment when attachment is added to bug (#1018)
* Add attachment operation * Call 'create_comment' by default on attachment events * Add comment by default when an attachment is created * Improve past verb in comment
1 parent 84b7c23 commit 4595e60

File tree

8 files changed

+78
-20
lines changed

8 files changed

+78
-20
lines changed

jbi/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class Operation(str, Enum):
1919
UPDATE = "update"
2020
DELETE = "delete"
2121
COMMENT = "comment"
22+
ATTACHMENT = "attachment"
2223
LINK = "link"
2324

2425

jbi/jira/service.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,23 @@ def add_jira_comment(self, context: ActionContext):
118118
"""Publish a comment on the specified Jira issue"""
119119
context = context.update(operation=Operation.COMMENT)
120120
commenter = context.event.user.login if context.event.user else "unknown"
121-
comment = context.bug.comment
122-
assert comment # See jbi.steps.create_comment()
123-
assert comment.body # Also see jbi.steps.create_comment()
121+
122+
if context.event.target == "attachment":
123+
routing_key = (
124+
context.event.routing_key or ".modify" # only to please type checking.
125+
)
126+
_, verb = routing_key.rsplit(".", 1)
127+
past_verb = {"modify": "modified"}.get(verb, f"{verb}d")
128+
formatted_comment = f"*{commenter}* {past_verb} an attachment"
129+
else:
130+
comment = context.bug.comment
131+
assert comment # See jbi.steps.create_comment()
132+
assert comment.body # Also see jbi.steps.create_comment()
133+
formatted_comment = (
134+
f"*{commenter}* commented: \n{markdown_to_jira(comment.body)}"
135+
)
124136

125137
issue_key = context.jira.issue
126-
formatted_comment = (
127-
f"*{commenter}* commented: \n{markdown_to_jira(comment.body)}"
128-
)
129138
jira_response = self.client.issue_add_comment(
130139
issue_key=issue_key,
131140
comment=formatted_comment,

jbi/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ class ActionSteps(BaseModel, frozen=True):
4343
comment: list[str] = [
4444
"create_comment",
4545
]
46+
attachment: list[str] = [
47+
"create_comment",
48+
]
4649

4750
@field_validator("*")
4851
@classmethod

jbi/runner.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"new": Operation.CREATE,
3838
"existing": Operation.UPDATE,
3939
"comment": Operation.COMMENT,
40+
"attachment": Operation.ATTACHMENT,
4041
}
4142

4243

@@ -288,6 +289,9 @@ def execute_action(
288289
elif event.target == "comment":
289290
action_context = action_context.update(operation=Operation.COMMENT)
290291

292+
elif event.target == "attachment":
293+
action_context = action_context.update(operation=Operation.ATTACHMENT)
294+
291295
if action_context.operation == Operation.IGNORE:
292296
raise IgnoreInvalidRequestError(
293297
f"ignore event target {action_context.event.target!r}"

jbi/steps.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,20 @@ def create_comment(context: ActionContext, *, jira_service: JiraService) -> Step
5050
"""Create a Jira comment using `context.bug.comment`"""
5151
bug = context.bug
5252

53-
if bug.comment is None:
54-
logger.info(
55-
"No matching comment found in payload",
56-
extra=context.model_dump(),
57-
)
58-
return (StepStatus.NOOP, context)
53+
if context.event.target == "comment":
54+
if bug.comment is None:
55+
logger.info(
56+
"No matching comment found in payload",
57+
extra=context.model_dump(),
58+
)
59+
return (StepStatus.NOOP, context)
5960

60-
if not bug.comment.body:
61-
logger.info(
62-
"Comment message is empty",
63-
extra=context.model_dump(),
64-
)
65-
return (StepStatus.NOOP, context)
61+
if not bug.comment.body:
62+
logger.info(
63+
"Comment message is empty",
64+
extra=context.model_dump(),
65+
)
66+
return (StepStatus.NOOP, context)
6667

6768
jira_response = jira_service.add_jira_comment(context)
6869
context = context.append_responses(jira_response)

tests/conftest.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,18 @@ def context_comment_example(action_context_factory) -> ActionContext:
165165
)
166166

167167

168+
@pytest.fixture
169+
def context_attachment_example(action_context_factory) -> ActionContext:
170+
return action_context_factory(
171+
operation=Operation.ATTACHMENT,
172+
bug__see_also=["https://mozilla.atlassian.net/browse/JBI-234"],
173+
event__target="attachment",
174+
event__routed_key="attachment.create",
175+
event__user__login="[email protected]",
176+
jira__issue="JBI-234",
177+
)
178+
179+
168180
@pytest.fixture(autouse=True)
169181
def sleepless(monkeypatch):
170182
# https://stackoverflow.com/a/54829577

tests/unit/test_runner.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,7 @@ def test_default_invalid_init():
386386
def test_unspecified_groups_come_from_default_steps(action_params_factory):
387387
action = Executor(action_params_factory(steps={"comment": ["create_comment"]}))
388388

389-
assert len(action.steps) == 3
390-
assert action.steps
389+
assert len(action.steps) == 4
391390

392391

393392
def test_default_returns_callable_without_data(action_params):
@@ -589,6 +588,20 @@ def test_counter_is_incremented_for_comment(
589588
mocked.incr.assert_any_call("jbi.operation.comment.count")
590589

591590

591+
def test_counter_is_incremented_for_attachment(
592+
actions, webhook_request_factory, mocked_bugzilla, mocked_jira
593+
):
594+
webhook_payload = webhook_request_factory(
595+
event__target="attachment",
596+
bug__see_also=["https://mozilla.atlassian.net/browse/JBI-234"],
597+
)
598+
mocked_bugzilla.get_bug.return_value = webhook_payload.bug
599+
mocked_jira.get_issue.return_value = {"fields": {"project": {"key": "JBI"}}}
600+
with mock.patch("jbi.runner.statsd") as mocked:
601+
execute_action(request=webhook_payload, actions=actions)
602+
mocked.incr.assert_any_call("jbi.operation.attachment.count")
603+
604+
592605
@pytest.mark.parametrize(
593606
"whiteboard",
594607
[

tests/unit/test_steps.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,21 @@ def test_added_comment(
234234
)
235235

236236

237+
def test_added_attachment(
238+
context_attachment_example: ActionContext, mocked_jira, action_params_factory
239+
):
240+
callable_object = Executor(
241+
action_params_factory(jira_project_key=context_attachment_example.jira.project)
242+
)
243+
244+
callable_object(context=context_attachment_example)
245+
246+
mocked_jira.issue_add_comment.assert_called_once_with(
247+
issue_key="JBI-234",
248+
comment="*[email protected]* created an attachment",
249+
)
250+
251+
237252
def test_empty_comment_not_added(
238253
action_context_factory, mocked_jira, action_params_factory
239254
):

0 commit comments

Comments
 (0)