pipeline { parameters { string( name: 'IMAGE_VERSION', defaultValue: '', description: 'Optional override for the Docker image tag (e.g., stable, release, 0.0.2). Leave empty to use the commit hash.' ) string( name: 'GIT_REF', defaultValue: '', description: 'Branch or tag to build. Leave empty to use Jenkins-provided branch or default to main.' ) booleanParam( name: 'CLEAN_BUILD', defaultValue: false, description: 'Run docker build --pull --no-cache when true.' ) } agent any environment { GIT_URL = 'https://gitea.mindboost.team/mindboost/education-flagger.git' HEADER_IMAGE_NAME = 'mindboost/education-flagger-header' UPDATER_IMAGE_NAME = 'mindboost/education-flagger-updater' LOCAL_HEADER_IMAGE_NAME = 'education_flagger_header_image' LOCAL_UPDATER_IMAGE_NAME = 'education_flagger_updater_image' GIT_CREDENTIALS_ID = 'b5f383be-8c74-40f9-b7e1-3a9c5856df0e' REGISTRY_CREDENTIALS_ID = '62d300cc-d8c6-437a-8699-c58b9e1edcb0' REGISTRY_SCHEME = 'https' REGISTRY_HOST = 'gitea.mindboost.team' } stages { stage('Checkout') { steps { script { def selectedRef = params?.GIT_REF?.trim() if (!selectedRef) { selectedRef = env.CHANGE_BRANCH ?: env.BRANCH_NAME ?: env.GIT_BRANCH } if (!selectedRef) { selectedRef = 'main' echo "No GIT_REF supplied. Falling back to 'main'." } def normalizedRef = selectedRef.replaceFirst('^origin/', '') def branchSpec = normalizedRef.startsWith('refs/') ? normalizedRef : "*/${normalizedRef}" echo "Checking out '${branchSpec}' from ${env.GIT_URL}" checkout([ $class: 'GitSCM', branches: [[name: branchSpec]], userRemoteConfigs: [[ url: env.GIT_URL, credentialsId: env.GIT_CREDENTIALS_ID ]] ]) } } } stage('Check Repository') { steps { script { sh 'pwd' sh 'ls -la' sh 'git status' } } } stage('Determine Version') { steps { script { def imageVersion = '' if (params?.IMAGE_VERSION) { imageVersion = params.IMAGE_VERSION.trim() echo "Using build parameter IMAGE_VERSION=${imageVersion}" } if (!imageVersion) { def longSha = sh( script: 'git rev-parse HEAD', returnStdout: true ).trim() imageVersion = "sha256-${longSha}" echo "No IMAGE_VERSION provided. Falling back to commit hash: ${imageVersion}" } def sanitized = imageVersion.replaceAll('[^A-Za-z0-9_.-]', '-') if (sanitized != imageVersion) { echo "Sanitized version value from '${imageVersion}' to '${sanitized}' for Docker tag compatibility." } env.IMAGE_TAG = sanitized echo "Resolved image tag: ${env.IMAGE_TAG}" } } } stage('Get Commit Hash') { steps { script { env.GIT_COMMIT_SHORT = sh( script: 'git rev-parse --short HEAD', returnStdout: true ).trim() echo "Commit Hash: ${env.GIT_COMMIT_SHORT}" } } } stage('Check Docker Images with the same tag') { steps { script { def cleanBuild = params?.CLEAN_BUILD == true def headerImageExists = sh( script: "docker images -q ${env.LOCAL_HEADER_IMAGE_NAME}:${env.IMAGE_TAG} || true", returnStdout: true ).trim() def updaterImageExists = sh( script: "docker images -q ${env.LOCAL_UPDATER_IMAGE_NAME}:${env.IMAGE_TAG} || true", returnStdout: true ).trim() if (cleanBuild) { echo "CLEAN_BUILD=true: ignoring existing local images for tag ${env.IMAGE_TAG}." } else if (headerImageExists && updaterImageExists) { echo "Both Docker images with tag ${env.IMAGE_TAG} already exist locally. Skipping build." currentBuild.result = 'SUCCESS' return } else { echo 'At least one local Docker image is missing. Building fresh images.' } } } } stage('Build Docker Images') { when { expression { currentBuild.result == null } } steps { script { def cleanBuild = params?.CLEAN_BUILD == true def buildFlags = cleanBuild ? '--pull --no-cache ' : '' sh "docker build ${buildFlags}-t ${env.LOCAL_HEADER_IMAGE_NAME}:${env.IMAGE_TAG} ." sh "docker build ${buildFlags}-t ${env.LOCAL_UPDATER_IMAGE_NAME}:${env.IMAGE_TAG} ./asn-updater" } } } stage('Push Docker Images') { when { expression { currentBuild.result == null } } steps { script { withCredentials([ usernamePassword( credentialsId: env.REGISTRY_CREDENTIALS_ID, usernameVariable: 'REGISTRY_USER', passwordVariable: 'REGISTRY_PASS' ) ]) { def registryAuthority = env.REGISTRY_HOST def registryEndpoint = "${env.REGISTRY_SCHEME}://${registryAuthority}" def remoteHeaderImageTag = "${registryAuthority}/${env.HEADER_IMAGE_NAME}:${env.IMAGE_TAG}" def remoteUpdaterImageTag = "${registryAuthority}/${env.UPDATER_IMAGE_NAME}:${env.IMAGE_TAG}" withEnv([ "REGISTRY_AUTHORITY=${registryAuthority}", "REGISTRY_ENDPOINT=${registryEndpoint}", "REMOTE_HEADER_IMAGE_TAG=${remoteHeaderImageTag}", "REMOTE_UPDATER_IMAGE_TAG=${remoteUpdaterImageTag}" ]) { sh ''' set -eux if [ -z "${IMAGE_TAG:-}" ]; then echo "IMAGE_TAG is empty. Did the Determine Version stage run?" >&2 exit 1 fi if [ -z "${REGISTRY_USER:-}" ]; then echo "REGISTRY_USER is empty. Check Jenkins credentials mapping." >&2 exit 1 fi if [ -z "${REGISTRY_PASS:-}" ]; then echo "REGISTRY_PASS is empty. Check Jenkins credentials mapping." >&2 exit 1 fi if [ -z "${REGISTRY_AUTHORITY:-}" ]; then echo "REGISTRY_AUTHORITY is empty. Registry authority not resolved." >&2 exit 1 fi if [ -z "${REGISTRY_ENDPOINT:-}" ]; then echo "REGISTRY_ENDPOINT is empty. Registry endpoint not resolved." >&2 exit 1 fi if [ -z "${REMOTE_HEADER_IMAGE_TAG:-}" ]; then echo "REMOTE_HEADER_IMAGE_TAG is empty. Derived header Docker tag missing." >&2 exit 1 fi if [ -z "${REMOTE_UPDATER_IMAGE_TAG:-}" ]; then echo "REMOTE_UPDATER_IMAGE_TAG is empty. Derived updater Docker tag missing." >&2 exit 1 fi docker --version docker info docker image inspect "$LOCAL_HEADER_IMAGE_NAME:$IMAGE_TAG" >/dev/null docker image inspect "$LOCAL_UPDATER_IMAGE_NAME:$IMAGE_TAG" >/dev/null echo "Logging into Docker registry $REGISTRY_ENDPOINT as $REGISTRY_USER" echo "$REGISTRY_PASS" | docker login "$REGISTRY_ENDPOINT" --username "$REGISTRY_USER" --password-stdin docker tag "$LOCAL_HEADER_IMAGE_NAME:$IMAGE_TAG" "$REMOTE_HEADER_IMAGE_TAG" docker tag "$LOCAL_UPDATER_IMAGE_NAME:$IMAGE_TAG" "$REMOTE_UPDATER_IMAGE_TAG" echo "Pushing Docker image $REMOTE_HEADER_IMAGE_TAG to $REGISTRY_AUTHORITY" docker push "$REMOTE_HEADER_IMAGE_TAG" echo "Pushing Docker image $REMOTE_UPDATER_IMAGE_TAG to $REGISTRY_AUTHORITY" docker push "$REMOTE_UPDATER_IMAGE_TAG" docker logout "$REGISTRY_ENDPOINT" ''' } } } } } stage('Cleanup Docker Images') { when { expression { currentBuild.result == null } } steps { sh ''' set -eux docker image prune -f docker builder prune -f ''' } } } }