diff --git a/ci/scripts/publish_test_metrics.py b/ci/scripts/publish_test_metrics.py index 662653c7..a9bf2d51 100644 --- a/ci/scripts/publish_test_metrics.py +++ b/ci/scripts/publish_test_metrics.py @@ -183,6 +183,7 @@ def _build_payload( failed_count: int, branch: str, build_number: str, + jenkins_job: str, summary: dict | None = None, workspace_line_coverage_percent: float = 0.0, source_lines_over_500: int = 0, @@ -195,8 +196,15 @@ def _build_payload( "suite": suite, "branch": branch or "unknown", "build_number": build_number or "unknown", + "jenkins_job": jenkins_job or suite, } ) + test_case_base_labels = { + "suite": suite, + "branch": branch or "unknown", + "build_number": build_number or "unknown", + "jenkins_job": jenkins_job or suite, + } lines = [ "# TYPE platform_quality_gate_runs_total counter", f'platform_quality_gate_runs_total{{suite="{suite}",status="ok"}} {ok_count}', @@ -228,12 +236,18 @@ def _build_payload( lines.append("# TYPE platform_quality_gate_test_case_result gauge") if test_cases: for test_name, test_status in test_cases: + labels = { + **test_case_base_labels, + "test": test_name, + "status": test_status, + } lines.append( - f'platform_quality_gate_test_case_result{{suite="{suite}",test="{_escape_label(test_name)}",status="{_escape_label(test_status)}"}} 1' + f"platform_quality_gate_test_case_result{_label_str(labels)} 1" ) else: + labels = {**test_case_base_labels, "test": "__no_test_cases__", "status": "skipped"} lines.append( - f'platform_quality_gate_test_case_result{{suite="{suite}",test="__no_test_cases__",status="skipped"}} 1' + f"platform_quality_gate_test_case_result{_label_str(labels)} 1" ) return "\n".join(lines) + "\n" @@ -250,6 +264,7 @@ def main() -> int: if branch.startswith("origin/"): branch = branch[len("origin/") :] build_number = os.getenv("BUILD_NUMBER", "") + jenkins_job = os.getenv("JOB_NAME", "titan-iac") tests = _collect_junit_totals(junit_glob) test_cases = _collect_junit_cases(junit_glob) @@ -303,6 +318,7 @@ def main() -> int: failed_count=failed_count, branch=branch, build_number=build_number, + jenkins_job=jenkins_job, summary=summary, workspace_line_coverage_percent=workspace_line_coverage_percent, source_lines_over_500=source_lines_over_500, diff --git a/scripts/dashboards_render_atlas.py b/scripts/dashboards_render_atlas.py index 8f079f16..db6ae8bf 100644 --- a/scripts/dashboards_render_atlas.py +++ b/scripts/dashboards_render_atlas.py @@ -920,6 +920,7 @@ def timeseries_panel( targets=None, field_overrides=None, description=None, + data_links=None, ): """Return a Grafana time-series panel definition.""" target_list = targets if targets is not None else [{"expr": expr, "refId": "A"}] @@ -949,6 +950,8 @@ def timeseries_panel( panel["timeFrom"] = time_from if links: panel["links"] = links + if data_links: + panel["fieldConfig"]["defaults"]["links"] = data_links if description: panel["description"] = description return panel @@ -1125,7 +1128,7 @@ def testing_case_variable(): "name": "test", "label": "Test Case", "type": "query", - "query": f'label_values(platform_quality_gate_test_case_result{{suite=~"${{suite:regex}}",test!="__no_test_cases__",{PLATFORM_TEST_EXPORT_FILTER}}}, test)', + "query": f'label_values(platform_quality_gate_test_case_result{{suite=~"${{suite:regex}}",branch=~"${{branch:regex}}",test!="__no_test_cases__",{PLATFORM_TEST_EXPORT_FILTER}}}, test)', "current": {"text": "All", "value": "$__all", "selected": True}, "options": [], "hide": 0, @@ -1194,6 +1197,36 @@ def jenkins_suite_links(base_var="${jenkins_base}"): return links +def jenkins_artifact_data_links(base_var="${jenkins_base}"): + return [ + { + "title": "Open build artifacts", + "url": f"{base_var}/job/${{__field.labels.jenkins_job}}/${{__field.labels.build_number}}/artifact/", + "targetBlank": True, + }, + { + "title": "Open build", + "url": f"{base_var}/job/${{__field.labels.jenkins_job}}/${{__field.labels.build_number}}/", + "targetBlank": True, + }, + ] + + +def jenkins_latest_artifact_data_links(base_var="${jenkins_base}"): + return [ + { + "title": "Open latest artifacts", + "url": f"{base_var}/job/${{__field.labels.jenkins_job}}/lastCompletedBuild/artifact/", + "targetBlank": True, + }, + { + "title": "Open Jenkins job", + "url": f"{base_var}/job/${{__field.labels.jenkins_job}}/", + "targetBlank": True, + }, + ] + + def bargauge_panel( panel_id, title, @@ -1209,6 +1242,7 @@ def bargauge_panel( decimals=None, instant=False, overrides=None, + data_links=None, ): """Return a bar gauge panel with label-aware reduction.""" cleaned_expr = expr.strip() @@ -1265,6 +1299,8 @@ def bargauge_panel( panel["fieldConfig"]["defaults"]["decimals"] = decimals if links: panel["links"] = links + if data_links: + panel["fieldConfig"]["defaults"]["links"] = data_links # Keep bars ordered by value descending for readability. panel["transformations"] = [ { @@ -3049,7 +3085,7 @@ def build_jobs_dashboard(): coverage_metric_selector = f'__name__=~".*_quality_gate_coverage_percent",suite=~"{suite_var}",{exported}' workspace_coverage_selector = f'suite=~"{suite_var}",{exported}' smell_selector = f'suite=~"{suite_var}",{exported}' - test_case_selector = f'suite=~"{suite_var}",test=~"{test_var}",test!="__no_test_cases__",{exported}' + test_case_selector = f'suite=~"{suite_var}",branch=~"{branch_var}",test=~"{test_var}",test!="__no_test_cases__",{exported}' build_info_selector = f'suite=~"{suite_var}",branch=~"{branch_var}",{exported}' suite_universe = " or ".join( @@ -3134,28 +3170,28 @@ def build_jobs_dashboard(): return f'({core}) or on(suite) (0 * ({suite_universe}))' problematic_tests_history_core = ( - f'topk(12, sum by (suite, test) (increase(platform_quality_gate_test_case_result{{suite=~"{suite_var}",test!="__no_test_cases__",status="failed",{exported}}}[$__interval])))' + f'topk(12, sum by (suite, test, jenkins_job) (increase(platform_quality_gate_test_case_result{{suite=~"{suite_var}",branch=~"{branch_var}",test!="__no_test_cases__",status="failed",{exported}}}[$__interval])))' ) problematic_tests_history = f"({problematic_tests_history_core}) or on() vector(0)" worst_test_per_suite_core = ( - f'topk by (suite) (1, sum by (suite, test) (increase(platform_quality_gate_test_case_result{{suite=~"{suite_var}",test!="__no_test_cases__",status="failed",{exported}}}[30d])))' + f'topk by (suite) (1, sum by (suite, test, jenkins_job) (increase(platform_quality_gate_test_case_result{{suite=~"{suite_var}",branch=~"{branch_var}",test!="__no_test_cases__",status="failed",{exported}}}[30d])))' ) worst_test_per_suite = f"({worst_test_per_suite_core}) or on() vector(0)" selected_test_pass_fail = [ { "refId": "A", - "expr": f'sum by (suite) (increase(platform_quality_gate_test_case_result{{{test_case_selector},status="passed"}}[$__interval])) or on() vector(0)', - "legendFormat": "passed · {{suite}}", + "expr": f'sum by (suite, test, status, jenkins_job, build_number) (max_over_time(platform_quality_gate_test_case_result{{{test_case_selector},status="passed"}}[$__interval])) or on() vector(0)', + "legendFormat": "passed · {{suite}} · #{{build_number}}", }, { "refId": "B", - "expr": f'sum by (suite) (increase(platform_quality_gate_test_case_result{{{test_case_selector},status="failed"}}[$__interval])) or on() vector(0)', - "legendFormat": "failed · {{suite}}", + "expr": f'sum by (suite, test, status, jenkins_job, build_number) (max_over_time(platform_quality_gate_test_case_result{{{test_case_selector},status="failed"}}[$__interval])) or on() vector(0)', + "legendFormat": "failed · {{suite}} · #{{build_number}}", }, { "refId": "C", - "expr": f'sum by (suite) (increase(platform_quality_gate_test_case_result{{{test_case_selector},status="skipped"}}[$__interval])) or on() vector(0)', - "legendFormat": "skipped · {{suite}}", + "expr": f'sum by (suite, test, status, jenkins_job, build_number) (max_over_time(platform_quality_gate_test_case_result{{{test_case_selector},status="skipped"}}[$__interval])) or on() vector(0)', + "legendFormat": "skipped · {{suite}} · #{{build_number}}", }, ] recent_branch_evidence = ( @@ -3722,6 +3758,7 @@ def build_jobs_dashboard(): legend_placement="bottom", legend_calcs=["lastNotNull", "max", "sum"], links=jenkins_suite_links(), + data_links=jenkins_latest_artifact_data_links(), ) ) panels.append( @@ -3736,6 +3773,7 @@ def build_jobs_dashboard(): legend_placement="bottom", legend_calcs=["lastNotNull", "sum"], links=jenkins_suite_links(), + data_links=jenkins_artifact_data_links(), ) ) panels.append( @@ -3751,6 +3789,7 @@ def build_jobs_dashboard(): thresholds=failures_thresholds, limit=9, links=jenkins_suite_links(), + data_links=jenkins_latest_artifact_data_links(), ) ) @@ -3962,8 +4001,8 @@ def build_jobs_dashboard(): "templating": { "list": [ testing_suite_variable(), - testing_case_variable(), testing_branch_variable(), + testing_case_variable(), jenkins_base_variable(), ] }, diff --git a/services/logging/Jenkinsfile.data-prepper b/services/logging/Jenkinsfile.data-prepper index a2ca396a..5b6adf14 100644 --- a/services/logging/Jenkinsfile.data-prepper +++ b/services/logging/Jenkinsfile.data-prepper @@ -295,8 +295,11 @@ EOF if [ "${status}" != "ok" ]; then gate_glue_check="failed" fi - metric_branch="$(printf '%s' "${BRANCH_NAME:-${GIT_BRANCH:-unknown}}" | jq -Rsa . | sed -e 's/^"//' -e 's/"$//')" + metric_branch_raw="${BRANCH_NAME:-${GIT_BRANCH:-unknown}}" + metric_branch_raw="${metric_branch_raw#origin/}" + metric_branch="$(printf '%s' "${metric_branch_raw}" | jq -Rsa . | sed -e 's/^"//' -e 's/"$//')" metric_build_number="$(printf '%s' "${BUILD_NUMBER:-unknown}" | jq -Rsa . | sed -e 's/^"//' -e 's/"$//')" + metric_jenkins_job="$(printf '%s' "${JOB_NAME:-data-prepper}" | jq -Rsa . | sed -e 's/^"//' -e 's/"$//')" cat </dev/null || \ echo "warning: metrics push failed for suite=${suite}" >&2 # TYPE platform_quality_gate_runs_total counter @@ -312,7 +315,7 @@ platform_quality_gate_workspace_line_coverage_percent{suite="${suite}"} 0 # TYPE platform_quality_gate_source_lines_over_500_total gauge platform_quality_gate_source_lines_over_500_total{suite="${suite}"} 0 # TYPE platform_quality_gate_build_info gauge -platform_quality_gate_build_info{suite="${suite}",branch="${metric_branch}",build_number="${metric_build_number}"} 1 +platform_quality_gate_build_info{suite="${suite}",branch="${metric_branch}",build_number="${metric_build_number}",jenkins_job="${metric_jenkins_job}"} 1 # TYPE data_prepper_quality_gate_checks_total gauge data_prepper_quality_gate_checks_total{suite="${suite}",check="tests",result="not_applicable"} 1 data_prepper_quality_gate_checks_total{suite="${suite}",check="coverage",result="not_applicable"} 1 @@ -322,7 +325,7 @@ data_prepper_quality_gate_checks_total{suite="${suite}",check="gate_glue",result data_prepper_quality_gate_checks_total{suite="${suite}",check="sonarqube",result="${sonarqube_check}"} 1 data_prepper_quality_gate_checks_total{suite="${suite}",check="supply_chain",result="${supply_chain_check}"} 1 # TYPE platform_quality_gate_test_case_result gauge -platform_quality_gate_test_case_result{suite="${suite}",test="__no_test_cases__",status="skipped"} 1 +platform_quality_gate_test_case_result{suite="${suite}",branch="${metric_branch}",build_number="${metric_build_number}",jenkins_job="${metric_jenkins_job}",test="__no_test_cases__",status="skipped"} 1 METRICS ''' } diff --git a/services/monitoring/dashboards/atlas-jobs.json b/services/monitoring/dashboards/atlas-jobs.json index 35a7db74..ff1e4ed5 100644 --- a/services/monitoring/dashboards/atlas-jobs.json +++ b/services/monitoring/dashboards/atlas-jobs.json @@ -2060,14 +2060,26 @@ }, "targets": [ { - "expr": "(topk(12, sum by (suite, test) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test!=\"__no_test_cases__\",status=\"failed\",exported_job=\"platform-quality-ci\"}[$__interval])))) or on() vector(0)", + "expr": "(topk(12, sum by (suite, test, jenkins_job) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test!=\"__no_test_cases__\",status=\"failed\",exported_job=\"platform-quality-ci\"}[$__interval])))) or on() vector(0)", "refId": "A", "legendFormat": "{{suite}} \u00b7 {{test}}" } ], "fieldConfig": { "defaults": { - "unit": "none" + "unit": "none", + "links": [ + { + "title": "Open latest artifacts", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/lastCompletedBuild/artifact/", + "targetBlank": true + }, + { + "title": "Open Jenkins job", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/", + "targetBlank": true + } + ] }, "overrides": [] }, @@ -2200,23 +2212,35 @@ "targets": [ { "refId": "A", - "expr": "sum by (suite) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"passed\"}[$__interval])) or on() vector(0)", - "legendFormat": "passed \u00b7 {{suite}}" + "expr": "sum by (suite, test, status, jenkins_job, build_number) (max_over_time(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"passed\"}[$__interval])) or on() vector(0)", + "legendFormat": "passed \u00b7 {{suite}} \u00b7 #{{build_number}}" }, { "refId": "B", - "expr": "sum by (suite) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"failed\"}[$__interval])) or on() vector(0)", - "legendFormat": "failed \u00b7 {{suite}}" + "expr": "sum by (suite, test, status, jenkins_job, build_number) (max_over_time(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"failed\"}[$__interval])) or on() vector(0)", + "legendFormat": "failed \u00b7 {{suite}} \u00b7 #{{build_number}}" }, { "refId": "C", - "expr": "sum by (suite) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"skipped\"}[$__interval])) or on() vector(0)", - "legendFormat": "skipped \u00b7 {{suite}}" + "expr": "sum by (suite, test, status, jenkins_job, build_number) (max_over_time(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"skipped\"}[$__interval])) or on() vector(0)", + "legendFormat": "skipped \u00b7 {{suite}} \u00b7 #{{build_number}}" } ], "fieldConfig": { "defaults": { - "unit": "none" + "unit": "none", + "links": [ + { + "title": "Open build artifacts", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/${__field.labels.build_number}/artifact/", + "targetBlank": true + }, + { + "title": "Open build", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/${__field.labels.build_number}/", + "targetBlank": true + } + ] }, "overrides": [] }, @@ -2347,7 +2371,7 @@ }, "targets": [ { - "expr": "sort_desc((topk by (suite) (1, sum by (suite, test) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test!=\"__no_test_cases__\",status=\"failed\",exported_job=\"platform-quality-ci\"}[30d])))) or on() vector(0))", + "expr": "sort_desc((topk by (suite) (1, sum by (suite, test, jenkins_job) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test!=\"__no_test_cases__\",status=\"failed\",exported_job=\"platform-quality-ci\"}[30d])))) or on() vector(0))", "refId": "A", "legendFormat": "{{suite}} \u00b7 {{test}}", "instant": true @@ -2378,7 +2402,19 @@ "value": 5 } ] - } + }, + "links": [ + { + "title": "Open latest artifacts", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/lastCompletedBuild/artifact/", + "targetBlank": true + }, + { + "title": "Open Jenkins job", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/", + "targetBlank": true + } + ] }, "overrides": [] }, @@ -3760,10 +3796,10 @@ "skipUrlSync": false }, { - "name": "test", - "label": "Test Case", + "name": "branch", + "label": "Branch", "type": "query", - "query": "label_values(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\"}, test)", + "query": "label_values(platform_quality_gate_build_info{suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\"}, branch)", "current": { "text": "All", "value": "$__all", @@ -3779,10 +3815,10 @@ "skipUrlSync": false }, { - "name": "branch", - "label": "Branch", + "name": "test", + "label": "Test Case", "type": "query", - "query": "label_values(platform_quality_gate_build_info{suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\"}, branch)", + "query": "label_values(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\"}, test)", "current": { "text": "All", "value": "$__all", diff --git a/services/monitoring/grafana-dashboard-jobs.yaml b/services/monitoring/grafana-dashboard-jobs.yaml index a149788c..76625bbd 100644 --- a/services/monitoring/grafana-dashboard-jobs.yaml +++ b/services/monitoring/grafana-dashboard-jobs.yaml @@ -2069,14 +2069,26 @@ data: }, "targets": [ { - "expr": "(topk(12, sum by (suite, test) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test!=\"__no_test_cases__\",status=\"failed\",exported_job=\"platform-quality-ci\"}[$__interval])))) or on() vector(0)", + "expr": "(topk(12, sum by (suite, test, jenkins_job) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test!=\"__no_test_cases__\",status=\"failed\",exported_job=\"platform-quality-ci\"}[$__interval])))) or on() vector(0)", "refId": "A", "legendFormat": "{{suite}} \u00b7 {{test}}" } ], "fieldConfig": { "defaults": { - "unit": "none" + "unit": "none", + "links": [ + { + "title": "Open latest artifacts", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/lastCompletedBuild/artifact/", + "targetBlank": true + }, + { + "title": "Open Jenkins job", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/", + "targetBlank": true + } + ] }, "overrides": [] }, @@ -2209,23 +2221,35 @@ data: "targets": [ { "refId": "A", - "expr": "sum by (suite) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"passed\"}[$__interval])) or on() vector(0)", - "legendFormat": "passed \u00b7 {{suite}}" + "expr": "sum by (suite, test, status, jenkins_job, build_number) (max_over_time(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"passed\"}[$__interval])) or on() vector(0)", + "legendFormat": "passed \u00b7 {{suite}} \u00b7 #{{build_number}}" }, { "refId": "B", - "expr": "sum by (suite) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"failed\"}[$__interval])) or on() vector(0)", - "legendFormat": "failed \u00b7 {{suite}}" + "expr": "sum by (suite, test, status, jenkins_job, build_number) (max_over_time(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"failed\"}[$__interval])) or on() vector(0)", + "legendFormat": "failed \u00b7 {{suite}} \u00b7 #{{build_number}}" }, { "refId": "C", - "expr": "sum by (suite) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"skipped\"}[$__interval])) or on() vector(0)", - "legendFormat": "skipped \u00b7 {{suite}}" + "expr": "sum by (suite, test, status, jenkins_job, build_number) (max_over_time(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test=~\"${test:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\",status=\"skipped\"}[$__interval])) or on() vector(0)", + "legendFormat": "skipped \u00b7 {{suite}} \u00b7 #{{build_number}}" } ], "fieldConfig": { "defaults": { - "unit": "none" + "unit": "none", + "links": [ + { + "title": "Open build artifacts", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/${__field.labels.build_number}/artifact/", + "targetBlank": true + }, + { + "title": "Open build", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/${__field.labels.build_number}/", + "targetBlank": true + } + ] }, "overrides": [] }, @@ -2356,7 +2380,7 @@ data: }, "targets": [ { - "expr": "sort_desc((topk by (suite) (1, sum by (suite, test) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test!=\"__no_test_cases__\",status=\"failed\",exported_job=\"platform-quality-ci\"}[30d])))) or on() vector(0))", + "expr": "sort_desc((topk by (suite) (1, sum by (suite, test, jenkins_job) (increase(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test!=\"__no_test_cases__\",status=\"failed\",exported_job=\"platform-quality-ci\"}[30d])))) or on() vector(0))", "refId": "A", "legendFormat": "{{suite}} \u00b7 {{test}}", "instant": true @@ -2387,7 +2411,19 @@ data: "value": 5 } ] - } + }, + "links": [ + { + "title": "Open latest artifacts", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/lastCompletedBuild/artifact/", + "targetBlank": true + }, + { + "title": "Open Jenkins job", + "url": "${jenkins_base}/job/${__field.labels.jenkins_job}/", + "targetBlank": true + } + ] }, "overrides": [] }, @@ -3769,10 +3805,10 @@ data: "skipUrlSync": false }, { - "name": "test", - "label": "Test Case", + "name": "branch", + "label": "Branch", "type": "query", - "query": "label_values(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\"}, test)", + "query": "label_values(platform_quality_gate_build_info{suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\"}, branch)", "current": { "text": "All", "value": "$__all", @@ -3788,10 +3824,10 @@ data: "skipUrlSync": false }, { - "name": "branch", - "label": "Branch", + "name": "test", + "label": "Test Case", "type": "query", - "query": "label_values(platform_quality_gate_build_info{suite=~\"${suite:regex}\",exported_job=\"platform-quality-ci\"}, branch)", + "query": "label_values(platform_quality_gate_test_case_result{suite=~\"${suite:regex}\",branch=~\"${branch:regex}\",test!=\"__no_test_cases__\",exported_job=\"platform-quality-ci\"}, test)", "current": { "text": "All", "value": "$__all", diff --git a/testing/tests/test_publish_test_metrics.py b/testing/tests/test_publish_test_metrics.py index b8b170a5..6f129638 100644 --- a/testing/tests/test_publish_test_metrics.py +++ b/testing/tests/test_publish_test_metrics.py @@ -330,6 +330,7 @@ def test_build_payload_includes_canonical_checks(): failed_count=2, branch="main", build_number="42", + jenkins_job="titan-iac", workspace_line_coverage_percent=95.0, source_lines_over_500=0, check_statuses={ @@ -358,6 +359,7 @@ def test_build_payload_omits_checks_block_without_check_statuses(): failed_count=2, branch="", build_number="", + jenkins_job="titan-iac", workspace_line_coverage_percent=0.0, source_lines_over_500=1, ) diff --git a/testing/tests/test_publish_test_metrics_paths.py b/testing/tests/test_publish_test_metrics_paths.py index 39acd796..50d45cd8 100644 --- a/testing/tests/test_publish_test_metrics_paths.py +++ b/testing/tests/test_publish_test_metrics_paths.py @@ -49,13 +49,20 @@ def test_build_payload_includes_explicit_test_case_series(): failed_count=1, branch="main", build_number="5", + jenkins_job="titan-iac", workspace_line_coverage_percent=95.0, source_lines_over_500=0, check_statuses={"tests": "failed"}, ) - assert 'platform_quality_gate_test_case_result{suite="titan-iac",test="alpha::case_one",status="failed"} 1' in payload - assert 'platform_quality_gate_test_case_result{suite="titan-iac",test="beta::case_two",status="passed"} 1' in payload + assert ( + 'platform_quality_gate_test_case_result{suite="titan-iac",branch="main",build_number="5",jenkins_job="titan-iac",test="alpha::case_one",status="failed"} 1' + in payload + ) + assert ( + 'platform_quality_gate_test_case_result{suite="titan-iac",branch="main",build_number="5",jenkins_job="titan-iac",test="beta::case_two",status="passed"} 1' + in payload + ) def test_main_uses_reported_coverage_and_loc_without_fallback(tmp_path: Path, monkeypatch, capsys):