parsgin the xml for coverage

This commit is contained in:
Karma Riuk
2025-03-17 15:50:46 +01:00
parent 211f9dde99
commit 04c66f0d8a

View File

@ -1,7 +1,9 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
import os, re, docker, signal, sys import os, re, docker, signal, sys
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from typing import Optional from typing import Generator, Optional
import xml.etree.ElementTree as ET
USER_ID = os.getuid() # for container user USER_ID = os.getuid() # for container user
GROUP_ID = os.getgid() GROUP_ID = os.getgid()
@ -104,22 +106,19 @@ class BuildHandler(ABC):
if result.exit_code != 0: if result.exit_code != 0:
raise CantExecJacoco(clean_output(result.output)) raise CantExecJacoco(clean_output(result.output))
def check_coverage(self, filename: str) -> None: def check_coverage(self, filename: str) -> float:
""" """
Check if the given filename is covered by JaCoCo. Check if the given filename is covered by JaCoCo.
""" """
coverage_report_path = self.get_jacoco_report_path() for coverage_report_path in self.get_jacoco_report_paths():
if not os.path.exists(coverage_report_path): if not os.path.exists(coverage_report_path):
raise NoCoverageReportFound(f"Coverage report file '{coverage_report_path}' does not exist") raise NoCoverageReportFound(f"Coverage report file '{coverage_report_path}' does not exist")
with open(coverage_report_path, "r") as file: coverage = get_coverage_for_file(coverage_report_path, filename)
soup = BeautifulSoup(file, "html.parser") if coverage != -1:
return coverage
# Extract all files listed in the JaCoCo coverage report raise FileNotCovered(f"File '{filename}' didn't have any coverage in any of the jacoco report.")
covered_files = [a.text.strip() for a in soup.select("table tbody tr td a")]
if filename not in covered_files:
raise FileNotCovered(f"The file '{filename}' was not present in the report '{coverage_report_path}'")
def clean_repo(self) -> None: def clean_repo(self) -> None:
self.container.exec_run(self.clean_cmd()) self.container.exec_run(self.clean_cmd())
@ -296,6 +295,9 @@ class NoCoverageReportFound(Exception):
class FileNotCovered(Exception): class FileNotCovered(Exception):
pass pass
class GradleAggregateReportNotFound(Exception):
pass
def merge_download_lines(lines: list) -> list: def merge_download_lines(lines: list) -> list:
""" """
Merges lines that are part of the same download block in Maven output. Merges lines that are part of the same download block in Maven output.
@ -350,6 +352,29 @@ def clean_output(output: bytes) -> str:
return "\n".join(cleaned_lines) return "\n".join(cleaned_lines)
def get_coverage_for_file(xml_file: str, target_filename: str) -> float:
# Parse the XML file
tree = ET.parse(xml_file)
root = tree.getroot()
# Find coverage for the target file
for package in root.findall(".//package"):
for sourcefile in package.findall("sourcefile"):
if sourcefile.get("name") == target_filename:
# Extract line coverage data
line_counter = sourcefile.find("counter[@type='LINE']")
if line_counter is not None:
counter = line_counter.get("missed")
assert isinstance(counter, str)
missed = int(counter)
counter = line_counter.get("covered")
assert isinstance(counter, str)
covered = int(counter)
total = missed + covered
coverage = (covered / total) * 100 if total > 0 else 0
return coverage
return -1
def get_build_handler(root: str, repo: str, updates: dict, verbose: bool = False) -> Optional[BuildHandler]: def get_build_handler(root: str, repo: str, updates: dict, verbose: bool = False) -> Optional[BuildHandler]:
""" """
Get the path to the build file of a repository. The build file is either a Get the path to the build file of a repository. The build file is either a