Coverage for src/debputy/linting/lint_report_junit.py: 25%
40 statements
« prev ^ index » next coverage.py v7.6.0, created at 2025-03-24 16:38 +0000
« prev ^ index » next coverage.py v7.6.0, created at 2025-03-24 16:38 +0000
1import textwrap
2from typing import Iterable, TYPE_CHECKING
4from debputy.util import _info
6if TYPE_CHECKING:
7 from junit_xml import TestSuite, TestCase, to_xml_report_file
8else:
9 try:
10 from junit_xml import TestSuite, TestCase, to_xml_report_file
11 except ImportError:
12 pass
15from debputy.linting.lint_util import (
16 LintReport,
17 LintDiagnosticResult,
18 LintDiagnosticResultState,
19 debputy_severity,
20)
23class JunitLintReport(LintReport):
25 def __init__(self, output_filename: str) -> None:
26 super().__init__()
27 self._output_filename = output_filename
29 def finish_report(self) -> None:
30 # Nothing to do for now
31 all_test_cases = list(self._as_test_cases())
32 test_suites = [
33 TestSuite(
34 "debputy lint",
35 test_cases=all_test_cases,
36 timestamp=str(self.start_timestamp),
37 )
38 ]
39 with open(self._output_filename, "w", encoding="utf-8") as wfd:
40 to_xml_report_file(wfd, test_suites, encoding="utf-8")
41 _info(f"Wrote {self._output_filename}")
43 def _as_test_cases(self) -> Iterable["TestCase"]:
44 for filename, duration in self.durations.items():
45 results = self.diagnostics_by_file.get(filename, [])
46 yield self._as_test_case(filename, results, duration)
48 def _as_test_case(
49 self,
50 filename: str,
51 diagnostic_results: Iterable[LintDiagnosticResult],
52 duration: float,
53 ) -> "TestCase":
54 if not duration:
55 duration = 0.000001
56 case = TestCase(
57 filename,
58 # The JUnit schema has `classname` as mandatory
59 classname=filename,
60 allow_multiple_subelements=True,
61 elapsed_sec=duration,
62 )
63 for diagnostic_result in diagnostic_results:
64 if diagnostic_result.result_state == LintDiagnosticResultState.FIXED:
65 continue
66 diagnostic = diagnostic_result.diagnostic
67 severity = debputy_severity(diagnostic)
68 if diagnostic_result.is_file_level_diagnostic:
69 range_desc = "entire file"
70 else:
71 range_desc = str(diagnostic.range)
72 code = f" [{diagnostic.code}]" if diagnostic.code else ""
73 authority = diagnostic.source
74 assert authority is not None
75 output = textwrap.dedent(
76 f"""\
77 \
78 {filename}{code} ({severity}) {range_desc} [{authority}]: {diagnostic.message}
79 """
80 )
81 case.add_failure_info(
82 message=f"[{severity}]: {diagnostic.message}",
83 output=output,
84 )
85 return case