ci(ananke): publish branch-aware quality metrics

This commit is contained in:
codex 2026-06-04 21:36:50 -03:00
parent 304e9ba4c5
commit 61dc0a9ef4
2 changed files with 33 additions and 28 deletions

View File

@ -113,6 +113,10 @@ def _build_payload(
"build_number": build_number or "unknown", "build_number": build_number or "unknown",
"jenkins_job": jenkins_job, "jenkins_job": jenkins_job,
} }
base_labels = {
"suite": suite,
"branch": branch or "unknown",
}
test_case_base_labels = { test_case_base_labels = {
"suite": suite, "suite": suite,
"branch": branch, "branch": branch,
@ -121,29 +125,29 @@ def _build_payload(
} }
lines = [ lines = [
"# TYPE platform_quality_gate_runs_total counter", "# 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{_label_str({**base_labels, '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': 'failed'})} {failed_count}",
"# TYPE ananke_quality_gate_tests_total gauge", "# 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{_label_str({**base_labels, 'result': 'passed'})} {tests_passed}",
f'ananke_quality_gate_tests_total{{suite="{suite}",result="failed"}} {tests_failed}', f"ananke_quality_gate_tests_total{_label_str({**base_labels, 'result': 'failed'})} {tests_failed}",
f'ananke_quality_gate_tests_total{{suite="{suite}",result="error"}} {tests_errors}', f"ananke_quality_gate_tests_total{_label_str({**base_labels, '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': 'skipped'})} {tests_skipped}",
"# TYPE ananke_quality_gate_coverage_percent gauge", "# 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", "# 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", "# 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", "# 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", "# TYPE platform_quality_gate_build_info gauge",
f"platform_quality_gate_build_info{_label_str(build_labels)} 1", f"platform_quality_gate_build_info{_label_str(build_labels)} 1",
"# TYPE ananke_quality_gate_checks_total gauge", "# TYPE ananke_quality_gate_checks_total gauge",
"# TYPE ananke_quality_gate_publish_info 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( 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() for check_name, check_status in checks.items()
) )
lines.append("# TYPE platform_quality_gate_test_case_result gauge") lines.append("# TYPE platform_quality_gate_test_case_result gauge")

View File

@ -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( exit_code = publisher.main(
[ [
"--pushgateway-url", "--pushgateway-url",
@ -119,13 +119,14 @@ class PublishQualityMetricsTest(unittest.TestCase):
self.assertEqual(len(_GatewayHandler.posts), 1) self.assertEqual(len(_GatewayHandler.posts), 1)
path, body = _GatewayHandler.posts[0] path, body = _GatewayHandler.posts[0]
self.assertEqual(path, "/metrics/job/platform-quality-ci/suite/ananke") 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",branch="main",status="ok"} 8', 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="failed"} 1', body)
self.assertIn('ananke_quality_gate_publish_info{suite="ananke",trigger="host"} 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"}', body) self.assertIn('ananke_quality_gate_coverage_percent{suite="ananke",branch="main"}', body)
self.assertIn('platform_quality_gate_workspace_line_coverage_percent{suite="ananke"}', 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"}', 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"}', 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: def test_publish_does_not_double_count_same_build(self) -> None:
_GatewayHandler.metrics_text = "\n".join( _GatewayHandler.metrics_text = "\n".join(
@ -163,13 +164,13 @@ class PublishQualityMetricsTest(unittest.TestCase):
self.assertEqual(exit_code, 0) self.assertEqual(exit_code, 0)
_, body = _GatewayHandler.posts[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",branch="main",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="failed"} 1', body)
def test_publish_falls_back_to_local_counters_when_metrics_read_fails(self) -> None: def test_publish_falls_back_to_local_counters_when_metrics_read_fails(self) -> None:
_GatewayHandler.fail_metrics_read = True _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( exit_code = publisher.main(
[ [
"--pushgateway-url", "--pushgateway-url",
@ -188,11 +189,11 @@ class PublishQualityMetricsTest(unittest.TestCase):
self.assertEqual(exit_code, 0) self.assertEqual(exit_code, 0)
self.assertEqual(len(_GatewayHandler.posts), 1) self.assertEqual(len(_GatewayHandler.posts), 1)
_, body = _GatewayHandler.posts[0] _, 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",branch="main",status="ok"} 11', body)
self.assertIn('platform_quality_gate_runs_total{suite="ananke",status="failed"} 3', 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"}', 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"}', 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"}', body) self.assertIn('platform_quality_gate_source_lines_over_500_total{suite="ananke",branch="main"}', body)
if __name__ == "__main__": if __name__ == "__main__":