from __future__ import annotations import logging from datetime import datetime, UTC from yuxi.channel.extensions.github.types import ( GitHubEventType, GitHubSessionKind, GitHubWebhookEvent, ) from yuxi.channel.message.models import ( GroupContext, MessageType, PeerInfo, UnifiedMessage, ) from yuxi.channel.routing.models import PeerKind logger = logging.getLogger(__name__) class GitHubMonitor: def event_to_unified_message(self, event: GitHubWebhookEvent) -> UnifiedMessage | None: if not event.repository: return None repo_full_name = event.repository.full_name sender_id = f"github:{event.sender.login}" if event.sender else "" sender_name = event.sender.login if event.sender else "" content = "" session_kind = GitHubSessionKind.ISSUE session_number = 0 session_title = "" msg_id = f"gh:{event.event_id}" timestamp = datetime.now(UTC) reply_to_id = None if event.event_type == GitHubEventType.ISSUE_COMMENT and event.issue and event.comment: content = event.comment.body session_kind = GitHubSessionKind.ISSUE session_number = event.issue.number session_title = event.issue.title msg_id = f"gh:comment:{event.comment.id}" reply_to_id = f"gh:issue:{event.issue.node_id}" if event.comment.created_at: try: timestamp = datetime.fromisoformat(event.comment.created_at.replace("Z", "+00:00")) except ValueError: pass elif event.event_type == GitHubEventType.ISSUES and event.issue: session_kind = GitHubSessionKind.ISSUE session_number = event.issue.number session_title = event.issue.title msg_id = f"gh:issue:{event.issue.node_id}" if event.action == "opened": content = event.issue.body elif event.action == "closed": content = f"Issue #{event.issue.number} 已关闭: {event.issue.title}" elif event.action == "reopened": content = f"Issue #{event.issue.number} 已重新打开: {event.issue.title}" elif event.action == "labeled" and event.raw_payload.get("label"): label_name = event.raw_payload["label"].get("name", "") content = f"Issue #{event.issue.number} 已添加标签: {label_name}" elif event.event_type == GitHubEventType.DISCUSSION_COMMENT and event.discussion and event.comment: content = event.comment.body session_kind = GitHubSessionKind.DISCUSSION session_number = event.discussion.number session_title = event.discussion.title msg_id = f"gh:discussion_comment:{event.comment.id}" elif event.event_type == GitHubEventType.PULL_REQUEST_REVIEW and event.pull_request: content = (event.review.body or "") if event.review else "" session_kind = GitHubSessionKind.PULL_REQUEST session_number = event.pull_request.number session_title = event.pull_request.title msg_id = f"gh:pr_review:{event.review.id}" if event.review else f"gh:{event.event_id}" if event.review and event.review.submitted_at: try: timestamp = datetime.fromisoformat(event.review.submitted_at.replace("Z", "+00:00")) except ValueError: pass elif event.event_type == GitHubEventType.DISCUSSION and event.discussion: content = event.discussion.body session_kind = GitHubSessionKind.DISCUSSION session_number = event.discussion.number session_title = event.discussion.title msg_id = f"gh:discussion:{event.discussion.node_id}" elif event.event_type == GitHubEventType.PULL_REQUEST and event.pull_request: content = event.pull_request.body session_kind = GitHubSessionKind.PULL_REQUEST session_number = event.pull_request.number session_title = event.pull_request.title msg_id = f"gh:pr:{event.pull_request.node_id}" elif event.event_type == GitHubEventType.PULL_REQUEST_REVIEW_COMMENT and event.comment: content = event.comment.body session_kind = GitHubSessionKind.PULL_REQUEST session_number = 0 session_title = "" if event.pull_request: session_number = event.pull_request.number session_title = event.pull_request.title msg_id = f"gh:pr_review_comment:{event.comment.id}" if not content.strip(): return None sender_info = PeerInfo( kind=PeerKind.GROUP, id=sender_id, display_name=sender_name, ) group = GroupContext( id=f"github:{repo_full_name}:{session_kind.value}:{session_number}", kind="group", name=session_title, ) html_url = ( event.issue.html_url if event.issue else event.pull_request.html_url if event.pull_request else "" ) return UnifiedMessage( msg_id=msg_id, channel_type="github", account_id="default", content=content, sender=sender_info, message_type=MessageType.TEXT, media_urls=[], group=group, timestamp=timestamp, reply_to_id=reply_to_id, raw_payload=event.raw_payload, metadata={ "repository": repo_full_name, "kind": session_kind.value, "number": session_number, "title": session_title, "html_url": html_url, "review_state": event.review.state if event.review else None, }, )