Files
lijiaoqiao/scripts/auto_review/auto_review.sh

487 lines
16 KiB
Bash
Raw Normal View History

#!/bin/bash
#===============================================================================
# 自动化周期性Review脚本
# 功能每3小时执行一次项目全面review生成报告并分发任务
# 使用:./auto_review.sh [hourly|daily|force]
#===============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
REVIEW_DIR="$PROJECT_ROOT/review"
REPORT_DIR="$REVIEW_DIR/daily_reports"
KNOWLEDGE_DIR="$REVIEW_DIR/knowledge_base"
TASK_QUEUE="$REVIEW_DIR/task_queue.json"
LOG_DIR="$PROJECT_ROOT/logs/auto_review"
# 加载配置
source "$SCRIPT_DIR/auto_review_config.sh"
#-------------------------------------------------------------------------------
# 日志函数
#-------------------------------------------------------------------------------
log() {
local level=$1
shift
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*"
echo "$msg"
echo "$msg" >> "$LOG_DIR/review_$(date '+%Y%m%d').log"
}
#-------------------------------------------------------------------------------
# 初始化
#-------------------------------------------------------------------------------
init() {
mkdir -p "$LOG_DIR" "$REPORT_DIR" "$KNOWLEDGE_DIR"
# 初始化任务队列
if [ ! -f "$TASK_QUEUE" ]; then
echo '{"tasks":[], "last_updated":"", "last_review_date":""}' > "$TASK_QUEUE"
fi
log "INFO" "Auto review system initialized"
}
#-------------------------------------------------------------------------------
# 获取文档变更状态
#-------------------------------------------------------------------------------
get_doc_changes() {
local since="${1:-24h}"
git -C "$PROJECT_ROOT" diff --name-only --since="$since" -- "docs/" "review/" 2>/dev/null || echo ""
}
#-------------------------------------------------------------------------------
# 读取上一份报告
#-------------------------------------------------------------------------------
read_last_report() {
local last_report=$(ls -t "$REPORT_DIR"/daily_review_*.md 2>/dev/null | head -1)
if [ -n "$last_report" ]; then
echo "$last_report"
else
echo ""
fi
}
#-------------------------------------------------------------------------------
# 提取未完成任务
#-------------------------------------------------------------------------------
extract_pending_tasks() {
local report_file="$1"
if [ -z "$report_file" ] || [ ! -f "$report_file" ]; then
echo "[]"
return
fi
# 提取P0/P1任务
grep -E "^\s*\|.*P[01].*\|" "$report_file" 2>/dev/null | \
grep -v "完成\|已关闭\|CLOSED" | \
sed -E 's/\|/,/g' | \
awk -F',' '{print "{\"id\":\""$1"\",\"desc\":\""$3"\",\"owner\":\""$4"\"}"}' | \
jq -s '.' 2>/dev/null || echo "[]"
}
#-------------------------------------------------------------------------------
# 执行Review检查
#-------------------------------------------------------------------------------
perform_review() {
local review_type="$1"
log "INFO" "Starting $review_type review..."
# 收集变更文件
local changes=""
local change_count=0
changes=$(get_doc_changes "3 hours ago" 2>/dev/null || echo "")
change_count=$(echo "$changes" | grep -c "." 2>/dev/null || echo "0")
# 检查是否有新的设计文档
local new_docs=0
new_docs=$(git -C "$PROJECT_ROOT" status --porcelain "docs/" 2>/dev/null | grep "^??" | wc -l 2>/dev/null || echo "0")
new_docs=${new_docs:-0}
# 检查未完成任务
local last_report=$(read_last_report)
local pending_tasks="[]"
local pending_count=0
if [ -n "$last_report" ] && [ -f "$last_report" ]; then
pending_tasks=$(extract_pending_tasks "$last_report" 2>/dev/null || echo "[]")
pending_count=$(echo "$pending_tasks" | jq 'length' 2>/dev/null || echo "0")
fi
pending_count=${pending_count:-0}
# 执行快速检查模拟专家review
local issues_found=0
# 检查关键文档是否存在
local critical_doc
for critical_doc in "$REVIEW_DIR/comprehensive_expert_review_report_v2_2026-03-18.md" "$PROJECT_ROOT/docs/architecture_solution_v1_2026-03-18.md"; do
if [ ! -f "$critical_doc" ]; then
log "WARN" "Critical document missing: $critical_doc"
issues_found=$((issues_found + 1))
fi
done
# 构建JSON确保所有值都是有效的
local change_files_json="[]"
if [ -n "$changes" ]; then
change_files_json=$(echo "$changes" | jq -R -s 'split("\n") | map(select(length > 0))' 2>/dev/null || echo "[]")
fi
# 确定是否需要处理
local action_required="false"
if [ "$issues_found" -gt 0 ] || [ "$change_count" -gt 0 ]; then
action_required="true"
fi
# 返回Review结果
cat << EOF
{
"review_type": "$review_type",
"timestamp": "$(date -Iseconds)",
"changes_count": $change_count,
"new_docs_count": $new_docs,
"pending_tasks_count": $pending_count,
"issues_found": $issues_found,
"change_files": $change_files_json,
"action_required": $action_required
}
EOF
}
#-------------------------------------------------------------------------------
# 生成每日报告
#-------------------------------------------------------------------------------
generate_daily_report() {
local review_data="$1"
local date_str=$(date '+%Y-%m-%d')
log "INFO" "Generating daily review report for $date_str..."
local report_file="$REPORT_DIR/daily_review_${date_str}.md"
local last_report=$(read_last_report)
# 提取review数据
local changes_count new_docs_count pending_tasks_count issues_found
changes_count=$(echo "$review_data" | jq -r '.changes_count // 0' 2>/dev/null || echo "0")
new_docs_count=$(echo "$review_data" | jq -r '.new_docs_count // 0' 2>/dev/null || echo "0")
pending_tasks_count=$(echo "$review_data" | jq -r '.pending_tasks_count // 0' 2>/dev/null || echo "0")
issues_found=$(echo "$review_data" | jq -r '.issues_found // 0' 2>/dev/null || echo "0")
# 提取变更文件列表
local change_list
change_list=$(echo "$review_data" | jq -r '.change_files[] // empty' 2>/dev/null | sed 's/^/- /' || echo "无变更")
# 生成报告头部
cat > "$report_file" << EOF
# 立交桥项目每日Review报告
> 生成时间:$(date '+%Y-%m-%d %H:%M:%S')
> 报告日期:$date_str
> Review类型每日全面检查
---
## 一、Review执行摘要
| 指标 | 数值 | 较昨日 |
|------|------|--------|
| 文档变更数 | $changes_count | - |
| 新增文档数 | $new_docs_count | - |
| 待完成任务 | $pending_tasks_count | - |
| 发现问题 | $issues_found | - |
---
## 二、变更文件清单
$change_list
---
## 三、待完成任务追踪
### 3.1 P0问题阻断上线
EOF
# 添加P0任务列表
if [ -n "$last_report" ]; then
grep -A 50 "### 3.1 P0问题" "$last_report" 2>/dev/null | head -30 >> "$report_file" || echo "| - | - | - | - |" >> "$report_file"
else
echo "| 编号 | 问题描述 | Owner | 状态 |" >> "$report_file"
echo "|-----|----------|-------|------|" >> "$report_file"
echo "| - | 暂无 | - | - |" >> "$report_file"
fi
cat >> "$report_file" << EOF
### 3.2 P1问题高优先级
EOF
if [ -n "$last_report" ]; then
grep -A 30 "### 3.2 P1问题" "$last_report" 2>/dev/null | head -20 >> "$report_file" || echo "| - | - | - |" >> "$report_file"
else
echo "| 编号 | 问题描述 | Owner |" >> "$report_file"
echo "|-----|----------|-------|" >> "$report_file"
fi
# 确定行动项文本
local action_text="无"
local new_issue_text="| - | - | 无新问题 | - |"
if [ "$issues_found" -gt 0 ]; then
action_text="存在 $issues_found 个问题需处理"
new_issue_text="| NEW-001 | P1 | 新发现的问题(待详细记录) | $(date '+%Y-%m-%d %H:%M') |"
fi
cat >> "$report_file" << EOF
---
## 四、新发现问题
| 编号 | 等级 | 问题描述 | 发现时间 |
|------|------|----------|----------|
$new_issue_text
---
## 五、建议行动项
1. **立即处理**$action_text
2. **持续跟进**$pending_tasks_count 个待办任务
3. **文档更新**$new_docs_count 个新文档待审核
---
## 六、专家评审状态
| 轮次 | 主题 | 结论 | 日期 |
|------|------|------|------|
| Round-1 | 架构与替换路径 | CONDITIONAL GO | 2026-03-19 |
| Round-2 | 兼容与计费一致性 | CONDITIONAL GO | 2026-03-22 |
| Round-3 | 安全与合规攻防 | CONDITIONAL GO | 2026-03-25 |
| Round-4 | 可靠性与回滚演练 | CONDITIONAL GO | 2026-03-29 |
---
**报告状态**:自动生成
**下次更新**$(date -d '+3 hours' '+%Y-%m-%d %H:%M')
EOF
log "INFO" "Daily report generated: $report_file"
echo "$report_file"
}
#-------------------------------------------------------------------------------
# 更新任务队列
#-------------------------------------------------------------------------------
update_task_queue() {
local review_data="$1"
local date_str=$(date '+%Y-%m-%d')
# 提取数据
local changes_count issues_found action_required
changes_count=$(echo "$review_data" | jq -r '.changes_count // 0' 2>/dev/null || echo "0")
issues_found=$(echo "$review_data" | jq -r '.issues_found // 0' 2>/dev/null || echo "0")
action_required=$(echo "$review_data" | jq -r '.action_required // "false"' 2>/dev/null || echo "false")
# 读取当前队列
local current_queue=$(cat "$TASK_QUEUE" 2>/dev/null || echo '{"tasks":[]}')
# 更新JSON
local updated
updated=$(echo "$current_queue" | jq --arg timestamp "$(date -Iseconds)" \
--arg date "$date_str" \
--argjson changes "$changes_count" \
--argjson issues "$issues_found" \
'.last_updated = $timestamp | .last_review_date = $date | .review_stats.total_reviews += 1 | .review_stats.issues_found += $issues')
echo "$updated" > "$TASK_QUEUE"
# 如果有问题需要处理,生成任务文件
if [ "$issues_found" -gt 0 ]; then
local task_file="$REVIEW_DIR/pending_tasks_$(date '+%Y%m%d_%H%M%S').json"
echo "$review_data" > "$task_file"
log "WARN" "Issues found! Task file created: $task_file"
fi
}
#-------------------------------------------------------------------------------
# 生成Claude Code任务
#-------------------------------------------------------------------------------
generate_claude_tasks() {
local review_data="$1"
local date_str=$(date '+%Y-%m-%d')
# 提取数据
local needs_action issues_found changes_count pending_tasks_count
needs_action=$(echo "$review_data" | jq -r '.action_required // "false"' 2>/dev/null || echo "false")
issues_found=$(echo "$review_data" | jq -r '.issues_found // 0' 2>/dev/null || echo "0")
changes_count=$(echo "$review_data" | jq -r '.changes_count // 0' 2>/dev/null || echo "0")
pending_tasks_count=$(echo "$review_data" | jq -r '.pending_tasks_count // 0' 2>/dev/null || echo "0")
# 提取变更文件列表
local change_list
change_list=$(echo "$review_data" | jq -r '.change_files[] // empty' 2>/dev/null | sed 's/^/1. 审核文档:/' || echo "1. 检查并处理review发现的问题")
if [ "$needs_action" = "true" ]; then
local task_file="$REVIEW_DIR/claude_tasks_${date_str}.md"
cat > "$task_file" << EOF
# Claude Code 执行任务
> 生成时间:$(date '+%Y-%m-%d %H:%M:%S')
> 触发条件Review发现需要处理的问题
## 执行要求
请Claude Code CLI按照以下规范执行
1. **遵循superpowers插件规范**
2. **严格按照项目规划设计执行**
3. **优先处理P0问题**
## 待处理问题清单
- 问题数量:$issues_found
- 文档变更:$changes_count 个文件
- 待办任务:$pending_tasks_count
## 具体任务
$change_list
---
**状态**:等待执行
**优先级**:高
EOF
log "INFO" "Claude tasks generated: $task_file"
echo "$task_file"
else
echo ""
fi
}
#-------------------------------------------------------------------------------
# 更新经验知识库每日3点执行
#-------------------------------------------------------------------------------
update_knowledge_base() {
local is_daily=$(date '+%H')
# 只在每天3点执行
if [ "$is_daily" != "03" ]; then
log "INFO" "Skipping knowledge base update (not 3am, current: ${is_daily}00)"
return 0
fi
log "INFO" "Updating knowledge base..."
local date_str=$(date '+%Y-%m-%d')
local kb_file="$KNOWLEDGE_BASE/rules_and_experience_${date_str}.md"
# 收集当天经验
local issues=""
local last_report=$(read_last_report)
if [ -n "$last_report" ]; then
issues=$(grep -E "^\|.*P[01]" "$last_report" 2>/dev/null | wc -l)
fi
cat > "$kb_file" << EOF
# 立交桥项目经验与规则
> 更新时间:$(date '+%Y-%m-%d %H:%M:%S')
> 版本:$(date '+%Y%m%d')
## 一、项目关键规范
### 1.1 架构原则
- Provider Adapter抽象层设计
- 三层降级策略(同平台换号/同区域换平台/全局降级)
- 分阶段验证S2-A/B/C1/C2
### 1.2 安全红线
- 内网隔离 + mTLS双向认证
- 契约漂移CI阻断
- 密钥90天轮换
### 1.3 质量门禁
- 接管率 >= 99.9% 覆盖率
- 自动回滚 <= 10分钟
- 服务恢复 <= 30分钟
- 用户通知 <= 15分钟
## 二、待解决P0问题
- 数量:$issues 个(来自最新报告)
## 三、专家评审结论
| 维度 | 结论 | 评分 |
|------|------|------|
| 架构 | CONDITIONAL GO | 3.5/5 |
| API设计 | CONDITIONAL GO | 4.0/5 |
| 安全防护 | CONDITIONAL GO | 3.0/5 |
| 业务合规 | CONDITIONAL GO | 3.5/5 |
| 计费精度 | CONDITIONAL GO | 4.0/5 |
| 可靠性 | CONDITIONAL GO | 3.0/5 |
## 四、行动优先级
1. **P0**:安全验证、契约测试、降级演练
2. **P1**用户体验、SLA文档、计费准确性
3. **P2**SDK开发、法务确认、DDoS防护
---
**状态**:每日自动更新
**下次更新**$(date -d '+1 day' -d '3:00' '+%Y-%m-%d %H:%M')
EOF
log "INFO" "Knowledge base updated: $kb_file"
}
#-------------------------------------------------------------------------------
# 主函数
#-------------------------------------------------------------------------------
main() {
local mode="${1:-hourly}"
init
case "$mode" in
hourly)
log "INFO" "Running hourly review..."
local review_result=$(perform_review "hourly")
update_task_queue "$review_result"
generate_claude_tasks "$review_result"
;;
daily)
log "INFO" "Running daily full review..."
local review_result=$(perform_review "daily")
local report=$(generate_daily_report "$review_result")
update_task_queue "$review_result"
generate_claude_tasks "$review_result"
update_knowledge_base
log "INFO" "Daily review completed. Report: $report"
;;
force)
log "WARN" "Running forced full review..."
local review_result=$(perform_review "force")
local report=$(generate_daily_report "$review_result")
update_task_queue "$review_result"
generate_claude_tasks "$review_result"
log "INFO" "Forced review completed. Report: $report"
;;
*)
echo "Usage: $0 [hourly|daily|force]"
exit 1
;;
esac
}
main "$@"