Skip to content

Commit

Permalink
Generate CGAL TestSuite Markdown Report (#8620)
Browse files Browse the repository at this point in the history
  • Loading branch information
lrineau authored Dec 19, 2024
2 parents 5050ba0 + b3a59ac commit db347ea
Show file tree
Hide file tree
Showing 4 changed files with 520 additions and 1 deletion.
7 changes: 7 additions & 0 deletions .markdownlint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"default": true,
"line-length": false,
"no-duplicate-heading": {
"siblings_only": true
}
}
4 changes: 3 additions & 1 deletion Maintenance/test_handling/create_testresult_page
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,8 @@ sub create_summary_page {
my ($platform_num, $platform) = (0, "");
foreach $platform (@platforms_to_do) {
my $platform_info = $platforms_info{$platform};
my $build_type = $platform_is_optimized{$platform} ? " - " : "YES";
$platform_info->{debug} = $build_type;
foreach my $test_directory (sort keys %test_directories) {
my $result_letter = $testresults[$platform_num]->{$test_directory};
if (defined($result_letter) && grep { $_ eq $result_letter } @letters) {
Expand All @@ -769,7 +771,7 @@ sub create_summary_page {
release => $release_name,
platforms => \@platforms_data,
};
my $json = JSON->new->allow_nonref;
my $json = JSON->new->allow_nonref->pretty;
my $json_text = $json->encode($final_data);
my $fh = new IO::Compress::Gzip "$testresult_dir/$release_name/search_index.json.gz"
or die "IO::Compress::Gzip failed: $GzipError\n";
Expand Down
190 changes: 190 additions & 0 deletions Scripts/developer_scripts/cgal_testsuite_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#!/usr/bin/env python3
import os
import json
from typing import Dict, List
from dataclasses import dataclass
from datetime import datetime
import subprocess
import re
import requests

CGAL_SERVER_URL = "https://cgal.geometryfactory.com/CGAL"
LATEST_VERSION_URL = f"{CGAL_SERVER_URL}/Releases/LATEST"
JSON_DATA_URL_TEMPLATE = f"{
CGAL_SERVER_URL}/testsuite/CGAL-{{version}}/search_index.json"
TESTSUITE_URL_TEMPLATE = f"{
CGAL_SERVER_URL}/testsuite/results-{{version}}.shtml"
TIMEOUT_DURATION = 10


@dataclass
class TPLInfo:
name: str
version: str
status: str


@dataclass
class PlatformInfo:
name: str
debug: str
os: str
tester: str
compiler: str
tpl_info: List[TPLInfo]


def fetch_data_from_url(url: str) -> str:
"""Fetch data from a given URL."""
response = requests.get(url, timeout=TIMEOUT_DURATION)
response.raise_for_status()
return response.text.strip()


def get_latest_version() -> str:
"""Return latest CGAL version from LATEST (CGAL-<version>.tar.gz)"""
tarball_name = fetch_data_from_url(LATEST_VERSION_URL)
match = re.match(r'CGAL-([^.]+\.[^-]+-[^-]+-\d+)', tarball_name)
if not match:
raise ValueError(f"Unexpected tarball name format: {tarball_name}")
return match.group(1)


def fetch_json_data(version: str) -> Dict:
"""Fetch JSON data for the given CGAL testsuite."""
url = JSON_DATA_URL_TEMPLATE.format(version=version)
json_data = fetch_data_from_url(url)
return json.loads(json_data)


def analyze_tpl_data(json_data: Dict) -> List[PlatformInfo]:
"""Analyze TPL data from JSON and return a list of PlatformInfo."""
platforms_info = []
for platform in json_data.get('platforms', []):
tpl_list = [
TPLInfo(
name=item.get('name', 'Unknown'),
version=item.get('version', 'N/A'),
status=item.get('status', 'unknown')
)
for item in platform.get('third_party_libs', [])
]
platform_info = PlatformInfo(
name=platform.get('platform_name', 'Unknown Platform'),
debug=platform.get('debug', '-'),
os=platform.get('operating_system', '-'),
tester=platform.get('tester_name', '-'),
compiler=platform.get('compiler', '-'),
tpl_info=tpl_list
)
platforms_info.append(platform_info)
return platforms_info


def get_docker_images() -> Dict[str, List[str]]:
"""
Get Docker image information by calling `list_test_runner_machines`.
Returns a dictionary with machine names as keys and lists of images as values.
"""
try:
script_dir = os.path.dirname(os.path.abspath(__file__))
result = subprocess.run(
[os.path.join(script_dir, 'list_test_runner_machines'), '--plain'],
capture_output=True,
text=True,
check=True
)
output = result.stdout.strip()

machines_info = {}
current_machine = None
parsing_images = False

for line in output.splitlines():
if line.startswith("## "):
current_machine = line.strip("# ").strip()
machines_info[current_machine] = []
parsing_images = False

elif line.startswith("Tested images:"):
parsing_images = True

elif parsing_images and (line.startswith("cgal/testsuite-docker:") or line.startswith("docker.io/cgal/testsuite-docker:")):
machines_info[current_machine].append(line.strip())

return machines_info

except subprocess.CalledProcessError as e:
raise RuntimeError(
f"Error running `list_test_runner_machines`: {e}") from e
except Exception as e:
raise RuntimeError(f"Error parsing Docker information: {e}") from e


def add_docker_summary(report: List[str], machines_info: Dict[str, List[str]]):
"""Add a summary of Docker images used on each machine to the report."""
report.append("\n## Docker Test Summary")
for machine, images in machines_info.items():
report.append(f"\n### Machine: {machine} ({len(images)} images)")
report.append("\n#### Tested Images\n")
for image in images:
report.append(f"- {image}")


def generate_markdown_report(platforms_info: List[PlatformInfo], version: str) -> str:
"""Generate a markdown report from the platforms information."""
machines_info = get_docker_images()
report = []
report.append("# TestSuite Report")
report.append(f"\nGenerated on: {
datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
url = TESTSUITE_URL_TEMPLATE.format(version=version)
report.append(f"\nCGAL Version: [{version}]({url})")
add_docker_summary(report, machines_info)
report.append("\n## Platforms Summary\n")
report.append("| Platform | Debug | OS | Tester | Compiler |")
report.append("|----------|-------|----|--------|----------|")
for platform in platforms_info:
report.append(
f"| {platform.name} | {platform.debug} | {platform.os} | "
f"{platform.tester} | {platform.compiler} |"
)
report.append("\n## Detailed Third-party Libraries")
for platform in platforms_info:
report.append(f"\n### Platform: {platform.name}\n")
tpl_list = sorted(platform.tpl_info, key=lambda x: x.name)
report.append("| Library Name | Version | Status |")
report.append("|--------------|---------|--------|")
for tpl in tpl_list:
version_str = str(tpl.version) if tpl.version else "N/A"
status_str = "❌" if tpl.version == "not found" else "✅"
report.append(f"| {tpl.name} | {version_str} | {status_str} |")
found_tpls = sum(1 for tpl in tpl_list if tpl.version != "not found")
total_tpls = len(tpl_list)
report.append(
f"\n**Summary**: found {found_tpls} third-party libraries out of {total_tpls}")
return "\n".join(report)


def main():
"""Main function to generate the testsuite report."""
try:
version = get_latest_version()
json_data = fetch_json_data(version)
platforms_info = analyze_tpl_data(json_data)
markdown_report = generate_markdown_report(platforms_info, version)
print(markdown_report)
except requests.RequestException as e:
print(f"**Error fetching data:**\n\n```\n{str(e)}\n```\n")
raise
except json.JSONDecodeError as e:
print(f"**Error: Invalid JSON data**\n\n```\n{str(e)}\n```")
print(f"\nFile:\n\n```json\n{e.doc}\n```")
raise
except Exception as e:
print(f"**Error processing data:**\n\n```\n{str(e)}\n```\n")
raise


if __name__ == "__main__":
main()
Loading

0 comments on commit db347ea

Please sign in to comment.