pegasus/Jenkinsfile

196 lines
5.2 KiB
Plaintext
Raw Normal View History

pipeline {
agent {
kubernetes {
label 'pegasus-tests'
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.22-bookworm
command: ["cat"]
tty: true
volumeMounts:
- name: workspace-volume
mountPath: /home/jenkins/agent
- name: node-tester
image: node:20-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 = 'pegasus'
PUSHGATEWAY_URL = 'http://platform-quality-gateway.monitoring.svc.cluster.local:9091'
}
options {
disableConcurrentBuilds()
}
triggers {
pollSCM('H/5 * * * *')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Backend unit tests') {
steps {
container('go-tester') {
sh '''
set -euo pipefail
mkdir -p build
cd backend
go install github.com/jstemmer/go-junit-report/v2@latest
set +e
go test -coverprofile=../build/coverage-backend.out ./... > ../build/backend-test.out 2>&1
test_rc=$?
set -e
cat ../build/backend-test.out
"$(go env GOPATH)/bin/go-junit-report" < ../build/backend-test.out > ../build/junit-backend.xml
coverage="0"
if [ -f ../build/coverage-backend.out ]; then
coverage="$(go tool cover -func=../build/coverage-backend.out | awk '/^total:/ {gsub("%","",$3); print $3}')"
fi
printf '%s\n' "${coverage}" > ../build/coverage-backend-percent.txt
printf '%s\n' "${test_rc}" > ../build/backend-test.rc
'''
}
}
}
stage('Frontend unit tests') {
steps {
container('node-tester') {
sh '''
set -euo pipefail
mkdir -p build
cd frontend
npm ci
set +e
npm run test:ci > ../build/frontend-test.out 2>&1
test_rc=$?
set -e
cat ../build/frontend-test.out
if [ -f ../build/frontend-coverage/coverage-summary.json ]; then
node -e 'const fs=require("fs");const p=JSON.parse(fs.readFileSync("../build/frontend-coverage/coverage-summary.json","utf8"));const pct=((p.total||{}).lines||{}).pct||0;process.stdout.write(String(pct));' > ../build/coverage-frontend-percent.txt
else
echo "0" > ../build/coverage-frontend-percent.txt
fi
printf '%s\n' "${test_rc}" > ../build/frontend-test.rc
'''
}
}
}
stage('Combine coverage summary') {
steps {
container('publisher') {
sh '''
set -euo pipefail
python - <<'PY'
import json
from pathlib import Path
build = Path('build')
def read_float(path: Path) -> float:
if not path.exists():
return 0.0
try:
return float(path.read_text(encoding='utf-8').strip())
except ValueError:
return 0.0
backend = read_float(build / 'coverage-backend-percent.txt')
frontend = read_float(build / 'coverage-frontend-percent.txt')
combined = (backend + frontend) / 2 if (backend or frontend) else 0.0
(build / 'coverage.json').write_text(
json.dumps(
{
'summary': {
'backend_percent': backend,
'frontend_percent': frontend,
'percent_covered': combined,
}
},
indent=2,
) + '\n',
encoding='utf-8',
)
print(f'Combined Pegasus coverage: {combined:.2f}%')
PY
'''
}
}
}
stage('Publish test metrics') {
steps {
container('publisher') {
sh '''
set -euo pipefail
python scripts/publish_test_metrics.py
'''
}
}
}
stage('Quality gate') {
steps {
container('publisher') {
sh '''
set -euo pipefail
backend_rc="$(cat build/backend-test.rc 2>/dev/null || echo 1)"
frontend_rc="$(cat build/frontend-test.rc 2>/dev/null || echo 1)"
if [ "${backend_rc}" -ne 0 ] || [ "${frontend_rc}" -ne 0 ]; then
echo "Pegasus test suite failed (backend=${backend_rc}, frontend=${frontend_rc})"
exit 1
fi
'''
}
}
}
}
post {
always {
script {
if (fileExists('build/junit-backend.xml') || fileExists('build/junit-frontend.xml')) {
try {
junit allowEmptyResults: true, testResults: 'build/junit-backend.xml,build/junit-frontend.xml'
} catch (Throwable err) {
echo "junit step unavailable: ${err.class.simpleName}"
}
}
}
archiveArtifacts artifacts: 'build/**', allowEmptyArchive: true, fingerprint: true
}
}
}