221 lines
9.9 KiB
YAML
221 lines
9.9 KiB
YAML
name: Code Review
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
paths:
|
||
- 'apps/**'
|
||
- 'k8s/**'
|
||
- '!k8s/awoooi-prod/kustomization.yaml'
|
||
- 'ops/**'
|
||
- 'scripts/**'
|
||
- '.gitea/workflows/**'
|
||
workflow_dispatch:
|
||
|
||
concurrency:
|
||
group: code-review-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
env:
|
||
REPORT_URL: https://mo.wooo.work/code-review/
|
||
GITEA_ACTIONS_URL: http://192.168.0.110:3001/wooo/awoooi/actions
|
||
SRE_GROUP_CHAT_ID: "-1003711974679"
|
||
|
||
jobs:
|
||
ai-code-review:
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 8
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 50
|
||
|
||
- name: Guard Workflow Secret Surfaces
|
||
run: node scripts/ci/check-gitea-step-env-secrets.js
|
||
|
||
- name: Skip Stale Main Push
|
||
id: stale
|
||
run: |
|
||
set -euo pipefail
|
||
BRANCH="${GITHUB_REF_NAME:-${GITHUB_REF#refs/heads/}}"
|
||
if [ "${GITHUB_EVENT_NAME:-}" != "push" ] || [ "$BRANCH" != "main" ]; then
|
||
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||
exit 0
|
||
fi
|
||
LATEST="$(git ls-remote origin refs/heads/main | awk '{print $1}')"
|
||
if [ -n "$LATEST" ] && [ "$LATEST" != "$GITHUB_SHA" ]; then
|
||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||
echo "Skip stale code review: current=$GITHUB_SHA latest=$LATEST"
|
||
else
|
||
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||
fi
|
||
|
||
- name: Prepare Review Context
|
||
id: ctx
|
||
if: steps.stale.outputs.skip != 'true'
|
||
env:
|
||
BASE_SHA: ${{ github.event.before }}
|
||
run: |
|
||
set -euo pipefail
|
||
SHORT_SHA="${GITHUB_SHA::7}"
|
||
BRANCH="${GITHUB_REF_NAME:-${GITHUB_REF#refs/heads/}}"
|
||
if [ -z "$BRANCH" ] || [ "$BRANCH" = "$GITHUB_REF" ]; then
|
||
BRANCH="main"
|
||
fi
|
||
COMMIT_MSG="$(git log -1 --pretty=%s)"
|
||
COMMIT_MSG="${COMMIT_MSG:0:120}"
|
||
BASE="${BASE_SHA:-}"
|
||
if [ -n "$BASE" ] && [ "$BASE" != "0000000000000000000000000000000000000000" ]; then
|
||
git rev-parse --verify "${BASE}^{commit}" >/dev/null 2>&1 || git fetch --no-tags origin "$BASE" --depth=1 || true
|
||
fi
|
||
|
||
if [ -n "$BASE" ] && git rev-parse --verify "${BASE}^{commit}" >/dev/null 2>&1; then
|
||
RANGE="$BASE..$GITHUB_SHA"
|
||
elif git rev-parse --verify "${GITHUB_SHA}^" >/dev/null 2>&1; then
|
||
BASE="${GITHUB_SHA}^"
|
||
RANGE="${GITHUB_SHA}^..$GITHUB_SHA"
|
||
else
|
||
BASE=""
|
||
RANGE="$GITHUB_SHA"
|
||
fi
|
||
|
||
FILES="$(git diff --name-only "$RANGE" || git show --pretty= --name-only "$GITHUB_SHA")"
|
||
if [ -z "$FILES" ]; then
|
||
FILES="(no files reported)"
|
||
fi
|
||
FILE_COUNT="$(printf '%s\n' "$FILES" | grep -c . || true)"
|
||
FILES_DISPLAY="$(printf '%s\n' "$FILES" | sed -n '1,6s/^/• /p')"
|
||
if [ "$FILE_COUNT" -gt 6 ]; then
|
||
FILES_DISPLAY="$(printf '%s\n• ... and %s more' "$FILES_DISPLAY" "$((FILE_COUNT - 6))")"
|
||
fi
|
||
|
||
{
|
||
echo "short_sha=$SHORT_SHA"
|
||
echo "branch=$BRANCH"
|
||
echo "base_sha=$BASE"
|
||
echo "file_count=$FILE_COUNT"
|
||
echo "commit_msg<<EOF"
|
||
printf '%s\n' "$COMMIT_MSG"
|
||
echo "EOF"
|
||
echo "files_display<<EOF"
|
||
printf '%s\n' "$FILES_DISPLAY"
|
||
echo "EOF"
|
||
} >> "$GITHUB_OUTPUT"
|
||
|
||
- name: Notify Code Review Start
|
||
if: steps.stale.outputs.skip != 'true'
|
||
env:
|
||
SRE_GROUP_CHAT_ID: ${{ env.SRE_GROUP_CHAT_ID }}
|
||
SHORT_SHA: ${{ steps.ctx.outputs.short_sha }}
|
||
BRANCH: ${{ steps.ctx.outputs.branch }}
|
||
COMMIT_MSG: ${{ steps.ctx.outputs.commit_msg }}
|
||
FILES_DISPLAY: ${{ steps.ctx.outputs.files_display }}
|
||
run: |
|
||
set -euo pipefail
|
||
TG_BOT_TOKEN="$(cat <<'AWOOOI_SECRET_TG_BOT_TOKEN'
|
||
${{ secrets.TELEGRAM_BOT_TOKEN }}
|
||
AWOOOI_SECRET_TG_BOT_TOKEN
|
||
)"
|
||
html_escape() { sed 's/&/\&/g; s/</\</g; s/>/\>/g'; }
|
||
COMMIT_ESC="$(printf '%s' "$COMMIT_MSG" | html_escape)"
|
||
FILES_ESC="$(printf '%s\n' "$FILES_DISPLAY" | html_escape)"
|
||
MSG="$(printf '🔍 <b>Code Review 啟動</b>\n──────────────────────\n📦 Commit <code>%s</code> 🌿 <code>%s</code>\n📝 <code>%s</code>\n📁 <b>變更檔案:</b>\n%s\n──────────────────────\n🤖 <b>Hermes → OpenClaw → Elephant Alpha → NemoTron</b>\n📊 即時進度:<a href=\"%s\">%s</a>' "$SHORT_SHA" "$BRANCH" "$COMMIT_ESC" "$FILES_ESC" "$REPORT_URL" "$REPORT_URL")"
|
||
if AWOOI_CICD_STATUS=running \
|
||
AWOOI_CICD_STAGE=code-review \
|
||
AWOOI_CICD_JOB_NAME="Code Review 啟動" \
|
||
AWOOI_CICD_COMMIT_SHA="${GITHUB_SHA}" \
|
||
AWOOI_CICD_TRIGGERED_BY="${GITHUB_ACTOR:-CI}" \
|
||
AWOOI_CICD_SUMMARY="${COMMIT_MSG}" \
|
||
AWOOI_CICD_WORKFLOW_URL="${REPORT_URL}" \
|
||
scripts/ci/notify-awoooi-cicd.sh; then
|
||
echo "Code review start notification mirrored through AWOOI API"
|
||
else
|
||
if [ -z "${TG_BOT_TOKEN:-}" ] || [ -z "${SRE_GROUP_CHAT_ID:-}" ]; then
|
||
echo "Telegram secret missing and AWOOI API notify failed; skip start notification"
|
||
exit 0
|
||
fi
|
||
curl -fsS -X POST "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$(jq -n --arg c "$SRE_GROUP_CHAT_ID" --arg t "$MSG" '{chat_id:$c,text:$t,parse_mode:"HTML",disable_web_page_preview:true}')" \
|
||
>/dev/null
|
||
fi
|
||
|
||
- name: Run Deterministic Review
|
||
if: steps.stale.outputs.skip != 'true'
|
||
env:
|
||
BASE_SHA: ${{ steps.ctx.outputs.base_sha }}
|
||
run: |
|
||
set -euo pipefail
|
||
python3 scripts/ci_code_review.py \
|
||
--base "${BASE_SHA:-}" \
|
||
--head "$GITHUB_SHA" \
|
||
--repo "." \
|
||
--output /tmp/code-review-report.json
|
||
jq . /tmp/code-review-report.json
|
||
|
||
- name: Notify Code Review Completion
|
||
if: always() && steps.stale.outputs.skip != 'true'
|
||
env:
|
||
SRE_GROUP_CHAT_ID: ${{ env.SRE_GROUP_CHAT_ID }}
|
||
SHORT_SHA: ${{ steps.ctx.outputs.short_sha }}
|
||
run: |
|
||
set -euo pipefail
|
||
TG_BOT_TOKEN="$(cat <<'AWOOOI_SECRET_TG_BOT_TOKEN'
|
||
${{ secrets.TELEGRAM_BOT_TOKEN }}
|
||
AWOOOI_SECRET_TG_BOT_TOKEN
|
||
)"
|
||
REPORT=/tmp/code-review-report.json
|
||
if [ ! -s "$REPORT" ]; then
|
||
cat > "$REPORT" <<'JSON'
|
||
{"counts":{"critical":0,"high":0,"medium":1,"low":0},"risk":"MEDIUM","summary":"Code Review workflow 未產生報告,需查看 Gitea Actions 日誌。","action":"查看 workflow logs","top_issue":"報告產生失敗","agents":["Hermes","OpenClaw","ElephantAlpha","NemoTron"]}
|
||
JSON
|
||
fi
|
||
CRITICAL="$(jq -r '.counts.critical' "$REPORT")"
|
||
HIGH="$(jq -r '.counts.high' "$REPORT")"
|
||
MEDIUM="$(jq -r '.counts.medium' "$REPORT")"
|
||
LOW="$(jq -r '.counts.low' "$REPORT")"
|
||
RISK="$(jq -r '.risk' "$REPORT")"
|
||
SUMMARY="$(jq -r '.summary' "$REPORT")"
|
||
ACTION="$(jq -r '.action' "$REPORT")"
|
||
TOP_ISSUE="$(jq -r '.top_issue' "$REPORT")"
|
||
|
||
if [ "$RISK" = "LOW" ]; then
|
||
STATUS="🟢"
|
||
ISSUE_LINE="✅ 無高風險問題"
|
||
elif [ "$RISK" = "MEDIUM" ]; then
|
||
STATUS="🟡"
|
||
ISSUE_LINE="⚠️ 有中風險註記"
|
||
else
|
||
STATUS="🔴"
|
||
ISSUE_LINE="🚨 需人工複核"
|
||
fi
|
||
|
||
html_escape() { sed 's/&/\&/g; s/</\</g; s/>/\>/g'; }
|
||
SUMMARY_ESC="$(printf '%s' "$SUMMARY" | html_escape)"
|
||
ACTION_ESC="$(printf '%s' "$ACTION" | html_escape)"
|
||
TOP_ESC="$(printf '%s' "$TOP_ISSUE" | html_escape)"
|
||
|
||
MSG="$(printf '%s <b>Code Review 完成・%s</b>\n──────────────────────\n🔴 CRITICAL <code>%s</code> 🟠 HIGH <code>%s</code> 🟡 MEDIUM <code>%s</code> 🟢 LOW <code>%s</code>\n──────────────────────\n⚠️ <b>主要問題</b>\n%s\n\n🔍 <b>整體風險等級</b>\n%s:%s\n\n⚠️ <b>最高關注問題</b>\n1. %s\n──────────────────────\n🤖 Elephant Alpha:<b>%s</b> ✅ %s\n📊 完整報告:<a href=\"%s\">%s</a>' "$STATUS" "$SHORT_SHA" "$CRITICAL" "$HIGH" "$MEDIUM" "$LOW" "$ISSUE_LINE" "$RISK" "$SUMMARY_ESC" "$TOP_ESC" "$RISK" "$ACTION_ESC" "$REPORT_URL" "$REPORT_URL")"
|
||
CICD_STATUS=success
|
||
if [ "$RISK" = "MEDIUM" ]; then CICD_STATUS=pending; fi
|
||
if [ "$RISK" = "HIGH" ] || [ "$RISK" = "CRITICAL" ]; then CICD_STATUS=failed; fi
|
||
if AWOOI_CICD_STATUS="${CICD_STATUS}" \
|
||
AWOOI_CICD_STAGE=code-review \
|
||
AWOOI_CICD_JOB_NAME="Code Review 完成・${RISK}" \
|
||
AWOOI_CICD_COMMIT_SHA="${GITHUB_SHA}" \
|
||
AWOOI_CICD_TRIGGERED_BY="${GITHUB_ACTOR:-CI}" \
|
||
AWOOI_CICD_SUMMARY="CRITICAL=${CRITICAL}; HIGH=${HIGH}; MEDIUM=${MEDIUM}; LOW=${LOW}; ${SUMMARY}" \
|
||
AWOOI_CICD_WORKFLOW_URL="${REPORT_URL}" \
|
||
scripts/ci/notify-awoooi-cicd.sh; then
|
||
echo "Code review completion notification mirrored through AWOOI API"
|
||
else
|
||
if [ -z "${TG_BOT_TOKEN:-}" ] || [ -z "${SRE_GROUP_CHAT_ID:-}" ]; then
|
||
echo "Telegram secret missing and AWOOI API notify failed; skip completion notification"
|
||
exit 0
|
||
fi
|
||
curl -fsS -X POST "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$(jq -n --arg c "$SRE_GROUP_CHAT_ID" --arg t "$MSG" '{chat_id:$c,text:$t,parse_mode:"HTML",disable_web_page_preview:true}')" \
|
||
>/dev/null
|
||
fi
|