Skip to content

Commit 352a3cd

Browse files
committed
Merge branch 'pull_request_conversation_1' into pull_request_conversation_2
2 parents e906af8 + 0842516 commit 352a3cd

File tree

6 files changed

+69
-2
lines changed

6 files changed

+69
-2
lines changed

packages/slackBotFunction/app/handler.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ def handler(event: dict, context: LambdaContext) -> dict:
2727
3. Lazy Async invocation processes Bedrock query and responds to Slack
2828
2929
If message starts with pr: then pull request id is extracted from message and it invokes lambda in pull request
30-
This message has a pull_request_processing property so when it is received by the lambda in the pull request
30+
This message has a pull_request_event property so when it is received by the lambda in the pull request
3131
It triggers function process_pull_request_slack_event
32+
When a session is started with a pr: prefix, the pull request is stored in dynamo
33+
When subsequent actions or events are processed, this is looked up, and if it exists, then the pull request lambda
34+
is triggered with either pull_request_event or pull_request_action
3235
"""
3336
app = get_app(logger=logger)
3437
# handle pull request processing requests

packages/slackBotFunction/app/services/app.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
@lru_cache
1111
def get_app(logger: Logger) -> App:
1212
bot_token, signing_secret = get_ssm_params()
13+
# pass the correct logger to slack bolt so it can be pickled correctly
1314
powertools_logger = logging.getLogger(name=logger.name)
1415

1516
# initialise the Slack app

packages/slackBotFunction/app/slack/slack_events.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ def process_async_slack_action(body: Dict[str, Any], client: WebClient) -> None:
262262

263263

264264
def process_async_slack_event(event: Dict[str, Any], event_id: str, client: WebClient) -> None:
265+
logger.debug("Processing async Slack event", extra={"event_id": event_id, "event": event})
265266
original_message_text = (event.get("text") or "").strip()
266267
message_text = strip_mentions(message_text=original_message_text)
267268
conversation_key, thread_ts = conversation_key_and_root(event)

packages/slackBotFunction/app/slack/slack_handlers.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
forward_event_to_pull_request_lambda,
2424
gate_common,
2525
respond_with_eyes,
26+
should_reply_to_message,
2627
)
2728
from app.slack.slack_events import process_async_slack_action, process_async_slack_event
2829

@@ -49,7 +50,8 @@ def setup_handlers(app: App) -> None:
4950

5051
# ack function for events where we respond with eyes
5152
def respond_to_events(event: Dict[str, Any], ack: Ack, client: WebClient):
52-
respond_with_eyes(event=event, client=client)
53+
if should_reply_to_message(event):
54+
respond_with_eyes(event=event, client=client)
5355
logger.debug("Sending ack response")
5456
ack()
5557

@@ -94,8 +96,17 @@ def unified_message_handler(client: WebClient, event: Dict[str, Any], body: Dict
9496
9597
"""
9698
event_id = gate_common(event=event, body=body)
99+
logger.debug("logging result of gate_common", extra={"event_id": event_id, "body": body})
97100
if not event_id:
98101
return
102+
# if its in a group chat
103+
# and its a message
104+
# and its not in a thread
105+
# then ignore it as it will be handled as an app_mention event
106+
if not should_reply_to_message(event):
107+
logger.debug("Ignoring message in group chat not in a thread", extra={"event": event})
108+
# ignore messages in group chats
109+
return
99110
user_id = event.get("user", "unknown")
100111
conversation_key, _ = conversation_key_and_root(event=event)
101112
session_pull_request_id = extract_session_pull_request_id(conversation_key)

packages/slackBotFunction/app/utils/handler_utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def is_duplicate_event(event_id: str) -> bool:
3838
return False # Not a duplicate
3939
except ClientError as e:
4040
if e.response["Error"]["Code"] == "ConditionalCheckFailedException":
41+
logger.info(f"Duplicate event detected: {event_id}")
4142
return True # Duplicate
4243
logger.error("Error checking event duplication", extra={"error": traceback.format_exc()})
4344
return False
@@ -203,3 +204,17 @@ def extract_session_pull_request_id(conversation_key: str) -> str | None:
203204
except Exception as e:
204205
logger.error(f"Error checking pull request session: {e}", extra={"error": traceback.format_exc()})
205206
return None
207+
208+
209+
def should_reply_to_message(event: Dict[str, Any]) -> bool:
210+
"""
211+
Determine if the bot should reply to the message.
212+
213+
Conditions:
214+
should not reply if:
215+
- Message is in a group chat (channel_type == 'group') but not in a thread
216+
"""
217+
218+
if event.get("channel_type") == "group" and event.get("type") == "message" and event.get("thread_ts") is None:
219+
return False
220+
return True

packages/slackBotFunction/tests/test_slack_handlers.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,42 @@ def test_unified_message_handler_successful_call(
3939
mock_forward_event_to_pull_request_lambda.assert_not_called()
4040

4141

42+
@patch("app.slack.slack_events.process_async_slack_event")
43+
@patch("app.utils.handler_utils.extract_session_pull_request_id")
44+
@patch("app.utils.handler_utils.forward_event_to_pull_request_lambda")
45+
def test_unified_message_handler_messages_with_no_thread_are_dropped(
46+
mock_forward_event_to_pull_request_lambda: Mock,
47+
mock_extract_session_pull_request_id: Mock,
48+
mock_process_async_slack_event: Mock,
49+
mock_get_parameter: Mock,
50+
mock_env: Mock,
51+
):
52+
"""Test app mention handler execution"""
53+
# set up mocks
54+
mock_event = {
55+
"user": "U123",
56+
"text": "<@U456> test",
57+
"channel": "C123",
58+
"channel_type": "group",
59+
"type": "message",
60+
}
61+
mock_body = {"event_id": "evt123"}
62+
mock_client = Mock()
63+
mock_extract_session_pull_request_id.return_value = None
64+
65+
# delete and import module to test
66+
if "app.slack.slack_handlers" in sys.modules:
67+
del sys.modules["app.slack.slack_handlers"]
68+
from app.slack.slack_handlers import unified_message_handler
69+
70+
# perform operation
71+
unified_message_handler(event=mock_event, body=mock_body, client=mock_client)
72+
73+
# assertions
74+
mock_process_async_slack_event.assert_not_called()
75+
mock_forward_event_to_pull_request_lambda.assert_not_called()
76+
77+
4278
@patch("app.slack.slack_events.process_async_slack_event")
4379
@patch("app.utils.handler_utils.extract_session_pull_request_id")
4480
@patch("app.utils.handler_utils.forward_event_to_pull_request_lambda")

0 commit comments

Comments
 (0)