This commit is contained in:
@@ -1,40 +1,102 @@
|
||||
name: AI Code Review
|
||||
name: "AI Code Review (Skill-Driven)"
|
||||
|
||||
# 触发条件:当向 main 分支发起 PR,或者 PR 有新代码提交时触发
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
code-review:
|
||||
review_with_skill:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# 1. 拉取代码
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
# 1. 拉取代码及 Skill 规则文件
|
||||
- name: Checkout Code & Skills
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # 必须设置为 0,获取完整提交历史,以便 AI 对比代码差异
|
||||
fetch-depth: 0
|
||||
|
||||
# 2. 运行 AI 代码审查
|
||||
- name: Run AI Code Review
|
||||
uses: anc95/ChatGPT-CodeReview@main
|
||||
# 2. 运行 AI 审查脚本
|
||||
- name: Run Review Engine
|
||||
env:
|
||||
# Gitea 自带的 Token,用于让机器人能自动在你的 PR 下方发评论(系统自带,无需你手动配置)
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# 刚刚你在 Gitea "工作流 -> 密钥" 里配置的中转站 API Key
|
||||
OPENAI_API_KEY: ${{ secrets.LLM_API_KEY }}
|
||||
|
||||
# 你的中转站 API 基础地址(务必保留结尾的 /v1)
|
||||
OPENAI_API_ENDPOINT: "https://api.maxmodel.com/v1"
|
||||
|
||||
# 你想使用的模型名称(请填入你中转站支持的模型,比如 gpt-4o 或 deepseek-chat)
|
||||
MODEL: "gpt-4o"
|
||||
|
||||
# 设置 AI 评论的语言
|
||||
LANGUAGE: "Chinese"
|
||||
|
||||
# 给 AI 的设定提示词,让它重点关注你关心的漏洞
|
||||
SYSTEM_MESSAGE: "你是一个资深的 Python 架构师。请严格检查代码中的安全隐患(如硬编码密钥)、性能问题(如在 async 中使用同步阻塞 I/O)以及代码健壮性缺失,并提供具体的修复建议和代码示例。"
|
||||
# 🔑 中转站 API Key(在 Gitea Secrets 配置)
|
||||
API_KEY: ${{ secrets.LLM_API_KEY }}
|
||||
# 🌐 中转站 Base URL(在 Gitea Secrets 配置)
|
||||
BASE_URL: ${{ secrets.LLM_BASE_URL }}
|
||||
# 🤖 选择的模型名称(按需修改)
|
||||
MODEL_NAME: "gpt-4o"
|
||||
# Gitea 自动注入的 Token,无需手动配置
|
||||
GITEA_TOKEN: ${{ gitea.token }}
|
||||
GITEA_SERVER_URL: ${{ gitea.server_url }}
|
||||
GITEA_REPOSITORY: ${{ gitea.repository }}
|
||||
GITEA_PR_NUMBER: ${{ gitea.event.number }}
|
||||
GITEA_BASE_REF: ${{ gitea.base_ref }}
|
||||
GITEA_HEAD_REF: ${{ gitea.head_ref }}
|
||||
run: |
|
||||
# 提取当前 PR 的代码差异
|
||||
git diff origin/$GITEA_BASE_REF...origin/$GITEA_HEAD_REF > diff.txt
|
||||
|
||||
# 使用 Python 执行审查(纯标准库,无需 pip install)
|
||||
python3 -c "
|
||||
import os, json, urllib.request, urllib.error
|
||||
|
||||
# ========== 1. 读取 Skill 规则书 ==========
|
||||
skill_base_path = '.claude/skills/code-review-skill/'
|
||||
try:
|
||||
skill_config = open(os.path.join(skill_base_path, 'SKILL.md'), encoding='utf-8').read()
|
||||
python_rules = open(os.path.join(skill_base_path, 'reference/python.md'), encoding='utf-8').read()
|
||||
except FileNotFoundError as e:
|
||||
print(f'❌ 未找到 Skill 规则文件: {e}'); exit(1)
|
||||
|
||||
full_skill_prompt = f'{skill_config}\n\n以下是针对当前语言的补充规范:\n{python_rules}'
|
||||
|
||||
# ========== 2. 读取代码变动 ==========
|
||||
diff_data = open('diff.txt', encoding='utf-8').read()
|
||||
if not diff_data.strip():
|
||||
print('✅ 没有检测到代码变更,跳过审查。'); exit(0)
|
||||
|
||||
# ========== 3. 调用中转站大模型 API ==========
|
||||
base_url = os.getenv('BASE_URL', 'https://api.maxmodel.com/v1').rstrip('/')
|
||||
api_url = f'{base_url}/chat/completions'
|
||||
model_name = os.getenv('MODEL_NAME', 'gpt-4o')
|
||||
|
||||
print(f'🚀 正在调用模型: {model_name} @ {base_url}')
|
||||
|
||||
headers = {
|
||||
'Authorization': f'Bearer {os.getenv(\"API_KEY\")}',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
payload = {
|
||||
'model': model_name,
|
||||
'messages': [
|
||||
{'role': 'system', 'content': full_skill_prompt},
|
||||
{'role': 'user', 'content': f'请严格对照上述 Skill 规范,评审以下 FastAPI 代码改动,并用中文输出评审意见:\n\n{diff_data}'}
|
||||
],
|
||||
'temperature': 0.2
|
||||
}
|
||||
|
||||
req = urllib.request.Request(api_url, data=json.dumps(payload).encode('utf-8'), headers=headers, method='POST')
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=120) as response:
|
||||
res = json.loads(response.read().decode('utf-8'))
|
||||
comment_body = res['choices'][0]['message']['content']
|
||||
print('✅ 大模型已返回审查意见')
|
||||
except urllib.error.HTTPError as e:
|
||||
error_body = e.read().decode('utf-8')
|
||||
print(f'❌ 请求中转站失败 [{e.code}]: {error_body}'); exit(1)
|
||||
except Exception as e:
|
||||
print(f'❌ 请求中转站异常: {e}'); exit(1)
|
||||
|
||||
# ========== 4. 发表到 Gitea PR 评论区 ==========
|
||||
gitea_url = f'{os.getenv(\"GITEA_SERVER_URL\")}/api/v1/repos/{os.getenv(\"GITEA_REPOSITORY\")}/issues/{os.getenv(\"GITEA_PR_NUMBER\")}/comments'
|
||||
gitea_headers = {
|
||||
'Authorization': f'token {os.getenv(\"GITEA_TOKEN\")}',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
gitea_payload = {'body': f'### 🤖 AI 自动化审查报告 (基于 Code Review Skill)\n\n> 模型: \`{model_name}\` | 中转站: maxmodel\n\n{comment_body}'}
|
||||
|
||||
gitea_req = urllib.request.Request(gitea_url, data=json.dumps(gitea_payload).encode('utf-8'), headers=gitea_headers, method='POST')
|
||||
try:
|
||||
urllib.request.urlopen(gitea_req, timeout=30)
|
||||
print('🎉 Skill 审查报告已成功发表到 PR!')
|
||||
except Exception as e:
|
||||
print(f'❌ 发表评论失败: {e}'); exit(1)
|
||||
"
|
||||
Reference in New Issue
Block a user