Skip to content
Open
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
7 changes: 5 additions & 2 deletions fenn/notification/notifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,13 @@ def remove_service(self, service: Type[Service]) -> None:
)
raise

def notify(self, message: str) -> None:
def notify(self, message: str, is_success: bool = True) -> None:
"""Send notification to all registered services.

Args:
message: The message to send.
is_success: Whether the operation succeeded (default: True).
Services can use this to filter notifications.
"""
if not self._services:
return
Expand All @@ -63,7 +65,8 @@ def notify(self, message: str) -> None:

for service in self._services:
try:
service.send_notification(message)
if service.should_notify(is_success):
service.send_notification(message)
successful_services.append(service.__class__.__name__)
# logger.info(f"Successfully sent notification via {service.__class__.__name__}")
except Exception as e:
Expand Down
14 changes: 14 additions & 0 deletions fenn/notification/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,17 @@ def send_notification(self, message: str) -> None:
Exception: If the notification fails to send.
"""
pass

def should_notify(self, is_success: bool) -> bool:
"""Determine if a notification should be sent based on status.

This method can be overridden by subclasses to filter notifications
based on success/failure status.

Args:
is_success: True if the operation succeeded, False if it failed.

Returns:
True if the notification should be sent, False otherwise.
"""
return True
24 changes: 22 additions & 2 deletions fenn/notification/services/discord.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@
class Discord(Service):
"""Discord notification service using webhooks."""

def __init__(self, webhook_url: str):
"""Initialize Discord service."""
def __init__(self, webhook_url: str, notify_on_success: bool = False):
"""Initialize Discord service.

Args:
webhook_url: Discord webhook URL.
notify_on_success: If False (default), only send notifications on failure.
If True, send notifications for both success and failure.
"""
super().__init__()

self._discord_webhook_url = webhook_url
self._notify_on_success = notify_on_success

def send_notification(self, message: str) -> None:
"""Send notification to Discord channel.
Expand All @@ -30,3 +37,16 @@ def send_notification(self, message: str) -> None:
raise requests.exceptions.RequestException(
f"Failed to send Discord notification: {err}"
)

def should_notify(self, is_success: bool) -> bool:
"""Determine if a notification should be sent based on status.

Args:
is_success: True if the operation succeeded, False if it failed.

Returns:
True if the notification should be sent, False otherwise.
"""
if is_success:
return self._notify_on_success
return True
3 changes: 1 addition & 2 deletions fenn/remote/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@

import os
import sys
import tomllib
from dataclasses import dataclass
from pathlib import Path
from typing import Dict, Optional

import tomllib

from fenn.remote.exceptions import CredentialsError

DEFAULT_PROFILE = "default"
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/notification/test_discord_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,30 @@ def test_send_notification_error(self, send_message_to_discord, message):
)

assert "400" in str(exc_info.value)

def test_notify_on_success_false_blocks_success(self):
"""Test that notify_on_success=False blocks success notifications."""
discord = Discord(
"https://discord.com/api/webhooks/123/abc", notify_on_success=False
)
assert discord.should_notify(is_success=True) is False

def test_notify_on_success_false_allows_failure(self):
"""Test that notify_on_success=False allows failure notifications."""
discord = Discord(
"https://discord.com/api/webhooks/123/abc", notify_on_success=False
)
assert discord.should_notify(is_success=False) is True

def test_notify_on_success_true_allows_both(self):
"""Test that notify_on_success=True allows both success and failure notifications."""
discord = Discord(
"https://discord.com/api/webhooks/123/abc", notify_on_success=True
)
assert discord.should_notify(is_success=True) is True
assert discord.should_notify(is_success=False) is True

def test_default_notify_on_success_is_false(self):
"""Test that the default value of notify_on_success is False."""
discord = Discord("https://discord.com/api/webhooks/123/abc")
assert discord.should_notify(is_success=True) is False
Loading