ci: add auto PR review with DeepSeek

This commit is contained in:
t8y2 2026-05-08 15:40:49 +08:00
parent 53702984b1
commit 6dc6e15ff3
2 changed files with 86 additions and 10 deletions

69
.github/workflows/auto-review.yml vendored Normal file
View File

@ -0,0 +1,69 @@
name: Auto Review
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get PR diff
id: diff
env:
GH_TOKEN: ${{ github.token }}
run: |
gh pr diff ${{ github.event.pull_request.number }} > /tmp/pr.diff
# Truncate to ~30k chars to stay within LLM context
head -c 30000 /tmp/pr.diff > /tmp/pr_truncated.diff
- name: Review with DeepSeek
id: review
env:
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
run: |
DIFF=$(cat /tmp/pr_truncated.diff | jq -Rs .)
TITLE=$(echo '${{ github.event.pull_request.title }}' | jq -Rs .)
BODY=$(echo '${{ github.event.pull_request.body }}' | head -c 2000 | jq -Rs .)
RESPONSE=$(curl -s https://api.deepseek.com/chat/completions \
-H "Authorization: Bearer ${DEEPSEEK_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"deepseek-chat\",
\"messages\": [
{
\"role\": \"system\",
\"content\": \"你是一个专业的代码审查员。请审查以下 Pull Request 的代码变更给出简洁的中文评审意见。重点关注1. 潜在的 bug 或逻辑错误 2. 安全问题 3. 性能问题 4. 代码风格和可读性。如果代码没有问题,简单说 LGTM 并给出简短总结。不要逐行重复代码。\"
},
{
\"role\": \"user\",
\"content\": \"PR 标题: ${TITLE}\n\nPR 描述: ${BODY}\n\n代码变更:\n${DIFF}\"
}
],
\"max_tokens\": 2000
}")
REVIEW=$(echo "$RESPONSE" | jq -r '.choices[0].message.content // "审查失败,请手动检查。"')
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
echo "comment<<$EOF" >> "$GITHUB_OUTPUT"
echo "$REVIEW" >> "$GITHUB_OUTPUT"
echo "$EOF" >> "$GITHUB_OUTPUT"
- name: Post review comment
env:
GH_TOKEN: ${{ github.token }}
run: |
gh pr comment ${{ github.event.pull_request.number }} --body "$(cat <<'EOF'
🤖 **Auto Review by DeepSeek**
${{ steps.review.outputs.comment }}
EOF
)"

View File

@ -38,7 +38,7 @@ fn value_to_json(val: &rust_oracle::Value) -> serde_json::Value {
}
pub async fn list_databases(conn: &OracleClient) -> Result<Vec<DatabaseInfo>, String> {
log::debug!("[oracle] list_databases: querying all_users");
log::info!("[oracle] list_databases: START");
let result = conn
.query(
"SELECT username FROM all_users \
@ -49,11 +49,15 @@ pub async fn list_databases(conn: &OracleClient) -> Result<Vec<DatabaseInfo>, St
)
.await;
log::info!("[oracle] list_databases: primary done, ok={}", result.is_ok());
let result = match result {
Ok(r) => r,
Err(_) => conn
.query(
"SELECT username FROM all_users \
Err(e) => {
log::info!("[oracle] list_databases: primary err={e}, trying fallback...");
let r = conn
.query(
"SELECT username FROM all_users \
WHERE username NOT IN (\
'SYS','SYSTEM','SYSMAN','DBSNMP','SYSBACKUP','SYSDG','SYSKM','OUTLN',\
'AUDSYS','LBACSYS','DVF','DVSYS','APPQOSSYS','CTXSYS','MDSYS','MDDATA',\
@ -63,15 +67,18 @@ pub async fn list_databases(conn: &OracleClient) -> Result<Vec<DatabaseInfo>, St
'REMOTE_SCHEDULER_AGENT','PDBADMIN','DGPDB_INT','OPS$ORACLE',\
'GGSYS','FLOWS_FILES','APEX_PUBLIC_USER'\
) ORDER BY username",
&[],
)
.await
.map_err(|e| {
log::error!("[oracle] list_databases failed: {e}");
&[],
)
.await;
log::info!("[oracle] list_databases: fallback done, ok={}", r.is_ok());
r.map_err(|e| {
log::error!("[oracle] list_databases fallback err: {e}");
e.to_string()
})?,
})?
}
};
log::info!("[oracle] list_databases: DONE, {} rows", result.rows.len());
Ok(result.rows.iter().map(|row| DatabaseInfo { name: row.get_string(0).unwrap_or("").to_string() }).collect())
}