|
@@ -0,0 +1,772 @@
|
|
|
|
|
+#!/bin/bash
|
|
|
|
|
+
|
|
|
|
|
+# ============================================================================
|
|
|
|
|
+# 禅道 Bug 追踪模块 - DEV 开发环境专用版本
|
|
|
|
|
+# ============================================================================
|
|
|
|
|
+# ⚠️ 重要提示:
|
|
|
|
|
+# 此文件仅供 Jenkinsfile.dev 使用
|
|
|
|
|
+# Jenkinsfile.release 严禁使用此文件,必须使用 zentao_dev.sh
|
|
|
|
|
+#
|
|
|
|
|
+# 功能说明:
|
|
|
|
|
+# 1. 从 Git 提交历史中提取 Bug 修复信息
|
|
|
|
|
+# 2. 调用禅道 API 自动更新 Bug 状态为 "resolved"
|
|
|
|
|
+# 3. 发送飞书(Lark)通知 - 每个 Bug 单独发送绿色卡片
|
|
|
|
|
+# 4. 发送飞书版本发布汇总通知 - 蓝色卡片汇总所有已解决Bug
|
|
|
|
|
+# 5. 发送 Telegram 汇总通知
|
|
|
|
|
+#
|
|
|
|
|
+# 使用场景:
|
|
|
|
|
+# - dev 环境: 每次代码推送自动执行
|
|
|
|
|
+# - 分析范围: 从上次成功构建到当前 HEAD 的所有提交
|
|
|
|
|
+# - 自动更新: 将 active/wait 状态的 Bug 更新为 resolved
|
|
|
|
|
+# - 即时通知: 每解决一个 Bug 立即发送飞书通知
|
|
|
|
|
+#
|
|
|
|
|
+# 环境隔离:
|
|
|
|
|
+# ✅ 仅用于开发环境 (Jenkinsfile.dev)
|
|
|
|
|
+# ❌ 不得用于生产发布 (Jenkinsfile.release)
|
|
|
|
|
+# ============================================================================
|
|
|
|
|
+
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+# 配置部分
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+# ⚠️ 重要提示:
|
|
|
|
|
+# 所有配置项必须从 Jenkinsfile 的 environment 部分传入
|
|
|
|
|
+# 此脚本不包含任何硬编码配置,确保配置集中管理
|
|
|
|
|
+#
|
|
|
|
|
+# 必需的环境变量:
|
|
|
|
|
+# - ZENTAO_PRODUCT_ID: 禅道产品 ID
|
|
|
|
|
+# - ZENTAO_API_URL: 禅道 API 地址
|
|
|
|
|
+# - ZENTAO_BUG_BASE_URL: 禅道 Bug 详情页基础 URL
|
|
|
|
|
+# - COMMIT_BASE_URL: Git 提交详情页基础 URL
|
|
|
|
|
+# - LARK_WEBHOOK_URL: Lark Webhook URL
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+# 验证必需的环境变量
|
|
|
|
|
+if [ -z "${ZENTAO_PRODUCT_ID}" ] || [ -z "${ZENTAO_API_URL}" ] ||
|
|
|
|
|
+ [ -z "${ZENTAO_BUG_BASE_URL}" ] || [ -z "${COMMIT_BASE_URL}" ] ||
|
|
|
|
|
+ [ -z "${LARK_WEBHOOK_URL}" ]; then
|
|
|
|
|
+ echo "错误: 缺少必需的环境变量配置" >&2
|
|
|
|
|
+ echo "请确保在 Jenkinsfile 的 environment 部分设置了所有必需变量" >&2
|
|
|
|
|
+ exit 1
|
|
|
|
|
+fi
|
|
|
|
|
+
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+# 函数: 发送单个 Bug 解决通知到飞书
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+# 参数:
|
|
|
|
|
+# $1: bug_id - Bug ID (例如: 2262)
|
|
|
|
|
+# $2: bug_title - Bug 标题 (例如: "登录页面404错误")
|
|
|
|
|
+# $3: old_status - 旧状态 (例如: "active")
|
|
|
|
|
+# $4: commit_info - 提交信息 (例如: "[abc123] 修复登录问题")
|
|
|
|
|
+# $5: bug_url - Bug 详情页 URL
|
|
|
|
|
+#
|
|
|
|
|
+# 功能:
|
|
|
|
|
+# 发送一个绿色的飞书卡片,显示单个 Bug 的解决信息,包含查看详情按钮
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+send_bug_resolved_notification() {
|
|
|
|
|
+ local bug_id="$1"
|
|
|
|
|
+ local bug_title="$2"
|
|
|
|
|
+ local old_status="$3"
|
|
|
|
|
+ local commit_info="$4"
|
|
|
|
|
+ local bug_url="$5"
|
|
|
|
|
+ local code_url="$6"
|
|
|
|
|
+ # 发送 POST 请求到飞书 Webhook
|
|
|
|
|
+ curl -s -X POST "${LARK_WEBHOOK_URL}" \
|
|
|
|
|
+ -H "Content-Type: application/json" \
|
|
|
|
|
+ -d "{
|
|
|
|
|
+ \"msg_type\": \"interactive\",
|
|
|
|
|
+ \"card\": {
|
|
|
|
|
+ \"header\": {
|
|
|
|
|
+ \"title\": {
|
|
|
|
|
+ \"tag\": \"plain_text\",
|
|
|
|
|
+ \"content\": \"🐛 pwtk管端端Bug更新\"
|
|
|
|
|
+ },
|
|
|
|
|
+ \"template\": \"green\"
|
|
|
|
|
+ },
|
|
|
|
|
+ \"elements\": [
|
|
|
|
|
+ {
|
|
|
|
|
+ \"tag\": \"div\",
|
|
|
|
|
+ \"text\": {
|
|
|
|
|
+ \"tag\": \"lark_md\",
|
|
|
|
|
+ \"content\": \"**Bug #${bug_id}**: ${bug_title}\"
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ \"tag\": \"action\",
|
|
|
|
|
+ \"actions\": [
|
|
|
|
|
+ {
|
|
|
|
|
+ \"tag\": \"button\",
|
|
|
|
|
+ \"text\": {
|
|
|
|
|
+ \"tag\": \"plain_text\",
|
|
|
|
|
+ \"content\": \"查看代码\"
|
|
|
|
|
+ },
|
|
|
|
|
+ \"type\": \"primary\",
|
|
|
|
|
+ \"url\": \"${code_url}\"
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ }" >/dev/null
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+# 函数: 发送版本发布汇总通知到飞书
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+# 参数:
|
|
|
|
|
+# $1: previous_tag - 上一个版本标签 (例如: "v1.2.30" 或 "dev")
|
|
|
|
|
+# $2: current_tag - 当前版本标签 (例如: "v1.2.31" 或 "abc123")
|
|
|
|
|
+# $3: resolved_count - 已解决的 Bug 数量
|
|
|
|
|
+# $4: resolved_bugs - 已解决的 Bug 列表 (格式: "bug_info|bug_url" 每行一个)
|
|
|
|
|
+#
|
|
|
|
|
+# 功能:
|
|
|
|
|
+# 发送一个蓝色的飞书卡片,汇总本次发布解决的所有 Bug
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+send_release_summary_notification() {
|
|
|
|
|
+ local previous_tag="$1"
|
|
|
|
|
+ local current_tag="$2"
|
|
|
|
|
+ local resolved_count="$3"
|
|
|
|
|
+ local resolved_bugs="$4"
|
|
|
|
|
+
|
|
|
|
|
+ # 构建已解决 Bug 链接列表
|
|
|
|
|
+ local resolved_links=""
|
|
|
|
|
+ if [ -n "$resolved_bugs" ]; then
|
|
|
|
|
+ # 逐行读取 Bug 信息,格式化为 Markdown 链接
|
|
|
|
|
+ while IFS='|' read -r bug_info bug_url; do
|
|
|
|
|
+ if [ -n "$bug_info" ]; then
|
|
|
|
|
+ resolved_links="${resolved_links}• [${bug_info}](${bug_url})\\n"
|
|
|
|
|
+ fi
|
|
|
|
|
+ done <<<"$resolved_bugs"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 构建完整消息内容
|
|
|
|
|
+ local content="**版本**: ${previous_tag} → ${current_tag}\\n\\n"
|
|
|
|
|
+
|
|
|
|
|
+ if [ ${resolved_count} -gt 0 ]; then
|
|
|
|
|
+ content="${content}**已解决Bug** (${resolved_count}个):\\n${resolved_links}"
|
|
|
|
|
+ else
|
|
|
|
|
+ content="${content}**本次发布未解决Bug**"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 发送 POST 请求到飞书 Webhook
|
|
|
|
|
+ curl -s -X POST "${LARK_WEBHOOK_URL}" \
|
|
|
|
|
+ -H "Content-Type: application/json" \
|
|
|
|
|
+ -d "{
|
|
|
|
|
+ \"msg_type\": \"interactive\",
|
|
|
|
|
+ \"card\": {
|
|
|
|
|
+ \"header\": {
|
|
|
|
|
+ \"title\": {
|
|
|
|
|
+ \"tag\": \"plain_text\",
|
|
|
|
|
+ \"content\": \"🚀 pwtk管端端版本发布\"
|
|
|
|
|
+ },
|
|
|
|
|
+ \"template\": \"blue\"
|
|
|
|
|
+ },
|
|
|
|
|
+ \"elements\": [
|
|
|
|
|
+ {
|
|
|
|
|
+ \"tag\": \"div\",
|
|
|
|
|
+ \"text\": {
|
|
|
|
|
+ \"tag\": \"lark_md\",
|
|
|
|
|
+ \"content\": \"${content}\"
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ }" >/dev/null
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+# 函数: 禅道 Bug 追踪主流程
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+# 参数:
|
|
|
|
|
+# $1: start_ref - 起始 Git 引用 (例如: "HEAD~10" 或 "v1.2.30")
|
|
|
|
|
+# $2: end_ref - 结束 Git 引用 (例如: "HEAD" 或 "v1.2.31")
|
|
|
|
|
+# $3: version_info - 版本信息 (例如: "dev (abc123)" 或 "v1.2.30 → v1.2.31")
|
|
|
|
|
+# $4: update_status - 是否更新禅道状态 ("true"=更新, "false"=只汇总)
|
|
|
|
|
+#
|
|
|
|
|
+# 功能:
|
|
|
|
|
+# 1. 从 Git 提交历史中提取符合格式的 Bug 修复 (fix:2262, fix-2262, fix: 2262 2265)
|
|
|
|
|
+# 2. 查询禅道获取 Bug 状态和标题
|
|
|
|
|
+# 3. 如果 update_status=true,调用禅道 API 更新 Bug 状态为 "resolved"
|
|
|
|
|
+# 4. 发送飞书通知 (每个 Bug 单独发送 + 最后发送汇总)
|
|
|
|
|
+# 5. 发送 Telegram 汇总通知
|
|
|
|
|
+#
|
|
|
|
|
+# 提交格式支持:
|
|
|
|
|
+# - fix:2262 修复登录问题
|
|
|
|
|
+# - fix-2262 修复登录问题
|
|
|
|
|
+# - fix: 2262 修复登录问题
|
|
|
|
|
+# - fix: 2262 2265 修复多个问题 (一次提交修复多个 Bug)
|
|
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
|
|
+process_zentao_bugs() {
|
|
|
|
|
+ local start_ref="$1"
|
|
|
|
|
+ local end_ref="$2"
|
|
|
|
|
+ local version_info="$3"
|
|
|
|
|
+ local update_status="${4:-false}" # 默认为 false,只汇总不更新
|
|
|
|
|
+
|
|
|
|
|
+ # 输出开始信息
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "=============== 禅道 Bug 追踪开始 ==============="
|
|
|
|
|
+ log_message "分析范围: ${start_ref}..${end_ref}"
|
|
|
|
|
+ log_message "版本信息: ${version_info}"
|
|
|
|
|
+ log_message "更新禅道状态: ${update_status}"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 初始化 bug 列表关联数组
|
|
|
|
|
+ # 格式: BUG_MAP[bug_id] = "commit_hash|author|message\ncommit_hash|author|message"
|
|
|
|
|
+ declare -A BUG_MAP
|
|
|
|
|
+
|
|
|
|
|
+ # 获取所有符合格式的提交 (保存到变量以避免管道子shell问题)
|
|
|
|
|
+ # 格式: commit_hash|author|subject
|
|
|
|
|
+ COMMITS=$(git log "${start_ref}..${end_ref}" --pretty=format:"%h|%an|%s")
|
|
|
|
|
+
|
|
|
|
|
+ # 遍历每个提交,提取 Bug ID
|
|
|
|
|
+ while IFS='|' read -r commit_hash author commit_message; do
|
|
|
|
|
+ # 检查提交信息是否包含 fix: 或 fix- 格式
|
|
|
|
|
+ if echo "$commit_message" | grep -qE "fix[:-]\s*[0-9]"; then
|
|
|
|
|
+ # 提取所有 Bug ID (支持多个 Bug ID,用空格分隔)
|
|
|
|
|
+ # 例如: "fix: 2262 2265" 提取出 "2262 2265"
|
|
|
|
|
+ # 步骤1: 提取 fix: 或 fix- 后面的所有数字
|
|
|
|
|
+ # 步骤2: 移除 fix: 或 fix-
|
|
|
|
|
+ # 步骤3: 使用 xargs 自动trim前后空格
|
|
|
|
|
+ bug_ids=$(echo "$commit_message" | grep -oE "fix[:-]\s*([0-9]+(\s+[0-9]+)*)" | sed -E 's/fix[:-]//' | xargs)
|
|
|
|
|
+
|
|
|
|
|
+ if [ -n "$bug_ids" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "发现 Bug 修复: [$commit_hash] $author - $commit_message"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 分割多个 Bug ID,逐个处理
|
|
|
|
|
+ for bug_id in $bug_ids; do
|
|
|
|
|
+ if [ -n "$bug_id" ]; then
|
|
|
|
|
+ # 存储到关联数组 (如果已存在则追加,支持一个 Bug 多次提交修复)
|
|
|
|
|
+ if [ -n "${BUG_MAP[$bug_id]}" ]; then
|
|
|
|
|
+ BUG_MAP[$bug_id]="${BUG_MAP[$bug_id]}
|
|
|
|
|
+${commit_hash}|${author}|${commit_message}"
|
|
|
|
|
+ else
|
|
|
|
|
+ BUG_MAP[$bug_id]="${commit_hash}|${author}|${commit_message}"
|
|
|
|
|
+ fi
|
|
|
|
|
+ fi
|
|
|
|
|
+ done
|
|
|
|
|
+ fi
|
|
|
|
|
+ fi
|
|
|
|
|
+ done <<<"$COMMITS"
|
|
|
|
|
+
|
|
|
|
|
+ # 统计发现的 Bug 数量
|
|
|
|
|
+ BUG_COUNT=${#BUG_MAP[@]}
|
|
|
|
|
+
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "共发现 ${BUG_COUNT} 个 Bug"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 如果没有发现 Bug,直接返回
|
|
|
|
|
+ if [ $BUG_COUNT -eq 0 ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "本次构建未发现符合格式的 Bug 修复"
|
|
|
|
|
+ log_message "=============== 禅道 Bug 追踪结束 ==============="
|
|
|
|
|
+ fi
|
|
|
|
|
+ return 0
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 获取禅道 API Token
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "正在获取禅道 API Token..."
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 调用禅道登录接口获取 Token
|
|
|
|
|
+ ZENTAO_TOKEN_RESPONSE=$(curl -s -X POST "${ZENTAO_API_URL}/tokens" \
|
|
|
|
|
+ -H "Content-Type: application/json" \
|
|
|
|
|
+ -d "{\"account\":\"${ZENTAO_USERNAME}\",\"password\":\"${ZENTAO_PASSWORD}\"}")
|
|
|
|
|
+
|
|
|
|
|
+ # 从响应中提取 Token
|
|
|
|
|
+ ZENTAO_TOKEN=$(echo "$ZENTAO_TOKEN_RESPONSE" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
|
|
|
|
|
+
|
|
|
|
|
+ # 检查 Token 是否获取成功
|
|
|
|
|
+ if [ -z "$ZENTAO_TOKEN" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "警告: 无法获取禅道 Token,仅生成链接列表"
|
|
|
|
|
+ log_message "响应: ${ZENTAO_TOKEN_RESPONSE}"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # Token 获取失败,只生成链接列表不更新状态
|
|
|
|
|
+ BUG_LINKS=""
|
|
|
|
|
+ for bug_id in $(echo "${!BUG_MAP[@]}" | tr ' ' '\n' | sort -n); do
|
|
|
|
|
+ COMMIT_INFO=""
|
|
|
|
|
+ # 遍历该 Bug 的所有相关提交
|
|
|
|
|
+ while IFS= read -r commit_line; do
|
|
|
|
|
+ commit_hash=$(echo "$commit_line" | cut -d'|' -f1)
|
|
|
|
|
+ author=$(echo "$commit_line" | cut -d'|' -f2)
|
|
|
|
|
+ COMMIT_INFO="${COMMIT_INFO} 修复人: ${author} [${commit_hash}]
|
|
|
|
|
+"
|
|
|
|
|
+ done <<<"${BUG_MAP[$bug_id]}"
|
|
|
|
|
+
|
|
|
|
|
+ BUG_LINKS="${BUG_LINKS}#${bug_id}
|
|
|
|
|
+${COMMIT_INFO} ${ZENTAO_BUG_BASE_URL}${bug_id}.html
|
|
|
|
|
+
|
|
|
|
|
+"
|
|
|
|
|
+ done
|
|
|
|
|
+
|
|
|
|
|
+ # 发送 Telegram 通知 (包含警告信息)
|
|
|
|
|
+ if type -t send_telegram_message >/dev/null 2>&1; then
|
|
|
|
|
+ send_telegram_message "🐛 Bug 修复汇总
|
|
|
|
|
+版本: ${version_info}
|
|
|
|
|
+
|
|
|
|
|
+${BUG_LINKS}
|
|
|
|
|
+📊 总计: ${BUG_COUNT} 个 Bug 已修复
|
|
|
|
|
+⚠️ 禅道状态未更新(Token获取失败)"
|
|
|
|
|
+ fi
|
|
|
|
|
+ return 1
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "成功获取禅道 Token"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 初始化汇总信息
|
|
|
|
|
+ BUG_LINKS="" # Telegram 消息用的链接列表
|
|
|
|
|
+ RESOLVED_COUNT=0 # 已解决的 Bug 数量
|
|
|
|
|
+ ERROR_COUNT=0 # 失败的 Bug 数量
|
|
|
|
|
+ RESOLVED_BUGS_LIST="" # 飞书汇总用的 Bug 列表
|
|
|
|
|
+
|
|
|
|
|
+ # 处理每个 Bug (按 Bug ID 排序)
|
|
|
|
|
+ for bug_id in $(echo "${!BUG_MAP[@]}" | tr ' ' '\n' | sort -n); do
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "----------------------------------------"
|
|
|
|
|
+ log_message "处理 Bug #${bug_id}"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 查询 Bug 状态
|
|
|
|
|
+ BUG_INFO=$(curl -s -X GET "${ZENTAO_API_URL}/bugs/${bug_id}" \
|
|
|
|
|
+ -H "Token: ${ZENTAO_TOKEN}")
|
|
|
|
|
+
|
|
|
|
|
+ # 使用 Python 解析 JSON,正确处理中文
|
|
|
|
|
+ BUG_STATUS=$(echo "$BUG_INFO" | python3 -c "import sys, json; data=json.load(sys.stdin); print(data.get('status', ''))" 2>/dev/null)
|
|
|
|
|
+ BUG_TITLE=$(echo "$BUG_INFO" | python3 -c "import sys, json; data=json.load(sys.stdin); print(data.get('title', ''))" 2>/dev/null)
|
|
|
|
|
+ BUG_OPENED_BY=$(echo "$BUG_INFO" | python3 -c "import sys, json; data=json.load(sys.stdin); openedBy=data.get('openedBy', {}); print(openedBy.get('account', '') if isinstance(openedBy, dict) else '')" 2>/dev/null)
|
|
|
|
|
+
|
|
|
|
|
+ # 检查是否成功获取 Bug 信息
|
|
|
|
|
+ if [ -z "$BUG_STATUS" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "警告: 无法获取 Bug #${bug_id} 的状态信息"
|
|
|
|
|
+ fi
|
|
|
|
|
+ ERROR_COUNT=$((ERROR_COUNT + 1))
|
|
|
|
|
+
|
|
|
|
|
+ # 添加到失败列表
|
|
|
|
|
+ COMMIT_INFO=""
|
|
|
|
|
+ while IFS= read -r commit_line; do
|
|
|
|
|
+ commit_hash=$(echo "$commit_line" | cut -d'|' -f1)
|
|
|
|
|
+ author=$(echo "$commit_line" | cut -d'|' -f2)
|
|
|
|
|
+ COMMIT_INFO="${COMMIT_INFO} 修复人: ${author} [${commit_hash}]
|
|
|
|
|
+"
|
|
|
|
|
+ done <<<"${BUG_MAP[$bug_id]}"
|
|
|
|
|
+
|
|
|
|
|
+ BUG_LINKS="${BUG_LINKS}❌ #${bug_id} (查询失败)
|
|
|
|
|
+${COMMIT_INFO} ${ZENTAO_BUG_BASE_URL}${bug_id}.html
|
|
|
|
|
+
|
|
|
|
|
+"
|
|
|
|
|
+ continue
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "Bug #${bug_id} 状态: ${BUG_STATUS}"
|
|
|
|
|
+ log_message "Bug #${bug_id} 标题: ${BUG_TITLE}"
|
|
|
|
|
+ log_message "Bug #${bug_id} 创建者: ${BUG_OPENED_BY}"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 获取提交信息 (所有情况都需要)
|
|
|
|
|
+ COMMIT_INFO=""
|
|
|
|
|
+ while IFS= read -r commit_line; do
|
|
|
|
|
+ commit_hash=$(echo "$commit_line" | cut -d'|' -f1)
|
|
|
|
|
+ author=$(echo "$commit_line" | cut -d'|' -f2)
|
|
|
|
|
+ COMMIT_INFO="${COMMIT_INFO} 修复人: ${author} [${commit_hash}]
|
|
|
|
|
+"
|
|
|
|
|
+ done <<<"${BUG_MAP[$bug_id]}"
|
|
|
|
|
+
|
|
|
|
|
+ # 检查是否为未解决状态 (active 或 wait 状态才需要处理)
|
|
|
|
|
+ if [ "$BUG_STATUS" = "active" ] || [ "$BUG_STATUS" = "wait" ]; then
|
|
|
|
|
+ # 根据 update_status 参数决定是否更新禅道状态
|
|
|
|
|
+ if [ "$update_status" = "true" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "Bug #${bug_id} 状态为未解决,准备更新为已解决..."
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 准备评论内容 (包含所有相关 commit 信息)
|
|
|
|
|
+ COMMENT="已修复该问题
|
|
|
|
|
+
|
|
|
|
|
+相关提交:"
|
|
|
|
|
+ while IFS= read -r commit_info; do
|
|
|
|
|
+ commit_hash=$(echo "$commit_info" | cut -d'|' -f1)
|
|
|
|
|
+ author=$(echo "$commit_info" | cut -d'|' -f2)
|
|
|
|
|
+ message=$(echo "$commit_info" | cut -d'|' -f3)
|
|
|
|
|
+ COMMENT="${COMMENT}
|
|
|
|
|
+- [${commit_hash}] ${author}: ${message}"
|
|
|
|
|
+ done <<<"${BUG_MAP[$bug_id]}"
|
|
|
|
|
+
|
|
|
|
|
+ COMMENT="${COMMENT}
|
|
|
|
|
+
|
|
|
|
|
+代码提交: <a href=\"${COMMIT_BASE_URL}${commit_hash}\" target=\"_blank\">点击查看</a>"
|
|
|
|
|
+
|
|
|
|
|
+ # 生成解决 Bug 的 JSON 临时文件
|
|
|
|
|
+ RESOLVE_JSON_FILE="/tmp/zentao_resolve_${bug_id}_$$.json"
|
|
|
|
|
+
|
|
|
|
|
+ # 确定指派对象:优先使用创建者,如果获取失败则使用当前用户
|
|
|
|
|
+ ASSIGNEE="${BUG_OPENED_BY}"
|
|
|
|
|
+ if [ -z "$ASSIGNEE" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "警告: 无法获取 Bug #${bug_id} 创建者,将指派给当前用户 ${ZENTAO_USERNAME}"
|
|
|
|
|
+ fi
|
|
|
|
|
+ ASSIGNEE="${ZENTAO_USERNAME}"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 使用 Python 生成 JSON (确保正确处理中文和特殊字符)
|
|
|
|
|
+ python3 -c "import json; print(json.dumps({
|
|
|
|
|
+ 'resolution': 'fixed',
|
|
|
|
|
+ 'resolvedBuild': 'trunk',
|
|
|
|
|
+ 'resolvedDate': '$(date "+%Y-%m-%d %H:%M:%S")',
|
|
|
|
|
+ 'assignedTo': '${ASSIGNEE}',
|
|
|
|
|
+ 'comment': '''${COMMENT}'''
|
|
|
|
|
+}, ensure_ascii=False, indent=2))" >"$RESOLVE_JSON_FILE"
|
|
|
|
|
+
|
|
|
|
|
+ # 调用禅道 API 解决 Bug
|
|
|
|
|
+ RESOLVE_RESPONSE=$(curl -s -X POST "${ZENTAO_API_URL}/bugs/${bug_id}/resolve" \
|
|
|
|
|
+ -H "Token: ${ZENTAO_TOKEN}" \
|
|
|
|
|
+ -H "Content-Type: application/json" \
|
|
|
|
|
+ -d @"$RESOLVE_JSON_FILE")
|
|
|
|
|
+
|
|
|
|
|
+ # 清理临时文件
|
|
|
|
|
+ rm -f "$RESOLVE_JSON_FILE"
|
|
|
|
|
+
|
|
|
|
|
+ # 检查是否成功 (响应包含 "id" 字段表示成功)
|
|
|
|
|
+ if echo "$RESOLVE_RESPONSE" | grep -q '"id"'; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "✅ 成功解决 Bug #${bug_id}"
|
|
|
|
|
+ fi
|
|
|
|
|
+ RESOLVED_COUNT=$((RESOLVED_COUNT + 1))
|
|
|
|
|
+ BUG_LINKS="${BUG_LINKS}✅ #${bug_id} - ${BUG_TITLE}
|
|
|
|
|
+${COMMIT_INFO} ${ZENTAO_BUG_BASE_URL}${bug_id}.html
|
|
|
|
|
+
|
|
|
|
|
+"
|
|
|
|
|
+ # 添加到已解决 Bug 列表 (用于飞书汇总通知)
|
|
|
|
|
+ RESOLVED_BUGS_LIST="${RESOLVED_BUGS_LIST}#${bug_id} ${BUG_TITLE}|${ZENTAO_BUG_BASE_URL}${bug_id}.html
|
|
|
|
|
+"
|
|
|
|
|
+
|
|
|
|
|
+ # 发送飞书单个 Bug 通知
|
|
|
|
|
+ BUG_URL="${ZENTAO_BUG_BASE_URL}${bug_id}.html"
|
|
|
|
|
+ CODE_URL="${COMMIT_BASE_URL}${commit_hash}"
|
|
|
|
|
+ COMMIT_SUMMARY=$(echo "${BUG_MAP[$bug_id]}" | head -1 | awk -F'|' '{print "[" $1 "] " $3}')
|
|
|
|
|
+ send_bug_resolved_notification "${bug_id}" "${BUG_TITLE}" "${BUG_STATUS}" "${COMMIT_SUMMARY}" "${BUG_URL}" "${CODE_URL}"
|
|
|
|
|
+
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "飞书通知已发送 (Bug #${bug_id})"
|
|
|
|
|
+ fi
|
|
|
|
|
+ else
|
|
|
|
|
+ # 更新失败
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "❌ 解决 Bug #${bug_id} 失败: ${RESOLVE_RESPONSE}"
|
|
|
|
|
+ fi
|
|
|
|
|
+ ERROR_COUNT=$((ERROR_COUNT + 1))
|
|
|
|
|
+ BUG_LINKS="${BUG_LINKS}❌ #${bug_id} - ${BUG_TITLE} (更新失败)
|
|
|
|
|
+${COMMIT_INFO} ${ZENTAO_BUG_BASE_URL}${bug_id}.html
|
|
|
|
|
+
|
|
|
|
|
+"
|
|
|
|
|
+ fi
|
|
|
|
|
+ else
|
|
|
|
|
+ # update_status = false: 只汇总,不更新禅道状态
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "Bug #${bug_id} 状态为未解决,但只汇总不更新禅道状态"
|
|
|
|
|
+ fi
|
|
|
|
|
+ RESOLVED_COUNT=$((RESOLVED_COUNT + 1))
|
|
|
|
|
+ BUG_LINKS="${BUG_LINKS}📋 #${bug_id} - ${BUG_TITLE}
|
|
|
|
|
+${COMMIT_INFO} ${ZENTAO_BUG_BASE_URL}${bug_id}.html
|
|
|
|
|
+
|
|
|
|
|
+"
|
|
|
|
|
+ # 添加到已解决 Bug 列表
|
|
|
|
|
+ RESOLVED_BUGS_LIST="${RESOLVED_BUGS_LIST}#${bug_id} ${BUG_TITLE}|${ZENTAO_BUG_BASE_URL}${bug_id}.html
|
|
|
|
|
+"
|
|
|
|
|
+ fi
|
|
|
|
|
+ elif [ "$BUG_STATUS" = "resolved" ] || [ "$BUG_STATUS" = "closed" ]; then
|
|
|
|
|
+ # Bug 已经是 resolved 或 closed 状态,跳过处理
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "Bug #${bug_id} 已经是 ${BUG_STATUS} 状态,跳过更新(不显示在通知中)"
|
|
|
|
|
+ fi
|
|
|
|
|
+ # 不添加到 BUG_LINKS,不计数,不发通知
|
|
|
|
|
+ else
|
|
|
|
|
+ # 其他状态 (例如: testing),跳过处理
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "Bug #${bug_id} 状态为 ${BUG_STATUS},跳过更新(不显示在通知中)"
|
|
|
|
|
+ fi
|
|
|
|
|
+ # 不添加到 BUG_LINKS,不计数,不发通知
|
|
|
|
|
+ fi
|
|
|
|
|
+ done
|
|
|
|
|
+
|
|
|
|
|
+ # 输出汇总信息
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "=============== 禅道 Bug 追踪完成 ==============="
|
|
|
|
|
+ log_message "总计: ${BUG_COUNT} 个 Bug"
|
|
|
|
|
+ log_message "已解决: ${RESOLVED_COUNT} 个"
|
|
|
|
|
+ log_message "失败: ${ERROR_COUNT} 个"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 发送 Telegram 汇总通知
|
|
|
|
|
+ if type -t send_telegram_message >/dev/null 2>&1; then
|
|
|
|
|
+ send_telegram_message "🐛 Bug 修复汇总
|
|
|
|
|
+版本: ${version_info}
|
|
|
|
|
+
|
|
|
|
|
+${BUG_LINKS}
|
|
|
|
|
+📊 统计:
|
|
|
|
|
+- 已解决: ${RESOLVED_COUNT} 个
|
|
|
|
|
+- 失败: ${ERROR_COUNT} 个"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 发送飞书版本发布汇总通知 (仅在有解决 Bug 时发送)
|
|
|
|
|
+ if [ ${RESOLVED_COUNT} -gt 0 ] || [ ${ERROR_COUNT} -gt 0 ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "发送飞书版本发布汇总通知..."
|
|
|
|
|
+ fi
|
|
|
|
|
+ send_release_summary_notification "${start_ref}" "${end_ref}" "${RESOLVED_COUNT}" "${RESOLVED_BUGS_LIST}"
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "飞书版本发布通知已发送"
|
|
|
|
|
+ fi
|
|
|
|
|
+ else
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "本次构建无Bug状态变更,跳过飞书版本汇总通知"
|
|
|
|
|
+ fi
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "=============== 禅道 Bug 追踪结束 ==============="
|
|
|
|
|
+ fi
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+resolve_zentao_bugs() {
|
|
|
|
|
+ local workspace_dir="${1:-${WORKSPACE:-.}}"
|
|
|
|
|
+ local last_success_file="${workspace_dir}/.last_success_commit"
|
|
|
|
|
+
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "=============== 禅道 Bug 自动解决开始 ==============="
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 确定分析范围
|
|
|
|
|
+ LAST_SUCCESS_HASH=$(cat "$last_success_file" 2>/dev/null || echo "")
|
|
|
|
|
+
|
|
|
|
|
+ if [ -z "$LAST_SUCCESS_HASH" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "首次构建,分析最近 20 个包含 fix: 的提交"
|
|
|
|
|
+ fi
|
|
|
|
|
+ # 获取最近 20 个包含 fix: 的提交
|
|
|
|
|
+ FIX_COMMITS=$(git log -20 --pretty=format:"%h|%an|%s" | grep -E "fix[:-]\s*[0-9]" || true)
|
|
|
|
|
+ else
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "上次成功构建: ${LAST_SUCCESS_HASH}"
|
|
|
|
|
+ log_message "分析从 ${LAST_SUCCESS_HASH} 到 HEAD 的所有 fix: 提交"
|
|
|
|
|
+ fi
|
|
|
|
|
+ # 获取从上次成功构建到 HEAD 的所有包含 fix: 的提交
|
|
|
|
|
+ FIX_COMMITS=$(git log ${LAST_SUCCESS_HASH}..HEAD --pretty=format:"%h|%an|%s" | grep -E "fix[:-]\s*[0-9]" || true)
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if [ -z "$FIX_COMMITS" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "未发现包含 Bug 修复标记 (fix:) 的提交"
|
|
|
|
|
+ log_message "=============== 禅道 Bug 自动解决结束 ==============="
|
|
|
|
|
+ fi
|
|
|
|
|
+ return 0
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 统计找到的提交数
|
|
|
|
|
+ COMMIT_COUNT=$(echo "$FIX_COMMITS" | wc -l | tr -d ' ')
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "找到 ${COMMIT_COUNT} 个包含 fix: 的提交"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 初始化 bug 映射数组(bug_id => 最新的提交信息)
|
|
|
|
|
+ # 使用关联数组存储每个 bug 的最新提交(最上面的提交是最新的)
|
|
|
|
|
+ declare -A BUG_MAP
|
|
|
|
|
+
|
|
|
|
|
+ # 解析提交,提取 bug IDs(从新到旧的顺序)
|
|
|
|
|
+ while IFS='|' read -r commit_hash author commit_message; do
|
|
|
|
|
+ # 提取所有 bug IDs
|
|
|
|
|
+ if echo "$commit_message" | grep -qE "fix[:-]\s*[0-9]"; then
|
|
|
|
|
+ bug_ids=$(echo "$commit_message" | grep -oE "fix[:-]\s*([0-9]+(\s+[0-9]+)*)" | sed -E 's/fix[:-]\s*//')
|
|
|
|
|
+
|
|
|
|
|
+ for bug_id in $bug_ids; do
|
|
|
|
|
+ if [ -n "$bug_id" ]; then
|
|
|
|
|
+ # 只在 bug 第一次出现时记录(即最新的提交)
|
|
|
|
|
+ if [ -z "${BUG_MAP[$bug_id]}" ]; then
|
|
|
|
|
+ BUG_MAP[$bug_id]="${commit_hash}|${author}|${commit_message}"
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "发现 Bug #${bug_id}: [$commit_hash] $commit_message"
|
|
|
|
|
+ fi
|
|
|
|
|
+ fi
|
|
|
|
|
+ fi
|
|
|
|
|
+ done
|
|
|
|
|
+ fi
|
|
|
|
|
+ done <<<"$FIX_COMMITS"
|
|
|
|
|
+
|
|
|
|
|
+ # 统计发现的 bug 数量
|
|
|
|
|
+ BUG_COUNT=${#BUG_MAP[@]}
|
|
|
|
|
+
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "共发现 ${BUG_COUNT} 个唯一的 Bug"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if [ $BUG_COUNT -eq 0 ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "未能提取到有效的 Bug ID"
|
|
|
|
|
+ log_message "=============== 禅道 Bug 自动解决结束 ==============="
|
|
|
|
|
+ fi
|
|
|
|
|
+ return 0
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 获取禅道 Token
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "正在获取禅道 API Token..."
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ ZENTAO_TOKEN_RESPONSE=$(curl -s -X POST "${ZENTAO_API_URL}/tokens" \
|
|
|
|
|
+ -H "Content-Type: application/json" \
|
|
|
|
|
+ -d "{\"account\":\"${ZENTAO_USERNAME}\",\"password\":\"${ZENTAO_PASSWORD}\"}")
|
|
|
|
|
+
|
|
|
|
|
+ ZENTAO_TOKEN=$(echo "$ZENTAO_TOKEN_RESPONSE" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
|
|
|
|
|
+
|
|
|
|
|
+ if [ -z "$ZENTAO_TOKEN" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "错误: 无法获取禅道 Token"
|
|
|
|
|
+ log_message "响应: ${ZENTAO_TOKEN_RESPONSE}"
|
|
|
|
|
+ log_message "=============== 禅道 Bug 自动解决结束 ==============="
|
|
|
|
|
+ fi
|
|
|
|
|
+ return 1
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "成功获取禅道 Token"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 初始化统计计数器
|
|
|
|
|
+ RESOLVED_COUNT=0
|
|
|
|
|
+ SKIPPED_COUNT=0
|
|
|
|
|
+ ERROR_COUNT=0
|
|
|
|
|
+
|
|
|
|
|
+ # 处理每个 bug(按 bug ID 排序)
|
|
|
|
|
+ for bug_id in $(echo "${!BUG_MAP[@]}" | tr ' ' '\n' | sort -n); do
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "----------------------------------------"
|
|
|
|
|
+ log_message "处理 Bug #${bug_id}"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 获取该 bug 的最新提交信息
|
|
|
|
|
+ commit_info="${BUG_MAP[$bug_id]}"
|
|
|
|
|
+ commit_hash=$(echo "$commit_info" | cut -d'|' -f1)
|
|
|
|
|
+ author=$(echo "$commit_info" | cut -d'|' -f2)
|
|
|
|
|
+ commit_message=$(echo "$commit_info" | cut -d'|' -f3)
|
|
|
|
|
+
|
|
|
|
|
+ # 查询 bug 详情
|
|
|
|
|
+ BUG_INFO=$(curl -s -X GET "${ZENTAO_API_URL}/bugs/${bug_id}" \
|
|
|
|
|
+ -H "Token: ${ZENTAO_TOKEN}")
|
|
|
|
|
+
|
|
|
|
|
+ # 使用 Python 解析 JSON
|
|
|
|
|
+ BUG_STATUS=$(echo "$BUG_INFO" | python3 -c "import sys, json; data=json.load(sys.stdin); print(data.get('status', ''))" 2>/dev/null)
|
|
|
|
|
+ BUG_TITLE=$(echo "$BUG_INFO" | python3 -c "import sys, json; data=json.load(sys.stdin); print(data.get('title', ''))" 2>/dev/null)
|
|
|
|
|
+ BUG_OPENED_BY=$(echo "$BUG_INFO" | python3 -c "import sys, json; data=json.load(sys.stdin); openedBy=data.get('openedBy', {}); print(openedBy.get('account', '') if isinstance(openedBy, dict) else '')" 2>/dev/null)
|
|
|
|
|
+
|
|
|
|
|
+ if [ -z "$BUG_STATUS" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "警告: 无法获取 Bug #${bug_id} 的状态信息"
|
|
|
|
|
+ fi
|
|
|
|
|
+ ERROR_COUNT=$((ERROR_COUNT + 1))
|
|
|
|
|
+ continue
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "Bug #${bug_id} 状态: ${BUG_STATUS}"
|
|
|
|
|
+ log_message "Bug #${bug_id} 标题: ${BUG_TITLE}"
|
|
|
|
|
+ log_message "Bug #${bug_id} 创建者: ${BUG_OPENED_BY}"
|
|
|
|
|
+ log_message "最新修复提交: [${commit_hash}] ${author}"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 检查是否为未解决状态
|
|
|
|
|
+ if [ "$BUG_STATUS" = "active" ] || [ "$BUG_STATUS" = "wait" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "Bug #${bug_id} 状态为未解决,准备解决..."
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ # 准备 comment(只包含最新的提交)
|
|
|
|
|
+ COMMENT="已修复该问题
|
|
|
|
|
+
|
|
|
|
|
+相关提交:
|
|
|
|
|
+- [${commit_hash}] ${author}: ${commit_message}
|
|
|
|
|
+
|
|
|
|
|
+代码详情: ${COMMIT_BASE_URL}${commit_hash}"
|
|
|
|
|
+
|
|
|
|
|
+ # 生成解决 bug 的 JSON payload
|
|
|
|
|
+ RESOLVE_JSON_FILE="/tmp/zentao_resolve_${bug_id}_$$.json"
|
|
|
|
|
+
|
|
|
|
|
+ # 确定指派对象:优先使用创建者,如果获取失败则使用当前用户
|
|
|
|
|
+ ASSIGNEE="${BUG_OPENED_BY}"
|
|
|
|
|
+ if [ -z "$ASSIGNEE" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "警告: 无法获取 Bug #${bug_id} 创建者,将指派给当前用户 ${ZENTAO_USERNAME}"
|
|
|
|
|
+ fi
|
|
|
|
|
+ ASSIGNEE="${ZENTAO_USERNAME}"
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ python3 -c "import json; print(json.dumps({
|
|
|
|
|
+ 'resolution': 'fixed',
|
|
|
|
|
+ 'resolvedBuild': 'trunk',
|
|
|
|
|
+ 'resolvedDate': '$(date "+%Y-%m-%d %H:%M:%S")',
|
|
|
|
|
+ 'assignedTo': '${ASSIGNEE}',
|
|
|
|
|
+ 'comment': '''${COMMENT}'''
|
|
|
|
|
+}, ensure_ascii=False, indent=2))" >"$RESOLVE_JSON_FILE"
|
|
|
|
|
+
|
|
|
|
|
+ # 调用 API 解决 bug
|
|
|
|
|
+ RESOLVE_RESPONSE=$(curl -s -X POST "${ZENTAO_API_URL}/bugs/${bug_id}/resolve" \
|
|
|
|
|
+ -H "Token: ${ZENTAO_TOKEN}" \
|
|
|
|
|
+ -H "Content-Type: application/json" \
|
|
|
|
|
+ -d @"$RESOLVE_JSON_FILE")
|
|
|
|
|
+
|
|
|
|
|
+ # 清理临时文件
|
|
|
|
|
+ rm -f "$RESOLVE_JSON_FILE"
|
|
|
|
|
+
|
|
|
|
|
+ # 检查是否成功
|
|
|
|
|
+ if echo "$RESOLVE_RESPONSE" | grep -q '"id"'; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "✅ 成功解决 Bug #${bug_id}"
|
|
|
|
|
+ fi
|
|
|
|
|
+ RESOLVED_COUNT=$((RESOLVED_COUNT + 1))
|
|
|
|
|
+
|
|
|
|
|
+ # 发送飞书通知(每个 bug 单独通知)
|
|
|
|
|
+ BUG_URL="${ZENTAO_BUG_BASE_URL}${bug_id}.html"
|
|
|
|
|
+ CODE_URL="${COMMIT_BASE_URL}${commit_hash}"
|
|
|
|
|
+ COMMIT_SUMMARY="[${commit_hash}] ${commit_message}"
|
|
|
|
|
+ send_bug_resolved_notification "${bug_id}" "${BUG_TITLE}" "${BUG_STATUS}" "${COMMIT_SUMMARY}" "${BUG_URL}" "${CODE_URL}"
|
|
|
|
|
+
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "飞书通知已发送 (Bug #${bug_id})"
|
|
|
|
|
+ fi
|
|
|
|
|
+ else
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "❌ 解决 Bug #${bug_id} 失败: ${RESOLVE_RESPONSE}"
|
|
|
|
|
+ fi
|
|
|
|
|
+ ERROR_COUNT=$((ERROR_COUNT + 1))
|
|
|
|
|
+ fi
|
|
|
|
|
+ elif [ "$BUG_STATUS" = "resolved" ] || [ "$BUG_STATUS" = "closed" ]; then
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "Bug #${bug_id} 已经是 ${BUG_STATUS} 状态,跳过处理"
|
|
|
|
|
+ fi
|
|
|
|
|
+ SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
|
|
|
|
|
+ else
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "Bug #${bug_id} 状态为 ${BUG_STATUS},跳过处理"
|
|
|
|
|
+ fi
|
|
|
|
|
+ SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
|
|
|
|
|
+ fi
|
|
|
|
|
+ done
|
|
|
|
|
+
|
|
|
|
|
+ if type -t log_message >/dev/null 2>&1; then
|
|
|
|
|
+ log_message "=============== 禅道 Bug 自动解决完成 ==============="
|
|
|
|
|
+ log_message "分析提交数: ${COMMIT_COUNT}"
|
|
|
|
|
+ log_message "发现 Bug 数: ${BUG_COUNT}"
|
|
|
|
|
+ log_message "已解决: ${RESOLVED_COUNT} 个"
|
|
|
|
|
+ log_message "已跳过: ${SKIPPED_COUNT} 个"
|
|
|
|
|
+ log_message "失败: ${ERROR_COUNT} 个"
|
|
|
|
|
+ log_message "=============== 禅道 Bug 自动解决结束 ==============="
|
|
|
|
|
+ fi
|
|
|
|
|
+
|
|
|
|
|
+ return 0
|
|
|
|
|
+}
|