mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 14:14:11 +00:00 
			
		
		
		
	ci: fix bin size report generation
This commit is contained in:
		@@ -23,7 +23,7 @@ def main() -> None:
 | 
			
		||||
    parser: argparse.ArgumentParser = setup_argument_parser()
 | 
			
		||||
    args: argparse.Namespace = parser.parse_args()
 | 
			
		||||
 | 
			
		||||
    report_actions: t.Dict[str, t.Callable[[argparse.Namespace], None]] = {
 | 
			
		||||
    report_actions: dict[str, t.Callable[[argparse.Namespace], None]] = {
 | 
			
		||||
        'build': generate_build_report,
 | 
			
		||||
        'target_test': generate_target_test_report,
 | 
			
		||||
        'job': generate_jobs_report,
 | 
			
		||||
@@ -42,7 +42,7 @@ def setup_argument_parser() -> argparse.ArgumentParser:
 | 
			
		||||
        '--report-type', choices=['build', 'target_test', 'job'], required=True, help='Type of report to generate'
 | 
			
		||||
    )
 | 
			
		||||
    report_type_args: argparse.Namespace
 | 
			
		||||
    remaining_args: t.List[str]
 | 
			
		||||
    remaining_args: list[str]
 | 
			
		||||
    report_type_args, remaining_args = report_type_parser.parse_known_args()
 | 
			
		||||
 | 
			
		||||
    parser: argparse.ArgumentParser = argparse.ArgumentParser(
 | 
			
		||||
@@ -105,7 +105,7 @@ def generate_build_report(args: argparse.Namespace) -> None:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_target_test_report(args: argparse.Namespace) -> None:
 | 
			
		||||
    test_cases: t.List[t.Any] = parse_testcases_from_filepattern(args.junit_report_filepattern)
 | 
			
		||||
    test_cases: list[t.Any] = parse_testcases_from_filepattern(args.junit_report_filepattern)
 | 
			
		||||
    report_generator = TargetTestReportGenerator(
 | 
			
		||||
        args.project_id,
 | 
			
		||||
        args.mr_iid,
 | 
			
		||||
@@ -123,7 +123,7 @@ def generate_target_test_report(args: argparse.Namespace) -> None:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_jobs_report(args: argparse.Namespace) -> None:
 | 
			
		||||
    jobs: t.List[t.Any] = fetch_failed_jobs(args.commit_id)
 | 
			
		||||
    jobs: list[t.Any] = fetch_failed_jobs(args.commit_id)
 | 
			
		||||
 | 
			
		||||
    if not jobs:
 | 
			
		||||
        return
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@
 | 
			
		||||
import glob
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
import typing as t
 | 
			
		||||
import xml.etree.ElementTree as ET
 | 
			
		||||
from urllib.parse import quote
 | 
			
		||||
from urllib.parse import urlencode
 | 
			
		||||
@@ -20,7 +19,7 @@ from .models import GitlabJob
 | 
			
		||||
from .models import TestCase
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def parse_testcases_from_filepattern(junit_report_filepattern: str) -> t.List[TestCase]:
 | 
			
		||||
def parse_testcases_from_filepattern(junit_report_filepattern: str) -> list[TestCase]:
 | 
			
		||||
    """
 | 
			
		||||
    Parses test cases from XML files matching the provided file pattern.
 | 
			
		||||
 | 
			
		||||
@@ -38,12 +37,12 @@ def parse_testcases_from_filepattern(junit_report_filepattern: str) -> t.List[Te
 | 
			
		||||
    return test_cases
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def load_known_failure_cases() -> t.Optional[t.Set[str]]:
 | 
			
		||||
def load_known_failure_cases() -> set[str] | None:
 | 
			
		||||
    known_failures_file = os.getenv('KNOWN_FAILURE_CASES_FILE_NAME', '')
 | 
			
		||||
    if not known_failures_file:
 | 
			
		||||
        return None
 | 
			
		||||
    try:
 | 
			
		||||
        with open(known_failures_file, 'r') as f:
 | 
			
		||||
        with open(known_failures_file) as f:
 | 
			
		||||
            file_content = f.read()
 | 
			
		||||
 | 
			
		||||
        pattern = re.compile(r'^(.*?)\s+#\s+([A-Z]+)-\d+', re.MULTILINE)
 | 
			
		||||
@@ -66,7 +65,7 @@ def is_url(string: str) -> bool:
 | 
			
		||||
    return bool(parsed.scheme) and bool(parsed.netloc)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def fetch_failed_jobs(commit_id: str) -> t.List[GitlabJob]:
 | 
			
		||||
def fetch_failed_jobs(commit_id: str) -> list[GitlabJob]:
 | 
			
		||||
    """
 | 
			
		||||
    Fetches a list of jobs from the specified commit_id using an API request to ci-dashboard-api.
 | 
			
		||||
    :param commit_id: The commit ID for which to fetch jobs.
 | 
			
		||||
@@ -110,7 +109,7 @@ def fetch_failed_jobs(commit_id: str) -> t.List[GitlabJob]:
 | 
			
		||||
    return combined_jobs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def fetch_failed_testcases_failure_ratio(failed_testcases: t.List[TestCase], branches_filter: dict) -> t.List[TestCase]:
 | 
			
		||||
def fetch_failed_testcases_failure_ratio(failed_testcases: list[TestCase], branches_filter: dict) -> list[TestCase]:
 | 
			
		||||
    """
 | 
			
		||||
    Fetches info about failure rates of testcases using an API request to ci-dashboard-api.
 | 
			
		||||
    :param failed_testcases: The list of failed testcases models.
 | 
			
		||||
@@ -140,13 +139,14 @@ def fetch_failed_testcases_failure_ratio(failed_testcases: t.List[TestCase], bra
 | 
			
		||||
def fetch_app_metrics(
 | 
			
		||||
    source_commit_sha: str,
 | 
			
		||||
    target_commit_sha: str,
 | 
			
		||||
) -> t.Dict:
 | 
			
		||||
) -> dict:
 | 
			
		||||
    """
 | 
			
		||||
    Fetches the app metrics for the given source commit SHA and target branch SHA.
 | 
			
		||||
    :param source_commit_sha: The source commit SHA.
 | 
			
		||||
    :param target_branch_sha: The commit SHA of the branch to compare app sizes against.
 | 
			
		||||
    :return: A dict of sizes of built binaries.
 | 
			
		||||
    """
 | 
			
		||||
    print(f'Fetching bin size info: {source_commit_sha=} {target_commit_sha=}')
 | 
			
		||||
    build_info_map = dict()
 | 
			
		||||
    response = requests.post(
 | 
			
		||||
        f'{CI_DASHBOARD_API}/apps/metrics',
 | 
			
		||||
@@ -174,7 +174,7 @@ def load_file(file_path: str) -> str:
 | 
			
		||||
    :param file_path: The path to the file needs to be loaded.
 | 
			
		||||
    :return: The content of the file as a string.
 | 
			
		||||
    """
 | 
			
		||||
    with open(file_path, 'r') as file:
 | 
			
		||||
    with open(file_path) as file:
 | 
			
		||||
        return file.read()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ from dynamic_pipelines.constants import BINARY_SIZE_METRIC_NAME
 | 
			
		||||
from idf_build_apps import App
 | 
			
		||||
from idf_build_apps import CMakeApp
 | 
			
		||||
from idf_build_apps.utils import rmdir
 | 
			
		||||
from idf_ci_utils import idf_relpath
 | 
			
		||||
 | 
			
		||||
if t.TYPE_CHECKING:
 | 
			
		||||
    pass
 | 
			
		||||
@@ -53,17 +54,17 @@ class Metrics:
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        source_value: t.Optional[float] = None,
 | 
			
		||||
        target_value: t.Optional[float] = None,
 | 
			
		||||
        difference: t.Optional[float] = None,
 | 
			
		||||
        difference_percentage: t.Optional[float] = None,
 | 
			
		||||
        source_value: float | None = None,
 | 
			
		||||
        target_value: float | None = None,
 | 
			
		||||
        difference: float | None = None,
 | 
			
		||||
        difference_percentage: float | None = None,
 | 
			
		||||
    ) -> None:
 | 
			
		||||
        self.source_value = source_value or 0.0
 | 
			
		||||
        self.target_value = target_value or 0.0
 | 
			
		||||
        self.difference = difference or 0.0
 | 
			
		||||
        self.difference_percentage = difference_percentage or 0.0
 | 
			
		||||
 | 
			
		||||
    def to_dict(self) -> t.Dict[str, t.Any]:
 | 
			
		||||
    def to_dict(self) -> dict[str, t.Any]:
 | 
			
		||||
        """
 | 
			
		||||
        Converts the Metrics object to a dictionary.
 | 
			
		||||
        """
 | 
			
		||||
@@ -76,7 +77,7 @@ class Metrics:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AppWithMetricsInfo(IdfCMakeApp):
 | 
			
		||||
    metrics: t.Dict[str, Metrics]
 | 
			
		||||
    metrics: dict[str, Metrics]
 | 
			
		||||
    is_new_app: bool
 | 
			
		||||
 | 
			
		||||
    def __init__(self, **kwargs: t.Any) -> None:
 | 
			
		||||
@@ -90,13 +91,13 @@ class AppWithMetricsInfo(IdfCMakeApp):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def enrich_apps_with_metrics_info(
 | 
			
		||||
    app_metrics_info_map: t.Dict[str, t.Dict[str, t.Any]], apps: t.List[App]
 | 
			
		||||
) -> t.List[AppWithMetricsInfo]:
 | 
			
		||||
    def _get_full_attributes(obj: App) -> t.Dict[str, t.Any]:
 | 
			
		||||
    app_metrics_info_map: dict[str, dict[str, t.Any]], apps: list[App]
 | 
			
		||||
) -> list[AppWithMetricsInfo]:
 | 
			
		||||
    def _get_full_attributes(obj: App) -> dict[str, t.Any]:
 | 
			
		||||
        """
 | 
			
		||||
        Retrieves all attributes of an object, including properties and computed fields.
 | 
			
		||||
        """
 | 
			
		||||
        attributes: t.Dict[str, t.Any] = obj.__dict__.copy()
 | 
			
		||||
        attributes: dict[str, t.Any] = obj.__dict__.copy()
 | 
			
		||||
        for attr in dir(obj):
 | 
			
		||||
            if not attr.startswith('_'):  # Skip private/internal attributes
 | 
			
		||||
                try:
 | 
			
		||||
@@ -120,6 +121,7 @@ def enrich_apps_with_metrics_info(
 | 
			
		||||
 | 
			
		||||
    apps_with_metrics_info = []
 | 
			
		||||
    for app in apps:
 | 
			
		||||
        app.app_dir = idf_relpath(app.app_dir)
 | 
			
		||||
        key = f'{app.app_dir}_{app.config_name}_{app.target}'
 | 
			
		||||
        app_attributes = _get_full_attributes(app)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user