From f9cb0028162f626905355b55ac17dd06ad5efc38 Mon Sep 17 00:00:00 2001 From: Richard Gibert Date: Fri, 5 Jun 2026 09:33:11 -0400 Subject: [PATCH 01/10] feat(incidents): Set channel topic on status channels Status channels were created without a topic, while the main incident channel always had one set. Now the status channel gets the same topic as the main channel at creation time and whenever the topic-relevant fields (title, severity, captain) change. Co-Authored-By: Claude Agent transcript: https://claudescope.sentry.dev/share/AvmWtSfOOeXg5PYEsqE2lSHWXgDXqqOQpUbwYuyXvng --- src/firetower/incidents/hooks.py | 55 ++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/src/firetower/incidents/hooks.py b/src/firetower/incidents/hooks.py index 7de9c47a..13c1acdf 100644 --- a/src/firetower/incidents/hooks.py +++ b/src/firetower/incidents/hooks.py @@ -436,7 +436,10 @@ def _save_status_channel_link(incident: Incident, status_channel_id: str) -> Non def _create_status_channel_for_context( - ctx: ChannelSetupContext, slack_service: SlackService + ctx: ChannelSetupContext, + slack_service: SlackService, + *, + topic: str | None = None, ) -> str | None: """Create a companion status channel. No DB access. @@ -463,6 +466,14 @@ def _create_status_channel_for_context( ) return None + if topic: + try: + slack_service.set_channel_topic(status_channel_id, topic) + except Exception: + logger.exception( + f"Failed to set topic on status channel {status_channel_name}" + ) + label = ctx.incident_number or ctx.channel_name message_lines = [f"This is the status channel for *{label}*."] if ctx.incident_url and ctx.incident_number: @@ -526,7 +537,10 @@ def _create_status_channel(incident: Incident, main_channel_id: str) -> None: incident_url=_build_incident_url(incident), incident_number=incident.incident_number, ) - status_channel_id = _create_status_channel_for_context(ctx, _slack_service) + topic = build_channel_topic(incident, captain_slack_id) + status_channel_id = _create_status_channel_for_context( + ctx, _slack_service, topic=topic + ) if status_channel_id: _save_status_channel_link(incident, status_channel_id) @@ -768,6 +782,7 @@ def decorate_incident_channel( skip_datadog: bool = False, skip_notion: bool = False, paged_policies: set[str] | None = None, + status_channel_topic: str | None = None, ) -> str | None: """ Shared channel setup called by both the normal and fallback creation paths. @@ -889,7 +904,9 @@ def decorate_incident_channel( status_channel_id: str | None = None try: - status_channel_id = _create_status_channel_for_context(ctx, slack_service) + status_channel_id = _create_status_channel_for_context( + ctx, slack_service, topic=status_channel_topic + ) except Exception: logger.exception(f"Failed to create status channel for {ctx.channel_name}") @@ -1248,12 +1265,14 @@ def on_incident_created(incident: Incident) -> None: incident_url=incident_url, incident_number=incident.incident_number, ) + channel_topic = build_channel_topic(incident, captain_slack_id) status_channel_id = decorate_incident_channel( ctx, _slack_service, skip_datadog=True, skip_notion=True, paged_policies=paged_policies, + status_channel_topic=channel_topic, ) if status_channel_id: _save_status_channel_link(incident, status_channel_id) @@ -1313,7 +1332,11 @@ def on_severity_changed(incident: Incident, old_severity: str) -> None: try: channel_id = _get_channel_id(incident) if channel_id: - _slack_service.set_channel_topic(channel_id, build_channel_topic(incident)) + topic = build_channel_topic(incident) + _slack_service.set_channel_topic(channel_id, topic) + status_channel_id = _get_status_channel_id(incident) + if status_channel_id: + _slack_service.set_channel_topic(status_channel_id, topic) incident_url = _build_incident_url(incident) _slack_service.post_message( channel_id, @@ -1377,7 +1400,11 @@ def on_title_changed(incident: Incident) -> None: try: channel_id = _get_channel_id(incident) if channel_id: - _slack_service.set_channel_topic(channel_id, build_channel_topic(incident)) + topic = build_channel_topic(incident) + _slack_service.set_channel_topic(channel_id, topic) + status_channel_id = _get_status_channel_id(incident) + if status_channel_id: + _slack_service.set_channel_topic(status_channel_id, topic) except Exception: logger.exception(f"Error in on_title_changed for incident {incident.id}") @@ -1408,7 +1435,11 @@ def on_captain_changed(incident: Incident) -> None: if not channel_id: return - _slack_service.set_channel_topic(channel_id, build_channel_topic(incident)) + topic = build_channel_topic(incident) + _slack_service.set_channel_topic(channel_id, topic) + status_channel_id = _get_status_channel_id(incident) + if status_channel_id: + _slack_service.set_channel_topic(status_channel_id, topic) incident_url = _build_incident_url(incident) if incident.captain: @@ -1457,13 +1488,23 @@ def on_incident_updated( if channel_id and ( old_title is not None or old_severity is not None or captain_changed ): + topic = build_channel_topic(incident) try: - _slack_service.set_channel_topic(channel_id, build_channel_topic(incident)) + _slack_service.set_channel_topic(channel_id, topic) except Exception: logger.exception( f"Error setting channel topic in on_incident_updated for incident {incident.id}" ) + status_channel_id = _get_status_channel_id(incident) + if status_channel_id: + try: + _slack_service.set_channel_topic(status_channel_id, topic) + except Exception: + logger.exception( + f"Error setting status channel topic in on_incident_updated for incident {incident.id}" + ) + # --- Build combined notification lines --- lines: list[str] = [] From 85fe3850bcb5ee4ed30260854318dc8e19719e80 Mon Sep 17 00:00:00 2001 From: Richard Gibert Date: Fri, 5 Jun 2026 10:01:37 -0400 Subject: [PATCH 02/10] fix(incidents): Isolate status channel topic errors from other operations Wrap status channel set_channel_topic calls in their own try/except blocks in on_severity_changed, on_title_changed, and on_captain_changed so a failure does not skip subsequent message posting or user invites. Co-Authored-By: Claude Agent transcript: https://claudescope.sentry.dev/share/sbcLyL6uXbXaI0a1CGpm4p26nvdj-LI_WJ1J6FNVDSQ --- src/firetower/incidents/hooks.py | 33 +++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/firetower/incidents/hooks.py b/src/firetower/incidents/hooks.py index 13c1acdf..2d7ddb7b 100644 --- a/src/firetower/incidents/hooks.py +++ b/src/firetower/incidents/hooks.py @@ -1334,9 +1334,14 @@ def on_severity_changed(incident: Incident, old_severity: str) -> None: if channel_id: topic = build_channel_topic(incident) _slack_service.set_channel_topic(channel_id, topic) - status_channel_id = _get_status_channel_id(incident) - if status_channel_id: - _slack_service.set_channel_topic(status_channel_id, topic) + try: + status_channel_id = _get_status_channel_id(incident) + if status_channel_id: + _slack_service.set_channel_topic(status_channel_id, topic) + except Exception: + logger.exception( + f"Failed to set status channel topic in on_severity_changed for incident {incident.id}" + ) incident_url = _build_incident_url(incident) _slack_service.post_message( channel_id, @@ -1402,9 +1407,14 @@ def on_title_changed(incident: Incident) -> None: if channel_id: topic = build_channel_topic(incident) _slack_service.set_channel_topic(channel_id, topic) - status_channel_id = _get_status_channel_id(incident) - if status_channel_id: - _slack_service.set_channel_topic(status_channel_id, topic) + try: + status_channel_id = _get_status_channel_id(incident) + if status_channel_id: + _slack_service.set_channel_topic(status_channel_id, topic) + except Exception: + logger.exception( + f"Failed to set status channel topic in on_title_changed for incident {incident.id}" + ) except Exception: logger.exception(f"Error in on_title_changed for incident {incident.id}") @@ -1437,9 +1447,14 @@ def on_captain_changed(incident: Incident) -> None: topic = build_channel_topic(incident) _slack_service.set_channel_topic(channel_id, topic) - status_channel_id = _get_status_channel_id(incident) - if status_channel_id: - _slack_service.set_channel_topic(status_channel_id, topic) + try: + status_channel_id = _get_status_channel_id(incident) + if status_channel_id: + _slack_service.set_channel_topic(status_channel_id, topic) + except Exception: + logger.exception( + f"Failed to set status channel topic in on_captain_changed for incident {incident.id}" + ) incident_url = _build_incident_url(incident) if incident.captain: From 9a5b4efb275efe9f391fb71c7eb6076ec676317f Mon Sep 17 00:00:00 2001 From: Richard Gibert Date: Fri, 5 Jun 2026 10:16:54 -0400 Subject: [PATCH 03/10] fix(incidents): Wrap status channel lookup in on_incident_updated with try/except An unhandled exception from _get_status_channel_id would halt the rest of on_incident_updated, skipping notifications, slack dumps, and severity escalation handling. Co-Authored-By: Claude --- src/firetower/incidents/hooks.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/firetower/incidents/hooks.py b/src/firetower/incidents/hooks.py index 2d7ddb7b..f05bd691 100644 --- a/src/firetower/incidents/hooks.py +++ b/src/firetower/incidents/hooks.py @@ -1511,14 +1511,14 @@ def on_incident_updated( f"Error setting channel topic in on_incident_updated for incident {incident.id}" ) - status_channel_id = _get_status_channel_id(incident) - if status_channel_id: - try: + try: + status_channel_id = _get_status_channel_id(incident) + if status_channel_id: _slack_service.set_channel_topic(status_channel_id, topic) - except Exception: - logger.exception( - f"Error setting status channel topic in on_incident_updated for incident {incident.id}" - ) + except Exception: + logger.exception( + f"Error setting status channel topic in on_incident_updated for incident {incident.id}" + ) # --- Build combined notification lines --- lines: list[str] = [] From 160fffaf3541ace70cea2fb6b4f25083212e9fdc Mon Sep 17 00:00:00 2001 From: Richard Gibert Date: Fri, 5 Jun 2026 10:30:44 -0400 Subject: [PATCH 04/10] fix(incidents): Move build_channel_topic back inside try/except in on_incident_updated The refactor inadvertently moved build_channel_topic outside the try/except block, meaning a failure in topic construction would propagate uncaught and abort the rest of on_incident_updated. Co-Authored-By: Claude --- src/firetower/incidents/hooks.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/firetower/incidents/hooks.py b/src/firetower/incidents/hooks.py index f05bd691..8d021513 100644 --- a/src/firetower/incidents/hooks.py +++ b/src/firetower/incidents/hooks.py @@ -1503,22 +1503,24 @@ def on_incident_updated( if channel_id and ( old_title is not None or old_severity is not None or captain_changed ): - topic = build_channel_topic(incident) try: + topic = build_channel_topic(incident) _slack_service.set_channel_topic(channel_id, topic) except Exception: + topic = None logger.exception( f"Error setting channel topic in on_incident_updated for incident {incident.id}" ) - try: - status_channel_id = _get_status_channel_id(incident) - if status_channel_id: - _slack_service.set_channel_topic(status_channel_id, topic) - except Exception: - logger.exception( - f"Error setting status channel topic in on_incident_updated for incident {incident.id}" - ) + if topic: + try: + status_channel_id = _get_status_channel_id(incident) + if status_channel_id: + _slack_service.set_channel_topic(status_channel_id, topic) + except Exception: + logger.exception( + f"Error setting status channel topic in on_incident_updated for incident {incident.id}" + ) # --- Build combined notification lines --- lines: list[str] = [] From 80614bed488f8c2499508bf64afb5da5a25f9db0 Mon Sep 17 00:00:00 2001 From: Richard Gibert Date: Fri, 5 Jun 2026 10:40:54 -0400 Subject: [PATCH 05/10] fix(incidents): Isolate main and status channel topic updates from each other In on_severity_changed and on_title_changed, a failure setting the main channel topic no longer skips the status channel update. In on_incident_updated, build_channel_topic is now separated from the set_channel_topic call so a Slack API failure does not discard the already-built topic and skip the status channel update. Co-Authored-By: Claude --- src/firetower/incidents/hooks.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/firetower/incidents/hooks.py b/src/firetower/incidents/hooks.py index 8d021513..6a4f3838 100644 --- a/src/firetower/incidents/hooks.py +++ b/src/firetower/incidents/hooks.py @@ -1333,7 +1333,12 @@ def on_severity_changed(incident: Incident, old_severity: str) -> None: channel_id = _get_channel_id(incident) if channel_id: topic = build_channel_topic(incident) - _slack_service.set_channel_topic(channel_id, topic) + try: + _slack_service.set_channel_topic(channel_id, topic) + except Exception: + logger.exception( + f"Failed to set main channel topic in on_severity_changed for incident {incident.id}" + ) try: status_channel_id = _get_status_channel_id(incident) if status_channel_id: @@ -1406,7 +1411,12 @@ def on_title_changed(incident: Incident) -> None: channel_id = _get_channel_id(incident) if channel_id: topic = build_channel_topic(incident) - _slack_service.set_channel_topic(channel_id, topic) + try: + _slack_service.set_channel_topic(channel_id, topic) + except Exception: + logger.exception( + f"Failed to set main channel topic in on_title_changed for incident {incident.id}" + ) try: status_channel_id = _get_status_channel_id(incident) if status_channel_id: @@ -1505,14 +1515,19 @@ def on_incident_updated( ): try: topic = build_channel_topic(incident) - _slack_service.set_channel_topic(channel_id, topic) except Exception: topic = None logger.exception( - f"Error setting channel topic in on_incident_updated for incident {incident.id}" + f"Error building channel topic in on_incident_updated for incident {incident.id}" ) if topic: + try: + _slack_service.set_channel_topic(channel_id, topic) + except Exception: + logger.exception( + f"Error setting channel topic in on_incident_updated for incident {incident.id}" + ) try: status_channel_id = _get_status_channel_id(incident) if status_channel_id: From 1db27a5c8f4dc2767f60e04310fca2b0800d6042 Mon Sep 17 00:00:00 2001 From: Richard Gibert Date: Fri, 5 Jun 2026 10:45:00 -0400 Subject: [PATCH 06/10] fix(incidents): Isolate main channel topic update in on_captain_changed Wrap set_channel_topic for the main channel in its own try/except so a failure does not skip posting the captain update message or inviting the new captain to the channel. Co-Authored-By: Claude --- src/firetower/incidents/hooks.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/firetower/incidents/hooks.py b/src/firetower/incidents/hooks.py index 6a4f3838..99df2b75 100644 --- a/src/firetower/incidents/hooks.py +++ b/src/firetower/incidents/hooks.py @@ -1456,7 +1456,12 @@ def on_captain_changed(incident: Incident) -> None: return topic = build_channel_topic(incident) - _slack_service.set_channel_topic(channel_id, topic) + try: + _slack_service.set_channel_topic(channel_id, topic) + except Exception: + logger.exception( + f"Failed to set main channel topic in on_captain_changed for incident {incident.id}" + ) try: status_channel_id = _get_status_channel_id(incident) if status_channel_id: From 51ac16b213bd9103fb5fc20836cdf08f433c2478 Mon Sep 17 00:00:00 2001 From: Richard Gibert Date: Fri, 5 Jun 2026 15:28:21 -0400 Subject: [PATCH 07/10] reduce duplication --- src/firetower/incidents/hooks.py | 99 ++++++-------------- src/firetower/integrations/services/slack.py | 5 + 2 files changed, 34 insertions(+), 70 deletions(-) diff --git a/src/firetower/incidents/hooks.py b/src/firetower/incidents/hooks.py index 99df2b75..0645daaa 100644 --- a/src/firetower/incidents/hooks.py +++ b/src/firetower/incidents/hooks.py @@ -96,6 +96,7 @@ class ChannelSetupContext: description: str | None = None incident_url: str | None = None incident_number: str | None = None + topic: str | None = None def page_for_channel( @@ -258,6 +259,24 @@ def _get_status_channel_id(incident: Incident) -> str | None: return _slack_service.parse_channel_id_from_url(slack_link.url) +def _set_topic_on_all_channels(incident: Incident, topic: str) -> None: + channel_ids: list[str] = [] + try: + channel_id = _get_channel_id(incident) + if channel_id: + channel_ids.append(channel_id) + except Exception: + logger.exception(f"Failed to get channel id for incident {incident.id}") + try: + status_channel_id = _get_status_channel_id(incident) + if status_channel_id: + channel_ids.append(status_channel_id) + except Exception: + logger.exception(f"Failed to get status channel id for incident {incident.id}") + if channel_ids: + _slack_service.set_all_channel_topics(channel_ids, topic) + + def _invite_user_to_channel( channel_id: str, user: User, slack_user_id: str | None = None ) -> None: @@ -438,8 +457,6 @@ def _save_status_channel_link(incident: Incident, status_channel_id: str) -> Non def _create_status_channel_for_context( ctx: ChannelSetupContext, slack_service: SlackService, - *, - topic: str | None = None, ) -> str | None: """Create a companion status channel. No DB access. @@ -466,9 +483,9 @@ def _create_status_channel_for_context( ) return None - if topic: + if ctx.topic: try: - slack_service.set_channel_topic(status_channel_id, topic) + slack_service.set_channel_topic(status_channel_id, ctx.topic) except Exception: logger.exception( f"Failed to set topic on status channel {status_channel_name}" @@ -536,11 +553,9 @@ def _create_status_channel(incident: Incident, main_channel_id: str) -> None: reporter_slack_id=reporter_slack_id, incident_url=_build_incident_url(incident), incident_number=incident.incident_number, + topic=build_channel_topic(incident, captain_slack_id), ) - topic = build_channel_topic(incident, captain_slack_id) - status_channel_id = _create_status_channel_for_context( - ctx, _slack_service, topic=topic - ) + status_channel_id = _create_status_channel_for_context(ctx, _slack_service) if status_channel_id: _save_status_channel_link(incident, status_channel_id) @@ -782,7 +797,6 @@ def decorate_incident_channel( skip_datadog: bool = False, skip_notion: bool = False, paged_policies: set[str] | None = None, - status_channel_topic: str | None = None, ) -> str | None: """ Shared channel setup called by both the normal and fallback creation paths. @@ -904,9 +918,7 @@ def decorate_incident_channel( status_channel_id: str | None = None try: - status_channel_id = _create_status_channel_for_context( - ctx, slack_service, topic=status_channel_topic - ) + status_channel_id = _create_status_channel_for_context(ctx, slack_service) except Exception: logger.exception(f"Failed to create status channel for {ctx.channel_name}") @@ -1264,15 +1276,14 @@ def on_incident_created(incident: Incident) -> None: description=incident.description, incident_url=incident_url, incident_number=incident.incident_number, + topic=build_channel_topic(incident, captain_slack_id), ) - channel_topic = build_channel_topic(incident, captain_slack_id) status_channel_id = decorate_incident_channel( ctx, _slack_service, skip_datadog=True, skip_notion=True, paged_policies=paged_policies, - status_channel_topic=channel_topic, ) if status_channel_id: _save_status_channel_link(incident, status_channel_id) @@ -1333,20 +1344,7 @@ def on_severity_changed(incident: Incident, old_severity: str) -> None: channel_id = _get_channel_id(incident) if channel_id: topic = build_channel_topic(incident) - try: - _slack_service.set_channel_topic(channel_id, topic) - except Exception: - logger.exception( - f"Failed to set main channel topic in on_severity_changed for incident {incident.id}" - ) - try: - status_channel_id = _get_status_channel_id(incident) - if status_channel_id: - _slack_service.set_channel_topic(status_channel_id, topic) - except Exception: - logger.exception( - f"Failed to set status channel topic in on_severity_changed for incident {incident.id}" - ) + _set_topic_on_all_channels(incident, topic) incident_url = _build_incident_url(incident) _slack_service.post_message( channel_id, @@ -1411,20 +1409,7 @@ def on_title_changed(incident: Incident) -> None: channel_id = _get_channel_id(incident) if channel_id: topic = build_channel_topic(incident) - try: - _slack_service.set_channel_topic(channel_id, topic) - except Exception: - logger.exception( - f"Failed to set main channel topic in on_title_changed for incident {incident.id}" - ) - try: - status_channel_id = _get_status_channel_id(incident) - if status_channel_id: - _slack_service.set_channel_topic(status_channel_id, topic) - except Exception: - logger.exception( - f"Failed to set status channel topic in on_title_changed for incident {incident.id}" - ) + _set_topic_on_all_channels(incident, topic) except Exception: logger.exception(f"Error in on_title_changed for incident {incident.id}") @@ -1456,20 +1441,7 @@ def on_captain_changed(incident: Incident) -> None: return topic = build_channel_topic(incident) - try: - _slack_service.set_channel_topic(channel_id, topic) - except Exception: - logger.exception( - f"Failed to set main channel topic in on_captain_changed for incident {incident.id}" - ) - try: - status_channel_id = _get_status_channel_id(incident) - if status_channel_id: - _slack_service.set_channel_topic(status_channel_id, topic) - except Exception: - logger.exception( - f"Failed to set status channel topic in on_captain_changed for incident {incident.id}" - ) + _set_topic_on_all_channels(incident, topic) incident_url = _build_incident_url(incident) if incident.captain: @@ -1527,20 +1499,7 @@ def on_incident_updated( ) if topic: - try: - _slack_service.set_channel_topic(channel_id, topic) - except Exception: - logger.exception( - f"Error setting channel topic in on_incident_updated for incident {incident.id}" - ) - try: - status_channel_id = _get_status_channel_id(incident) - if status_channel_id: - _slack_service.set_channel_topic(status_channel_id, topic) - except Exception: - logger.exception( - f"Error setting status channel topic in on_incident_updated for incident {incident.id}" - ) + _set_topic_on_all_channels(incident, topic) # --- Build combined notification lines --- lines: list[str] = [] diff --git a/src/firetower/integrations/services/slack.py b/src/firetower/integrations/services/slack.py index 692b0332..4c6bafd3 100644 --- a/src/firetower/integrations/services/slack.py +++ b/src/firetower/integrations/services/slack.py @@ -227,6 +227,11 @@ def set_channel_topic(self, channel_id: str, topic: str) -> bool: ) return False + def set_all_channel_topics( + self, channel_ids: list[str], topic: str + ) -> dict[str, bool]: + return {cid: self.set_channel_topic(cid, topic) for cid in channel_ids} + def invite_to_channel(self, channel_id: str, user_ids: list[str]) -> bool: if not self.client: logger.warning("Cannot invite to channel - Slack client not initialized") From 9e20d874f7ec2c500a15df5f155c58a39ed6bb5e Mon Sep 17 00:00:00 2001 From: Richard Gibert Date: Fri, 5 Jun 2026 15:30:39 -0400 Subject: [PATCH 08/10] early exit when client on initialized --- src/firetower/integrations/services/slack.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/firetower/integrations/services/slack.py b/src/firetower/integrations/services/slack.py index 4c6bafd3..165e9cef 100644 --- a/src/firetower/integrations/services/slack.py +++ b/src/firetower/integrations/services/slack.py @@ -230,6 +230,9 @@ def set_channel_topic(self, channel_id: str, topic: str) -> bool: def set_all_channel_topics( self, channel_ids: list[str], topic: str ) -> dict[str, bool]: + if not self.client: + logger.warning("Cannot set topics - Slack client not initialized") + return dict.fromkeys(channel_ids, False) return {cid: self.set_channel_topic(cid, topic) for cid in channel_ids} def invite_to_channel(self, channel_id: str, user_ids: list[str]) -> bool: From a641bf4e46824e12a9811a1d7740388ca3ec2b8c Mon Sep 17 00:00:00 2001 From: Richard Gibert Date: Fri, 5 Jun 2026 15:32:24 -0400 Subject: [PATCH 09/10] add missing try --- src/firetower/incidents/hooks.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/firetower/incidents/hooks.py b/src/firetower/incidents/hooks.py index 0645daaa..bb9d9b87 100644 --- a/src/firetower/incidents/hooks.py +++ b/src/firetower/incidents/hooks.py @@ -1343,8 +1343,13 @@ def on_severity_changed(incident: Incident, old_severity: str) -> None: try: channel_id = _get_channel_id(incident) if channel_id: - topic = build_channel_topic(incident) - _set_topic_on_all_channels(incident, topic) + try: + topic = build_channel_topic(incident) + _set_topic_on_all_channels(incident, topic) + except Exception: + logger.exception( + f"Failed to set channel topic for incident {incident.id}" + ) incident_url = _build_incident_url(incident) _slack_service.post_message( channel_id, From 503c765ef7e73647c27acfc6481bee61e6f79ae9 Mon Sep 17 00:00:00 2001 From: Richard Gibert Date: Fri, 5 Jun 2026 15:52:44 -0400 Subject: [PATCH 10/10] fix ci --- src/firetower/incidents/tests/test_hooks.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/firetower/incidents/tests/test_hooks.py b/src/firetower/incidents/tests/test_hooks.py index bca3b59a..00fb7ff3 100644 --- a/src/firetower/incidents/tests/test_hooks.py +++ b/src/firetower/incidents/tests/test_hooks.py @@ -403,7 +403,7 @@ def test_posts_status_update_message(self, mock_slack, mock_dump_async): mock_slack.post_message.assert_called_once() assert "Active" in mock_slack.post_message.call_args[0][1] assert "Mitigated" in mock_slack.post_message.call_args[0][1] - mock_slack.set_channel_topic.assert_not_called() + mock_slack.set_all_channel_topics.assert_not_called() @patch("firetower.incidents.hooks._slack_service") def test_noop_without_slack_link(self, mock_slack): @@ -509,7 +509,7 @@ def test_posts_severity_update_message( mock_slack.post_message.assert_called_once() assert "P2" in mock_slack.post_message.call_args[0][1] assert "P0" in mock_slack.post_message.call_args[0][1] - mock_slack.set_channel_topic.assert_called_once() + mock_slack.set_all_channel_topics.assert_called_once() @patch("firetower.incidents.hooks._slack_service") def test_noop_without_slack_link(self, mock_slack): @@ -541,7 +541,7 @@ def test_updates_topic(self, mock_slack): on_title_changed(incident) - mock_slack.set_channel_topic.assert_called_once() + mock_slack.set_all_channel_topics.assert_called_once() @patch("firetower.incidents.hooks._slack_service") def test_noop_without_slack_link(self, mock_slack): @@ -552,7 +552,7 @@ def test_noop_without_slack_link(self, mock_slack): on_title_changed(incident) - mock_slack.set_channel_topic.assert_not_called() + mock_slack.set_all_channel_topics.assert_not_called() @pytest.mark.django_db @@ -642,7 +642,7 @@ def test_updates_topic_and_invites(self, mock_slack): on_captain_changed(incident) - mock_slack.set_channel_topic.assert_called_once() + mock_slack.set_all_channel_topics.assert_called_once() mock_slack.post_message.assert_called_once() assert "<@U_NEW>" in mock_slack.post_message.call_args[0][1] mock_slack.invite_to_channel.assert_called_once_with("C12345", ["U_NEW"]) @@ -671,7 +671,7 @@ def test_updates_topic_and_posts_name_when_no_slack_profile(self, mock_slack): on_captain_changed(incident) - mock_slack.set_channel_topic.assert_called_once() + mock_slack.set_all_channel_topics.assert_called_once() mock_slack.post_message.assert_called_once() assert "New Captain" in mock_slack.post_message.call_args[0][1] @@ -692,7 +692,7 @@ def test_updates_topic_only_when_captain_cleared(self, mock_slack): on_captain_changed(incident) - mock_slack.set_channel_topic.assert_called_once() + mock_slack.set_all_channel_topics.assert_called_once() mock_slack.post_message.assert_not_called() @patch("firetower.incidents.hooks._slack_service") @@ -780,7 +780,7 @@ def test_noop_without_slack_link(self, mock_slack): on_captain_changed(incident) - mock_slack.set_channel_topic.assert_not_called() + mock_slack.set_all_channel_topics.assert_not_called() MOCK_PD_CONFIG = { @@ -3347,7 +3347,7 @@ def test_sets_topic_once_when_severity_and_captain_change(self, mock_slack): incident, old_severity=IncidentSeverity.P4, captain_changed=True ) - mock_slack.set_channel_topic.assert_called_once() + mock_slack.set_all_channel_topics.assert_called_once() @patch("firetower.incidents.hooks._slack_service") def test_no_message_when_nothing_changed(self, mock_slack): @@ -3397,7 +3397,7 @@ def test_no_captain_line_when_captain_cleared(self, mock_slack): on_incident_updated(incident, captain_changed=True) - mock_slack.set_channel_topic.assert_called_once() + mock_slack.set_all_channel_topics.assert_called_once() mock_slack.post_message.assert_not_called() @patch("firetower.slack_app.handlers.dumpslack.trigger_slack_dump_async")