diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 43da6a0..cc7e8c8 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -412,93 +412,8 @@ jobs: if [ -f test-results.xml ]; then echo "āœ… Test results XML file generated" - # Parse JUnit XML if python is available - python3 << 'PYTHON_EOF' || true -import xml.etree.ElementTree as ET -import sys - -try: - tree = ET.parse('test-results.xml') - root = tree.getroot() - - # Get test suite statistics - testsuites = root.findall('.//testsuite') - total_tests = 0 - total_failures = 0 - total_errors = 0 - total_skipped = 0 - total_time = 0.0 - - for suite in testsuites: - total_tests += int(suite.get('tests', 0)) - total_failures += int(suite.get('failures', 0)) - total_errors += int(suite.get('errors', 0)) - total_skipped += int(suite.get('skipped', 0)) - total_time += float(suite.get('time', 0)) - - total_passed = total_tests - total_failures - total_errors - total_skipped - - print(f"") - print(f"šŸ“ˆ TEST STATISTICS:") - print(f" Total Tests: {total_tests}") - print(f" āœ… Passed: {total_passed}") - print(f" āŒ Failed: {total_failures}") - print(f" āš ļø Errors: {total_errors}") - print(f" ā­ļø Skipped: {total_skipped}") - print(f" ā±ļø Duration: {total_time:.2f}s") - print(f"") - - # List failed tests - if total_failures > 0 or total_errors > 0: - print(f"āŒ FAILED TESTS:") - print(f" ───────────────────────────────────────────────────────────") - - for suite in testsuites: - for testcase in suite.findall('.//testcase'): - failure = testcase.find('failure') - error = testcase.find('error') - - if failure is not None or error is not None: - test_name = testcase.get('name', 'unknown') - class_name = testcase.get('classname', 'unknown') - full_name = f"{class_name}::{test_name}" if class_name != 'unknown' else test_name - - message = "" - if failure is not None: - message = failure.get('message', '')[:100] # Truncate long messages - elif error is not None: - message = error.get('message', '')[:100] - - print(f" • {full_name}") - if message: - print(f" └─ {message}") - - print(f"") - - # Coverage summary if available - try: - with open('coverage.xml', 'r') as f: - import xml.etree.ElementTree as ET2 - cov_tree = ET2.parse('coverage.xml') - cov_root = cov_tree.getroot() - - line_rate = float(cov_root.get('line-rate', 0)) * 100 - branch_rate = float(cov_root.get('branch-rate', 0)) * 100 - - print(f"šŸ“Š CODE COVERAGE:") - print(f" Line Coverage: {line_rate:.1f}%") - print(f" Branch Coverage: {branch_rate:.1f}%") - print(f"") - except: - pass - - # Overall status - if total_failures == 0 and total_errors == 0: - print(f"āœ… ALL TESTS PASSED") - else: - print(f"āŒ {total_failures + total_errors} TEST(S) FAILED") - # Don't exit with error here - let the test step handle failure -PYTHON_EOF + # Parse JUnit XML if python is available (simplified to avoid YAML parsing issues) + python3 -c "import xml.etree.ElementTree as ET; tree = ET.parse('test-results.xml') if __import__('os').path.exists('test-results.xml') else None; root = tree.getroot() if tree else None; suites = root.findall('.//testsuite') if root else []; total = sum(int(s.get('tests', 0)) for s in suites); failures = sum(int(s.get('failures', 0)) for s in suites); errors = sum(int(s.get('errors', 0)) for s in suites); skipped = sum(int(s.get('skipped', 0)) for s in suites); time = sum(float(s.get('time', 0)) for s in suites); passed = total - failures - errors - skipped; print(f'\nšŸ“ˆ TEST STATISTICS:\n Total Tests: {total}\n āœ… Passed: {passed}\n āŒ Failed: {failures}\n āš ļø Errors: {errors}\n ā­ļø Skipped: {skipped}\n ā±ļø Duration: {time:.2f}s\n'); print('āœ… ALL TESTS PASSED' if failures == 0 and errors == 0 else f'āŒ {failures + errors} TEST(S) FAILED')" || true else echo "āš ļø Test results XML not found" echo " Run 'pytest tests/ -v' locally to see detailed results." @@ -520,105 +435,8 @@ PYTHON_EOF echo "" if [ -f test-results.xml ]; then - python3 << 'PYTHON_EOF' || true -import xml.etree.ElementTree as ET -import sys - -try: - tree = ET.parse('test-results.xml') - root = tree.getroot() - - testsuites = root.findall('.//testsuite') - total_tests = 0 - total_failures = 0 - total_errors = 0 - total_skipped = 0 - total_time = 0.0 - - for suite in testsuites: - total_tests += int(suite.get('tests', 0)) - total_failures += int(suite.get('failures', 0)) - total_errors += int(suite.get('errors', 0)) - total_skipped += int(suite.get('skipped', 0)) - total_time += float(suite.get('time', 0)) - - total_passed = total_tests - total_failures - total_errors - total_skipped - - # Status emoji - if total_failures == 0 and total_errors == 0: - status_emoji = "āœ…" - status_text = "All tests passed" - else: - status_emoji = "āŒ" - status_text = f"{total_failures + total_errors} test(s) failed" - - print(f"### {status_emoji} {status_text}") - print("") - print("| Metric | Count |") - print("|--------|-------|") - print(f"| Total Tests | {total_tests} |") - print(f"| āœ… Passed | {total_passed} |") - print(f"| āŒ Failed | {total_failures} |") - print(f"| āš ļø Errors | {total_errors} |") - print(f"| ā­ļø Skipped | {total_skipped} |") - print(f"| ā±ļø Duration | {total_time:.2f}s |") - print("") - - # List failed tests - if total_failures > 0 or total_errors > 0: - print("### āŒ Failed Tests") - print("") - for suite in testsuites: - for testcase in suite.findall('.//testcase'): - failure = testcase.find('failure') - error = testcase.find('error') - - if failure is not None or error is not None: - test_name = testcase.get('name', 'unknown') - class_name = testcase.get('classname', 'unknown') - full_name = f"{class_name}::{test_name}" if class_name != 'unknown' else test_name - - message = "" - if failure is not None: - message = failure.get('message', '')[:200] - elif error is not None: - message = error.get('message', '')[:200] - - print(f"- **{full_name}**") - if message: - print(f" - `{message}`") - print("") - - # Coverage summary - try: - with open('coverage.xml', 'r') as f: - import xml.etree.ElementTree as ET2 - cov_tree = ET2.parse('coverage.xml') - cov_root = cov_tree.getroot() - - line_rate = float(cov_root.get('line-rate', 0)) * 100 - branch_rate = float(cov_root.get('branch-rate', 0)) * 100 - - print("### šŸ“Š Code Coverage") - print("") - print(f"- **Line Coverage:** {line_rate:.1f}%") - print(f"- **Branch Coverage:** {branch_rate:.1f}%") - print("") - except: - pass - - print("### šŸ’” Tips") - print("") - print("- To run tests locally: `pytest tests/ -v`") - print("- To run a specific test: `pytest tests/test_api_auth.py::TestLogin::test_login_success -v`") - print("- To see coverage: `pytest tests/ --cov=backend --cov-report=html`") - print("- Check the 'Run backend tests' step above for full pytest output") - -except Exception as e: - print(f"āš ļø Could not parse test results: {e}") - print("") - print("Check the 'Run backend tests' step above for detailed output.") -PYTHON_EOF + # Parse test results with a simple Python one-liner to avoid YAML issues + python3 -c "import xml.etree.ElementTree as ET; t=ET.parse('test-results.xml'); s=t.findall('.//testsuite'); total=sum(int(x.get('tests',0)) for x in s); fails=sum(int(x.get('failures',0)) for x in s); errs=sum(int(x.get('errors',0)) for x in s); skips=sum(int(x.get('skipped',0)) for x in s); time=sum(float(x.get('time',0)) for x in s); passed=total-fails-errs-skips; emoji='āœ…' if fails==0 and errs==0 else 'āŒ'; status='All tests passed' if fails==0 and errs==0 else f'{fails+errs} test(s) failed'; print(f'### {emoji} {status}\n\n| Metric | Count |\n|--------|-------|\n| Total Tests | {total} |\n| āœ… Passed | {passed} |\n| āŒ Failed | {fails} |\n| āš ļø Errors | {errs} |\n| ā­ļø Skipped | {skips} |\n| ā±ļø Duration | {time:.2f}s |\n\n### šŸ’” Tips\n\n- To run tests locally: `pytest tests/ -v`\n- Check the Run backend tests step above for full pytest output')" || echo "āš ļø Could not parse test results" } >> "$GITHUB_STEP_SUMMARY" || true else {