import groovy.json.JsonOutput String shellQuote(String value) { return "'" + value.replace("'", "'\"'\"'") + "'" } pipeline { agent any options { timestamps() disableConcurrentBuilds() buildDiscarder(logRotator(numToKeepStr: '30')) } parameters { string(name: 'GIT_REF', defaultValue: 'main', description: 'Git branch, tag, or commit to build.') string(name: 'IMAGE_TAG', defaultValue: '', description: 'Optional Harbor image tag override. Defaults to --.') string(name: 'HARBOR_REGISTRY', defaultValue: '10.2.1.3:18082', description: 'Harbor registry address reachable from the Jenkins agent.') string(name: 'HARBOR_PROJECT', defaultValue: 'likei', description: 'Harbor project name.') string(name: 'HARBOR_CREDENTIALS_ID', defaultValue: 'likei-harbor-robot', description: 'Jenkins username/password credentials id for Harbor.') string(name: 'DOCKER_PLATFORM', defaultValue: 'linux/amd64', description: 'Docker build platform.') } environment { DOCKER_BUILDKIT = '1' } stages { stage('Checkout') { steps { checkout scm script { if (params.GIT_REF?.trim()) { sh """#!/usr/bin/env bash set -euo pipefail git fetch --all --tags --prune git checkout --force ${shellQuote(params.GIT_REF.trim())} """ } } sh 'mkdir -p ci-out' } } stage('Resolve Inputs') { steps { script { def branch = (env.BRANCH_NAME ?: env.GIT_BRANCH ?: 'manual').replaceAll('[^0-9A-Za-z._-]+', '-') env.RESOLVED_GIT_COMMIT = sh(returnStdout: true, script: 'git rev-parse HEAD').trim() env.RESOLVED_GIT_COMMIT_SHORT = sh(returnStdout: true, script: 'git rev-parse --short=12 HEAD').trim() env.RESOLVED_IMAGE_TAG = params.IMAGE_TAG?.trim() ? params.IMAGE_TAG.trim() : "${branch}-${env.RESOLVED_GIT_COMMIT_SHORT}-${env.BUILD_NUMBER}" writeFile( file: 'ci-out/request.json', text: JsonOutput.prettyPrint(JsonOutput.toJson([ repo: 'chatapp3-admin', gitRef: params.GIT_REF?.trim() ?: 'main', commit: env.RESOLVED_GIT_COMMIT, imageTag: env.RESOLVED_IMAGE_TAG, ])) + '\n', ) } } } stage('Login Harbor') { steps { withCredentials([usernamePassword(credentialsId: params.HARBOR_CREDENTIALS_ID, usernameVariable: 'HARBOR_USER', passwordVariable: 'HARBOR_PASS')]) { sh '''#!/usr/bin/env bash set -euo pipefail printf '%s' "$HARBOR_PASS" | docker login "$HARBOR_REGISTRY" -u "$HARBOR_USER" --password-stdin ''' } } } stage('Build And Push') { steps { script { def imageRef = "${params.HARBOR_REGISTRY}/${params.HARBOR_PROJECT}/chatapp3-admin:${env.RESOLVED_IMAGE_TAG}" sh """#!/usr/bin/env bash set -euo pipefail DOCKER_PLATFORM='${params.DOCKER_PLATFORM}' ./ci/build-image.sh '${imageRef}' docker push '${imageRef}' """ def digest = sh(returnStdout: true, script: "docker image inspect '${imageRef}' --format '{{index .RepoDigests 0}}'").trim() def serviceImages = ['chatapp3-admin': digest] writeFile(file: 'ci-out/service-images.json', text: JsonOutput.prettyPrint(JsonOutput.toJson(serviceImages)) + '\n') writeFile( file: 'ci-out/deploy-params.json', text: JsonOutput.prettyPrint(JsonOutput.toJson([ components: ['chatapp3-admin'], ref: env.RESOLVED_GIT_COMMIT, serviceImages: serviceImages, note: 'admin still uses bundle deploy in chatapp3-deploy; this image metadata is reserved for the next Harbor deploy step.', ])) + '\n', ) writeFile( file: 'ci-out/build-metadata.json', text: JsonOutput.prettyPrint(JsonOutput.toJson([ repo: 'chatapp3-admin', gitRef: params.GIT_REF?.trim() ?: 'main', commit: env.RESOLVED_GIT_COMMIT, imageTag: env.RESOLVED_IMAGE_TAG, serviceImages: serviceImages, ])) + '\n', ) } } } } post { always { archiveArtifacts artifacts: 'ci-out/*.json', fingerprint: true, allowEmptyArchive: false } } }