From 596495674348c09e1cfc17a417c7f8cd59e706ba Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Mon, 13 Jul 2026 12:38:15 +0100 Subject: [PATCH 1/5] Better job summary message when no common errors etc. --- .../check_build_stability.py | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/developer_support_script/check_build_stability.py b/developer_support_script/check_build_stability.py index bfdc597..22bb5ff 100644 --- a/developer_support_script/check_build_stability.py +++ b/developer_support_script/check_build_stability.py @@ -34,7 +34,7 @@ def request_json(url: str) -> dict | None: 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) -> str: """ Utility function to calculate log level based on a percentage. @@ -176,14 +176,20 @@ def _get_failed_tests(self) -> Counter: return counter - def print_results(self) -> None: + def print_message(self, level: str, msg: str) -> None: + print(f"{level}: {msg}") + + def print_results(self) -> set[str]: """ 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 + levels.add("WARNING") + return levels # Aborted builds. valid_builds = self.num_evaluate_builds + self.no_test_report_failures @@ -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}%]") - + self.print_message(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: @@ -208,10 +214,11 @@ 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}%]" + self.print_message( + 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(): @@ -222,7 +229,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}") + self.print_message(level, f"[{percentage_test_failure:.0f}%] {name}") + levels.add(level) + return levels def process_jobs(jobs: list[str], summary_name: str) -> None: @@ -238,7 +247,13 @@ def process_jobs(jobs: list[str], summary_name: str) -> None: job_data.print_results() print(f"****** Summary across {summary_name} jobs ******") - job_summary.print_results() + levels = job_summary.print_results() + for lev in ["INFO", "ERROR", "WARNING"]: + if lev not in levels: + print( + f"{lev}: threshold not reached when viewed/summed over {len(jobs)} jobs, " + "however individual jobs may have met the threshold" + ) if __name__ == "__main__": From 5464489a8a016e354132d9afa2259c55c29378e6 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Tue, 14 Jul 2026 01:28:01 +0100 Subject: [PATCH 2/5] Skip summary if just 1 job --- .../check_build_stability.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/developer_support_script/check_build_stability.py b/developer_support_script/check_build_stability.py index 22bb5ff..5887f67 100644 --- a/developer_support_script/check_build_stability.py +++ b/developer_support_script/check_build_stability.py @@ -246,14 +246,15 @@ 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 ******") - levels = job_summary.print_results() - for lev in ["INFO", "ERROR", "WARNING"]: - if lev not in levels: - print( - f"{lev}: threshold not reached when viewed/summed over {len(jobs)} jobs, " - "however individual jobs may have met the threshold" - ) + if len(jobs) > 0: + print(f"****** Summary across {len(jobs)} {summary_name} jobs ******") + levels = job_summary.print_results() + for lev in ["INFO", "ERROR", "WARNING"]: + if lev not in levels: + print( + f"{lev}: OK as threshold not reached when viewed/summed over {len(jobs)} jobs, " + "however individual jobs may have met the threshold" + ) if __name__ == "__main__": @@ -268,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") From 32df4815221d00079ae30398e0f4828523dbf75f Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Tue, 14 Jul 2026 15:37:50 +0100 Subject: [PATCH 3/5] Remove print_message() accidentally left in --- developer_support_script/check_build_stability.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/developer_support_script/check_build_stability.py b/developer_support_script/check_build_stability.py index 5887f67..3f88914 100644 --- a/developer_support_script/check_build_stability.py +++ b/developer_support_script/check_build_stability.py @@ -176,9 +176,6 @@ def _get_failed_tests(self) -> Counter: return counter - def print_message(self, level: str, msg: str) -> None: - print(f"{level}: {msg}") - def print_results(self) -> set[str]: """ Prints the percentage of aborted builds for the job, the percentage of @@ -200,7 +197,7 @@ def print_results(self) -> set[str]: level = calculate_level( percentage_aborted_builds, ERROR_THRESHOLD_PERCENTAGE, WARNING_THRESHOLD_PERCENTAGE ) - self.print_message(level, f"Aborted builds [{percentage_aborted_builds:.0f}%]") + print(f"{level}: 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 @@ -214,9 +211,9 @@ def print_results(self) -> set[str]: ERROR_THRESHOLD_PERCENTAGE, WARNING_THRESHOLD_PERCENTAGE, ) - self.print_message( - level, - f"Failed builds with no Test Report [{percentage_no_test_report_failures:.0f}%]", + print( + f"{level}: Failed builds with no Test Report " + f"[{percentage_no_test_report_failures:.0f}%]" ) levels.add(level) @@ -229,7 +226,7 @@ def print_results(self) -> set[str]: level = calculate_level( percentage_test_failure, ERROR_THRESHOLD_PERCENTAGE, WARNING_THRESHOLD_PERCENTAGE ) - self.print_message(level, f"[{percentage_test_failure:.0f}%] {name}") + print(f"{level}: [{percentage_test_failure:.0f}%] {name}") levels.add(level) return levels From 88ebe51104c291f7674a64780c52543a72e2bb4d Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Tue, 14 Jul 2026 15:46:28 +0100 Subject: [PATCH 4/5] pyright --- developer_support_script/check_build_stability.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer_support_script/check_build_stability.py b/developer_support_script/check_build_stability.py index 3f88914..35e5255 100644 --- a/developer_support_script/check_build_stability.py +++ b/developer_support_script/check_build_stability.py @@ -243,7 +243,7 @@ def process_jobs(jobs: list[str], summary_name: str) -> None: job_summary.add_job(job_data) job_data.print_results() - if len(jobs) > 0: + if job_summary is not None and len(jobs) > 0: print(f"****** Summary across {len(jobs)} {summary_name} jobs ******") levels = job_summary.print_results() for lev in ["INFO", "ERROR", "WARNING"]: From 52611c31986710ae7b375249bcfbd4d13c2540ac Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Tue, 14 Jul 2026 17:46:31 +0100 Subject: [PATCH 5/5] Use logger --- .../check_build_stability.py | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/developer_support_script/check_build_stability.py b/developer_support_script/check_build_stability.py index 35e5255..520d5e2 100644 --- a/developer_support_script/check_build_stability.py +++ b/developer_support_script/check_build_stability.py @@ -5,6 +5,7 @@ job via secret text environment variables """ +import logging import os from collections import Counter, defaultdict from typing import Any @@ -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: """ @@ -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: float, error_percentage: float, warning_percentage: float) -> str: +def calculate_level(percentage: float, error_percentage: float, warning_percentage: float) -> int: """ Utility function to calculate log level based on a percentage. @@ -44,11 +47,11 @@ def calculate_level(percentage: float, error_percentage: float, warning_percenta 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: @@ -176,7 +179,7 @@ def _get_failed_tests(self) -> Counter: return counter - def print_results(self) -> set[str]: + 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. @@ -184,8 +187,8 @@ def print_results(self) -> set[str]: """ levels = set() if not self.buildable: - print("WARNING: build is currently disabled") - levels.add("WARNING") + logging.warning("build is currently disabled") + levels.add(logging.WARNING) return levels # Aborted builds. @@ -197,7 +200,7 @@ def print_results(self) -> set[str]: 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 @@ -211,9 +214,8 @@ def print_results(self) -> set[str]: 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) @@ -226,7 +228,7 @@ def print_results(self) -> set[str]: 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 @@ -243,14 +245,15 @@ def process_jobs(jobs: list[str], summary_name: str) -> None: job_summary.add_job(job_data) job_data.print_results() - if job_summary is not None and len(jobs) > 0: + 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 ["INFO", "ERROR", "WARNING"]: + for lev in [logging.INFO, logging.ERROR, logging.WARNING]: if lev not in levels: - print( - f"{lev}: OK as threshold not reached when viewed/summed over {len(jobs)} jobs, " - "however individual jobs may have met the threshold" + logging.log( + lev, + f"OK as threshold not reached when viewed/summed over {len(jobs)} jobs, " + "however individual jobs may have met the threshold", )