Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate CGAL TestSuite Markdown Report #8620

Merged
merged 13 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading