diff --git a/jf b/jf new file mode 100644 index 0000000..1706c94 --- /dev/null +++ b/jf @@ -0,0 +1,319 @@ +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" + // ) + } + } + } +} \ No newline at end of file