You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python获取GitHub仓库最新活动并实现事件监听装饰器

实现思路

你要做的装饰器本质是回调注册器,核心逻辑是把被装饰的函数注册为对应事件的回调函数,当监听到对应事件触发时,自动把事件数据传给回调执行。
两种主流的事件监听方案可选:

  • 主动轮询:不需要公网服务器,本地就能跑,适合小体量、实时性要求不高(分钟级)的场景,通过定期调用GitHub API对比本地缓存的最新状态判断有没有新增事件
  • Webhook推送:实时性高(秒级),需要你有公网可访问的服务器接收GitHub的POST请求,适合生产环境使用
核心代码实现

以下是轮询模式的可运行示例,依赖PyGitHub封装GitHub API调用,你也可以替换为原生REST API实现:

from github import Github
import time
from typing import Callable, List, Dict
from dataclasses import dataclass

# 定义事件类型枚举
@dataclass
class EventType:
    NEW_COMMIT = "new_commit"
    NEW_ISSUE = "new_issue"
    NEW_ISSUE_COMMENT = "new_issue_comment"
    NEW_PR = "new_pull_request"
    NEW_DISCUSSION = "new_discussion"
    ALL_UPDATES = "all_updates"

class Repo:
    def __init__(self, repo_name: str, github_token: str):
        self.client = Github(github_token)
        self.repo = self.client.get_repo(repo_name)
        # 存储各事件的回调函数列表
        self.callbacks: Dict[str, List[Callable]] = {k: [] for k in EventType.__dict__.values() if not k.startswith('_')}
        # 存储各事件的最新状态缓存,用来判断有没有新事件
        self.latest_state = {
            "last_commit_sha": None,
            "last_issue_number": 0,
            "last_issue_comment_id": 0,
            "last_pr_number": 0,
            "last_discussion_id": 0
        }
        # 初始化缓存状态
        self._init_cache()

    def _init_cache(self):
        # 初始化时拉取当前最新的状态,避免启动时把历史事件全部推送一遍
        latest_commit = self.repo.get_commits()[0]
        self.latest_state["last_commit_sha"] = latest_commit.sha
        issues = self.repo.get_issues(state="all", sort="created", direction="desc")
        if issues.totalCount > 0:
            self.latest_state["last_issue_number"] = issues[0].number
        # 其他事件的初始化逻辑同理
        ...

    # 新commit事件装饰器
    def on_new_commit(self) -> Callable:
        def decorator(func: Callable) -> Callable:
            self.callbacks[EventType.NEW_COMMIT].append(func)
            return func
        return decorator

    # 新issue评论事件装饰器
    def on_new_issue_comment(self) -> Callable:
        def decorator(func: Callable) -> Callable:
            self.callbacks[EventType.NEW_ISSUE_COMMENT].append(func)
            return func
        return decorator

    # 全量更新事件装饰器
    def on_update(self) -> Callable:
        def decorator(func: Callable) -> Callable:
            self.callbacks[EventType.ALL_UPDATES].append(func)
            return func
        return decorator

    # 轮询检测新事件
    def _poll_events(self):
        all_new_events = []
        # 检测新commit
        latest_commit = self.repo.get_commits()[0]
        if latest_commit.sha != self.latest_state["last_commit_sha"]:
            self.latest_state["last_commit_sha"] = latest_commit.sha
            for cb in self.callbacks[EventType.NEW_COMMIT]:
                cb(latest_commit)
            all_new_events.append({"type": EventType.NEW_COMMIT, "data": latest_commit})
        
        # 检测新issue评论,其他事件检测逻辑同理
        latest_comments = self.repo.get_issue_comments(sort="created", direction="desc", per_page=5)
        for comment in latest_comments:
            if comment.id > self.latest_state["last_issue_comment_id"]:
                for cb in self.callbacks[EventType.NEW_ISSUE_COMMENT]:
                    cb(comment)
                all_new_events.append({"type": EventType.NEW_ISSUE_COMMENT, "data": comment})
                if comment.id > self.latest_state["last_issue_comment_id"]:
                    self.latest_state["last_issue_comment_id"] = comment.id

        # 触发全局更新回调
        if all_new_events:
            for cb in self.callbacks[EventType.ALL_UPDATES]:
                cb(all_new_events)

    # 启动监听
    def run(self, poll_interval: int = 60):
        # poll_interval是轮询间隔,单位秒,不要设太短避免触发GitHub API限流
        while True:
            self._poll_events()
            time.sleep(poll_interval)
使用示例
# 初始化Repo对象
repo = Repo(repo_name="用户名/仓库名", github_token="你的GitHub Personal Access Token")

# 注册新commit回调
@repo.on_new_commit()
def handle_new_commit(commit):
    print(f"收到新commit: {commit.sha}, 提交者: {commit.commit.author.name}")

# 注册全局更新回调
@repo.on_update()
def handle_all_updates(events):
    print(f"收到{len(events)}条新变动")
    for event in events:
        print(f"变动类型: {event['type']}")

# 启动监听
repo.run(poll_interval=30)
优化建议
  • 轮询模式下注意控制请求频率,GitHub公开API无token时限流是每小时60次,带token时是每小时5000次,合理设置轮询间隔避免被限流
  • 如果需要更高的实时性,换成Webhook模式:在Repo类里加一个接口接收GitHub的Webhook推送,解析请求的事件类型直接触发对应回调即可,不需要轮询
  • 可以加错误重试、断点续传逻辑,程序重启后不需要重新拉取所有历史事件,从缓存的最新状态开始监听即可
  • 如果需要监听discussion事件,PyGitHub目前原生支持不好,可以直接调用GitHub GraphQL API获取discussion数据

内容的提问来源于stack exchange,提问作者Shivang Kakkar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 17:54:00