RepoGuard-AI / core_system /report-generator.py
AbdulElahGwaith's picture
Upload folder using huggingface_hub
6d82353 verified
#!/usr/bin/env python3
"""
Auto-Guardian: Report Generator
================================
Generate detailed reports about code quality and send appropriate notifications
"""
import json
import sys
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from pathlib import Path
from typing import Optional
class ReportType(Enum):
"""Types of reports"""
PULL_REQUEST = "pull_request"
DAILY_SUMMARY = "daily_summary"
SECURITY_ALERT = "security_alert"
QUALITY_REPORT = "quality_report"
@dataclass
class ReportConfig:
"""Report configuration"""
scan_results_file: str
pr_number: Optional[int] = None
report_type: ReportType = ReportType.PULL_REQUEST
include_details: bool = True
include_suggestions: bool = True
class ReportGenerator:
"""Report generator"""
def __init__(self, config: ReportConfig):
self.config = config
self.results = self._load_results()
def _load_results(self) -> dict:
"""Load scan results"""
with open(self.config.scan_results_file, 'r', encoding='utf-8') as f:
return json.load(f)
def generate_pull_request_comment(self) -> str:
"""Generate comment for Pull Request"""
summary = self.results.get('summary', {})
critical_issues = self.results.get('critical_issues', [])
auto_fixable = self.results.get('auto_fixable_issues', [])
all_issues = self.results.get('all_issues', [])
# Severity emojis
severity_emojis = {
'critical': 'Critical',
'high': 'High',
'medium': 'Medium',
'low': 'Low',
'info': 'Info'
}
report = []
# Title
report.append("## Quality Scan Report - Auto-Guardian")
report.append("")
report.append(f"**Scan Date:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
report.append(f"**Files Scanned:** {summary.get('files_scanned', 0)}")
report.append(f"**Total Issues:** {summary.get('total_issues', 0)}")
report.append("")
# Summary by severity
report.append("### Issues Summary")
report.append("")
report.append("| Severity | Count |")
report.append("|----------|-------|")
for severity, count in summary.get('by_severity', {}).items():
emoji = severity_emojis.get(severity, 'Info')
report.append(f"| {emoji} | {count} |")
report.append("")
# Auto-fix status
if auto_fixable:
report.append("### Auto-Fixes Applied")
report.append("")
report.append(f"**{len(auto_fixable)}** issues were fixed automatically:")
report.append("")
for issue in auto_fixable[:10]: # Show first 10 only
file_path = Path(issue['file']).name
report.append(f"- Fixed `{file_path}`:{issue['line']} - {issue['message']}")
if len(auto_fixable) > 10:
report.append(f"- ... and **{len(auto_fixable) - 10}** more fixes")
report.append("")
# Issues requiring human intervention
if critical_issues:
report.append("### Issues Requiring Human Intervention")
report.append("")
report.append("**This code cannot be merged until these issues are resolved:**")
report.append("")
for issue in critical_issues:
file_path = Path(issue['file']).name
emoji = severity_emojis.get(issue['severity'], 'Critical')
report.append(f"- **{emoji} {issue['file']}:{issue['line']}**")
report.append(f" - Issue: {issue['message']}")
if issue.get('suggestion'):
report.append(f" - Suggestion: {issue['suggestion']}")
report.append("")
report.append("---")
report.append("### Merge Status: Blocked")
report.append("")
report.append("**This Pull Request is blocked from merging due to critical issues.**")
report.append("")
report.append("Please resolve the issues above and try again.")
else:
# No critical issues
report.append("---")
report.append("### Merge Status: Approved")
report.append("")
report.append("**This code passed all quality checks!**")
report.append("")
report.append("You can proceed with merging this Pull Request.")
# Footer
report.append("")
report.append("---")
report.append("*Report generated automatically by Auto-Guardian Bot*")
return '\n'.join(report)
def generate_daily_summary(self) -> dict:
"""Generate daily summary"""
summary = self.results.get('summary', {})
return {
"date": datetime.now().isoformat(),
"total_issues": summary.get('total_issues', 0),
"critical_issues": summary.get('critical_count', 0),
"auto_fixed": summary.get('auto_fixable_count', 0),
"by_severity": summary.get('by_severity', {}),
"by_type": summary.get('by_type', {})
}
def generate_security_alert(self) -> str:
"""Generate security alert"""
critical = self.results.get('critical_issues', [])
security_issues = [i for i in critical if 'security' in i.get('type', '')]
if not security_issues:
return None
alert = []
alert.append("Security Alert - Auto-Guardian")
alert.append("")
alert.append("Security vulnerabilities detected in code:")
alert.append("")
for issue in security_issues:
alert.append(f"- {issue['file']}:{issue['line']}")
alert.append(f" {issue['message']}")
if issue.get('suggestion'):
alert.append(f" Suggestion: {issue['suggestion']}")
return '\n'.join(alert)
def save_report(self, content: str, filename: str = "report.md") -> Path:
"""Save report to file"""
output_path = Path(filename)
with open(output_path, 'w', encoding='utf-8') as f:
f.write(content)
return output_path
def main():
"""Main function"""
import argparse
parser = argparse.ArgumentParser(description='Auto-Guardian Report Generator')
parser.add_argument('--scan-results', required=True, help='Scan results file')
parser.add_argument('--pr-number', type=int, help='Pull Request number')
parser.add_argument('--output', '-o', default="report.md", help='Output file')
parser.add_argument('--format', choices=['comment', 'summary', 'json'],
default='comment', help='Report format')
args = parser.parse_args()
config = ReportConfig(
scan_results_file=args.scan_results,
pr_number=args.pr_number,
report_type=ReportType.PULL_REQUEST
)
generator = ReportGenerator(config)
if args.format == 'comment':
report = generator.generate_pull_request_comment()
elif args.format == 'summary':
report = json.dumps(generator.generate_daily_summary(), indent=2)
else:
report = generator.generate_pull_request_comment()
# Print report
print(report)
# Save report
generator.save_report(report, args.output)
print(f"\nReport saved to {args.output}")
if __name__ == '__main__':
main()