pipeline { agent { kubernetes { label 'lesavka-tests-disk' defaultContainer 'rust-ci' workspaceVolume dynamicPVC(accessModes: 'ReadWriteOnce', requestsSize: '40Gi', storageClassName: 'longhorn') yaml """ apiVersion: v1 kind: Pod spec: securityContext: fsGroup: 1000 fsGroupChangePolicy: OnRootMismatch nodeSelector: kubernetes.io/arch: arm64 node-role.kubernetes.io/worker: "true" affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: NotIn values: - titan-04 - titan-06 - titan-11 - titan-12 - titan-13 - titan-14 - titan-15 - titan-17 - titan-18 - titan-19 preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 preference: matchExpressions: - key: kubernetes.io/hostname operator: In values: - titan-05 - titan-07 - titan-08 - weight: 90 preference: matchExpressions: - key: kubernetes.io/hostname operator: NotIn values: - titan-13 - titan-15 - titan-17 - titan-19 containers: - name: rust-ci image: registry.bstein.dev/bstein/lesavka-ci@sha256:699ff0a2b4461f8627fcc19353eae0dee49500486eb1819287b5713ad239c13f command: ["cat"] tty: true env: - name: CARGO_HOME value: /home/jenkins/agent/.cargo-home - name: CARGO_TARGET_DIR value: /home/jenkins/agent/workspace/lesavka/target resources: requests: cpu: "5m" memory: "1024Mi" ephemeral-storage: "4Gi" limits: memory: "6Gi" ephemeral-storage: "8Gi" volumeMounts: - name: workspace-volume mountPath: /home/jenkins/agent - name: jnlp image: jenkins/inbound-agent:3355.v388858a_47b_33-3-jdk21 resources: requests: cpu: "5m" memory: "128Mi" limits: cpu: "500m" memory: "1Gi" """ } } options { disableConcurrentBuilds() disableResume() } parameters { booleanParam(name: 'PUSH_IMAGES', defaultValue: false, description: 'Push images to registry (enable for release runs)') choice(name: 'LESAVKA_CI_PROFILE', choices: ['safe', 'daily', 'lab'], description: 'Safe is the normal non-disruptive gate; daily is intended for scheduled master/main runs; lab enables explicitly configured bare-metal probes.') booleanParam(name: 'RUN_DISRUPTIVE_INPUT_TESTS', defaultValue: false, description: 'Run virtual HID tests only on an isolated worker/session; these can emit keyboard/mouse events.') booleanParam(name: 'RUN_LAB_HARDWARE_GATES', defaultValue: false, description: 'Run opt-in bare-metal lab gates for Theia/Tethys/RCT probes when the Jenkins worker is prepared for them.') booleanParam(name: 'ENFORCE_COVERAGE_GATE', defaultValue: false, description: 'Fail CI when coverage is below the ratchet target; keep off while Lesavka is onboarding to the shared dashboard.') string(name: 'QUALITY_GATE_PUSHGATEWAY_URL', defaultValue: 'http://platform-quality-gateway.monitoring.svc.cluster.local:9091', description: 'Pushgateway base URL for quality gate metrics') string(name: 'REGISTRY_CREDENTIALS_ID', defaultValue: 'registry-bstein-dev', description: 'Jenkins credentials id for registry.bstein.dev') } environment { REGISTRY = 'registry.bstein.dev' IMAGE_PREFIX = "${REGISTRY}/lesavka" CARGO_TERM_COLOR = 'always' CARGO_BUILD_JOBS = '2' CARGO_INCREMENTAL = '0' CARGO_PROFILE_DEV_DEBUG = '0' CARGO_PROFILE_TEST_DEBUG = '0' CARGO_HOME = '/home/jenkins/agent/.cargo-home' CARGO_TARGET_DIR = "${WORKSPACE}/target" PATH = "/home/jenkins/agent/.cargo-home/bin:/usr/local/cargo/bin:${PATH}" RUSTFLAGS = '-C link-arg=-fuse-ld=lld' DOCKER_BUILDKIT = '1' LESAVKA_CI_PROFILE = "${params.LESAVKA_CI_PROFILE}" LESAVKA_COVERAGE_ENFORCE = "${params.ENFORCE_COVERAGE_GATE}" RUN_DISRUPTIVE_INPUT_TESTS = "${params.RUN_DISRUPTIVE_INPUT_TESTS}" RUN_LAB_HARDWARE_GATES = "${params.RUN_LAB_HARDWARE_GATES}" LESAVKA_CI_HEADLESS_GTK = '1' GDK_BACKEND = 'x11' NO_AT_BRIDGE = '1' QUALITY_GATE_PUSHGATEWAY_URL = "${params.QUALITY_GATE_PUSHGATEWAY_URL}" } stages { stage('Checkout') { steps { checkout scm } } stage('Bootstrap CI Toolchain') { steps { container('rust-ci') { sh ''' set -eu git config --global --add safe.directory "$WORKSPACE" if [ -z "${DISPLAY:-}" ] && ! command -v xvfb-run >/dev/null 2>&1; then apt-get update DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends xvfb xauth dbus-x11 rm -rf /var/lib/apt/lists/* fi ''' } } } stage('Safe Gate (Single Exec)') { when { expression { return params.LESAVKA_CI_PROFILE == 'safe' } } steps { container('rust-ci') { sh ''' set -eu git config --global --add safe.directory "$WORKSPACE" overall_rc=0 run_gate() { name="$1" shift printf '\\n== %s ==\\n' "$name" if "$@"; then return 0 else rc=$? printf 'gate failed: %s (rc=%s)\\n' "$name" "$rc" >&2 overall_rc=1 fi } export QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" run_gate "style/docs/loc/naming" scripts/ci/hygiene_gate.sh run_gate "tests" scripts/ci/test_gate.sh if ! cargo llvm-cov --version >/dev/null 2>&1; then if ! cargo install --locked cargo-llvm-cov; then overall_rc=1 fi fi run_gate "coverage" scripts/ci/quality_gate.sh run_gate "performance" scripts/ci/performance_gate.sh run_gate "media reliability" scripts/ci/media_reliability_gate.sh if [ "${RUN_DISRUPTIVE_INPUT_TESTS}" = "true" ]; then run_gate "input transport" env LESAVKA_ALLOW_DISRUPTIVE_INPUT_TESTS=1 scripts/ci/input_transport_gate.sh fi if [ "${RUN_LAB_HARDWARE_GATES}" = "true" ] || [ "${LESAVKA_CI_PROFILE}" = "lab" ]; then run_gate "bare-metal lab" env LESAVKA_ALLOW_LAB_HARDWARE_TESTS=1 scripts/ci/baremetal_lab_gate.sh fi run_gate "gate glue" scripts/ci/gate_glue_gate.sh run_gate "sonarqube" scripts/ci/sonarqube_gate.sh run_gate "build dist" scripts/ci/build-dist.sh run_gate "supply chain" scripts/ci/supply_chain_gate.sh exit "$overall_rc" ''' } } } stage('Daily Master Gate') { when { expression { return params.LESAVKA_CI_PROFILE == 'daily' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh 'QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" scripts/ci/daily_master_gate.sh' } } } } stage('Style Docs LOC Naming') { when { expression { return params.LESAVKA_CI_PROFILE != 'daily' && params.LESAVKA_CI_PROFILE != 'safe' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh 'QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" scripts/ci/hygiene_gate.sh' } } } } stage('Tests') { when { expression { return params.LESAVKA_CI_PROFILE != 'daily' && params.LESAVKA_CI_PROFILE != 'safe' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh 'QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" scripts/ci/test_gate.sh' } } } } stage('Coverage') { when { expression { return params.LESAVKA_CI_PROFILE != 'daily' && params.LESAVKA_CI_PROFILE != 'safe' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh ''' set -eu if ! cargo llvm-cov --version >/dev/null 2>&1; then cargo install --locked cargo-llvm-cov fi QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" scripts/ci/quality_gate.sh ''' } } } } stage('Performance') { when { expression { return params.LESAVKA_CI_PROFILE != 'daily' && params.LESAVKA_CI_PROFILE != 'safe' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh 'QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" scripts/ci/performance_gate.sh' } } } } stage('Media Reliability') { when { expression { return params.LESAVKA_CI_PROFILE != 'daily' && params.LESAVKA_CI_PROFILE != 'safe' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh 'QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" scripts/ci/media_reliability_gate.sh' } } } } stage('Input Transport (Isolated Opt-In)') { when { expression { return params.RUN_DISRUPTIVE_INPUT_TESTS && params.LESAVKA_CI_PROFILE != 'safe' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh 'QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" LESAVKA_ALLOW_DISRUPTIVE_INPUT_TESTS=1 scripts/ci/input_transport_gate.sh' } } } } stage('Bare-Metal Lab Gates (Opt-In)') { when { expression { return (params.RUN_LAB_HARDWARE_GATES || params.LESAVKA_CI_PROFILE == 'lab') && params.LESAVKA_CI_PROFILE != 'safe' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh 'QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" LESAVKA_ALLOW_LAB_HARDWARE_TESTS=1 scripts/ci/baremetal_lab_gate.sh' } } } } stage('Gate Glue') { when { expression { return params.LESAVKA_CI_PROFILE != 'daily' && params.LESAVKA_CI_PROFILE != 'safe' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh 'QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" scripts/ci/gate_glue_gate.sh' } } } } stage('SonarQube') { when { expression { return params.LESAVKA_CI_PROFILE != 'daily' && params.LESAVKA_CI_PROFILE != 'safe' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh 'QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" scripts/ci/sonarqube_gate.sh' } } } } stage('Build Dist') { when { expression { return params.LESAVKA_CI_PROFILE != 'daily' && params.LESAVKA_CI_PROFILE != 'safe' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh 'scripts/ci/build-dist.sh' } } } } stage('Supply Chain Artifact Security') { when { expression { return params.LESAVKA_CI_PROFILE != 'daily' && params.LESAVKA_CI_PROFILE != 'safe' } } steps { container('rust-ci') { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { sh 'QUALITY_GATE_PUSHGATEWAY_URL="${QUALITY_GATE_PUSHGATEWAY_URL}" scripts/ci/supply_chain_gate.sh' } } } } stage('Docker Login') { when { expression { return params.LESAVKA_CI_PROFILE != 'daily' && params.PUSH_IMAGES } } steps { withCredentials([ usernamePassword( credentialsId: params.REGISTRY_CREDENTIALS_ID, usernameVariable: 'REGISTRY_USER', passwordVariable: 'REGISTRY_PASS' ) ]) { sh 'echo "$REGISTRY_PASS" | docker login "$REGISTRY" -u "$REGISTRY_USER" --password-stdin' } } } stage('Build Images') { when { expression { return params.LESAVKA_CI_PROFILE != 'daily' && params.PUSH_IMAGES } } steps { sh 'PUSH_IMAGES=${PUSH_IMAGES} scripts/ci/build-images.sh' } } } post { always { script { try { archiveArtifacts artifacts: 'dist/**,target/test-gate/**,target/quality-gate/**,target/hygiene-gate/**,target/daily-master-gate/**,target/performance-gate/**,target/media-reliability-gate/**,target/input-transport-gate/**,target/baremetal-lab-gate/**,target/video-downstream-gate/**,target/gate-glue-gate/**,target/sonarqube-gate/**,target/supply-chain-gate/**', fingerprint: true, allowEmptyArchive: true } catch (Throwable err) { echo "archive step unavailable: ${err.class.simpleName}" } } } } }