OnyxMunk/AudioForge
0
1#!/usr/bin/env python3
2"""
3Generate comprehensive launch readiness report
4Combines all verification checks into a single PDF/HTML report
5"""
6
7import asyncio
8import json
9import subprocess
10import sys
11from datetime import datetime
12from pathlib import Path
13from typing import Dict, List, Any
14
15try:
16 from jinja2 import Template
17 import markdown
18except ImportError:
19 print("Installing required packages...")
20 subprocess.run([sys.executable, "-m", "pip", "install", "jinja2", "markdown"], check=True)
21 from jinja2 import Template
22 import markdown
23
24
25HTML_TEMPLATE = """
26<!DOCTYPE html>
27<html lang="en">
28<head>
29 <meta charset="UTF-8">
30 <meta name="viewport" content="width=device-width, initial-scale=1.0">
31 <title>AudioForge Launch Report - {{ timestamp }}</title>
32 <style>
33 * {
34 margin: 0;
35 padding: 0;
36 box-sizing: border-box;
37 }
38
39 body {
40 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
41 line-height: 1.6;
42 color: #333;
43 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
44 padding: 20px;
45 }
46
47 .container {
48 max-width: 1200px;
49 margin: 0 auto;
50 background: white;
51 border-radius: 12px;
52 box-shadow: 0 20px 60px rgba(0,0,0,0.3);
53 overflow: hidden;
54 }
55
56 .header {
57 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
58 color: white;
59 padding: 40px;
60 text-align: center;
61 }
62
63 .header h1 {
64 font-size: 2.5em;
65 margin-bottom: 10px;
66 font-weight: 700;
67 }
68
69 .header .subtitle {
70 font-size: 1.2em;
71 opacity: 0.9;
72 }
73
74 .header .timestamp {
75 margin-top: 20px;
76 font-size: 0.9em;
77 opacity: 0.8;
78 }
79
80 .summary {
81 padding: 40px;
82 background: #f8f9fa;
83 border-bottom: 2px solid #e9ecef;
84 }
85
86 .summary-grid {
87 display: grid;
88 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
89 gap: 20px;
90 margin-top: 20px;
91 }
92
93 .summary-card {
94 background: white;
95 padding: 20px;
96 border-radius: 8px;
97 box-shadow: 0 2px 8px rgba(0,0,0,0.1);
98 text-align: center;
99 transition: transform 0.2s;
100 }
101
102 .summary-card:hover {
103 transform: translateY(-5px);
104 box-shadow: 0 4px 12px rgba(0,0,0,0.15);
105 }
106
107 .summary-card .value {
108 font-size: 2.5em;
109 font-weight: 700;
110 margin: 10px 0;
111 }
112
113 .summary-card .label {
114 color: #666;
115 font-size: 0.9em;
116 text-transform: uppercase;
117 letter-spacing: 1px;
118 }
119
120 .summary-card.success .value { color: #28a745; }
121 .summary-card.warning .value { color: #ffc107; }
122 .summary-card.danger .value { color: #dc3545; }
123 .summary-card.info .value { color: #17a2b8; }
124
125 .content {
126 padding: 40px;
127 }
128
129 .section {
130 margin-bottom: 40px;
131 }
132
133 .section-header {
134 display: flex;
135 align-items: center;
136 gap: 15px;
137 margin-bottom: 20px;
138 padding-bottom: 15px;
139 border-bottom: 2px solid #e9ecef;
140 }
141
142 .section-header h2 {
143 font-size: 1.8em;
144 color: #667eea;
145 }
146
147 .section-badge {
148 padding: 5px 15px;
149 border-radius: 20px;
150 font-size: 0.8em;
151 font-weight: 600;
152 }
153
154 .section-badge.pass {
155 background: #d4edda;
156 color: #155724;
157 }
158
159 .section-badge.fail {
160 background: #f8d7da;
161 color: #721c24;
162 }
163
164 .section-badge.warn {
165 background: #fff3cd;
166 color: #856404;
167 }
168
169 .checks-table {
170 width: 100%;
171 border-collapse: collapse;
172 margin-top: 20px;
173 }
174
175 .checks-table th {
176 background: #f8f9fa;
177 padding: 12px;
178 text-align: left;
179 font-weight: 600;
180 border-bottom: 2px solid #dee2e6;
181 }
182
183 .checks-table td {
184 padding: 12px;
185 border-bottom: 1px solid #e9ecef;
186 }
187
188 .checks-table tr:hover {
189 background: #f8f9fa;
190 }
191
192 .status-icon {
193 font-size: 1.5em;
194 display: inline-block;
195 width: 30px;
196 text-align: center;
197 }
198
199 .check-details {
200 font-size: 0.9em;
201 color: #666;
202 margin-top: 5px;
203 }
204
205 .fix-command {
206 background: #f8f9fa;
207 padding: 8px 12px;
208 border-radius: 4px;
209 font-family: 'Courier New', monospace;
210 font-size: 0.85em;
211 margin-top: 5px;
212 border-left: 3px solid #ffc107;
213 }
214
215 .footer {
216 background: #f8f9fa;
217 padding: 30px;
218 text-align: center;
219 color: #666;
220 border-top: 2px solid #e9ecef;
221 }
222
223 .footer .logo {
224 font-size: 2em;
225 margin-bottom: 10px;
226 }
227
228 .progress-bar {
229 width: 100%;
230 height: 30px;
231 background: #e9ecef;
232 border-radius: 15px;
233 overflow: hidden;
234 margin: 20px 0;
235 }
236
237 .progress-fill {
238 height: 100%;
239 background: linear-gradient(90deg, #28a745 0%, #20c997 100%);
240 display: flex;
241 align-items: center;
242 justify-content: center;
243 color: white;
244 font-weight: 600;
245 transition: width 0.3s ease;
246 }
247
248 .action-items {
249 background: #fff3cd;
250 border-left: 4px solid #ffc107;
251 padding: 20px;
252 margin: 20px 0;
253 border-radius: 4px;
254 }
255
256 .action-items h3 {
257 color: #856404;
258 margin-bottom: 15px;
259 }
260
261 .action-items ul {
262 list-style: none;
263 padding-left: 0;
264 }
265
266 .action-items li {
267 padding: 8px 0;
268 border-bottom: 1px solid #ffeaa7;
269 }
270
271 .action-items li:last-child {
272 border-bottom: none;
273 }
274
275 @media print {
276 body {
277 background: white;
278 padding: 0;
279 }
280
281 .container {
282 box-shadow: none;
283 }
284
285 .summary-card:hover {
286 transform: none;
287 }
288 }
289 </style>
290</head>
291<body>
292 <div class="container">
293 <div class="header">
294 <h1>๐ต AudioForge Launch Report</h1>
295 <div class="subtitle">Production Readiness Verification</div>
296 <div class="timestamp">Generated: {{ timestamp }}</div>
297 </div>
298
299 <div class="summary">
300 <h2>Executive Summary</h2>
301 <div class="progress-bar">
302 <div class="progress-fill" style="width: {{ overall_success_rate }}%;">
303 {{ overall_success_rate }}% Ready
304 </div>
305 </div>
306
307 <div class="summary-grid">
308 <div class="summary-card success">
309 <div class="label">Passed</div>
310 <div class="value">{{ total_passed }}</div>
311 </div>
312 <div class="summary-card danger">
313 <div class="label">Failed</div>
314 <div class="value">{{ total_failed }}</div>
315 </div>
316 <div class="summary-card warning">
317 <div class="label">Warnings</div>
318 <div class="value">{{ total_warned }}</div>
319 </div>
320 <div class="summary-card info">
321 <div class="label">Total Checks</div>
322 <div class="value">{{ total_checks }}</div>
323 </div>
324 </div>
325
326 {% if overall_success_rate == 100 %}
327 <div style="margin-top: 30px; padding: 20px; background: #d4edda; border-radius: 8px; text-align: center;">
328 <h3 style="color: #155724; font-size: 1.5em;">๐ READY TO LAUNCH!</h3>
329 <p style="color: #155724; margin-top: 10px;">All systems are go. You're cleared for production deployment.</p>
330 </div>
331 {% elif overall_success_rate >= 90 %}
332 <div style="margin-top: 30px; padding: 20px; background: #fff3cd; border-radius: 8px; text-align: center;">
333 <h3 style="color: #856404; font-size: 1.5em;">โ ๏ธ ALMOST READY</h3>
334 <p style="color: #856404; margin-top: 10px;">Minor issues to address before launch.</p>
335 </div>
336 {% else %}
337 <div style="margin-top: 30px; padding: 20px; background: #f8d7da; border-radius: 8px; text-align: center;">
338 <h3 style="color: #721c24; font-size: 1.5em;">โ NOT READY</h3>
339 <p style="color: #721c24; margin-top: 10px;">Critical issues must be resolved before launch.</p>
340 </div>
341 {% endif %}
342 </div>
343
344 <div class="content">
345 {% for section_name, section_data in sections.items() %}
346 <div class="section">
347 <div class="section-header">
348 <h2>{{ section_name }}</h2>
349 {% if section_data.success_rate == 100 %}
350 <span class="section-badge pass">โ
{{ section_data.passed }}/{{ section_data.total }}</span>
351 {% elif section_data.failed > 0 %}
352 <span class="section-badge fail">โ {{ section_data.failed }} Failed</span>
353 {% else %}
354 <span class="section-badge warn">โ ๏ธ {{ section_data.warned }} Warnings</span>
355 {% endif %}
356 </div>
357
358 <table class="checks-table">
359 <thead>
360 <tr>
361 <th style="width: 50px;">Status</th>
362 <th>Check</th>
363 <th>Message</th>
364 </tr>
365 </thead>
366 <tbody>
367 {% for check in section_data.checks %}
368 <tr>
369 <td><span class="status-icon">{{ check.status_icon }}</span></td>
370 <td><strong>{{ check.name }}</strong></td>
371 <td>
372 {{ check.message }}
373 {% if check.details %}
374 <div class="check-details">{{ check.details }}</div>
375 {% endif %}
376 {% if check.fix_command %}
377 <div class="fix-command">Fix: {{ check.fix_command }}</div>
378 {% endif %}
379 </td>
380 </tr>
381 {% endfor %}
382 </tbody>
383 </table>
384 </div>
385 {% endfor %}
386
387 {% if action_items %}
388 <div class="action-items">
389 <h3>โก Action Items</h3>
390 <ul>
391 {% for item in action_items %}
392 <li>{{ item }}</li>
393 {% endfor %}
394 </ul>
395 </div>
396 {% endif %}
397 </div>
398
399 <div class="footer">
400 <div class="logo">๐ผโก</div>
401 <p>AudioForge Launch Verification System</p>
402 <p style="margin-top: 10px; font-size: 0.9em;">
403 Forged by FusionPanda | {{ timestamp }}
404 </p>
405 </div>
406 </div>
407</body>
408</html>
409"""
410
411
412async def generate_report():
413 """Generate comprehensive launch report."""
414 print("๐ต Generating AudioForge Launch Report...")
415 print("=" * 60)
416
417 # Run verification script
418 print("\n๐ Running verification checks...")
419 result = subprocess.run(
420 [sys.executable, "scripts/launch_verification.py", "--json", "launch-results.json"],
421 capture_output=True,
422 text=True
423 )
424
425 # Load results
426 results_file = Path("launch-results.json")
427 if not results_file.exists():
428 print("โ Verification results not found!")
429 sys.exit(1)
430
431 with open(results_file) as f:
432 data = json.load(f)
433
434 # Calculate totals
435 total_passed = sum(section["passed"] for section in data.values())
436 total_failed = sum(section["failed"] for section in data.values())
437 total_warned = sum(section["warned"] for section in data.values())
438 total_checks = sum(section["total"] for section in data.values())
439 overall_success_rate = round((total_passed / total_checks * 100) if total_checks > 0 else 0, 1)
440
441 # Collect action items
442 action_items = []
443 for section_name, section_data in data.items():
444 for check in section_data["checks"]:
445 if check.get("details") and ("fix" in check["details"].lower() or "missing" in check["details"].lower()):
446 action_items.append(f"{section_name}: {check['name']} - {check['message']}")
447
448 # Prepare template data
449 template_data = {
450 "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
451 "total_passed": total_passed,
452 "total_failed": total_failed,
453 "total_warned": total_warned,
454 "total_checks": total_checks,
455 "overall_success_rate": overall_success_rate,
456 "sections": data,
457 "action_items": action_items[:10], # Top 10 action items
458 }
459
460 # Add status icons
461 status_icons = {
462 "PASS": "โ
",
463 "FAIL": "โ",
464 "WARN": "โ ๏ธ",
465 "SKIP": "โญ๏ธ",
466 "INFO": "โน๏ธ",
467 }
468
469 for section_data in template_data["sections"].values():
470 for check in section_data["checks"]:
471 check["status_icon"] = status_icons.get(check["status"], "โ")
472
473 # Generate HTML report
474 template = Template(HTML_TEMPLATE)
475 html_content = template.render(**template_data)
476
477 # Save report
478 report_path = Path("LAUNCH_REPORT.html")
479 report_path.write_text(html_content, encoding="utf-8")
480
481 print(f"\nโ
Report generated: {report_path.absolute()}")
482 print(f"๐ Overall Success Rate: {overall_success_rate}%")
483 print(f"โ
Passed: {total_passed}")
484 print(f"โ Failed: {total_failed}")
485 print(f"โ ๏ธ Warnings: {total_warned}")
486
487 # Print status
488 if overall_success_rate == 100:
489 print("\n๐ READY TO LAUNCH!")
490 elif overall_success_rate >= 90:
491 print("\nโ ๏ธ ALMOST READY - Minor issues to fix")
492 else:
493 print("\nโ NOT READY - Critical issues found")
494
495 # Open report in browser (optional)
496 try:
497 import webbrowser
498 webbrowser.open(f"file://{report_path.absolute()}")
499 print(f"\n๐ Opening report in browser...")
500 except Exception:
501 pass
502
503 return overall_success_rate >= 90
504
505
506if __name__ == "__main__":
507 success = asyncio.run(generate_report())
508 sys.exit(0 if success else 1)
509 