108 lines
4.7 KiB
Python
108 lines
4.7 KiB
Python
#!/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", active_page="code_review")
|