-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Generate CGAL TestSuite Markdown Report (#8620)
- Loading branch information
Showing
4 changed files
with
520 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
Oops, something went wrong.