pipeline { agent any // === BACKEND SERVICE CONFIGURATION === parameters { string(name: 'HARBOR_REGISTRY', defaultValue: 'harbor.example.com', description: 'Harbor registry URL') string(name: 'HARBOR_PROJECT', defaultValue: 'inventory', description: 'Harbor project name') string(name: 'IMAGE_NAME', defaultValue: 'backend', description: 'Image name') string(name: 'GIT_BRANCH', defaultValue: 'main', description: 'Git branch to build') string(name: 'ENVIRONMENT', defaultValue: 'prod', description: 'Target environment (dev/staging/prod)') booleanParam(name: 'SKIP_TESTS', defaultValue: false, description: 'Skip test execution') booleanParam(name: 'AUTO_DEPLOY', defaultValue: true, description: 'Auto-sync ArgoCD after push') } environment { // Service-specific paths SERVICE_NAME = 'backend-service' SERVICE_DIR = "${WORKSPACE}/${SERVICE_NAME}" // Image configuration IMAGE_FULL_NAME = "${params.HARBOR_REGISTRY}/${params.HARBOR_PROJECT}/${params.IMAGE_NAME}" IMAGE_TAG = "${params.GIT_BRANCH}-${env.BUILD_NUMBER}-${env.GIT_COMMIT?.take(7) ?: 'latest'}" // K8s manifests K8S_MANIFESTS_DIR = "${WORKSPACE}/k8s-manifests" KUSTOMIZE_DIR = "${K8S_MANIFESTS_DIR}/overlays/${params.ENVIRONMENT}" // Credentials HARBOR_CREDENTIALS = credentials('harbor-credentials') ARGOCD_CREDENTIALS = credentials('argocd-credentials') // ArgoCD ARGOCD_SERVER = 'argocd.example.com' ARGOCD_APP_NAME = 'inventory-app' } stages { // === STAGE 1: CHECKOUT CODE === stage('Checkout') { steps { script { echo "๐Ÿ”„ Cloning repository for Backend Service..." checkout scm env.GIT_COMMIT = sh(returnStdout: true, script: 'git rev-parse HEAD').trim() env.GIT_AUTHOR = sh(returnStdout: true, script: 'git log -1 --pretty=format:%an').trim() echo """ โœ… Checkout completed ๐Ÿ“ฆ Service: ${SERVICE_NAME} ๐Ÿ”– Commit: ${env.GIT_COMMIT} ๐Ÿ‘ค Author: ${env.GIT_AUTHOR} ๐ŸŒฟ Branch: ${params.GIT_BRANCH} """ } } } // === STAGE 2: RUN TESTS === stage('Test Backend') { when { expression { return !params.SKIP_TESTS } } steps { dir(SERVICE_DIR) { script { echo "๐Ÿงช Running backend tests..." // Install dependencies sh 'npm ci' // Run tests with coverage sh 'npm test' // Optional: Publish test results // junit 'coverage/junit.xml' // publishHTML(target: [ // reportDir: 'coverage', // reportFiles: 'index.html', // reportName: 'Test Coverage Report' // ]) echo "โœ… Backend tests passed" } } } } // === STAGE 3: CODE QUALITY (OPTIONAL) === // Uncomment to enable SonarQube scanning // stage('SonarQube Analysis') { // steps { // dir(SERVICE_DIR) { // script { // echo "๐Ÿ” Running SonarQube analysis..." // withSonarQubeEnv('SonarQube') { // sh 'sonar-scanner' // } // } // } // } // } // === STAGE 4: BUILD DOCKER IMAGE === stage('Build Image') { steps { dir(SERVICE_DIR) { script { echo "๐Ÿณ Building Docker image for backend..." sh """ docker build \ -t ${IMAGE_FULL_NAME}:${IMAGE_TAG} \ -t ${IMAGE_FULL_NAME}:${params.GIT_BRANCH}-latest \ --label "git.commit=${env.GIT_COMMIT}" \ --label "build.number=${env.BUILD_NUMBER}" \ --label "service=${SERVICE_NAME}" \ . """ echo """ โœ… Image built successfully ๐Ÿท๏ธ ${IMAGE_FULL_NAME}:${IMAGE_TAG} ๐Ÿท๏ธ ${IMAGE_FULL_NAME}:${params.GIT_BRANCH}-latest """ } } } } // === STAGE 5: SECURITY SCAN (OPTIONAL) === // Uncomment to enable Trivy security scanning // stage('Security Scan') { // steps { // script { // echo "๐Ÿ”’ Scanning image for vulnerabilities..." // sh """ // trivy image \ // --severity HIGH,CRITICAL \ // --exit-code 0 \ // ${IMAGE_FULL_NAME}:${IMAGE_TAG} // """ // echo "โœ… Security scan completed" // } // } // } // === STAGE 6: PUSH TO HARBOR === stage('Push to Harbor') { steps { script { echo "๐Ÿ“ฆ Pushing backend image to Harbor..." // Login to Harbor sh """ echo ${HARBOR_CREDENTIALS_PSW} | docker login ${params.HARBOR_REGISTRY} \ -u ${HARBOR_CREDENTIALS_USR} \ --password-stdin """ // Push images sh """ docker push ${IMAGE_FULL_NAME}:${IMAGE_TAG} docker push ${IMAGE_FULL_NAME}:${params.GIT_BRANCH}-latest """ // Logout sh "docker logout ${params.HARBOR_REGISTRY}" echo """ โœ… Images pushed to Harbor ๐Ÿ“ฆ ${IMAGE_FULL_NAME}:${IMAGE_TAG} ๐Ÿ“ฆ ${IMAGE_FULL_NAME}:${params.GIT_BRANCH}-latest """ } } } // === STAGE 7: UPDATE K8S MANIFESTS (GITOPS) === stage('Update Manifests') { steps { script { echo "๐Ÿ“ Updating Kubernetes manifests..." dir(KUSTOMIZE_DIR) { // Install kustomize if not available sh ''' if ! command -v kustomize &> /dev/null; then curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash sudo mv kustomize /usr/local/bin/ fi ''' // Update image tag using kustomize sh """ kustomize edit set image \ gitea.example.com/inventory/backend=${IMAGE_FULL_NAME}:${IMAGE_TAG} """ echo "๐Ÿ“„ Updated kustomization.yaml:" sh "cat kustomization.yaml" } // Commit and push changes sh """ cd ${K8S_MANIFESTS_DIR} git config user.email "jenkins@example.com" git config user.name "Jenkins Backend Pipeline" git add overlays/${params.ENVIRONMENT}/kustomization.yaml git commit -m "chore(backend): update image to ${IMAGE_TAG} Build: ${env.BUILD_NUMBER} Commit: ${env.GIT_COMMIT} Branch: ${params.GIT_BRANCH} Environment: ${params.ENVIRONMENT} Co-Authored-By: ${env.GIT_AUTHOR}" || echo "No changes to commit" git push origin ${params.GIT_BRANCH} """ echo "โœ… Manifests updated and pushed to Git" } } } // === STAGE 8: DEPLOY WITH ARGOCD === stage('Deploy') { when { expression { return params.AUTO_DEPLOY } } steps { script { echo "๐Ÿš€ Triggering ArgoCD sync..." // Install ArgoCD CLI if needed sh ''' if ! command -v argocd &> /dev/null; then curl -sSL -o /tmp/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64 chmod +x /tmp/argocd ARGOCD_CMD=/tmp/argocd else ARGOCD_CMD=argocd fi ''' // Login and sync sh """ ARGOCD_CMD=\$(command -v argocd || echo /tmp/argocd) \$ARGOCD_CMD login ${ARGOCD_SERVER} \ --username ${ARGOCD_CREDENTIALS_USR} \ --password ${ARGOCD_CREDENTIALS_PSW} \ --insecure \$ARGOCD_CMD app sync ${ARGOCD_APP_NAME} \ --prune \ --timeout 300 \$ARGOCD_CMD app wait ${ARGOCD_APP_NAME} \ --health \ --timeout 300 """ echo "โœ… Backend service deployed successfully" } } } } // === POST ACTIONS === post { always { script { echo "๐Ÿงน Cleaning up..." sh """ docker rmi ${IMAGE_FULL_NAME}:${IMAGE_TAG} || true docker rmi ${IMAGE_FULL_NAME}:${params.GIT_BRANCH}-latest || true """ } } success { script { echo """ โœ… ======================================== BACKEND BUILD SUCCESSFUL ======================================== ๐Ÿ“ฆ Service: ${SERVICE_NAME} ๐Ÿท๏ธ Image: ${IMAGE_FULL_NAME}:${IMAGE_TAG} ๐Ÿ”– Commit: ${env.GIT_COMMIT} ๐Ÿ”ข Build: ${env.BUILD_NUMBER} ๐ŸŒ Environment: ${params.ENVIRONMENT} ======================================== """ // Optional: Send notification // slackSend( // color: 'good', // message: "โœ… Backend build ${env.BUILD_NUMBER} succeeded\nImage: ${IMAGE_TAG}" // ) } } failure { script { echo """ BACKEND BUILD FAILED """ // Optional: Send notification // slackSend( // color: 'danger', // message: "โŒ Backend build ${env.BUILD_NUMBER} failed" // ) } } } }