Files
skill-seekers-reference/src/skill_seekers/sync/notifier.py
yusyus 51787e57bc style: Fix 411 ruff lint issues (Kimi's issue #4)
Auto-fixed lint issues with ruff --fix and --unsafe-fixes:

Issue #4: Ruff Lint Issues
- Before: 447 errors (originally reported as ~5,500)
- After: 55 errors remaining
- Fixed: 411 errors (92% reduction)

Auto-fixes applied:
- 156 UP006: List/Dict → list/dict (PEP 585)
- 63 UP045: Optional[X] → X | None (PEP 604)
- 52 F401: Removed unused imports
- 52 UP035: Fixed deprecated imports
- 34 E712: True/False comparisons → not/bool()
- 17 F841: Removed unused variables
- Plus 37 other auto-fixable issues

Remaining 55 errors (non-critical):
- 39 B904: Exception chaining (best practice)
- 5 F401: Unused imports (edge cases)
- 3 SIM105: Could use contextlib.suppress
- 8 other minor style issues

These remaining issues are code quality improvements, not critical bugs.

Result: Code quality significantly improved (92% of linting issues resolved)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 12:46:38 +03:00

144 lines
4.5 KiB
Python

"""
Notification system for sync events.
"""
import os
import requests
from .models import WebhookPayload
class Notifier:
"""
Send notifications about sync events.
Supports:
- Webhook (HTTP POST)
- Slack (via webhook)
- Email (SMTP) - TODO
- Console (stdout)
Examples:
notifier = Notifier()
payload = WebhookPayload(
event="change_detected",
skill_name="react",
changes=report
)
notifier.send(payload)
"""
def __init__(
self,
webhook_url: str | None = None,
slack_webhook: str | None = None,
email_recipients: list[str] | None = None,
console: bool = True
):
"""
Initialize notifier.
Args:
webhook_url: Webhook URL for HTTP notifications
slack_webhook: Slack webhook URL
email_recipients: List of email recipients
console: Whether to print to console
"""
self.webhook_url = webhook_url or os.getenv('SYNC_WEBHOOK_URL')
self.slack_webhook = slack_webhook or os.getenv('SLACK_WEBHOOK_URL')
self.email_recipients = email_recipients or []
self.console = console
def send(self, payload: WebhookPayload):
"""
Send notification via all configured channels.
Args:
payload: Notification payload
"""
if self.console:
self._send_console(payload)
if self.webhook_url:
self._send_webhook(payload)
if self.slack_webhook:
self._send_slack(payload)
if self.email_recipients:
self._send_email(payload)
def _send_console(self, payload: WebhookPayload):
"""Print to console."""
print(f"\n📢 {payload.event.upper()}: {payload.skill_name}")
if payload.changes:
changes = payload.changes
if changes.has_changes:
print(f" Changes detected: {changes.change_count}")
if changes.added:
print(f" ✅ Added: {len(changes.added)} pages")
if changes.modified:
print(f" ✏️ Modified: {len(changes.modified)} pages")
if changes.deleted:
print(f" ❌ Deleted: {len(changes.deleted)} pages")
else:
print(" No changes detected")
def _send_webhook(self, payload: WebhookPayload):
"""Send to generic webhook."""
try:
response = requests.post(
self.webhook_url,
json=payload.dict(),
headers={'Content-Type': 'application/json'},
timeout=10
)
response.raise_for_status()
print(f"✅ Webhook notification sent to {self.webhook_url}")
except Exception as e:
print(f"❌ Failed to send webhook: {e}")
def _send_slack(self, payload: WebhookPayload):
"""Send to Slack via webhook."""
try:
# Format Slack message
text = f"*{payload.event.upper()}*: {payload.skill_name}"
if payload.changes and payload.changes.has_changes:
changes = payload.changes
text += f"\n• Changes: {changes.change_count}"
text += f"\n• Added: {len(changes.added)}"
text += f"\n• Modified: {len(changes.modified)}"
text += f"\n• Deleted: {len(changes.deleted)}"
# Add URLs of changed pages
if changes.modified:
text += "\n\n*Modified Pages:*"
for change in changes.modified[:5]: # Limit to 5
text += f"\n{change.url}"
if len(changes.modified) > 5:
text += f"\n• ...and {len(changes.modified) - 5} more"
slack_payload = {
"text": text,
"username": "Skill Seekers Sync",
"icon_emoji": ":books:"
}
response = requests.post(
self.slack_webhook,
json=slack_payload,
timeout=10
)
response.raise_for_status()
print("✅ Slack notification sent")
except Exception as e:
print(f"❌ Failed to send Slack notification: {e}")
def _send_email(self, payload: WebhookPayload):
"""Send email notification."""
# TODO: Implement SMTP email sending
print(f"📧 Email notification (not implemented): {self.email_recipients}")