Files
ewoooc/routes/code_review_routes.py
ogt 2e0de960ce
All checks were successful
CD Pipeline / deploy (push) Successful in 1m21s
feat(code-review): 重建為 Post-Deploy AI Agent Pipeline
架構重建:
- 移除 pre-commit hook(本機 commit 不再阻塞)
- 改為 CD 健康檢查通過後自動觸發 webhook

新建 services/code_review_pipeline_service.py:
  5-Step Pipeline(後台 daemon thread)
  Step1 system        讀取部署後變更檔案內容
  Step2 Hermes        程式碼掃描(bugs/security/perf,hermes3:latest)
  Step3 OpenClaw      架構品質評估(Gemini 2.5 Flash)
  Step4 ElephantAlpha 決策協調(severity + auto_fix 裁量)
  Step5 NemoTron      action_plans 寫入 + AiderHeal 觸發
  全程 Telegram 告警(啟動/完成/錯誤)+ ai_insights DB 持久化

重建 routes/code_review_routes.py:
  POST /code-review/api/internal/trigger  CD webhook(X-Internal-Token)
  GET  /code-review/api/status            前端即時 polling
  GET  /code-review/api/history           歷史清單
  GET  /code-review/                      前端儀表板

重建 templates/code_review.html:
  深色儀表板,Pipeline 即時進度 + Severity 分佈 + 問題清單 + EA 決策
  3s polling(running)/ 30s(idle)

.gitea/workflows/cd.yaml:
  健康檢查通過後注入「觸發 AI Code Review」step
  continue-on-error: true(不影響部署結果)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 20:55:23 +08:00

108 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
routes/code_review_routes.py
Code Review 路由層
端點:
POST /code-review/api/internal/trigger — CD Webhook部署後觸發
GET /code-review/api/status — 前端 polling 即時狀態
GET /code-review/api/history — 歷史 review 清單
GET /code-review/ — 前端儀表板
"""
import logging
from flask import Blueprint, jsonify, render_template, request
logger = logging.getLogger(__name__)
code_review_bp = Blueprint("code_review", __name__, url_prefix="/code-review")
# ══════════════════════════════════════════════════════════════════════════════
# CD Webhook — 部署成功後由 Gitea Action 呼叫
# ══════════════════════════════════════════════════════════════════════════════
@code_review_bp.route("/api/internal/trigger", methods=["POST"])
def trigger_review():
"""
接受 Gitea CD pipeline 觸發 Code Review 的 webhook。
Request body (JSON):
commit_sha str 完整 commit SHA
changed_files list 變更檔案路徑清單
branch str 分支名稱(預設 main
deploy_type str sync | rebuild
Header:
X-Internal-Token 與 INTERNAL_WEBHOOK_TOKEN env 比對
"""
try:
from services.code_review_pipeline_service import (
trigger_post_deploy_review,
verify_internal_token,
)
# 驗證 token
token = request.headers.get("X-Internal-Token", "")
if not verify_internal_token(token):
logger.warning("[CodeReview] Webhook token 驗證失敗")
return jsonify({"ok": False, "error": "Unauthorized"}), 401
body = request.get_json(silent=True) or {}
commit_sha = body.get("commit_sha", "")
changed_files = body.get("changed_files", [])
branch = body.get("branch", "main")
deploy_type = body.get("deploy_type", "sync")
if not commit_sha:
return jsonify({"ok": False, "error": "commit_sha 必填"}), 400
pipeline_id = trigger_post_deploy_review(
commit_sha=commit_sha,
changed_files=changed_files,
branch=branch,
deploy_type=deploy_type,
)
logger.info("[CodeReview] Webhook 觸發成功 pipeline_id=%s", pipeline_id)
return jsonify({"ok": True, "pipeline_id": pipeline_id})
except Exception as e:
logger.error("[CodeReview] Webhook 處理失敗: %s", e, exc_info=True)
return jsonify({"ok": False, "error": str(e)}), 500
# ══════════════════════════════════════════════════════════════════════════════
# 前端 API — 即時狀態 / 歷史
# ══════════════════════════════════════════════════════════════════════════════
@code_review_bp.route("/api/status", methods=["GET"])
def api_status():
"""即時 Pipeline 狀態(前端每 3 秒 polling"""
try:
from services.code_review_pipeline_service import get_current_state
return jsonify(get_current_state())
except Exception as e:
return jsonify({"error": str(e)}), 500
@code_review_bp.route("/api/history", methods=["GET"])
def api_history():
"""歷史 Code Review 結果清單"""
try:
limit = min(int(request.args.get("limit", 20)), 50)
from services.code_review_pipeline_service import get_history
return jsonify(get_history(limit=limit))
except Exception as e:
return jsonify({"error": str(e)}), 500
# ══════════════════════════════════════════════════════════════════════════════
# 前端頁面
# ══════════════════════════════════════════════════════════════════════════════
@code_review_bp.route("/", methods=["GET"])
def dashboard():
return render_template("code_review.html")