")
for tc in suite.tests:
icon = _status_icon(tc.status)
error_block = ""
if tc.message or tc.text:
detail = (tc.text or tc.message)[:4000]
error_block = f"
{html.escape(detail)}
"
parts.append(
f"
"
f"
{icon}
"
f"
{html.escape(tc.name)}
"
f"
{html.escape(tc.classname)}
"
f"{error_block}
"
f"
{_fmt_time(tc.time)}
"
f"
"
)
parts.append("
")
parts.append("
")
parts.append(f"")
parts.append("")
return "\n".join(parts)
# ── CLI ──────────────────────────────────────────────────────────────────────
def main() -> int:
parser = argparse.ArgumentParser(description="Generate HTML report from Molecule JUnit XML files")
parser.add_argument("--xml-dir", default="/tmp/molecule-junit", help="Directory with JUnit XML files")
parser.add_argument("--output", default="/tmp/molecule-report.html", help="Output HTML file path")
args = parser.parse_args()
xml_dir = Path(args.xml_dir)
output = Path(args.output)
if not xml_dir.exists():
print(f"[warn] XML directory not found: {xml_dir}", file=sys.stderr)
suites = []
else:
print(f"Loading JUnit XML files from: {xml_dir}")
suites = load_all_suites(xml_dir)
print(f" Found {len(suites)} test suite(s)")
html_content = render_html(suites, datetime.now())
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(html_content, encoding="utf-8")
total_failed = sum(s.failed for s in suites)
total_tests = sum(s.total for s in suites)
print(f"\nReport: {output}")
print(f"Result: {total_tests - total_failed}/{total_tests} passed")
return 1 if total_failed > 0 else 0
if __name__ == "__main__":
sys.exit(main())