新增了完整的GitHub集成插件,包含认证、会话管理、Webhook处理、消息收发、反应支持等核心功能,支持Issues、Discussions、Pull Request的交互与通知。
153 lines
5.9 KiB
Python
153 lines
5.9 KiB
Python
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,
|
|
},
|
|
)
|