init
This commit is contained in:
1
report/__init__.py
Normal file
1
report/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Report 模块
|
||||
220
report/generator.py
Normal file
220
report/generator.py
Normal file
@@ -0,0 +1,220 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Markdown 报告生成器
|
||||
生成代码质量扫描报告
|
||||
"""
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ReportGenerator:
|
||||
"""代码质量扫描报告生成器"""
|
||||
|
||||
def __init__(self, config: Dict[str, Any]):
|
||||
"""
|
||||
初始化报告生成器
|
||||
|
||||
Args:
|
||||
config: 报告配置
|
||||
"""
|
||||
self.config = config
|
||||
self.output_dir = config.get('output_dir', './reports')
|
||||
self.keep_files = config.get('keep_files', True)
|
||||
|
||||
# 确保输出目录存在
|
||||
os.makedirs(self.output_dir, exist_ok=True)
|
||||
|
||||
def generate(
|
||||
self,
|
||||
repo_name: str,
|
||||
branch: str,
|
||||
commit_id: str,
|
||||
commit_message: str,
|
||||
author: str,
|
||||
scan_results: Dict[str, Any]
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
生成扫描报告
|
||||
|
||||
Args:
|
||||
repo_name: 仓库名称
|
||||
branch: 分支名
|
||||
commit_id: 提交 ID
|
||||
commit_message: 提交信息
|
||||
author: 提交者
|
||||
scan_results: 扫描结果
|
||||
|
||||
Returns:
|
||||
报告数据
|
||||
"""
|
||||
# 计算总体统计
|
||||
total_issues = 0
|
||||
total_errors = 0
|
||||
total_warnings = 0
|
||||
|
||||
for scanner_name, result in scan_results.items():
|
||||
summary = result.get('summary', {})
|
||||
total_issues += summary.get('total', 0)
|
||||
total_errors += summary.get('error', 0) + summary.get('high', 0)
|
||||
total_warnings += summary.get('warning', 0) + summary.get('medium', 0)
|
||||
|
||||
# 确定状态
|
||||
if total_issues == 0:
|
||||
status = 'pass'
|
||||
status_text = '✅ 扫描通过'
|
||||
elif total_errors > 0:
|
||||
status = 'fail'
|
||||
status_text = f'❌ 发现 {total_errors} 个错误'
|
||||
else:
|
||||
status = 'warning'
|
||||
status_text = f'⚠️ 发现 {total_warnings} 个警告'
|
||||
|
||||
# 生成报告数据
|
||||
report = {
|
||||
'repo_name': repo_name,
|
||||
'branch': branch,
|
||||
'commit_id': commit_id,
|
||||
'commit_message': commit_message,
|
||||
'author': author,
|
||||
'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'status': status,
|
||||
'status_text': status_text,
|
||||
'total_issues': total_issues,
|
||||
'total_errors': total_errors,
|
||||
'total_warnings': total_warnings,
|
||||
'scan_results': scan_results,
|
||||
'markdown': self._generate_markdown(
|
||||
repo_name, branch, commit_id, commit_message, author, scan_results, status, status_text
|
||||
)
|
||||
}
|
||||
|
||||
# 保存报告文件
|
||||
if self.keep_files:
|
||||
self._save_report(report)
|
||||
|
||||
return report
|
||||
|
||||
def _generate_markdown(
|
||||
self,
|
||||
repo_name: str,
|
||||
branch: str,
|
||||
commit_id: str,
|
||||
commit_message: str,
|
||||
author: str,
|
||||
scan_results: Dict[str, Any],
|
||||
status: str,
|
||||
status_text: str
|
||||
) -> str:
|
||||
"""生成 Markdown 格式的报告"""
|
||||
lines = []
|
||||
|
||||
# 标题
|
||||
lines.append('# 📊 代码质量扫描报告')
|
||||
lines.append('')
|
||||
|
||||
# 基本信息
|
||||
lines.append('## 📋 基本信息')
|
||||
lines.append('')
|
||||
lines.append(f'| 项目 | 内容 |')
|
||||
lines.append(f'|------|------|')
|
||||
lines.append(f'| 仓库 | `{repo_name}` |')
|
||||
lines.append(f'| 分支 | `{branch}` |')
|
||||
lines.append(f'| 提交 | `{commit_id}` |')
|
||||
lines.append(f'| 提交者 | {author} |')
|
||||
lines.append(f'| 提交信息 | {commit_message[:50]}... |' if len(commit_message) > 50 else f'| 提交信息 | {commit_message} |')
|
||||
lines.append(f'| 扫描时间 | {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} |')
|
||||
lines.append('')
|
||||
|
||||
# 扫描状态
|
||||
lines.append('## 📈 扫描状态')
|
||||
lines.append('')
|
||||
lines.append(f'**{status_text}**')
|
||||
lines.append('')
|
||||
|
||||
# 各扫描器结果汇总
|
||||
lines.append('## 🔍 扫描详情')
|
||||
lines.append('')
|
||||
|
||||
for scanner_name, result in scan_results.items():
|
||||
tool_name = result.get('tool', scanner_name)
|
||||
summary = result.get('summary', {})
|
||||
|
||||
lines.append(f'### {tool_name}')
|
||||
lines.append('')
|
||||
lines.append(f'- 扫描文件数: {result.get("files_scanned", 0)}')
|
||||
lines.append(f'- 总问题数: {summary.get("total", 0)}')
|
||||
|
||||
# 根据不同扫描器显示不同的摘要字段
|
||||
if 'error' in summary:
|
||||
lines.append(f' - 错误: {summary.get("error", 0)}')
|
||||
lines.append(f' - 警告: {summary.get("warning", 0)}')
|
||||
lines.append(f' - 提示: {summary.get("info", 0)}')
|
||||
elif 'high' in summary:
|
||||
lines.append(f' - 高危: {summary.get("high", 0)}')
|
||||
lines.append(f' - 中危: {summary.get("medium", 0)}')
|
||||
lines.append(f' - 低危: {summary.get("low", 0)}')
|
||||
|
||||
issues = result.get('issues', [])
|
||||
if issues and self.config.get('detailed', True):
|
||||
lines.append('')
|
||||
lines.append('**问题列表:**')
|
||||
lines.append('')
|
||||
|
||||
for i, issue in enumerate(issues[:10], 1): # 最多显示10个
|
||||
severity = issue.get('severity', 'Unknown')
|
||||
severity_emoji = {
|
||||
'HIGH': '🔴',
|
||||
'MEDIUM': '🟡',
|
||||
'LOW': '🔵',
|
||||
'ERROR': '🔴',
|
||||
'WARNING': '🟡',
|
||||
'INFO': 'ℹ️'
|
||||
}.get(severity.upper(), '⚪')
|
||||
|
||||
file_path = issue.get('file', 'unknown')
|
||||
line_num = issue.get('line', 0)
|
||||
message = issue.get('message', 'No message')
|
||||
|
||||
lines.append(f'{i}. {severity_emoji} **{severity}** - `{file_path}:{line_num}`')
|
||||
lines.append(f' - {message}')
|
||||
lines.append('')
|
||||
|
||||
# 添加报告链接或下一步操作
|
||||
lines.append('---')
|
||||
lines.append('')
|
||||
lines.append('*此报告由 AI Code Quality Scanner 自动生成*')
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
def _save_report(self, report: Dict[str, Any]):
|
||||
"""保存报告到文件"""
|
||||
try:
|
||||
# 生成文件名
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
repo_name = report['repo_name'].replace('/', '_')
|
||||
filename = f'{repo_name}_{report["commit_id"]}_{timestamp}.md'
|
||||
filepath = os.path.join(self.output_dir, filename)
|
||||
|
||||
# 写入文件
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(report['markdown'])
|
||||
|
||||
logger.info(f'报告已保存: {filepath}')
|
||||
|
||||
# 同时保存 JSON 格式(便于程序解析)
|
||||
json_filename = filename.replace('.md', '.json')
|
||||
json_filepath = os.path.join(self.output_dir, json_filename)
|
||||
|
||||
with open(json_filepath, 'w', encoding='utf-8') as f:
|
||||
json.dump(report, f, ensure_ascii=False, indent=2)
|
||||
|
||||
logger.info(f'JSON 报告已保存: {json_filepath}')
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'保存报告失败: {str(e)}')
|
||||
Reference in New Issue
Block a user