山东大学创新实训——AI智慧代码审查助手4.12
上一周里我把 FastAPI、Celery 和 GitProvider 粗粗串了一遍,结尾给自己立了个小目标:把 GitHub 侧从「注册到第一笔请求打进来」走通。
先说 GitHub 上要填的地址。路由并不是裸写在应用根路径上的,版本前缀来自配置项 api_v1_prefix,默认是 /api/v1,和 Settings 里的定义一致,读环境变量时也会覆盖默认值。
class Settings(BaseSettings):
app_env: str = "development"
api_v1_prefix: str = "/api/v1"
database_url: str = "mysql+pymysql://root:123456@localhost:3306/guardcode"
因此你在 GitHub 里配置的 Webhook URL,在本地直连后端时,完整路径应是 http://<主机>:8000/api/v1/webhooks/github。对应实现是 github_webhook 这个处理函数:路径片段 /webhooks/github 挂在路由器上,和 API_V1_PREFIX 拼起来就是上面这一条;返回 202 表示已接受,后面异步处理,避免 GitHub 因超时而反复重试。
@router.post(
"/webhooks/github",
response_model=ReviewTaskSummaryRead,
status_code=status.HTTP_202_ACCEPTED,
)
def github_webhook(
payload: GitHubWebhookPayload,
db: Session = Depends(get_db_session),
actor: str = Depends(get_actor),
) -> ReviewTaskSummaryRead:
task = create_review_task_from_github_webhook(db, payload, actor)
return serialize_review_task_summary(task)
GitHub 推过来的 JSON 里,课题关心的 opened、synchronize 会出现在 action 字段。我们用的 Pydantic 模型 GitHubWebhookPayload 显式包含了 action、repository 和 pull_request,和 PR 事件的主体结构对齐;以后若要在服务端只处理某几类 action,可以在这里加校验逻辑,而不必改路由签名。
class GitHubWebhookPayload(BaseModel):
action: str
repository: GitHubRepository
pull_request: GitHubPullRequest
环境变量方面,和 GitHub 相关的几项里,GITHUB_WEBHOOK_SECRET 要和控制台里为 Webhook 或 App 配置的 Secret 一致,后续做 X-Hub-Signature-256 校验时读的就是配置里的同一个值;GITHUB_TOKEN 留给拉 PR、发评论的 REST 调用;GIT_PROVIDER_MODE 在开发阶段可以先用 mock,不依赖真实令牌也能跑通流水线,需要测真实 diff 和评论时再切到 github。
GIT_PROVIDER_MODE=mock
GITHUB_TOKEN=
GITHUB_API_BASE=https://api.github.com
GITHUB_WEBHOOK_SECRET=changeme
这些键在代码侧对应 Settings 里的 git_provider_mode、github_token、github_api_base、github_webhook_secret,pydantic-settings 会从项目根或后端的 .env 加载,和 model_config 里写的 env_file=("../.env", ".env") 一致。
git_provider_mode: str = "mock"
github_token: str = ""
github_api_base: str = "https://api.github.com"
github_webhook_secret: str = "changeme"
当第一笔 Webhook 真正打到 github_webhook 时,业务入口是 create_review_task_from_github_webhook。我调试穿透是否成功时,最直观的就是看这里有没有执行下去:按仓库 full_name 找或建 Project 和 RepositoryBinding,再建 PullRequestSnapshot 和 ReviewTask,写一条 AuditLog 记录 webhook.received,最后 enqueue_review_task 把审查任务丢进 Celery。能在数据库里看到新任务、日志里有这条审计,就说明「GitHub 能推到你的机器、FastAPI 能解析、库能落盘」这一整段已经通了。
def create_review_task_from_github_webhook(
db: Session, payload: GitHubWebhookPayload, actor: str
) -> ReviewTask:
slug = payload.repository.full_name
project = db.scalar(select(Project).where(Project.slug == slug))
if project is None:
project = Project(name=payload.repository.name, slug=slug)
db.add(project)
db.flush()
binding = db.scalar(
select(RepositoryBinding).where(
RepositoryBinding.project_id == project.id,
RepositoryBinding.provider == "github",
RepositoryBinding.owner == payload.repository.owner.login,
RepositoryBinding.repo == payload.repository.name,
)
)
if binding is None:
binding = RepositoryBinding(
project=project,
provider="github",
owner=payload.repository.owner.login,
repo=payload.repository.name,
external_id=str(payload.repository.id or ""),
default_branch=payload.repository.default_branch,
)
db.add(binding)
db.flush()
snapshot = PullRequestSnapshot(
repository_binding=binding,
pr_number=payload.pull_request.number,
title=payload.pull_request.title,
author=payload.pull_request.user.login,
base_sha=payload.pull_request.base.sha,
head_sha=payload.pull_request.head.sha,
metadata_json=payload.model_dump(mode="json"),
diff_excerpt="Webhook received; diff will be fetched by the worker.",
)
db.add(snapshot)
db.flush()
task = ReviewTask(
pull_request_snapshot=snapshot,
status=ReviewTaskStatus.PENDING.value,
provider="github",
summary="等待审查流水线执行。",
)
db.add(task)
db.commit()
db.refresh(task)
db.add(
AuditLog(
action="webhook.received",
target_type="ReviewTask",
target_id=str(task.id),
actor=actor,
detail={"repository": slug, "pull_request": payload.pull_request.number},
)
)
db.commit()
enqueue_review_task(task.id)
return task
本地还有一个现实问题:GitHub 访问不到 localhost。我通常用内网穿透把本机 uvicorn 监听的端口暴露成公网 HTTPS,再把「穿透域名 + /api/v1/webhooks/github」填回 GitHub。若返回不是 202,我会先核对 URL 是否多写路径、服务是否在跑、穿透是否指到正确端口,再回头看 payload 是否被 Pydantic 拒掉(例如缺字段导致 422)。
收个尾。这一周的任务是在控制台里把 Webhook URL 和 Secret 配好,.env 与 Settings 对齐,用穿透验证请求能命中 github_webhook 并走进 create_review_task_from_github_webhook。代码里对签名的校验、对重复投递的幂,我将在下周完成,这样链路人能通、库里有据可查,之后再谈通了之后可信任、可统计,两者叠起来才贴近课题对 Webhook 可靠性的要求。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)