ci: split typhon telemetry from image publishing

This commit is contained in:
Brad Stein 2026-05-16 16:06:34 -03:00
parent d0143bfc71
commit 053d7a35e1

278
Jenkinsfile vendored
View File

@ -1,73 +1,17 @@
def isTimerBuild() {
return !currentBuild.getBuildCauses('hudson.triggers.TimerTrigger$TimerTriggerCause').isEmpty()
}
def isScmBuild() {
return !currentBuild.getBuildCauses('hudson.triggers.SCMTrigger$SCMTriggerCause').isEmpty()
}
def shouldPublishImage() {
return params.PUBLISH_IMAGE || (!isTimerBuild() && isScmBuild())
}
pipeline { pipeline {
agent { agent none
kubernetes {
defaultContainer 'node'
yaml """
apiVersion: v1
kind: Pod
spec:
nodeSelector:
kubernetes.io/arch: arm64
node-role.kubernetes.io/worker: "true"
containers:
- name: dind
image: docker:27-dind
securityContext:
privileged: true
env:
- name: DOCKER_TLS_CERTDIR
value: ""
command:
- /bin/sh
- -c
args:
- |
set -eu
exec dockerd-entrypoint.sh --mtu=1400 --host=unix:///var/run/docker.sock --host=tcp://0.0.0.0:2375
volumeMounts:
- name: dind-storage
mountPath: /var/lib/docker
- name: workspace-volume
mountPath: /home/jenkins/agent
- name: docker
image: docker:27
command: ['cat']
tty: true
env:
- name: DOCKER_HOST
value: tcp://localhost:2375
- name: DOCKER_TLS_CERTDIR
value: ""
volumeMounts:
- name: docker-config-writable
mountPath: /root/.docker
- name: docker-config-secret
mountPath: /docker-config
- name: workspace-volume
mountPath: /home/jenkins/agent
- name: node
image: node:22-bookworm
command: ['cat']
tty: true
volumeMounts:
- name: workspace-volume
mountPath: /home/jenkins/agent
volumes:
- name: docker-config-secret
secret:
secretName: harbor-robot-pipeline
items:
- key: .dockerconfigjson
path: config.json
- name: docker-config-writable
emptyDir: {}
- name: dind-storage
emptyDir: {}
- name: workspace-volume
emptyDir: {}
"""
}
}
options { options {
disableConcurrentBuilds() disableConcurrentBuilds()
@ -76,8 +20,8 @@ spec:
parameters { parameters {
booleanParam( booleanParam(
name: 'PUBLISH_IMAGE', name: 'PUBLISH_IMAGE',
defaultValue: true, defaultValue: false,
description: 'Build and push typhon image to Harbor on successful quality gate.' description: 'Build and push typhon image to Harbor; main branch SCM builds also publish automatically.'
) )
} }
@ -88,28 +32,43 @@ spec:
} }
stages { stages {
stage('Checkout') { stage('Quality and metrics') {
steps { agent {
checkout scm kubernetes {
} defaultContainer 'node'
} yaml """
apiVersion: v1
stage('Prep Docker Auth') { kind: Pod
steps { spec:
container('docker') { nodeSelector:
sh ''' kubernetes.io/arch: arm64
set -eu node-role.kubernetes.io/worker: "true"
mkdir -p /root/.docker containers:
cp /docker-config/config.json /root/.docker/config.json - name: node
''' image: node:22-bookworm-slim
command: ['cat']
tty: true
volumeMounts:
- name: workspace-volume
mountPath: /home/jenkins/agent
volumes:
- name: workspace-volume
emptyDir: {}
"""
} }
} }
}
stage('Run quality gate') { stages {
steps { stage('Checkout') {
container('node') { steps {
sh ''' checkout scm
}
}
stage('Run quality gate') {
steps {
container('node') {
sh '''
set -eu set -eu
set +e set +e
bash <<'GATE' bash <<'GATE'
@ -319,14 +278,14 @@ GATE
JSON JSON
fi fi
''' '''
}
}
} }
}
}
stage('Publish test metrics') { stage('Publish test metrics') {
steps { steps {
container('node') { container('node') {
sh ''' sh '''
set -eu set -eu
node <<'NODE' node <<'NODE'
const fs = require('fs'); const fs = require('fs');
@ -440,29 +399,103 @@ try {
} }
NODE NODE
''' '''
}
}
} }
}
}
stage('Enforce quality gate') { stage('Enforce quality gate') {
steps { steps {
container('node') { container('node') {
sh ''' sh '''
set -eu set -eu
test "$(cat build/quality-gate.rc 2>/dev/null || echo 1)" -eq 0 test "$(cat build/quality-gate.rc 2>/dev/null || echo 1)" -eq 0
''' '''
}
}
}
}
post {
always {
archiveArtifacts artifacts: 'build/**,dist/**,coverage/**', allowEmptyArchive: true, fingerprint: true
} }
} }
} }
stage('Buildx setup') { stage('Build & push image') {
when { when {
expression { return params.PUBLISH_IMAGE } expression { return shouldPublishImage() }
}
agent {
kubernetes {
defaultContainer 'docker'
yaml """
apiVersion: v1
kind: Pod
spec:
nodeSelector:
kubernetes.io/arch: arm64
node-role.kubernetes.io/worker: "true"
containers:
- name: dind
image: docker:27-dind
securityContext:
privileged: true
env:
- name: DOCKER_TLS_CERTDIR
value: ""
command:
- /bin/sh
- -c
args:
- |
set -eu
exec dockerd-entrypoint.sh --mtu=1400 --host=unix:///var/run/docker.sock --host=tcp://0.0.0.0:2375
volumeMounts:
- name: dind-storage
mountPath: /var/lib/docker
- name: workspace-volume
mountPath: /home/jenkins/agent
- name: docker
image: docker:27
command: ['cat']
tty: true
env:
- name: DOCKER_HOST
value: tcp://localhost:2375
- name: DOCKER_TLS_CERTDIR
value: ""
volumeMounts:
- name: docker-config-writable
mountPath: /root/.docker
- name: docker-config-secret
mountPath: /docker-config
- name: workspace-volume
mountPath: /home/jenkins/agent
volumes:
- name: docker-config-secret
secret:
secretName: harbor-robot-pipeline
items:
- key: .dockerconfigjson
path: config.json
- name: docker-config-writable
emptyDir: {}
- name: dind-storage
emptyDir: {}
- name: workspace-volume
emptyDir: {}
"""
}
} }
steps { steps {
checkout scm
container('docker') { container('docker') {
sh ''' sh '''
set -eu set -eu
mkdir -p /root/.docker
cp /docker-config/config.json /root/.docker/config.json
seq 1 20 | while read _; do seq 1 20 | while read _; do
docker info >/dev/null 2>&1 && break || sleep 2 docker info >/dev/null 2>&1 && break || sleep 2
done done
@ -470,17 +503,17 @@ NODE
BUILDER_NAME="typhon-${BUILD_NUMBER}" BUILDER_NAME="typhon-${BUILD_NUMBER}"
docker buildx rm "${BUILDER_NAME}" >/dev/null 2>&1 || true docker buildx rm "${BUILDER_NAME}" >/dev/null 2>&1 || true
docker buildx create --name "${BUILDER_NAME}" --driver docker-container --bootstrap --use docker buildx create --name "${BUILDER_NAME}" --driver docker-container --bootstrap --use
'''
}
}
}
stage('Build & push image') { APP_VERSION="$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p' package.json | head -n 1)"
when { SHORT_SHA="$(printf '%s' "${GIT_COMMIT:-nohash}" | cut -c1-8)"
expression { return params.PUBLISH_IMAGE } IMAGE_TAG="${APP_VERSION}-${BUILD_NUMBER}-${SHORT_SHA}"
}
steps { {
container('docker') { echo "IMAGE_REPO=${IMAGE_REPO}"
echo "IMAGE_TAG=${IMAGE_TAG}"
echo "IMAGE_CHANNEL_TAG=main"
} > build/image.env
'''
withCredentials([ withCredentials([
usernamePassword( usernamePassword(
credentialsId: 'harbor-robot', credentialsId: 'harbor-robot',
@ -490,10 +523,7 @@ NODE
]) { ]) {
sh ''' sh '''
set -eu set -eu
. build/version.env . build/image.env
SHORT_SHA="$(printf '%s' "${GIT_COMMIT:-nohash}" | cut -c1-8)"
IMAGE_TAG="${APP_VERSION}-${BUILD_NUMBER}-${SHORT_SHA}"
printf '%s' "${HARBOR_PASSWORD}" | docker login registry.bstein.dev -u "${HARBOR_USERNAME}" --password-stdin printf '%s' "${HARBOR_PASSWORD}" | docker login registry.bstein.dev -u "${HARBOR_USERNAME}" --password-stdin
docker buildx build --platform linux/arm64 \ docker buildx build --platform linux/arm64 \
@ -501,22 +531,10 @@ NODE
--tag "${IMAGE_REPO}:${IMAGE_TAG}" \ --tag "${IMAGE_REPO}:${IMAGE_TAG}" \
--tag "${IMAGE_REPO}:main" \ --tag "${IMAGE_REPO}:main" \
--push . --push .
{
echo "IMAGE_REPO=${IMAGE_REPO}"
echo "IMAGE_TAG=${IMAGE_TAG}"
echo "IMAGE_CHANNEL_TAG=main"
} > build/image.env
''' '''
} }
} }
} }
} }
} }
post {
always {
archiveArtifacts artifacts: 'build/**,dist/**,coverage/**', allowEmptyArchive: true, fingerprint: true
}
}
} }