pipeline { agent any environment { NODEJS_HOME = "${tool 'NodeJS'}" PATH = "${env.NODEJS_HOME}/bin:${env.PATH}" DOCKER_REGISTRY = "nexus.foodgame.fr:8123" IMAGE_NAME = "fatboar_repo/workflow_jenkins_1" IMAGE_TAG = "latest" } stages { // 1. Déterminer l'environnement en fonction de la branche stage('Select Environment') { steps { script { if (env.BRANCH_NAME == 'feature') { env.ENV = 'dev' env.COMPOSE_FILE = 'docker-compose.dev.yml' env.URL = "dev.foodgame.fr" env.BACKUP_CONTAINER = "mongodb-backup-dev" } else if (env.BRANCH_NAME == 'dev') { env.ENV = 'preprod' env.COMPOSE_FILE = 'docker-compose.preprod.yml' env.URL = "preprod.foodgame.fr" env.BACKUP_CONTAINER = "mongodb-backup-preprod" } else if (env.BRANCH_NAME == 'master') { env.ENV = 'prod' env.COMPOSE_FILE = 'docker-compose.prod.yml' env.URL = "fatboar.foodgame.fr" env.BACKUP_CONTAINER = "mongodb-backup-prod" } else { error "Branche non gérée : ${env.BRANCH_NAME}" } echo "Déploiement sur l'environnement ${env.ENV} (${env.URL})" } } } // 2. Installation des dépendances et tests unitaires Angular // stage('Unit Tests') { // agent { // docker { // image 'cypress/browsers:node14.17.0-chrome91-ff89' // args '-u root:root --shm-size=2g' // } // } // environment { // CHROME_BIN = '/usr/bin/google-chrome' // NODE_OPTIONS = '--max-old-space-size=4096' // DISPLAY = ':99' // } // steps { // dir('angular-client') { // sh ''' // echo "🔧 Configuration de l'environnement" // export DISPLAY=:99 // Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & // echo "✅ Installation des dépendances" // npm install --legacy-peer-deps // echo "🧪 Vérification de Chrome" // google-chrome --version // echo "🚀 Lancement des tests unitaires avec couverture" // npx ng test --no-watch --no-progress --browsers=ChromeHeadlessCI --code-coverage // ''' // } // } // post { // always { // // Publier le rapport de couverture HTML // publishHTML([ // allowMissing: false, // alwaysLinkToLastBuild: false, // keepAll: true, // reportDir: 'angular-client/coverage/fatboar-burger', // reportFiles: 'index.html', // reportName: 'Code Coverage Report', // reportTitles: 'Coverage Report' // ]) // // Archiver les artefacts de couverture // archiveArtifacts artifacts: 'angular-client/coverage/**/*', fingerprint: true // } // failure { // echo '❌ Tests échoués - Vérifiez les logs ci-dessus' // } // success { // echo '✅ Tests réussis avec couverture générée' // } // } // } // 3. Analyse SonarQube pour la qualité du code // stage('SonarQube Analysis') { // steps { // script { // def scannerHome = tool name: 'SonarQube Scanner', type: 'hudson.plugins.sonar.SonarRunnerInstallation' // withSonarQubeEnv('SonarQube') { // sh """ // ${scannerHome}/bin/sonar-scanner \ // -Dsonar.projectKey=FatboarProject-${env.BRANCH_NAME} \ // -Dsonar.sources=. \ // -Dsonar.host.url=https://sonarqube.foodgame.fr \ // -Dsonar.login=sqa_9ec3588a80a0b8458d9273dbb6eb7f6ae91b446a // """ // } // } // } // } // 4. Arrêt et nettoyage des anciens conteneurs // stage('Stop & Clean Containers') { // steps { // sh """ // docker-compose -f ${env.COMPOSE_FILE} down || true // docker system prune -f // """ // } // } // 5. Build et déploiement des services // stage('Build & Deploy') { // steps { // sh """ // docker-compose -f ${env.COMPOSE_FILE} build --no-cache // docker-compose -f ${env.COMPOSE_FILE} up -d --force-recreate --remove-orphans // """ // } // } // 6. Lancement des backups après déploiement // 6. Lancement des backups après déploiement stage('Backup') { steps { script { echo "🚀 Lancement du backup sur le container ${env.BACKUP_CONTAINER}" try { // Vérifier que le conteneur backup existe def containerExists = sh( script: "docker ps -a --filter name=${env.BACKUP_CONTAINER} --format '{{.Names}}'", returnStdout: true ).trim() if (!containerExists) { echo "⚠️ Container ${env.BACKUP_CONTAINER} n'existe pas, lancement du service..." sh "docker-compose -f ${env.COMPOSE_FILE} up -d mongodb-backup-${env.ENV}" sleep(30) // Attendre que le service soit prêt } // Vérifier que le conteneur est en cours d'exécution def containerStatus = sh( script: "docker ps --filter name=${env.BACKUP_CONTAINER} --format '{{.Status}}'", returnStdout: true ).trim() if (containerStatus.contains('Up')) { echo "✅ Container ${env.BACKUP_CONTAINER} est actif" // Attendre un peu que MongoDB soit prêt si le conteneur vient d'être démarré echo "⏳ Vérification de la connectivité MongoDB..." sleep(10) // Déclencher le backup manuel avec tiredofit/mongodb-backup echo "💾 Déclenchement du backup manuel..." def backupExitCode = sh( script: "docker exec ${env.BACKUP_CONTAINER} /usr/sbin/backup-now", returnStatus: true ) if (backupExitCode == 0) { // Vérifier les fichiers de backup créés def backupFiles = sh( script: "docker exec ${env.BACKUP_CONTAINER} find /backup -name '*.gz' -type f -mtime -1 | head -5", returnStdout: true ).trim() if (backupFiles) { echo "✅ Backup ${env.ENV.toUpperCase()} réussi !" echo "📁 Fichiers de backup récents :" backupFiles.split('\n').each { file -> if (file.trim()) { def fileInfo = sh( script: "docker exec ${env.BACKUP_CONTAINER} ls -lh '${file.trim()}'", returnStdout: true ).trim() echo " ${fileInfo}" } } } else { echo "⚠️ Aucun fichier de backup récent trouvé" } } else { echo "❌ Le processus de backup a retourné un code d'erreur : ${backupExitCode}" // Afficher les logs pour diagnostic def containerLogs = sh( script: "docker logs --tail 20 ${env.BACKUP_CONTAINER} 2>&1 || echo 'Impossible de récupérer les logs'", returnStdout: true ) echo "📋 Logs du conteneur backup :" echo "${containerLogs}" // Marquer comme unstable mais ne pas faire échouer le pipeline currentBuild.result = 'UNSTABLE' echo "⚠️ Backup échoué mais le déploiement continue" } } else { echo "❌ Container ${env.BACKUP_CONTAINER} n'est pas actif" echo "🔄 Tentative de redémarrage du service..." sh """ docker-compose -f ${env.COMPOSE_FILE} restart mongodb-backup-${env.ENV} || true sleep 30 """ // Nouvelle tentative après redémarrage def retryExitCode = sh( script: "docker exec ${env.BACKUP_CONTAINER} /usr/sbin/backup-now", returnStatus: true ) if (retryExitCode == 0) { echo "✅ Backup ${env.ENV.toUpperCase()} réussi après redémarrage" } else { echo "❌ Backup ${env.ENV.toUpperCase()} échoué même après redémarrage" currentBuild.result = 'UNSTABLE' } } } catch (Exception e) { echo "❌ Erreur lors du backup: ${e.getMessage()}" echo "⚠️ Le backup a échoué mais le déploiement continue" currentBuild.result = 'UNSTABLE' } } } } // 7. Push optionnel de l'image dans le registre Nexus // stage('Push to Private Registry') { // when { // anyOf { // branch 'dev' // branch 'master' // } // } // steps { // script { // docker.withRegistry("https://${DOCKER_REGISTRY}", 'nexus') { // sh """ // docker pull ${IMAGE_NAME}:${IMAGE_TAG} || true // docker tag ${IMAGE_NAME}:${IMAGE_TAG} ${DOCKER_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG} // docker push ${DOCKER_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG} // """ // } // } // } // } } post { success { echo "✅ Déploiement réussi sur ${env.ENV} !" } failure { echo "❌ Échec du pipeline sur ${env.ENV}." } } } // pipeline { // agent any // environment { // NODEJS_HOME = "${tool 'NodeJS'}" // PATH = "${env.NODEJS_HOME}/bin:${env.PATH}" // DEV_URL = "dev.foodgame.fr" // dev_URL = "dev.foodgame.fr" // PROD_URL = "prod.foodgame.fr" // } // stages { // stage('Setup Environment') { // steps { // script { // echo "Environnement détecté : ${env.BRANCH_NAME}" // if (env.BRANCH_NAME == 'test') { // echo "Déploiement sur DEV (${DEV_URL})" // } else if (env.BRANCH_NAME == 'dev') { // echo "Déploiement sur dev (${dev_URL})" // } else if (env.BRANCH_NAME == 'master') { // echo "Déploiement sur PROD (${PROD_URL})" // } else { // error "Branche non prise en charge : ${env.BRANCH_NAME}" // } // } // sh 'npm --version' // } // } // stage('Checkout Code') { // steps { // deleteDir() // checkout scm // } // } // stage('Stop Containers') { // steps { // sh ''' // docker ps | grep "workflow_" -v | awk -F " " '{ if(NR>1) print $1}' | xargs docker kill || true // docker system prune -f // ''' // } // } // stage('Build & Deploy') { // steps { // sh ''' // docker-compose stop // docker-compose build // docker-compose up -d // ''' // } // } // // stage('Push Docker Image (Nexus)') { // // when { // // branch 'master' // // } // // steps { // // withDockerRegistry([credentialsId: 'nexus', url: 'https://nexus.foodgame.fr']) { // // script { // // def dockerImageName = 'workflow_jenkins_1' // // def dockerImageTag = 'latest' // // def nexusRepository = 'fatboar_repo' // // sh """ // // docker tag ${dockerImageName}:${dockerImageTag} ${nexusRepository}/${dockerImageName}:${dockerImageTag} // // docker push ${nexusRepository}/${dockerImageName}:${dockerImageTag} // // """ // // } // // } // // } // // } // stage('Docker Registry Login, Pull, and Push') { // when { // branch 'dev' // } // steps { // script { // def registryUrl = 'nexus.foodgame.fr:8123' // def imageName = 'grafana/tns-db' // def imageVersion = 'latest' // docker.withRegistry("https://${registryUrl}", 'nexus') { // try { // Try pulling the image from the registry // echo "Trying to pull image: ${registryUrl}/${imageName}:${imageVersion}" // docker.image("${registryUrl}/${imageName}:${imageVersion}").pull() // } catch (Exception e) { // echo "Image pull failed. Attempting to build and push." // Pull base image from Docker Hub // echo "Pulling base image: ${imageName}:${imageVersion}" // sh "docker pull ${imageName}:${imageVersion}" // Tag the image for the private registry // echo "Tagging image for private registry" // sh "docker tag ${imageName}:${imageVersion} ${registryUrl}/${imageName}:${imageVersion}" // Push the tagged image to the private registry // echo "Pushing image to private registry" // sh "docker push ${registryUrl}/${imageName}:${imageVersion}" // } // } // } // } // } // stage('Cleanup') { // steps { // echo "Nettoyage terminé pour la branche ${env.BRANCH_NAME}" // } // } // stage('Fin du Pipeline') { // steps { // sh 'echo "Félicitations, le pipeline s\'est terminé avec succès !"' // } // } // } // post { // success { // echo "Pipeline exécuté avec succès pour la branche ${env.BRANCH_NAME}." // } // failure { // echo "Échec du pipeline pour la branche ${env.BRANCH_NAME}." // } // } // } // // node{ // // env.NODEJS_HOME = "${tool 'NodeJS'}" // // // on linux / mac // // env.PATH="${env.NODEJS_HOME}/bin:${env.PATH}" // // // on windows // // //env.PATH="${env.NODEJS_HOME};${env.PATH}" // // sh 'npm --version' // // stage('checkout') // // { // // deleteDir() // // checkout scm // // } // // stage('Stop Containers') // // { // // sh 'docker ps | grep "workflow_" -v | awk -F " " \'{ if(NR>1) print $1}\' |xargs docker kill |xargs docker rm || true' // // sh 'docker system prune -f' // // } // // // stage("Push dev images to nexus") // // // { // // // docker.withRegistry('http://localhost:8083','885ef60c-9352-489a-bd1c-e4b695747c21') // // // { // // // imageApache.push('latest') // // // imageExpress.push('latest') // // // }*/ // // // } // // // stage('SonarQube analysis') // // // { // // // def scannerHome = tool name: 'SonarQube Scanner', type: 'hudson.plugins.sonar.SonarRunnerInstallation'; // // // withSonarQubeEnv('SonarQube') // // // { // // // // If you have configured more than one global server connection, you can specify its name // // // sh "${scannerHome}/bin/sonar-scanner \ // // // -Dsonar.projectKey=FatboarProject \ // // // -Dsonar.sources=. \ // // // -Dsonar.host.url=https://sonarqube.foodgame.fr \ // // // -Dsonar.login=sqp_09ee9072c917af8212864baf0f75c950afc14c64" // // // } // // // } // // stage('Build Docker MEAN Stack(Test Deployment)') // // { // // sh 'docker-compose -v' // // sh 'docker-compose build' // // sh 'docker-compose up -d' // // } // // stage('Fin du Pipeline') // // { // // sh 'echo "Félicitation tout c\'est bien déroulé!"' // // } // // }