You've already forked GiteaToFeishuMsg
5.8 KiB
5.8 KiB
Gitea 到飞书 Webhook 中转服务设计
1. 概述
本服务作为 Gitea Webhook 和飞书机器人之间的中转层,接收 Gitea 发送的工单事件(创建、更新、关闭等),将其转换为更直观美观的飞书卡片消息,并转发给飞书群聊。
2. 系统架构
2.1 组件图
graph TD
A[Gitea] -->|发送 Webhook 事件| B(中转服务)
B -->|验证 & 解析| C{消息转换器}
C -->|生成飞书卡片| D[飞书 API 客户端]
D -->|POST 请求| E[飞书机器人]
E --> F[飞书群聊]
B --> G[日志存储]
B --> H[错误处理]
2.2 数据流
- Gitea 触发事件:用户在 Gitea 的 Kanban 中创建、更新或关闭工单。
- Webhook 发送:Gitea 向预设的中转服务 URL 发送 HTTP POST 请求,载荷为 JSON。
- 中转服务接收:Express 服务器在
/webhook/gitea端点接收请求。 - 验证与解析:验证请求签名(可选),解析 JSON 载荷。
- 消息转换:根据事件类型提取关键字段,映射为飞书卡片消息结构。
- 飞书 API 调用:使用飞书机器人的 Webhook URL 发送卡片消息。
- 响应与日志:记录成功/失败日志,返回适当 HTTP 状态码。
3. Gitea Webhook 数据结构
基于 Gitea 1.20+ 的 Webhook 文档,工单事件(Issue)的 JSON 示例:
{
"action": "opened",
"issue": {
"id": 123,
"number": 45,
"title": "工单标题",
"body": "工单描述",
"state": "open",
"created_at": "2025-12-02T05:00:00Z",
"updated_at": "2025-12-02T05:00:00Z",
"closed_at": null,
"user": {
"id": 1,
"login": "user1",
"full_name": "用户姓名"
},
"assignee": {
"id": 2,
"login": "user2",
"full_name": "指派给"
},
"labels": [
{"name": "bug", "color": "d73a4a"}
],
"milestone": {
"title": "里程碑"
}
},
"repository": {
"id": 1,
"name": "project",
"full_name": "org/project",
"html_url": "https://gitea.example.com/org/project"
},
"sender": {
"id": 1,
"login": "user1"
}
}
支持的事件类型:
opened:工单创建closed:工单关闭reopened:工单重新打开edited:工单编辑assigned:指派unassigned:取消指派labeled:添加标签unlabeled:移除标签
4. 飞书卡片消息格式
飞书卡片消息使用交互式卡片模板。基本结构:
{
"msg_type": "interactive",
"card": {
"config": {
"wide_screen_mode": true
},
"header": {
"title": {
"tag": "plain_text",
"content": "工单状态更新"
},
"template": "blue" // 根据状态变化颜色
},
"elements": [
{
"tag": "div",
"text": {
"tag": "lark_md",
"content": "**工单标题**:工单标题"
}
},
{
"tag": "div",
"text": {
"tag": "lark_md",
"content": "**状态**:打开"
}
},
{
"tag": "div",
"text": {
"tag": "lark_md",
"content": "**创建者**:用户姓名"
}
},
{
"tag": "div",
"text": {
"tag": "lark_md",
"content": "**优先级**:高"
}
},
{
"tag": "action",
"actions": [
{
"tag": "button",
"text": {
"tag": "plain_text",
"content": "查看工单"
},
"type": "primary",
"url": "https://gitea.example.com/org/project/issues/45"
}
]
}
]
}
}
5. 消息转换逻辑
5.1 事件类型映射
| Gitea 事件 | 飞书卡片标题 | 颜色模板 |
|---|---|---|
| opened | 新工单创建 | blue |
| closed | 工单关闭 | red |
| reopened | 工单重新打开 | orange |
| edited | 工单已编辑 | green |
| assigned | 工单已指派 | purple |
| unassigned | 工单取消指派 | grey |
5.2 字段提取
- 标题:
issue.title - 状态:
issue.state(open/closed) - 创建者:
issue.user.full_name或issue.user.login - 链接:
repository.html_url+/issues/+issue.number - 优先级:从
issue.labels中查找包含 "priority:" 的标签,或默认 "中"
5.3 转换规则
- 如果
action是opened,卡片标题为 "新工单创建"。 - 如果
action是closed,卡片标题为 "工单关闭",并显示关闭时间。 - 如果存在
assignee,添加 "指派给" 字段。 - 标签列表可显示为标签组(可选)。
6. 配置项
服务需要以下配置:
PORT:服务监听端口(默认 3000)FEISHU_WEBHOOK_URL:飞书机器人 Webhook URLGITEA_WEBHOOK_SECRET:Gitea Webhook 密钥(用于验证)LOG_LEVEL:日志级别(info, debug, error)
7. 部署说明
7.1 本地运行
npm install
npm start
7.2 Docker 部署
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "src/server.js"]
7.3 环境变量
在 .env 文件中设置:
PORT=3000
FEISHU_WEBHOOK_URL=https://open.feishu.cn/open-apis/bot/v2/hook/xxx
GITEA_WEBHOOK_SECRET=your_secret
8. 待办事项
- 收集需求并明确功能范围
- 设计系统架构和数据流
- 确定 Gitea webhook 数据结构
- 确定飞书机器人消息格式
- 设计消息转换逻辑
- 创建项目结构
- 实现 Express 服务器
- 实现 webhook 接收端点
- 实现消息转换器
- 实现飞书 API 调用
- 添加错误处理和日志
- 编写配置文件
- 编写部署说明
- 测试与验证