368 lines
9.3 KiB
Markdown
368 lines
9.3 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
|
||
```
|
||
|
||
该命令将安装以下依赖:
|
||
- express (5.x): Web框架和HTTP服务器
|
||
- axios (1.13.x): HTTP客户端库
|
||
- better-sqlite3 (9.x): SQLite数据库驱动
|
||
- dotenv (17.x): 环境变量加载
|
||
- express-rate-limit (8.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 直接运行
|
||
```bash
|
||
node index.js
|
||
```
|
||
|
||
输出示例:
|
||
```
|
||
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. 防无限循环
|
||
- 机器人识别防止自己操作的无限循环
|
||
- 熔断机制防止恶意攻击导致的无限请求
|
||
- 内存锁防止重复处理同一工单
|
||
|
||
## 代码结构
|
||
```
|
||
src/
|
||
config/ - 配置文件
|
||
env.js - 环境变量加载
|
||
mappings.js - 字段映射配置
|
||
db/ - 数据库相关
|
||
connection.js - 数据库连接
|
||
issueMap.js - 映射表操作
|
||
logic/ - 业务逻辑
|
||
converter.js - 数据转换
|
||
syncManager.js - Gitea->Jira同步
|
||
jiraSyncManager.js - Jira->Gitea同步
|
||
services/ - API服务
|
||
gitea.js - Gitea API客户端
|
||
jira.js - Jira API客户端
|
||
utils/ - 工具函数
|
||
logger.js - 日志模块
|
||
circuitBreaker.js - 熔断器
|
||
index.js - 主程序
|
||
mappings.json -映射表
|
||
```
|