Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/firetower/integrations/services/notion.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,11 @@ def apply_template(
page_id: str,
messages: list[dict[str, Any]],
update_slack: bool = False,
incident: Any | None = None,
) -> None:
if not update_slack and self.template_markdown:
if not self._send_markdown(page_id, self.template_markdown):
content = self._render_template(self.template_markdown, incident)
if not self._send_markdown(page_id, content):
raise RuntimeError(
f"Failed to apply markdown template to Notion page {page_id}"
)
Expand Down Expand Up @@ -330,6 +332,13 @@ def apply_template(
notion_index += 1
index = stopping_index

@staticmethod
def _render_template(template: str, incident: Any | None) -> str:
if incident is None:
return template
linear_url = incident.external_links_dict.get("linear", "")
return template.replace("{linear_url}", linear_url)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

easy peasy nice


def _send_markdown(self, page_id: str, content: str, max_retries: int = 3) -> bool:
# notion-client v3 does not wrap the Markdown API endpoint, so we call it directly.
for attempt in range(max_retries):
Expand Down
56 changes: 56 additions & 0 deletions src/firetower/integrations/tests/test_notion.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,38 @@ def test_omits_caption_when_source_url_empty(self, notion):
assert "caption" not in block["image"]


class TestRenderTemplate:
def test_returns_template_unchanged_when_no_incident(self):
result = NotionService._render_template("# Title\n{linear_url}", None)
assert result == "# Title\n{linear_url}"

def test_replaces_linear_url_placeholder(self):
incident = MagicMock()
incident.external_links_dict = {
"linear": "https://linear.app/team/issue/INC-100"
}
result = NotionService._render_template(
"[Action Items]({linear_url})", incident
)
assert result == "[Action Items](https://linear.app/team/issue/INC-100)"

def test_replaces_with_empty_string_when_no_linear_link(self):
incident = MagicMock()
incident.external_links_dict = {}
result = NotionService._render_template(
"[Action Items]({linear_url})", incident
)
assert result == "[Action Items]()"

def test_no_placeholder_passes_through(self):
incident = MagicMock()
incident.external_links_dict = {
"linear": "https://linear.app/team/issue/INC-100"
}
result = NotionService._render_template("# No placeholders here", incident)
assert result == "# No placeholders here"


class TestApplyTemplate:
def _make_append_response(self, block_id: str) -> dict:
return {"results": [{"id": block_id}]}
Expand Down Expand Up @@ -394,6 +426,30 @@ def test_raises_when_toggle_creation_fails(self, notion):
):
notion.apply_template("page-id", messages=[], update_slack=False)

def test_interpolates_incident_into_template(self):
svc = NotionService(
integration_token="test-key",
database_id="db-id",
template_markdown="# PM\n[Action Items]({linear_url})",
)
svc.client = MagicMock()
svc.client.blocks.children.append.return_value = self._make_append_response(
"toggle-id"
)
incident = MagicMock()
incident.external_links_dict = {
"linear": "https://linear.app/team/issue/INC-42"
}

with patch.object(svc, "_send_markdown", return_value=True) as mock_md:
svc.apply_template(
"page-id", messages=[], update_slack=False, incident=incident
)

mock_md.assert_called_once_with(
"page-id", "# PM\n[Action Items](https://linear.app/team/issue/INC-42)"
)

def test_update_slack_skips_markdown_template(self, notion):
notion.client.blocks.children.append.return_value = self._make_append_response(
"toggle-id"
Expand Down
4 changes: 3 additions & 1 deletion src/firetower/slack_app/handlers/dumpslack.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ def _trigger_slack_dump(client: Any, channel_id: str, incident: Any) -> None:
messages = _get_channel_messages(slack_service, channel_id)

try:
notion.apply_template(page_id, messages, update_slack=update_slack)
notion.apply_template(
page_id, messages, update_slack=update_slack, incident=incident
)
except Exception:
logger.exception("Failed to populate Notion page %s", page_id)
try:
Expand Down
Loading