代码评审自动化工具
这是一个基于 Gemini API 的自动化代码评审工具,可以自动分析 Git 仓库中的代码变更并生成评审报告。
功能特点
- 自动检测 Git 仓库中的代码变更
- 使用 Gemini AI 进行代码分析和评审
- 生成结构化的 Markdown 格式评审报告
- 支持多文件批量评审
- 自动处理特殊字符和编码问题
- 内置错误重试机制
- 自动选择最新的 AI 模型
使用前提
系统要求
- Linux/Unix 环境 (WSL也可以)
- Git 仓库
- curl
- jq (JSON处理工具)
API 配置
在使用前,需要配置以下参数:
API_URL="https://gemini.tangrenbin.us.kg" # API服务器地址
API_KEY="your_api_key_here" # 你的API密钥安装和配置
- 下载脚本到本地
- 添加执行权限:
chmod +x code_review.sh
- 修改 API 配置(如果需要)
使用方法
- 进入 Git 仓库目录
- 运行脚本:
./code_review.sh
脚本会自动:
- 检查必要的依赖
- 验证 Git 仓库
- 获取所有变更的文件
- 对每个文件进行 AI 评审
- 生成评审报告
评审报告
评审报告将保存在 review_reports 目录下,文件名格式为:
review_report_YYYYMMDD_HHMMSS.md
报告内容包括:
- 评审时间戳
- 变更文件列表
- 每个文件的详细评审意见
- 代码质量和可维护性
- 潜在的bug和安全问题
- 性能优化建议
- 最佳实践遵循情况
错误处理
脚本内置了多种错误处理机制:
- 依赖检查:自动检查必要的命令行工具
- API 重试:遇到网络问题时自动重试(最多3次)
- 文件编码:使用 base64 处理特殊字符
- 错误报告:详细的错误信息输出
调试模式
如果需要查看详细的调试信息,可以取消注释以下行:
# echo "DEBUG: 请求数据: $json_data" >&2
# echo "DEBUG: API响应: $response" >&2注意事项
- 确保在运行脚本前已经正确配置 API 密钥
- 脚本需要在 Git 仓库目录下运行
- 评审报告目录会自动创建
- 大文件评审可能需要较长时间
- 如果遇到 API 限制,请适当调整重试间隔
常见问题
-
权限问题
chmod +x code_review.sh
-
依赖安装
# Ubuntu/Debian sudo apt-get install curl jq # CentOS/RHEL sudo yum install curl jq
-
如果报告为空,请检查:
- Git 仓库是否有变更
- API 密钥是否正确
- 网络连接是否正常
#!/bin/bash
# Configuration
API_URL="https://gemini.tangrenbin.us.kg"
API_KEY="AIzaSyDOLKXvMTqw0EgLHVOA13fgBZHbS8NEvBs"
REPORT_DIR="review_reports"
# Check dependencies
check_dependencies() {
local missing_deps=()
if ! command -v jq &> /dev/null; then
missing_deps+=("jq")
fi
if ! command -v python3 &> /dev/null; then
missing_deps+=("python3")
fi
if ! command -v curl &> /dev/null; then
missing_deps+=("curl")
fi
if ! command -v git &> /dev/null; then
missing_deps+=("git")
fi
if [ ${#missing_deps[@]} -ne 0 ]; then
echo "错误: 缺少必要的依赖:"
printf '%s\n' "${missing_deps[@]}"
echo "请安装所需依赖后重试"
exit 1
fi
}
# Check if in git repository
check_git_repo() {
if ! git rev-parse --is-inside-work-tree &> /dev/null; then
echo "错误: 当前目录不是 git 仓库"
exit 1
fi
}
# Function to get available model
get_model() {
local response
response=$(curl -s -f -X GET "$API_URL/v1/models" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY") || {
echo "错误: API 请求失败" >&2
return 1
}
local model
model=$(echo "$response" | jq -r '.data[] | select(.id | contains("gemini")) | .id' 2>/dev/null | tail -n 1)
if [ -z "$model" ]; then
echo "错误: 无法获取可用的模型" >&2
echo "API返回: $response" >&2
return 1
fi
echo "$model"
}
# Function to get the full content of a file
get_file_content() {
local file="$1"
if [ ! -f "$file" ]; then
echo "错误: 文件不存在: $file" >&2
return 1
fi
# 使用 base64 编码处理特殊字符
base64 "$file" | base64 --decode 2>/dev/null || {
echo "错误: 文件内容读取失败: $file" >&2
return 1
}
}
# Function to call Gemini API
call_gemini_api() {
local prompt="$1"
local max_retries=3
local retry_count=0
# 获取可用模型
local model
if ! model=$(get_model); then
echo "错误: 无法获取可用模型" >&2
return 1
fi
while [ $retry_count -lt $max_retries ]; do
# 使用jq构建JSON请求
local json_data
json_data=$(jq -n \
--arg msg "$prompt" \
--arg model "$model" \
'{
model: $model,
messages: [
{
role: "user",
content: $msg
}
],
stream: false,
temperature: 0.7,
max_tokens: 2048
}') || {
echo "错误: JSON 数据准备失败" >&2
return 1
}
echo "DEBUG: 使用模型: $model" >&2
echo "DEBUG: 发送请求到 $API_URL/v1/chat/completions" >&2
# echo "DEBUG: 请求数据: $json_data" >&2
local response
response=$(curl -s -X POST "$API_URL/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d "$json_data")
local curl_exit_code=$?
echo "DEBUG: curl退出码: $curl_exit_code" >&2
# echo "DEBUG: API响应: $response" >&2
if [ $curl_exit_code -ne 0 ]; then
retry_count=$((retry_count + 1))
if [ $retry_count -eq $max_retries ]; then
echo "错误: API 调用失败,已重试 $max_retries 次" >&2
echo "错误详情: $response" >&2
return 1
fi
echo "警告: API 调用失败,正在重试 ($retry_count/$max_retries)..." >&2
sleep 2
continue
fi
if [ -n "$response" ]; then
# 检查响应是否包含错误信息
if echo "$response" | jq -e 'has("error")' > /dev/null; then
local error_msg=$(echo "$response" | jq -r '.error.message // .error')
echo "错误: API返回错误: $error_msg" >&2
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
continue
fi
# 从响应中提取内容
local content
content=$(echo "$response" | jq -r '.choices[0].message.content' 2>/dev/null)
if [ -n "$content" ] && [ "$content" != "null" ]; then
echo "$content"
return 0
fi
echo "$response"
return 0
fi
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
echo "错误: API 响应为空" >&2
return 1
}
main() {
# Run dependency check
check_dependencies
# Check if in git repository
check_git_repo
# Create reports directory
mkdir -p "$REPORT_DIR" || {
echo "错误: 无法创建报告目录" >&2
exit 1
}
# Generate report file path
local timestamp=$(date +"%Y%m%d_%H%M%S")
local report_file="$REPORT_DIR/review_report_${timestamp}.md"
# Initialize report file
{
echo "# 代码评审报告 - $(date '+%Y-%m-%d %H:%M:%S')"
echo -e "\n## 变更文件列表\n"
} > "$report_file" || {
echo "错误: 无法创建报告文件" >&2
exit 1
}
# Get list of changed files
local changed_files
changed_files=$(git diff --name-only) || {
echo "错误: 无法获取变更文件列表" >&2
exit 1
}
if [ -z "$changed_files" ]; then
echo "没有检测到文件变更。"
exit 0
fi
echo "开始代码评审..."
# Process each changed file
local success_count=0
local total_files=0
while IFS= read -r file; do
[ -z "$file" ] && continue
((total_files++))
if [ -f "$file" ]; then
echo "正在评审: $file"
echo -e "\n### $file\n" >> "$report_file"
# Get file content
local file_content
if ! file_content=$(get_file_content "$file"); then
echo "警告: 跳过文件 $file" >&2
continue
fi
# Prepare prompt
local prompt="请对以下代码进行代码评审,重点关注:
1. 代码质量和可维护性
2. 潜在的bug和安全问题
3. 性能优化建议
4. 最佳实践遵循情况
代码文件:$file
\`\`\`
$file_content
\`\`\`"
# Get review comments
local review_comments
if review_comments=$(call_gemini_api "$prompt"); then
echo -e "$review_comments\n" >> "$report_file"
echo "✓ 完成评审: $file"
((success_count++))
else
echo "✗ 评审失败: $file"
fi
fi
done <<< "$changed_files"
echo -e "\n评审完成: 成功评审 $success_count/$total_files 个文件"
echo "评审报告已保存至: $report_file"
}
# Run main function
main