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>
144 lines
4.5 KiB
Python
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}")
|