Files
GiteaToFeishuMsg/design.md
2025-12-02 13:27:52 +08:00

5.8 KiB
Raw Permalink Blame History

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 数据流

  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 示例:

{
  "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_nameissue.user.login
  • 链接repository.html_url + /issues/ + issue.number
  • 优先级:从 issue.labels 中查找包含 "priority:" 的标签,或默认 "中"

5.3 转换规则

  1. 如果 actionopened,卡片标题为 "新工单创建"。
  2. 如果 actionclosed,卡片标题为 "工单关闭",并显示关闭时间。
  3. 如果存在 assignee,添加 "指派给" 字段。
  4. 标签列表可显示为标签组(可选)。

6. 配置项

服务需要以下配置:

  • PORT:服务监听端口(默认 3000
  • FEISHU_WEBHOOK_URL:飞书机器人 Webhook URL
  • GITEA_WEBHOOK_SECRETGitea 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 调用
  • 添加错误处理和日志
  • 编写配置文件
  • 编写部署说明
  • 测试与验证