394 lines
11 KiB
Markdown
394 lines
11 KiB
Markdown
# Gitea-Jira工单同步系统
|
||
|
||
## 部署指南
|
||
|
||
### 第一步:环境准备
|
||
|
||
#### 1.1 系统要求
|
||
- Node.js版本: 14.0.0或更高
|
||
- npm版本: 6.0.0或更高
|
||
- SQLite: 3.0或更高
|
||
|
||
#### 1.2 依赖安装
|
||
```bash
|
||
cd /path/to/gitea-jira-sync
|
||
npm install
|
||
```
|
||
|
||
该命令将安装以下依赖:
|
||
- hono (4.x): 轻量级Web框架
|
||
- @hono/node-server (1.x): Hono Node.js服务器适配器
|
||
- axios (1.13.x): HTTP客户端库
|
||
- better-sqlite3 (12.x): SQLite数据库驱动
|
||
- dotenv (17.x): 环境变量加载
|
||
- j2m (1.1.x): Markdown与Jira格式转换库
|
||
|
||
### 第二步:环境变量配置
|
||
|
||
#### 2.1 创建.env文件
|
||
```bash
|
||
cp .env.example .env
|
||
```
|
||
|
||
#### 2.2 配置SQLite数据库
|
||
```
|
||
SQLITE_PATH=./data/gitea_jira_sync.db
|
||
```
|
||
|
||
获取方法:
|
||
- SQLITE_PATH: SQLite数据库文件路径(默认./data/gitea_jira_sync.db)
|
||
|
||
注意: 数据库文件和表会自动创建,无需手动初始化
|
||
|
||
#### 2.3 配置Gitea信息
|
||
```
|
||
GITEA_URL=https://gitea.example.com
|
||
GITEA_TOKEN=your_gitea_api_token
|
||
GITEA_BOT_ID=your_bot_user_id
|
||
GITEA_BOT_NAME=your_bot_username
|
||
```
|
||
|
||
获取方法:
|
||
- GITEA_URL: Gitea服务器地址
|
||
- GITEA_TOKEN: 登录Gitea后,访问设置->应用->创建新令牌(api_token)
|
||
- GITEA_BOT_ID: 登录机器人账号,访问API /api/v1/user 获取id字段
|
||
- GITEA_BOT_NAME: 机器人的用户名
|
||
|
||
#### 2.4 配置Jira信息
|
||
```
|
||
JIRA_URL=https://jira.example.com
|
||
JIRA_USERNAME=your_jira_username
|
||
JIRA_PASSWORD=your_jira_password_or_pat
|
||
JIRA_PROJECT_ID_1=10000
|
||
JIRA_PROJECT_KEY_1=TEST
|
||
JIRA_BOT_ID=jira_bot_id
|
||
JIRA_BOT_NAME=jira_bot_name
|
||
```
|
||
|
||
获取方法:
|
||
- JIRA_URL: Jira服务器地址
|
||
- JIRA_USERNAME: Jira用户名
|
||
- JIRA_PASSWORD: Jira密码或个人访问令牌(推荐使用PAT)
|
||
- JIRA_PROJECT_ID_1: 访问/rest/api/2/project获取id
|
||
- JIRA_PROJECT_KEY_1: 项目的英文标识符(如TEST、PROJ等)
|
||
- JIRA_BOT_ID: 机器人账号的ID或Key
|
||
- JIRA_BOT_NAME: 机器人显示名称
|
||
|
||
#### 2.5 配置Webhook签名密钥
|
||
```
|
||
GITEA_WEBHOOK_SECRET=your_webhook_secret_key
|
||
JIRA_WEBHOOK_SECRET=your_jira_webhook_secret
|
||
```
|
||
|
||
#### 2.6 配置熔断器参数(可选)
|
||
```
|
||
CIRCUIT_BREAKER_LIMIT=20
|
||
CIRCUIT_BREAKER_WINDOW=10000
|
||
DEBUG_MODE=false
|
||
```
|
||
|
||
参数说明:
|
||
- CIRCUIT_BREAKER_LIMIT: 时间窗口内允许的最大请求数(默认20)
|
||
- CIRCUIT_BREAKER_WINDOW: 时间窗口大小,单位毫秒(默认10000ms=10秒)
|
||
- DEBUG_MODE: 是否启用调试模式(默认false,启用后熔断器不会强制退出)
|
||
|
||
### 第三步:映射配置
|
||
|
||
#### 3.1 编辑mappings.json
|
||
配置需要同步的仓库及其字段映射
|
||
目前,已经开发了图形化配置工具,无需再手动配置,但是遇到特殊情况(比如json损坏、扫不出流转状态和sprint还是要手动,实测发生概率不大)
|
||
|
||
#### 3.2 获取Jira映射ID
|
||
|
||
**获取Priority ID**:
|
||
```bash
|
||
curl -u username:password https://jira.example.com/rest/api/2/priority
|
||
```
|
||
返回JSON中查看id字段
|
||
|
||
**获取Issue Type ID**:
|
||
```bash
|
||
curl -u username:password https://jira.example.com/rest/api/2/issuetype
|
||
```
|
||
返回JSON中查看id字段
|
||
|
||
**获取Sprint ID**:
|
||
```bash
|
||
curl -u username:password https://jira.example.com/rest/api/2/issue/TEST-1
|
||
```
|
||
搜索customfield_10105字段,格式:[id=37,name=Sprint Name,...]
|
||
|
||
**获取Transition ID**:
|
||
```bash
|
||
curl -u username:password https://jira.example.com/rest/api/2/issue/TEST-1/transitions
|
||
```
|
||
查看transitions数组中的id字段
|
||
|
||
### 第四步:启动服务
|
||
|
||
#### 4.1 使用PM2运行
|
||
```bash
|
||
npm install -g pm2
|
||
pm2 start index.js --name gitea-jira-sync
|
||
```
|
||
|
||
输出示例:
|
||
```
|
||
Server running on http://localhost:3000
|
||
Database initialized: issue_mapping table ready
|
||
Webhook endpoints ready:
|
||
POST /webhook/gitea
|
||
POST /webhook/jira
|
||
```
|
||
|
||
#### 4.2 后台运行(使用pm2)
|
||
```bash
|
||
npm install -g pm2
|
||
pm2 start index.js --name "gitea-jira-sync"
|
||
pm2 save
|
||
pm2 startup
|
||
```
|
||
|
||
#### 4.3 使用systemd服务(Linux)
|
||
创建/etc/systemd/system/gitea-jira-sync.service:
|
||
```ini
|
||
[Unit]
|
||
Description=Gitea-Jira Sync Service
|
||
After=network.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
User=your_user
|
||
WorkingDirectory=/path/to/gitea-jira-sync
|
||
ExecStart=/usr/bin/node index.js
|
||
Restart=always
|
||
RestartSec=10
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
启动服务:
|
||
```bash
|
||
sudo systemctl start gitea-jira-sync
|
||
sudo systemctl enable gitea-jira-sync
|
||
```
|
||
|
||
### 第五步:配置Webhook
|
||
|
||
#### 5.1 Gitea端配置
|
||
|
||
1. 进入仓库设置 -> 设置 -> Web Hooks -> Gitea
|
||
2. 点击"添加Webhook"
|
||
3. 填写以下信息:
|
||
- 推送地址: http://your_server:3000/webhook/gitea
|
||
- HTTP方法: POST
|
||
- POST内容类型: application/json
|
||
- 密钥: 与.env中GITEA_WEBHOOK_SECRET一致
|
||
- 触发事件: Issue和Comment(必选)
|
||
|
||
4. 测试Webhook确保连接正常
|
||
|
||
#### 5.2 Jira端配置
|
||
|
||
1. 访问Jira管理界面 -> 系统 -> Webhooks
|
||
2. 点击"创建webhook"
|
||
3. 填写以下信息:
|
||
- 名称: Gitea Sync Webhook
|
||
- URL: http://your_server:3000/webhook/jira
|
||
- 事件类型: jira:issue_created, jira:issue_updated, jira:issue_deleted
|
||
- 认证: Basic auth或Bearer token(与.env配置一致)
|
||
|
||
4. 点击"创建"
|
||
|
||
### 第六步:验证部署
|
||
|
||
#### 6.1 检查服务状态
|
||
```bash
|
||
curl http://localhost:3000/health
|
||
```
|
||
|
||
预期输出: 200状态码,表示服务运行正常
|
||
|
||
#### 6.2 查看日志
|
||
```bash
|
||
tail -f logs/$(date +%Y-%m-%d).log
|
||
```
|
||
|
||
观察同步操作的日志记录
|
||
|
||
#### 6.3 测试同步
|
||
|
||
**测试Gitea->Jira**:
|
||
1. 在Gitea中新建工单
|
||
2. 观察logs中出现同步日志
|
||
3. 检查Jira中是否创建了对应问题
|
||
|
||
**测试Jira->Gitea**:
|
||
1. 在Jira中新建问题
|
||
2. 观察logs中出现同步日志
|
||
3. 检查Gitea中是否创建了对应工单
|
||
|
||
## 使用指南
|
||
|
||
### 场景一:新建工单自动同步
|
||
|
||
**Gitea新建工单**:
|
||
1. 进入Gitea仓库
|
||
2. 点击Issues -> 新建Issue
|
||
3. 填写标题、描述、指派人、标签(优先级、类型)、里程碑
|
||
4. 点击提交
|
||
5. 系统自动在Jira创建对应问题
|
||
6. Gitea工单中添加评论,包含Jira问题链接
|
||
|
||
**Jira新建问题**:
|
||
1. 进入Jira项目
|
||
2. 点击创建按钮
|
||
3. 填写摘要、描述、经办人、优先级、问题类型、迭代
|
||
4. 点击创建
|
||
5. 系统自动在Gitea创建对应工单
|
||
6. Jira问题中添加评论,包含Gitea工单链接
|
||
|
||
### 场景二:更新工单字段
|
||
|
||
**修改优先级**:
|
||
1. 在任何一端修改优先级
|
||
2. 系统自动更新对方平台的对应标签
|
||
3. 对应标签根据mappings.js中的优先级映射进行转换
|
||
|
||
**修改工单类型**:
|
||
1. 在任何一端修改工单类型
|
||
2. 系统自动更新对方平台的对应标签
|
||
3. 对应标签根据mappings.js中的类型映射进行转换
|
||
|
||
**修改迭代/里程碑**:
|
||
1. 在任何一端修改迭代或里程碑
|
||
2. 系统自动更新对方平台
|
||
3. 里程碑名称与Sprint ID根据mappings.js进行映射
|
||
|
||
**重开操作**:
|
||
1. 在Gitea关闭工单 -> Jira问题自动转至完成状态
|
||
2. 在Jira完成问题 -> Gitea工单自动关闭
|
||
3. 重开操作会将对方平台状态改为处理中/打开
|
||
|
||
### 场景三:跨平台手动同步
|
||
|
||
**使用/resync命令**:
|
||
1. 在Gitea或Jira工单评论中输入`/resync`
|
||
2. 系统会强制重新同步所有字段
|
||
3. 如果对方平台不存在对应工单,会自动创建
|
||
4. 如果已存在,会更新所有字段
|
||
|
||
**#不同步标记**:
|
||
1. 在工单标题中添加`#不同步`标记
|
||
2. 该工单不会自动同步到对方平台
|
||
3. 使用`/resync`命令可以强制同步带有`#不同步`标记的工单
|
||
|
||
### 场景四:类型过滤
|
||
|
||
**类型未配置的工单不同步**:
|
||
1. 如果工单的类型标签在mappings.json中没有配置对应关系
|
||
2. 且mappings.json中没有设置`defaultType`
|
||
3. 该工单不会被同步,日志会记录跳过原因
|
||
|
||
### 启用DEBUG模式
|
||
|
||
用于开发和故障诊断:
|
||
|
||
```bash
|
||
DEBUG_MODE=true node index.js
|
||
```
|
||
|
||
DEBUG模式下:
|
||
- 打印所有webhook payload
|
||
- 打印API调用详情
|
||
- 跳过熔断器强制退出
|
||
- 输出详细的转换过程
|
||
|
||
## 性能优化
|
||
|
||
### 1. 连接池配置
|
||
- axios客户端使用keep-alive连接
|
||
- 自动复用TCP连接减少握手开销
|
||
|
||
### 2. 数据库优化
|
||
- SQLite支持并发访问和连接优化
|
||
- 映射表创建了repo_key、gitea_id、jira_key索引加速查询
|
||
- 支持事务和完整的ACID特性
|
||
|
||
### 3. 异步处理
|
||
- 日志写入使用异步队列
|
||
- Webhook响应立即返回,实际处理异步进行
|
||
|
||
### 4. 缓存策略
|
||
- 标签、优先级、工单类型信息在mappings.json中缓存
|
||
- 避免每次处理都请求Jira API
|
||
|
||
## 安全考虑
|
||
|
||
### 1. Webhook签名验证
|
||
- 所有webhook请求都经过HMAC签名验证
|
||
- 未通过验证的请求被直接拒绝
|
||
|
||
### 2. API认证
|
||
- Gitea使用token认证
|
||
- Jira支持Basic Auth和PAT认证
|
||
|
||
### 3. 敏感信息保护
|
||
- 环境变量不在代码中硬编码
|
||
- 日志不记录password和token字段
|
||
- SQLite数据库文件应该在安全位置存储
|
||
|
||
### 4. 防无限循环
|
||
- 机器人识别防止自己操作的无限循环
|
||
- 熔断机制防止恶意攻击导致的无限请求
|
||
- 内存锁防止重复处理同一工单
|
||
|
||
## 代码结构
|
||
|
||
```
|
||
gitea-jira-sync/
|
||
├── index.js - 主程序(Hono应用入口)
|
||
├── mappings.json - 映射配置文件
|
||
├── package.json - 项目依赖配置
|
||
├── README.md - 本文档
|
||
├── how-to-use.md - 使用指南
|
||
├── data/ - 数据目录
|
||
├── logs/ - 日志目录
|
||
├── public/ - 前端资源目录
|
||
│ ├── app.js - 配置编辑器应用脚本
|
||
│ ├── dashboard-app.js - 仪表板应用脚本
|
||
│ ├── dashboard.html - 仪表板页面
|
||
│ ├── editor.html - 配置编辑器页面
|
||
│ └── error.html - 错误页面
|
||
└── src/
|
||
├── config/ - 配置模块
|
||
│ ├── env.js - 环境变量加载
|
||
│ └── mappings.js - 字段映射配置管理
|
||
├── db/ - 数据库模块
|
||
│ ├── connection.js - 数据库连接管理
|
||
│ └── issueMap.js - 工单映射表操作
|
||
├── logic/ - 业务逻辑模块
|
||
│ ├── converter.js - 字段数据转换
|
||
│ ├── syncManager.js - Gitea->Jira同步管理
|
||
│ └── jiraSyncManager.js - Jira->Gitea同步管理
|
||
├── routes/ - 路由模块
|
||
│ └── control.js - 配置编辑器路由
|
||
├── services/ - 第三方API服务
|
||
│ ├── gitea.js - Gitea API客户端
|
||
│ └── jira.js - Jira API客户端
|
||
└── utils/ - 工具函数
|
||
├── logger.js - 日志模块
|
||
└── circuitBreaker.js - 熔断器实现
|
||
```
|
||
|
||
## 技术栈
|
||
|
||
- **Web框架**: Hono 4.x(轻量级、高性能)
|
||
- **服务器**: Node.js + @hono/node-server
|
||
- **数据库**: SQLite 3.x(better-sqlite3驱动)
|
||
- **HTTP客户端**: Axios
|
||
- **环境管理**: dotenv
|
||
- **格式转换**: j2m(Markdown↔Jira格式)
|
||
- **前端**: Vanilla JS(无框架依赖)
|