pipeline { agent { kubernetes { label 'ananke-quality' defaultContainer 'go-tester' yaml """ apiVersion: v1 kind: Pod spec: nodeSelector: kubernetes.io/arch: arm64 node-role.kubernetes.io/worker: "true" containers: - name: go-tester image: golang:1.25-bookworm command: ["cat"] tty: true volumeMounts: - name: workspace-volume mountPath: /home/jenkins/agent - name: publisher image: python:3.12-slim command: ["cat"] tty: true volumeMounts: - name: workspace-volume mountPath: /home/jenkins/agent volumes: - name: workspace-volume emptyDir: {} """ } } environment { SUITE_NAME = 'ananke' PUSHGATEWAY_URL = 'http://platform-quality-gateway.monitoring.svc.cluster.local:9091' } options { disableConcurrentBuilds() } triggers { pollSCM('H/5 * * * *') } stages { stage('Checkout') { steps { checkout scm } } stage('Run quality gate') { steps { container('go-tester') { sh ''' set -eu mkdir -p build set +e export GOFLAGS='-buildvcs=false' ANANKE_QUALITY_METRICS_ENABLED=0 \ ANANKE_QUALITY_PUSHGATEWAY_ENABLED=0 \ ANANKE_QUALITY_STATE_FILE="$PWD/build/quality-gate.state" \ ./scripts/quality_gate.sh > build/quality-gate.out 2>&1 gate_rc=$? set -e cat build/quality-gate.out printf '%s\\n' "${gate_rc}" > build/quality-gate.rc ''' } } } stage('Publish test metrics') { steps { container('publisher') { sh ''' set -eu ok_runs="$(awk -F= '$1=="ok"{print $2}' build/quality-gate.state 2>/dev/null | tail -n1)" failed_runs="$(awk -F= '$1=="failed"{print $2}' build/quality-gate.state 2>/dev/null | tail -n1)" [ -n "${ok_runs}" ] || ok_runs=0 [ -n "${failed_runs}" ] || failed_runs=0 gate_rc="$(cat build/quality-gate.rc 2>/dev/null || echo 1)" tests_passed=0 tests_failed=1 if [ "${gate_rc}" -eq 0 ]; then tests_passed=1 tests_failed=0 fi coverage_percent="$(python3 - <<'PY' import re from pathlib import Path log_path = Path("build/quality-gate.out") text = log_path.read_text(encoding="utf-8", errors="ignore") if log_path.exists() else "" values = [float(match.group(1)) for match in re.finditer(r"([0-9]+(?:\\.[0-9]+)?)%", text)] print(values[-1] if values else 0.0) PY )" source_lines_over_500="$(python3 - <<'PY' from pathlib import Path root = Path(".") skip = {".git", ".venv", "venv", "build", "dist", "node_modules", "__pycache__", ".pytest_cache"} suffixes = {".go", ".py", ".sh", ".json", ".yaml", ".yml"} count = 0 for path in root.rglob("*"): if not path.is_file(): continue if any(part in skip for part in path.parts): continue if path.name != "Jenkinsfile" and path.suffix.lower() not in suffixes: continue try: lines = sum(1 for _ in path.open("r", encoding="utf-8", errors="ignore")) except OSError: continue if lines > 500: count += 1 print(count) PY )" check_status="failed" if [ "${gate_rc}" -eq 0 ]; then check_status="ok" fi python3 scripts/publish_quality_metrics.py \ --pushgateway-url "${PUSHGATEWAY_URL}" \ --job-name platform-quality-ci \ --suite "${SUITE_NAME}" \ --trigger jenkins \ --local-ok "${ok_runs}" \ --local-failed "${failed_runs}" \ --tests-passed "${tests_passed}" \ --tests-failed "${tests_failed}" \ --tests-error 0 \ --tests-skipped 0 \ --coverage-percent "${coverage_percent}" \ --source-lines-over-500 "${source_lines_over_500}" \ --check "tests:${check_status}" \ --check "hygiene:${check_status}" \ --check "lint:${check_status}" \ --check "coverage:${check_status}" \ --check "gate:${check_status}" ''' } } } stage('Enforce quality gate') { steps { container('publisher') { sh ''' set -eu test "$(cat build/quality-gate.rc 2>/dev/null || echo 1)" -eq 0 ''' } } } } post { always { archiveArtifacts artifacts: 'build/quality-gate.out,build/quality-gate.rc', allowEmptyArchive: true, fingerprint: true } } }