Commit f258fa87 authored by Pierre Smeyers's avatar Pierre Smeyers
Browse files

feat: check report naming conventions

Closes #3
parent 06fa3473
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
@@ -371,6 +371,75 @@ def _check_var(
    return err_count


report_types_constraints = {
    "junit": {"formats": ["junit", "xunit"], "extensions": ["xml"]},
    "coverage_report": {"formats": ["cobertura"], "extensions": ["xml"]},
    "cyclonedx": {"formats": ["cyclonedx"], "extensions": ["json"]},
    "codequality": {"formats": ["codeclimate", "gitlab"], "extensions": ["json"]},
    "container_scanning": {"formats": ["gitlab"], "extensions": ["json"]},
    "load_performance": {"formats": ["summary"], "extensions": ["json"]},
}


def _check_report(
    job_name: str,
    type: str,
    path: str,
) -> int:
    """Check a report file."""
    if type in ["dotenv"]:
        # ignore
        return 0

    err_count = 0
    constraints = report_types_constraints.get(type)
    expected_formats = constraints["formats"] if constraints else None
    expected_exts = constraints["extensions"] if constraints else None
    if constraints is None:
        print(
            f"  {AnsiColors.HGRAY}? report '{path}' ({type}): unsupported report type{AnsiColors.RESET}"
        )

    path_parts = path.split("/")
    filename = path_parts[-1]
    filename_parts = filename.split(".")
    # check: first part shoud be job name
    if not filename_parts[0].startswith(job_name) or (
        len(filename_parts[0]) > len(job_name)
        and filename_parts[0][len(job_name)] != "-"
    ):
        print(
            f"  {AnsiColors.YELLOW}⚠ report '{path}' ({type}): filename (no extension) should preferably start with '{job_name}'{AnsiColors.RESET}"
        )
    # check: filename made of three parts
    if len(filename_parts) != 3:
        print(
            f"  {AnsiColors.YELLOW}⚠ report '{path}' ({type}): filename should preferably be in 3 parts '<job-name>.<format>.<extension>'{AnsiColors.RESET}"
        )
    else:
        # check: second part (format) matches report type
        if expected_formats and filename_parts[1] not in expected_formats:
            print(
                f"  {AnsiColors.RED}✕ report '{path}' ({type}): filename middle part must match '{'|'.join(expected_formats)}'{AnsiColors.RESET}"
            )
            err_count += 1

    # check: extension matches report type
    if expected_exts and filename_parts[-1] not in expected_exts:
        print(
            f"  {AnsiColors.RED}✕ report '{path}' ({type}): file extension must match '{'|'.join(expected_exts)}'{AnsiColors.RESET}"
        )
        err_count += 1

    # check: containing folder is 'reports/'
    if len(path_parts) < 2 or path_parts[-2] != "reports":
        print(
            f"  {AnsiColors.YELLOW}⚠ report '{path}' ({type}): should preferably be generated in a 'reports/' folder{AnsiColors.RESET}"
        )

    return err_count


def _check_tpl(
    kicker: dict[str, any],
    root_kicker: Optional[dict[str, any]],
@@ -414,6 +483,16 @@ def _check_tpl(
            )
            err_count += 1

        # check: tbc reports are compliant to naming convention
        reports = body.get("artifacts", {}).get("reports", {})
        for type, paths in reports.items():
            if type == "coverage_report":
                paths = paths["path"]
            if isinstance(paths, str):
                paths = [paths]
            for path in paths:
                err_count += _check_report(name, type, path)

    # check variables
    # ---------------
    var_prefix = prefix.upper() + "_"