You've already forked GiteaToFeishuMsg
initProject
This commit is contained in:
237
design.md
Normal file
237
design.md
Normal file
@@ -0,0 +1,237 @@
|
||||
# Gitea 到飞书 Webhook 中转服务设计
|
||||
|
||||
## 1. 概述
|
||||
|
||||
本服务作为 Gitea Webhook 和飞书机器人之间的中转层,接收 Gitea 发送的工单事件(创建、更新、关闭等),将其转换为更直观美观的飞书卡片消息,并转发给飞书群聊。
|
||||
|
||||
## 2. 系统架构
|
||||
|
||||
### 2.1 组件图
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Gitea] -->|发送 Webhook 事件| B(中转服务)
|
||||
B -->|验证 & 解析| C{消息转换器}
|
||||
C -->|生成飞书卡片| D[飞书 API 客户端]
|
||||
D -->|POST 请求| E[飞书机器人]
|
||||
E --> F[飞书群聊]
|
||||
B --> G[日志存储]
|
||||
B --> H[错误处理]
|
||||
```
|
||||
|
||||
### 2.2 数据流
|
||||
|
||||
1. **Gitea 触发事件**:用户在 Gitea 的 Kanban 中创建、更新或关闭工单。
|
||||
2. **Webhook 发送**:Gitea 向预设的中转服务 URL 发送 HTTP POST 请求,载荷为 JSON。
|
||||
3. **中转服务接收**:Express 服务器在 `/webhook/gitea` 端点接收请求。
|
||||
4. **验证与解析**:验证请求签名(可选),解析 JSON 载荷。
|
||||
5. **消息转换**:根据事件类型提取关键字段,映射为飞书卡片消息结构。
|
||||
6. **飞书 API 调用**:使用飞书机器人的 Webhook URL 发送卡片消息。
|
||||
7. **响应与日志**:记录成功/失败日志,返回适当 HTTP 状态码。
|
||||
|
||||
## 3. Gitea Webhook 数据结构
|
||||
|
||||
基于 Gitea 1.20+ 的 Webhook 文档,工单事件(Issue)的 JSON 示例:
|
||||
|
||||
```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. 飞书卡片消息格式
|
||||
|
||||
飞书卡片消息使用交互式卡片模板。基本结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"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 转换规则
|
||||
|
||||
1. 如果 `action` 是 `opened`,卡片标题为 "新工单创建"。
|
||||
2. 如果 `action` 是 `closed`,卡片标题为 "工单关闭",并显示关闭时间。
|
||||
3. 如果存在 `assignee`,添加 "指派给" 字段。
|
||||
4. 标签列表可显示为标签组(可选)。
|
||||
|
||||
## 6. 配置项
|
||||
|
||||
服务需要以下配置:
|
||||
|
||||
- `PORT`:服务监听端口(默认 3000)
|
||||
- `FEISHU_WEBHOOK_URL`:飞书机器人 Webhook URL
|
||||
- `GITEA_WEBHOOK_SECRET`:Gitea Webhook 密钥(用于验证)
|
||||
- `LOG_LEVEL`:日志级别(info, debug, error)
|
||||
|
||||
## 7. 部署说明
|
||||
|
||||
### 7.1 本地运行
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
### 7.2 Docker 部署
|
||||
|
||||
```dockerfile
|
||||
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` 文件中设置:
|
||||
|
||||
```env
|
||||
PORT=3000
|
||||
FEISHU_WEBHOOK_URL=https://open.feishu.cn/open-apis/bot/v2/hook/xxx
|
||||
GITEA_WEBHOOK_SECRET=your_secret
|
||||
```
|
||||
|
||||
## 8. 待办事项
|
||||
|
||||
- [x] 收集需求并明确功能范围
|
||||
- [x] 设计系统架构和数据流
|
||||
- [x] 确定 Gitea webhook 数据结构
|
||||
- [x] 确定飞书机器人消息格式
|
||||
- [x] 设计消息转换逻辑
|
||||
- [ ] 创建项目结构
|
||||
- [ ] 实现 Express 服务器
|
||||
- [ ] 实现 webhook 接收端点
|
||||
- [ ] 实现消息转换器
|
||||
- [ ] 实现飞书 API 调用
|
||||
- [ ] 添加错误处理和日志
|
||||
- [ ] 编写配置文件
|
||||
- [ ] 编写部署说明
|
||||
- [ ] 测试与验证
|
||||
Reference in New Issue
Block a user