新增了完整的GitHub集成插件,包含认证、会话管理、Webhook处理、消息收发、反应支持等核心功能,支持Issues、Discussions、Pull Request的交互与通知。
113 lines
4.2 KiB
Python
113 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import logging
|
|
import os
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class GitHubConfigAdapter:
|
|
def __init__(self):
|
|
self._config: dict = {}
|
|
|
|
@property
|
|
def _gh_cfg(self) -> dict:
|
|
return self._config.get("channels", {}).get("github", {})
|
|
|
|
def list_account_ids(self, config: dict) -> list[str]:
|
|
self._config = config
|
|
accounts = self._gh_cfg.get("accounts", {})
|
|
if accounts:
|
|
return list(accounts.keys())
|
|
if self._env_credentials_exist():
|
|
return ["default"]
|
|
return []
|
|
|
|
async def resolve_account(self, account_id: str) -> dict:
|
|
return self._build_account(account_id)
|
|
|
|
def is_configured(self, account: dict) -> bool:
|
|
return all([
|
|
account.get("app_id"),
|
|
account.get("private_key"),
|
|
account.get("installation_id"),
|
|
account.get("webhook_secret"),
|
|
])
|
|
|
|
def is_enabled(self, account: dict) -> bool:
|
|
return account.get("enabled", True)
|
|
|
|
def disabled_reason(self, account: dict) -> str:
|
|
if not self.is_configured(account):
|
|
return "GitHub App credentials (appId, privateKey, installationId, webhookSecret) are required"
|
|
return ""
|
|
|
|
async def resolve_allow_from(self, config: dict, account_id: str) -> list[str] | None:
|
|
account = await self.resolve_account(account_id)
|
|
return account.get("allow_from", [])
|
|
|
|
def describe_account(self, account: dict) -> dict:
|
|
return {
|
|
"account_id": account.get("account_id", ""),
|
|
"name": account.get("name", ""),
|
|
"bot_login": account.get("bot_login", ""),
|
|
"dm_policy": account.get("dm_policy", "open"),
|
|
"repositories": account.get("repositories", []),
|
|
"configured": self.is_configured(account),
|
|
}
|
|
|
|
def default_account_id(self) -> str:
|
|
return self._gh_cfg.get("defaultAccount", "default")
|
|
|
|
@staticmethod
|
|
def credential_fingerprint(app_id: int, installation_id: int) -> str:
|
|
return hashlib.sha256(f"{app_id}:{installation_id}".encode()).hexdigest()[:8]
|
|
|
|
@staticmethod
|
|
def _env_credentials_exist() -> bool:
|
|
return bool(
|
|
os.environ.get("GITHUB_APP_ID", "")
|
|
and os.environ.get("GITHUB_PRIVATE_KEY", "")
|
|
and os.environ.get("GITHUB_INSTALLATION_ID", "")
|
|
and os.environ.get("GITHUB_WEBHOOK_SECRET", "")
|
|
)
|
|
|
|
def _build_account(self, account_id: str) -> dict:
|
|
gh_cfg = self._gh_cfg
|
|
accounts = gh_cfg.get("accounts", {})
|
|
account_raw = accounts.get(account_id, {}) if account_id != "default" else gh_cfg
|
|
|
|
def _get(key: str, default=None):
|
|
return account_raw.get(key, gh_cfg.get(key, default))
|
|
|
|
app_id = int(os.environ.get("GITHUB_APP_ID", "0") or _get("appId", 0))
|
|
private_key = os.environ.get("GITHUB_PRIVATE_KEY", "") or _get("privateKey", "")
|
|
if private_key:
|
|
private_key = private_key.replace("\\n", "\n")
|
|
|
|
installation_id = int(os.environ.get("GITHUB_INSTALLATION_ID", "0") or _get("installationId", 0))
|
|
webhook_secret = os.environ.get("GITHUB_WEBHOOK_SECRET", "") or _get("webhookSecret", "")
|
|
bot_login = os.environ.get("GITHUB_BOT_LOGIN", "") or _get("botLogin", "")
|
|
|
|
return {
|
|
"account_id": account_id,
|
|
"app_id": app_id,
|
|
"private_key": private_key,
|
|
"installation_id": installation_id,
|
|
"webhook_secret": webhook_secret,
|
|
"webhook_path": _get("webhookPath", "/api/webhook/github"),
|
|
"bot_login": bot_login,
|
|
"repositories": _get("repositories", []),
|
|
"name": account_raw.get("name", account_id),
|
|
"label": account_raw.get("label"),
|
|
"dm_policy": _get("dmPolicy", "open"),
|
|
"allow_from": _get("allowFrom", []),
|
|
"group_policy": _get("groupPolicy", "open"),
|
|
"enabled": account_raw.get("enabled", True),
|
|
"text_chunk_limit": int(_get("textChunkLimit", 65000)),
|
|
"reaction_level": _get("reactionLevel", "ack"),
|
|
"streaming_mode": _get("streamingMode", "block"),
|
|
"config": gh_cfg,
|
|
}
|