mirror of
https://github.com/karma-riuk/crab.git
synced 2025-07-04 21:28:12 +02:00
generating and checking the coverage with jacoco
This commit is contained in:
64
handlers.py
64
handlers.py
@ -99,10 +99,31 @@ class BuildHandler(ABC):
|
||||
finally:
|
||||
signal.alarm(0) # Cancel the alarm
|
||||
|
||||
def generate_coverage_report(self):
|
||||
result = self.container.exec_run(self.generate_coverage_report_cmd())
|
||||
if result.exit_code != 0:
|
||||
raise CantExecJacoco(clean_output(result.output))
|
||||
|
||||
def check_coverage(self, filename: str) -> None:
|
||||
"""
|
||||
Check if the given filename is covered by JaCoCo.
|
||||
"""
|
||||
coverage_report_path = self.get_jacoco_report_path()
|
||||
if not os.path.exists(coverage_report_path):
|
||||
raise NoCoverageReportFound(f"Coverage report file '{coverage_report_path}' does not exist")
|
||||
|
||||
with open(coverage_report_path, "r") as file:
|
||||
soup = BeautifulSoup(file, "html.parser")
|
||||
|
||||
# Extract all files listed in the JaCoCo coverage 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:
|
||||
self.container.exec_run(self.clean_cmd())
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def compile_cmd(self) -> str:
|
||||
pass
|
||||
@ -119,6 +140,14 @@ class BuildHandler(ABC):
|
||||
def clean_cmd(self) -> str:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def generate_coverage_report_cmd(self) -> str:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_jacoco_report_path(self) -> str:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def container_name(self) -> str:
|
||||
pass
|
||||
@ -140,6 +169,9 @@ class MavenHandler(BuildHandler):
|
||||
def clean_cmd(self) -> str:
|
||||
return f"{self.base_cmd} clean"
|
||||
|
||||
def generate_coverage_report_cmd(self):
|
||||
return f"{self.base_cmd} jacoco:report"
|
||||
|
||||
def container_name(self) -> str:
|
||||
return "crab-maven"
|
||||
|
||||
@ -165,6 +197,9 @@ class MavenHandler(BuildHandler):
|
||||
self.updates["n_tests_skipped"] += skipped
|
||||
self.updates["n_tests_passed"] += (tests_run - (failures + errors)) # Calculate passed tests
|
||||
|
||||
def get_jacoco_report_path(self) -> str:
|
||||
return os.path.join(self.path, "target/site/jacoco/index.html")
|
||||
|
||||
class GradleHandler(BuildHandler):
|
||||
def __init__(self, repo_path: str, build_file: str, updates: dict) -> None:
|
||||
super().__init__(repo_path, build_file, updates)
|
||||
@ -179,6 +214,9 @@ class GradleHandler(BuildHandler):
|
||||
def clean_cmd(self) -> str:
|
||||
return f"{self.base_cmd} clean"
|
||||
|
||||
def generate_coverage_report_cmd(self) -> str:
|
||||
return f"{self.base_cmd}jacocoTestReport"
|
||||
|
||||
def container_name(self) -> str:
|
||||
return "crab-gradle"
|
||||
|
||||
@ -197,21 +235,25 @@ class GradleHandler(BuildHandler):
|
||||
with open(test_results_path, "r") as file:
|
||||
soup = BeautifulSoup(file, "html.parser")
|
||||
|
||||
test_div = soup.find("div", class_="infoBox", id="tests")
|
||||
# test_div = soup.select_one("div", class_="infoBox", id="tests")
|
||||
test_div = soup.select_one("div.infoBox#tests")
|
||||
if test_div is None:
|
||||
raise NoTestResultsToExtractError("No test results found (no div.infoBox#tests)")
|
||||
|
||||
counter_div = test_div.find("div", class_="counter")
|
||||
# counter_div = test_div.find("div", class_="counter")
|
||||
counter_div = test_div.select_one("div.counter")
|
||||
if counter_div is None:
|
||||
raise NoTestResultsToExtractError("No test results found (not div.counter for tests)")
|
||||
|
||||
self.updates["n_tests"] = int(counter_div.text.strip())
|
||||
|
||||
failures_div = soup.find("div", class_="infoBox", id="failures")
|
||||
# failures_div = soup.find("div", class_="infoBox", id="failures")
|
||||
failures_div = soup.select_one("div.infoBox#failures")
|
||||
if failures_div is None:
|
||||
raise NoTestResultsToExtractError("No test results found (no div.infoBox#failures)")
|
||||
|
||||
counter_div = failures_div.find("div", class_="counter")
|
||||
# counter_div = failures_div.find("div", class_="counter")
|
||||
counter_div = failures_div.select_one("div.counter")
|
||||
if counter_div is None:
|
||||
raise NoTestResultsToExtractError("No test results found (not div.counter for failures)")
|
||||
|
||||
@ -220,6 +262,9 @@ class GradleHandler(BuildHandler):
|
||||
# Calculate passed tests
|
||||
self.updates["n_tests_passed"] = self.updates["n_tests"] - self.updates["n_tests_failed"]
|
||||
|
||||
def get_jacoco_report_path(self) -> str:
|
||||
return os.path.join(self.path, "build/reports/jacoco/test/html/index.html")
|
||||
|
||||
class NoTestsFoundError(Exception):
|
||||
pass
|
||||
|
||||
@ -232,6 +277,15 @@ class FailedToTestError(Exception):
|
||||
class NoTestResultsToExtractError(Exception):
|
||||
pass
|
||||
|
||||
class CantExecJacoco(Exception):
|
||||
pass
|
||||
|
||||
class NoCoverageReportFound(Exception):
|
||||
pass
|
||||
|
||||
class FileNotCovered(Exception):
|
||||
pass
|
||||
|
||||
def merge_download_lines(lines: list) -> list:
|
||||
"""
|
||||
Merges lines that are part of the same download block in Maven output.
|
||||
|
@ -8,7 +8,7 @@ from tqdm import tqdm
|
||||
from datetime import datetime
|
||||
|
||||
from dataset import Dataset, DatasetEntry, FileData, Metadata, Diff
|
||||
from handlers import FailedToCompileError, FailedToTestError, NoTestsFoundError, NoTestResultsToExtractError, get_build_handler
|
||||
from handlers import CantExecJacoco, FailedToCompileError, FailedToTestError, FileNotCovered, NoCoverageReportFound, NoTestsFoundError, NoTestResultsToExtractError, get_build_handler
|
||||
from utils import has_only_1_comment, move_github_logging_to_file, clone
|
||||
|
||||
|
||||
@ -123,10 +123,16 @@ def process_pull(repo: Repository, pr: PullRequest, dataset: Dataset, repos_dir:
|
||||
return
|
||||
build_handler.set_client(docker_client)
|
||||
|
||||
def _check_coverage(files: list[str]):
|
||||
for file in files:
|
||||
build_handler.check_coverage(file)
|
||||
|
||||
steps = [
|
||||
("Checking for tests...", build_handler.check_for_tests),
|
||||
("Compiling...", build_handler.compile_repo),
|
||||
("Running tests...", build_handler.test_repo),
|
||||
("Generating coverage...", build_handler.generate_coverage_report),
|
||||
("Checking coverage...", lambda: _check_coverage([file.filename for file in pr.get_files()])),
|
||||
]
|
||||
|
||||
error_map = {
|
||||
@ -134,6 +140,9 @@ def process_pull(repo: Repository, pr: PullRequest, dataset: Dataset, repos_dir:
|
||||
FailedToCompileError: "Failed to compile",
|
||||
FailedToTestError: "Failed to test",
|
||||
NoTestResultsToExtractError: "Failed to extract test results",
|
||||
CantExecJacoco: "Coudln't execute jacoco",
|
||||
NoCoverageReportFound: "No coverage report was found",
|
||||
FileNotCovered: "A file from the PR was not coverege",
|
||||
}
|
||||
|
||||
with build_handler, tqdm(total=len(steps), desc="Processing PR", leave=False) as pbar:
|
||||
|
Reference in New Issue
Block a user