Skip to content
Merged
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
49 changes: 32 additions & 17 deletions developer_support_script/check_build_stability.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
job via secret text environment variables
"""

import logging
import os
from collections import Counter, defaultdict
from typing import Any
Expand All @@ -15,6 +16,8 @@
WARNING_THRESHOLD_PERCENTAGE = 10
ERROR_THRESHOLD_PERCENTAGE = 50

logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.INFO)


def request_json(url: str) -> dict | None:
"""
Expand All @@ -30,11 +33,11 @@ def request_json(url: str) -> dict | None:
if request.status_code == requests.codes["ok"]:
return request.json()
else:
print(f"ERROR: Failed to get '{url}': [{request.status_code}] {request.reason}")
logging.error(f"Failed to get '{url}': [{request.status_code}] {request.reason}")
return None


def calculate_level(percentage: int, error_percentage: int, warning_percentage: int) -> str:
def calculate_level(percentage: float, error_percentage: float, warning_percentage: float) -> int:
"""
Utility function to calculate log level based on a percentage.

Expand All @@ -44,11 +47,11 @@ def calculate_level(percentage: int, error_percentage: int, warning_percentage:
warning_percentage: The warning threshold.
"""
if percentage >= error_percentage:
return "ERROR"
return logging.ERROR
elif percentage >= warning_percentage:
return "WARNING"
return logging.WARNING
else:
return "INFO"
return logging.INFO


class JobData:
Expand Down Expand Up @@ -176,14 +179,17 @@ def _get_failed_tests(self) -> Counter:

return counter

def print_results(self) -> None:
def print_results(self) -> set[int]:
"""
Prints the percentage of aborted builds for the job, the percentage of
failures with no test report, and the percentage failure of each failing test.
returns levels messages printed at
"""
levels = set()
if not self.buildable:
print("WARNING: build is currently disabled")
return
logging.warning("build is currently disabled")
levels.add(logging.WARNING)
return levels

# Aborted builds.
valid_builds = self.num_evaluate_builds + self.no_test_report_failures
Expand All @@ -194,8 +200,8 @@ def print_results(self) -> None:
level = calculate_level(
percentage_aborted_builds, ERROR_THRESHOLD_PERCENTAGE, WARNING_THRESHOLD_PERCENTAGE
)
print(f"{level}: Aborted builds [{percentage_aborted_builds:.0f}%]")

logging.log(level, f"Aborted builds [{percentage_aborted_builds:.0f}%]")
levels.add(level)
# Failures with no test report
# valid_builds will only be 0 if self.no_test_report_failures is also 0
if valid_builds > 0:
Expand All @@ -208,10 +214,10 @@ def print_results(self) -> None:
ERROR_THRESHOLD_PERCENTAGE,
WARNING_THRESHOLD_PERCENTAGE,
)
print(
f"{level}: Failed builds with no Test Report "
f"[{percentage_no_test_report_failures:.0f}%]"
logging.log(
level, f"Failed builds with no Test Report [{percentage_no_test_report_failures:.0f}%]"
)
levels.add(level)

# Tests.
for name, num in self.failed_tests.most_common():
Expand All @@ -222,7 +228,9 @@ def print_results(self) -> None:
level = calculate_level(
percentage_test_failure, ERROR_THRESHOLD_PERCENTAGE, WARNING_THRESHOLD_PERCENTAGE
)
print(f"{level}: [{percentage_test_failure:.0f}%] {name}")
logging.log(level, f"[{percentage_test_failure:.0f}%] {name}")
levels.add(level)
return levels


def process_jobs(jobs: list[str], summary_name: str) -> None:
Expand All @@ -237,8 +245,16 @@ def process_jobs(jobs: list[str], summary_name: str) -> None:
job_summary.add_job(job_data)
job_data.print_results()

print(f"****** Summary across {summary_name} jobs ******")
job_summary.print_results()
if job_summary is not None and len(jobs) > 1:
print(f"****** Summary across {len(jobs)} {summary_name} jobs ******")
levels = job_summary.print_results()
for lev in [logging.INFO, logging.ERROR, logging.WARNING]:
if lev not in levels:
logging.log(
lev,
f"OK as threshold not reached when viewed/summed over {len(jobs)} jobs, "
"however individual jobs may have met the threshold",
)


if __name__ == "__main__":
Expand All @@ -253,7 +269,6 @@ def process_jobs(jobs: list[str], summary_name: str) -> None:
]
SQUISH_JOBS = [
"System_Tests_Squish",
"System_Tests_Squish_Win11",
]
process_jobs(EPICS_JOBS, "EPICS")
process_jobs(SQUISH_JOBS, "SQUISH")
Loading