From 726c21feac978fa721ef1441a003983081f9007b Mon Sep 17 00:00:00 2001 From: Dang Zerong Date: Fri, 13 Mar 2026 16:04:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=AF=E6=BC=94=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 34 +++++++ config.yaml | 9 +- docker-compose.yml | 9 ++ pyproject.toml | 24 +++++ requirements.txt | 6 ++ test.py | 218 --------------------------------------------- web/index.html | 142 ----------------------------- 7 files changed, 77 insertions(+), 365 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 pyproject.toml delete mode 100644 test.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..64d7923 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +# 使用中科大镜像源的 Python 基础镜像 +FROM python:3.11.15-slim + +# 设置工作目录 +WORKDIR /app + +# 设置环境变量 +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV FLASK_RUN_HOST=0.0.0.0 + +# 安装系统依赖(用于 git 等工具) +RUN apt-get update && apt-get install -y --no-install-recommends \ + git \ + && rm -rf /var/lib/apt/lists/* + +# 复制依赖文件 +COPY requirements.txt . + +# 安装 Python 依赖(显式安装,避免缓存导致遗漏) +RUN pip install --no-cache-dir -r requirements.txt \ + && pip install --no-cache-dir "GitPython>=3.1.0" "gitdb>=4.0.1" "smmap>=3.0.1" + +# 复制应用代码 +COPY . . + +# 创建报告目录 +RUN mkdir -p reports + +# 暴露端口 +EXPOSE 5000 + +# 启动应用 +CMD ["python", "app.py"] diff --git a/config.yaml b/config.yaml index 8b8e755..49dd481 100644 --- a/config.yaml +++ b/config.yaml @@ -49,13 +49,12 @@ ai: # AI 审查器配置 # 支持: "ollama" (本地) 或 "api" (在线API) provider: "api" - # 模型名称(硅基流动可用模型)- Qwen 最强语言模型 - model: "deepseek-ai/DeepSeek-V3.2" + # 模型名称(阿里云通义千问) + model: "qwen3.5-plus" # API 地址 - # 硅基流动: https://api.siliconflow.cn/v1 - api_url: "https://api.siliconflow.cn/v1" + api_url: "https://dashscope.aliyuncs.com/compatible-mode/v1" # API 密钥 - api_key: "sk-cqxhnsxdxaalxlykfkjksyinjftdyejnblmgkfxmhwmmvdyu" + api_key: "sk-616332b2afa94699b4572d0fe6ac370a" # 是否启用 AI 审查 enabled: true # 每次审查的最大代码行数 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2a46add --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +version: "3.8" + +services: + code-scan: + image: dcr-by1jwyxk44.71826370.xyz/whlaoding/code-scan:latest + container_name: code-scan + ports: + - "5000:5000" + restart: unless-stopped diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c187f72 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,24 @@ +[build-system] +requires = ["setuptools>=45", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "code-scan" +version = "1.0.0" +description = "代码扫描工具" +readme = "README.md" +requires-python = ">=3.8" +dependencies = [ + "flask>=2.0.0", + "pyyaml>=5.0", + "requests>=2.25.0", + "python-dotenv>=0.19.0", + "GitPython>=3.1.0", +] + +[project.scripts] +code-scan = "app:main" + +[tool.setuptools.packages.find] +where = ["."] +include = ["scanner*"] diff --git a/requirements.txt b/requirements.txt index 369f634..d2be847 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,9 @@ flask>=2.0.0 pyyaml>=5.0 requests>=2.25.0 python-dotenv>=0.19.0 +GitPython>=3.1.0 +gitdb>=4.0.1 +smmap>=3.0.1 +pylint>=2.17.0 +flake8>=6.0.0 +bandit>=1.7.0 diff --git a/test.py b/test.py deleted file mode 100644 index 14b50b7..0000000 --- a/test.py +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import os -import logging - - -os.environ.setdefault('FLASK_RUN_HOST', '0.0.0.0') - -from flask import Flask, request, jsonify -import yaml -from webhook.handler import GiteaWebhookHandler -from scanner.python_scanner import PythonScanner -from scanner.js_scanner import JavaScriptScanner -from scanner.security_scanner import SecurityScanner -from report.generator import ReportGenerator -from notify.feishu import FeishuNotifier - -# 配置日志 -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' -) -logger = logging.getLogger(__name__) - -# 加载配置 -def load_config(): - """加载配置文件""" - config_path = os.path.join(os.path.dirname(__file__), 'config.yaml') - with open(config_path, 'r', encoding='utf-8') as f: - return yaml.safe_load(f) - -# 全局配置 -config = load_config() - -# 初始化应用 -app = Flask(__name__) -app.config['SECRET_KEY'] = config.get('server', {}).get('secret_key', 'dev-secret-key') - -# 初始化组件 -webhook_handler = GiteaWebhookHandler(config['gitea']) -python_scanner = PythonScanner(config.get('scanner', {})) -js_scanner = JavaScriptScanner(config.get('scanner', {})) -security_scanner = SecurityScanner(config.get('scanner', {})) -report_generator = ReportGenerator(config.get('report', {})) -feishu_notifier = FeishuNotifier(config['feishu']) - - -@app.route('/') -def index(): - """健康检查接口""" - return jsonify({ - 'status': 'ok', - 'service': 'AI Code Quality Scanner', - 'version': '1.0.0' - }) - - -@app.route('/webhook/gitea', methods=['POST']) -def handle_gitea_webhook(): - """处理 Gitea Webhook 请求""" - try: - # 验证签名 - signature = request.headers.get('X-Gitea-Signature') - if signature: - if not webhook_handler.verify_signature( - request.data, - signature, - config['gitea']['webhook_secret'] - ): - logger.warning('Webhook 签名验证失败') - return jsonify({'error': 'Invalid signature'}), 401 - - # 解析 Webhook payload - payload = request.json - if not payload: - return jsonify({'error': 'No payload'}), 400 - - event_type = request.headers.get('X-Gitea-Event', 'push') - logger.info(f'收到 Gitea Webhook 事件: {event_type}') - - # 只处理 push 事件 - if event_type != 'push': - return jsonify({'message': 'Event ignored'}), 200 - - # 提取提交信息 - commits = payload.get('commits', []) - if not commits: - return jsonify({'message': 'No commits'}), 200 - - repo = payload.get('repository', {}) - repo_name = repo.get('full_name', 'unknown') - branch = payload.get('ref', '').replace('refs/heads/', '') - pusher = payload.get('pusher', {}).get('name', 'unknown') - - logger.info(f'处理仓库 {repo_name} 的 {len(commits)} 个提交') - - # 处理每个提交 - for commit in commits: - commit_id = commit.get('id', '')[:8] - commit_message = commit.get('message', '') - author = commit.get('author', {}).get('name', 'unknown') - - logger.info(f'扫描提交 {commit_id}: {commit_message}') - - try: - # 获取仓库 URL - clone_url = repo.get('clone_url') - if not clone_url: - # 尝试从 web_url 构建 - web_url = repo.get('web_url', '') - if web_url: - clone_url = web_url.replace('http://', 'http://').replace('https://', 'https://') - clone_url = clone_url.rstrip('/') + '.git' - - # 执行代码扫描 - scan_results = {} - - # Python 扫描 - if 'python' in config.get('scanner', {}).get('languages', []): - scan_results['python'] = python_scanner.scan( - clone_url, commit_id, branch - ) - - # JavaScript/TypeScript 扫描 - if any(lang in config.get('scanner', {}).get('languages', []) - for lang in ['javascript', 'typescript']): - scan_results['javascript'] = js_scanner.scan( - clone_url, commit_id, branch - ) - - # 安全扫描 - scan_results['security'] = security_scanner.scan( - clone_url, commit_id, branch - ) - - # 生成报告 - report = report_generator.generate( - repo_name=repo_name, - branch=branch, - commit_id=commit_id, - commit_message=commit_message, - author=author, - scan_results=scan_results - ) - - # 发送飞书通知 - feishu_notifier.send_report(report) - - logger.info(f'提交 {commit_id} 扫描完成') - - except Exception as e: - logger.error(f'扫描提交 {commit_id} 失败: {str(e)}') - # 继续处理其他提交 - continue - - return jsonify({'status': 'ok', 'message': 'Scan completed'}), 200 - - except Exception as e: - logger.error(f'处理 Webhook 失败: {str(e)}', exc_info=True) - return jsonify({'error': str(e)}), 500 - - -@app.route('/scan/manual', methods=['POST']) -def manual_scan(): - """手动触发扫描接口""" - try: - data = request.json - repo_url = data.get('repo_url') - branch = data.get('branch', 'main') - commit_id = data.get('commit_id') - - if not repo_url: - return jsonify({'error': 'repo_url is required'}), 400 - - # 执行扫描 - scan_results = {} - - if 'python' in config.get('scanner', {}).get('languages', []): - scan_results['python'] = python_scanner.scan(repo_url, commit_id, branch) - - if any(lang in config.get('scanner', {}).get('languages', []) - for lang in ['javascript', 'typescript']): - scan_results['javascript'] = js_scanner.scan(repo_url, commit_id, branch) - - scan_results['security'] = security_scanner.scan(repo_url, commit_id, branch) - - # 生成报告 - report = report_generator.generate( - repo_name=repo_url.split('/')[-1].replace('.git', ''), - branch=branch, - commit_id=commit_id or 'manual', - commit_message='Manual scan', - author='manual', - scan_results=scan_results - ) - - # 发送飞书通知 - feishu_notifier.send_report(report) - - return jsonify({ - 'status': 'ok', - 'report': report - }), 200 - - except Exception as e: - logger.error(f'手动扫描失败: {str(e)}', exc_info=True) - return jsonify({'error': str(e)}), 500 - - -if __name__ == '__main__': - # 强制监听所有网络接口 - host = "0.0.0.0" - port = config.get('server', {}).get('port', 5000) - debug = config.get('server', {}).get('debug', True) - - logger.info(f'启动服务: {host}:{port}') - app.run(host=host, port=port, debug=debug) diff --git a/web/index.html b/web/index.html index 0143622..0354850 100644 --- a/web/index.html +++ b/web/index.html @@ -97,30 +97,9 @@ -
AI 智能分析
- - -
- AI 引擎 -
基于大模型智能分析代码质量
-
- 在线 -
-
@@ -289,126 +268,6 @@ - - - - - @@ -660,7 +519,6 @@ if (page === 'dashboard') loadDashboard(); if (page === 'prs') loadPRs(); - if (page === 'ai-quality') loadAIQualityOverview(); } // 加载概览数据