ci: publish category test telemetry
This commit is contained in:
parent
980332a5cb
commit
0c8d4732ae
@ -28,12 +28,17 @@ commit=${GIT_COMMIT:-}
|
||||
if [[ -z "${commit}" ]]; then
|
||||
commit=$(git -C "${ROOT_DIR}" rev-parse --short HEAD 2>/dev/null || echo unknown)
|
||||
fi
|
||||
build_number=${BUILD_NUMBER:-unknown}
|
||||
jenkins_job=${JOB_NAME:-lesavka}
|
||||
|
||||
cat >"${METRICS_FILE}" <<METRICS
|
||||
# HELP platform_quality_gate_runs_total Number of quality gate runs by result.
|
||||
# TYPE platform_quality_gate_runs_total counter
|
||||
platform_quality_gate_runs_total{suite="lesavka",branch="${branch}",commit="${commit}",status="ok"} 0
|
||||
platform_quality_gate_runs_total{suite="lesavka",branch="${branch}",commit="${commit}",status="failed"} 1
|
||||
# HELP platform_quality_gate_build_info Build metadata for the latest lesavka gate run.
|
||||
# TYPE platform_quality_gate_build_info gauge
|
||||
platform_quality_gate_build_info{suite="lesavka",branch="${branch}",commit="${commit}",build_number="${build_number}",jenkins_job="${jenkins_job}"} 1
|
||||
METRICS
|
||||
|
||||
fetch_remote_counter() {
|
||||
@ -103,7 +108,7 @@ status=0
|
||||
# probe singleton runtime state. Keep coverage collection serial so per-file
|
||||
# percentages stay stable enough to serve as a baseline gate.
|
||||
if RUST_TEST_THREADS="${RUST_TEST_THREADS:-1}" cargo llvm-cov --workspace --all-targets --lcov --output-path "${COVERAGE_LCOV}"; then
|
||||
if python3 - "${COVERAGE_LCOV}" "${BASELINE_JSON}" "${METRICS_FILE}" "${SUMMARY_TXT}" "${ROOT_DIR}" "${COVERAGE_CONTRACT_JSON}" "${branch}" "${commit}" <<'PY'
|
||||
if python3 - "${COVERAGE_LCOV}" "${BASELINE_JSON}" "${METRICS_FILE}" "${SUMMARY_TXT}" "${ROOT_DIR}" "${COVERAGE_CONTRACT_JSON}" "${branch}" "${commit}" "${build_number}" "${jenkins_job}" <<'PY'
|
||||
import json
|
||||
import pathlib
|
||||
import subprocess
|
||||
@ -118,6 +123,8 @@ root = pathlib.Path(sys.argv[5])
|
||||
contract_path = pathlib.Path(sys.argv[6])
|
||||
branch = sys.argv[7]
|
||||
commit = sys.argv[8]
|
||||
build_number = sys.argv[9]
|
||||
jenkins_job = sys.argv[10]
|
||||
|
||||
def run_git(*args: str) -> list[str]:
|
||||
proc = subprocess.run(
|
||||
@ -259,6 +266,7 @@ def esc(value: str) -> str:
|
||||
return value.replace('\\', r'\\').replace('\n', r'\\n').replace('"', r'\"')
|
||||
|
||||
labels = f'suite="lesavka",branch="{esc(branch)}",commit="{esc(commit)}"'
|
||||
build_labels = f'{labels},build_number="{esc(build_number)}",jenkins_job="{esc(jenkins_job)}"'
|
||||
metrics = []
|
||||
metrics.append('# HELP platform_quality_gate_runs_total Number of quality gate runs by result.')
|
||||
metrics.append('# TYPE platform_quality_gate_runs_total counter')
|
||||
@ -266,6 +274,9 @@ status_label = 'ok' if not regressions and not contract_failures and not all_fil
|
||||
ok_value = 1 if status_label == 'ok' else 0
|
||||
failed_value = 1 if status_label == 'failed' else 0
|
||||
metrics.append(f'platform_quality_gate_runs_total{{{labels},status="{status_label}"}} 1')
|
||||
metrics.append('# HELP platform_quality_gate_build_info Build metadata for the latest lesavka gate run.')
|
||||
metrics.append('# TYPE platform_quality_gate_build_info gauge')
|
||||
metrics.append(f'platform_quality_gate_build_info{{{build_labels}}} 1')
|
||||
metrics.append('# HELP platform_quality_gate_checks_total Check outcomes from the latest lesavka gate run.')
|
||||
metrics.append('# TYPE platform_quality_gate_checks_total gauge')
|
||||
metrics.append(f'platform_quality_gate_checks_total{{{labels},check="coverage",status="ok"}} {ok_value}')
|
||||
|
||||
@ -9,7 +9,7 @@ SUMMARY_JSON="${REPORT_DIR}/summary.json"
|
||||
SUMMARY_TXT="${REPORT_DIR}/summary.txt"
|
||||
METRICS_FILE="${REPORT_DIR}/metrics.prom"
|
||||
PUSHGATEWAY_URL=${QUALITY_GATE_PUSHGATEWAY_URL:-}
|
||||
PUSHGATEWAY_JOB=${LESAVKA_TEST_GATE_PUSHGATEWAY_JOB:-lesavka-test-gate}
|
||||
PUSHGATEWAY_JOB=${LESAVKA_TEST_GATE_PUSHGATEWAY_JOB:-platform-quality-ci}
|
||||
|
||||
mkdir -p "${REPORT_DIR}"
|
||||
cd "${ROOT_DIR}"
|
||||
@ -48,7 +48,9 @@ python3 - \
|
||||
"${duration_seconds}" \
|
||||
"${branch}" \
|
||||
"${commit}" \
|
||||
"${build_url}" <<'PY'
|
||||
"${build_url}" \
|
||||
"${BUILD_NUMBER:-unknown}" \
|
||||
"${JOB_NAME:-lesavka}" <<'PY'
|
||||
import json
|
||||
import pathlib
|
||||
import re
|
||||
@ -64,6 +66,8 @@ duration_seconds = int(sys.argv[6])
|
||||
branch = sys.argv[7] or 'unknown'
|
||||
commit = sys.argv[8] or 'unknown'
|
||||
build_url = sys.argv[9]
|
||||
build_number = sys.argv[10] or 'unknown'
|
||||
jenkins_job = sys.argv[11] or 'lesavka'
|
||||
|
||||
result_re = re.compile(
|
||||
r'test result: (?:ok|FAILED)\. '
|
||||
@ -73,9 +77,46 @@ result_re = re.compile(
|
||||
r'(?P<measured>\d+) measured; '
|
||||
r'(?P<filtered>\d+) filtered out;'
|
||||
)
|
||||
running_re = re.compile(r'^\s*Running (?P<target>.+?)(?: \(|$)')
|
||||
test_re = re.compile(r'^test (?P<name>.+?) \.\.\. (?P<result>ok|FAILED|ignored)$')
|
||||
|
||||
counts = {'passed': 0, 'failed': 0, 'ignored': 0, 'measured': 0, 'filtered': 0}
|
||||
test_cases = []
|
||||
current_target = ''
|
||||
|
||||
manifest_path = pathlib.Path('tests/test-taxonomy-manifest.json')
|
||||
category_by_path = {}
|
||||
if manifest_path.exists():
|
||||
for item in json.loads(manifest_path.read_text(encoding='utf-8')):
|
||||
path = item.get('new', '')
|
||||
category = item.get('category', '')
|
||||
if path and category:
|
||||
category_by_path[path] = category
|
||||
|
||||
def category_for_target(target: str) -> str:
|
||||
if target in category_by_path:
|
||||
return category_by_path[target]
|
||||
parts = pathlib.PurePosixPath(target).parts
|
||||
if len(parts) >= 2 and parts[0] == 'tests':
|
||||
return parts[1]
|
||||
if target.startswith('src/'):
|
||||
return 'unit'
|
||||
return 'uncategorized'
|
||||
|
||||
for raw in log_path.read_text(encoding='utf-8', errors='replace').splitlines():
|
||||
running = running_re.search(raw)
|
||||
if running:
|
||||
current_target = running.group('target')
|
||||
continue
|
||||
test_match = test_re.search(raw.strip())
|
||||
if test_match:
|
||||
raw_result = test_match.group('result')
|
||||
test_cases.append({
|
||||
'test': f'{current_target or "unknown"}::{test_match.group("name")}',
|
||||
'category': category_for_target(current_target or 'unknown'),
|
||||
'status': {'ok': 'passed', 'FAILED': 'failed', 'ignored': 'skipped'}[raw_result],
|
||||
})
|
||||
continue
|
||||
match = result_re.search(raw)
|
||||
if not match:
|
||||
continue
|
||||
@ -113,6 +154,10 @@ def label_value(value: str) -> str:
|
||||
return value.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n')
|
||||
|
||||
labels = f'suite="lesavka",branch="{label_value(branch)}"'
|
||||
build_labels = (
|
||||
f'suite="lesavka",branch="{label_value(branch)}",commit="{label_value(commit)}",'
|
||||
f'build_number="{label_value(build_number)}",jenkins_job="{label_value(jenkins_job)}"'
|
||||
)
|
||||
success = 1 if outcome == 'ok' else 0
|
||||
failure = 1 - success
|
||||
lines = [
|
||||
@ -128,6 +173,9 @@ lines = [
|
||||
for result, value in counts.items():
|
||||
lines.append(f'lesavka_test_gate_tests{{{labels},result="{result}"}} {value}')
|
||||
lines.extend([
|
||||
'# HELP platform_quality_gate_build_info Build metadata for the latest lesavka gate run.',
|
||||
'# TYPE platform_quality_gate_build_info gauge',
|
||||
f'platform_quality_gate_build_info{{{build_labels}}} 1',
|
||||
'# HELP platform_quality_gate_tests_total Test result counts from the latest lesavka gate run.',
|
||||
'# TYPE platform_quality_gate_tests_total gauge',
|
||||
f'platform_quality_gate_tests_total{{{labels},result="passed"}} {counts["passed"]}',
|
||||
@ -137,7 +185,15 @@ lines.extend([
|
||||
'# TYPE platform_quality_gate_checks_total gauge',
|
||||
f'platform_quality_gate_checks_total{{{labels},check="tests",status="ok"}} {success}',
|
||||
f'platform_quality_gate_checks_total{{{labels},check="tests",status="failed"}} {failure}',
|
||||
'# HELP platform_quality_gate_test_case_result Per-test result from the latest lesavka gate run.',
|
||||
'# TYPE platform_quality_gate_test_case_result gauge',
|
||||
])
|
||||
for case in test_cases:
|
||||
case_labels = (
|
||||
f'{build_labels},category="{label_value(case["category"])}",'
|
||||
f'test="{label_value(case["test"])}",status="{label_value(case["status"])}"'
|
||||
)
|
||||
lines.append(f'platform_quality_gate_test_case_result{{{case_labels}}} 1')
|
||||
metrics_path.write_text('\n'.join(lines) + '\n', encoding='utf-8')
|
||||
PY
|
||||
|
||||
@ -149,7 +205,7 @@ publish_metrics() {
|
||||
|
||||
curl --fail --silent --show-error \
|
||||
--data-binary @"${METRICS_FILE}" \
|
||||
"${PUSHGATEWAY_URL%/}/metrics/job/${PUSHGATEWAY_JOB}/suite/lesavka"
|
||||
"${PUSHGATEWAY_URL%/}/metrics/job/${PUSHGATEWAY_JOB}/suite/lesavka/gate/tests"
|
||||
}
|
||||
|
||||
publish_status=0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user