From 61dc0a9ef41152d55c1a667d0d481ae9ef79c41e Mon Sep 17 00:00:00 2001 From: codex Date: Thu, 4 Jun 2026 21:36:50 -0300 Subject: [PATCH] ci(ananke): publish branch-aware quality metrics --- scripts/publish_quality_metrics.py | 28 ++++++++++++--------- scripts/publish_quality_metrics_test.py | 33 +++++++++++++------------ 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/scripts/publish_quality_metrics.py b/scripts/publish_quality_metrics.py index 760e62d..1f2097c 100755 --- a/scripts/publish_quality_metrics.py +++ b/scripts/publish_quality_metrics.py @@ -113,6 +113,10 @@ def _build_payload( "build_number": build_number or "unknown", "jenkins_job": jenkins_job, } + base_labels = { + "suite": suite, + "branch": branch or "unknown", + } test_case_base_labels = { "suite": suite, "branch": branch, @@ -121,29 +125,29 @@ def _build_payload( } lines = [ "# TYPE platform_quality_gate_runs_total counter", - f'platform_quality_gate_runs_total{{suite="{suite}",status="ok"}} {ok_count}', - f'platform_quality_gate_runs_total{{suite="{suite}",status="failed"}} {failed_count}', + f"platform_quality_gate_runs_total{_label_str({**base_labels, 'status': 'ok'})} {ok_count}", + f"platform_quality_gate_runs_total{_label_str({**base_labels, 'status': 'failed'})} {failed_count}", "# TYPE ananke_quality_gate_tests_total gauge", - f'ananke_quality_gate_tests_total{{suite="{suite}",result="passed"}} {tests_passed}', - f'ananke_quality_gate_tests_total{{suite="{suite}",result="failed"}} {tests_failed}', - f'ananke_quality_gate_tests_total{{suite="{suite}",result="error"}} {tests_errors}', - f'ananke_quality_gate_tests_total{{suite="{suite}",result="skipped"}} {tests_skipped}', + f"ananke_quality_gate_tests_total{_label_str({**base_labels, 'result': 'passed'})} {tests_passed}", + f"ananke_quality_gate_tests_total{_label_str({**base_labels, 'result': 'failed'})} {tests_failed}", + f"ananke_quality_gate_tests_total{_label_str({**base_labels, 'result': 'error'})} {tests_errors}", + f"ananke_quality_gate_tests_total{_label_str({**base_labels, 'result': 'skipped'})} {tests_skipped}", "# TYPE ananke_quality_gate_coverage_percent gauge", - f'ananke_quality_gate_coverage_percent{{suite="{suite}"}} {coverage_percent:.3f}', + f"ananke_quality_gate_coverage_percent{_label_str(base_labels)} {coverage_percent:.3f}", "# TYPE platform_quality_gate_workspace_line_coverage_percent gauge", - f'platform_quality_gate_workspace_line_coverage_percent{{suite="{suite}"}} {coverage_percent:.3f}', + f"platform_quality_gate_workspace_line_coverage_percent{_label_str(base_labels)} {coverage_percent:.3f}", "# TYPE platform_quality_gate_source_files_total gauge", - f'platform_quality_gate_source_files_total{{suite="{suite}"}} {source_files_total}', + f"platform_quality_gate_source_files_total{_label_str(base_labels)} {source_files_total}", "# TYPE platform_quality_gate_source_lines_over_500_total gauge", - f'platform_quality_gate_source_lines_over_500_total{{suite="{suite}"}} {source_lines_over_500}', + f"platform_quality_gate_source_lines_over_500_total{_label_str(base_labels)} {source_lines_over_500}", "# TYPE platform_quality_gate_build_info gauge", f"platform_quality_gate_build_info{_label_str(build_labels)} 1", "# TYPE ananke_quality_gate_checks_total gauge", "# TYPE ananke_quality_gate_publish_info gauge", - f'ananke_quality_gate_publish_info{_label_str({"suite": suite, "trigger": trigger})} 1', + f'ananke_quality_gate_publish_info{_label_str({**base_labels, "trigger": trigger})} 1', ] lines.extend( - f'ananke_quality_gate_checks_total{{suite="{suite}",check="{check_name}",result="{check_status}"}} 1' + f"ananke_quality_gate_checks_total{_label_str({**base_labels, 'check': check_name, 'result': check_status})} 1" for check_name, check_status in checks.items() ) lines.append("# TYPE platform_quality_gate_test_case_result gauge") diff --git a/scripts/publish_quality_metrics_test.py b/scripts/publish_quality_metrics_test.py index d7aba38..7a3aed4 100755 --- a/scripts/publish_quality_metrics_test.py +++ b/scripts/publish_quality_metrics_test.py @@ -97,7 +97,7 @@ class PublishQualityMetricsTest(unittest.TestCase): ] ) - with mock.patch.dict("os.environ", self._env_for_gate_status(0)): + with mock.patch.dict("os.environ", {**self._env_for_gate_status(0), "BRANCH_NAME": "main"}): exit_code = publisher.main( [ "--pushgateway-url", @@ -119,13 +119,14 @@ class PublishQualityMetricsTest(unittest.TestCase): self.assertEqual(len(_GatewayHandler.posts), 1) path, body = _GatewayHandler.posts[0] self.assertEqual(path, "/metrics/job/platform-quality-ci/suite/ananke") - self.assertIn('platform_quality_gate_runs_total{suite="ananke",status="ok"} 8', body) - self.assertIn('platform_quality_gate_runs_total{suite="ananke",status="failed"} 1', body) - self.assertIn('ananke_quality_gate_publish_info{suite="ananke",trigger="host"} 1', body) - self.assertIn('ananke_quality_gate_coverage_percent{suite="ananke"}', body) - self.assertIn('platform_quality_gate_workspace_line_coverage_percent{suite="ananke"}', body) - self.assertIn('platform_quality_gate_source_files_total{suite="ananke"}', body) - self.assertIn('platform_quality_gate_source_lines_over_500_total{suite="ananke"}', body) + self.assertIn('platform_quality_gate_runs_total{suite="ananke",branch="main",status="ok"} 8', body) + self.assertIn('platform_quality_gate_runs_total{suite="ananke",branch="main",status="failed"} 1', body) + self.assertIn('ananke_quality_gate_publish_info{suite="ananke",branch="main",trigger="host"} 1', body) + self.assertIn('ananke_quality_gate_coverage_percent{suite="ananke",branch="main"}', body) + self.assertIn('platform_quality_gate_workspace_line_coverage_percent{suite="ananke",branch="main"}', body) + self.assertIn('platform_quality_gate_source_files_total{suite="ananke",branch="main"}', body) + self.assertIn('platform_quality_gate_source_lines_over_500_total{suite="ananke",branch="main"}', body) + self.assertIn('ananke_quality_gate_checks_total{suite="ananke",branch="main",check="tests",result=', body) def test_publish_does_not_double_count_same_build(self) -> None: _GatewayHandler.metrics_text = "\n".join( @@ -163,13 +164,13 @@ class PublishQualityMetricsTest(unittest.TestCase): self.assertEqual(exit_code, 0) _, body = _GatewayHandler.posts[0] - self.assertIn('platform_quality_gate_runs_total{suite="ananke",status="ok"} 7', body) - self.assertIn('platform_quality_gate_runs_total{suite="ananke",status="failed"} 1', body) + self.assertIn('platform_quality_gate_runs_total{suite="ananke",branch="main",status="ok"} 7', body) + self.assertIn('platform_quality_gate_runs_total{suite="ananke",branch="main",status="failed"} 1', body) def test_publish_falls_back_to_local_counters_when_metrics_read_fails(self) -> None: _GatewayHandler.fail_metrics_read = True - with mock.patch.dict("os.environ", self._env_for_gate_status(0)): + with mock.patch.dict("os.environ", {**self._env_for_gate_status(0), "GIT_BRANCH": "origin/main"}): exit_code = publisher.main( [ "--pushgateway-url", @@ -188,11 +189,11 @@ class PublishQualityMetricsTest(unittest.TestCase): self.assertEqual(exit_code, 0) self.assertEqual(len(_GatewayHandler.posts), 1) _, body = _GatewayHandler.posts[0] - self.assertIn('platform_quality_gate_runs_total{suite="ananke",status="ok"} 11', body) - self.assertIn('platform_quality_gate_runs_total{suite="ananke",status="failed"} 3', body) - self.assertIn('platform_quality_gate_workspace_line_coverage_percent{suite="ananke"}', body) - self.assertIn('platform_quality_gate_source_files_total{suite="ananke"}', body) - self.assertIn('platform_quality_gate_source_lines_over_500_total{suite="ananke"}', body) + self.assertIn('platform_quality_gate_runs_total{suite="ananke",branch="main",status="ok"} 11', body) + self.assertIn('platform_quality_gate_runs_total{suite="ananke",branch="main",status="failed"} 3', body) + self.assertIn('platform_quality_gate_workspace_line_coverage_percent{suite="ananke",branch="main"}', body) + self.assertIn('platform_quality_gate_source_files_total{suite="ananke",branch="main"}', body) + self.assertIn('platform_quality_gate_source_lines_over_500_total{suite="ananke",branch="main"}', body) if __name__ == "__main__":