perf: optimize pipeline with npm cache and parallel stages

This commit is contained in:
soufiane 2025-11-25 15:35:45 +01:00
parent 1fdd0dccf3
commit c4ba5bda9a

94
Jenkinsfile vendored
View File

@ -1,9 +1,7 @@
pipeline {
agent any
// Déclenchement automatique sur push Git
triggers {
// Vérifie les changements toutes les minutes (polling SCM)
pollSCM('* * * * *')
}
@ -18,6 +16,7 @@ pipeline {
environment {
REGISTRY_URL = "registry.wk-archi-o24a-15m-g3.fr"
IMAGE_NAME = "the-tip-top-frontend"
NPM_CACHE = "/var/jenkins_home/npm-cache"
}
stages {
@ -53,33 +52,48 @@ pipeline {
}
}
stage('Tests & Qualité') {
stage('Install Dependencies') {
agent {
docker {
image 'node:20'
args '-u root'
args "-u root -v ${NPM_CACHE}:/root/.npm"
}
}
steps {
echo "🧪 Lancement des tests et analyse du code..."
echo "📦 Installation des dépendances..."
sh 'npm ci --prefer-offline'
stash includes: 'node_modules/**', name: 'node_modules'
}
}
stage('Quality Checks') {
parallel {
stage('Lint & Tests') {
agent {
docker {
image 'node:20'
args "-u root -v ${NPM_CACHE}:/root/.npm"
}
}
steps {
unstash 'node_modules'
echo "🧪 Lancement des tests et lint..."
script {
def lintStatus = sh(script: 'npm ci && npm run lint', returnStatus: true)
def lintStatus = sh(script: 'npm run lint', returnStatus: true)
def testStatus = sh(script: 'npm test', returnStatus: true)
if (lintStatus != 0) {
error "❌ ESLint a échoué - Le déploiement est bloqué"
error "❌ ESLint a échoué"
}
if (testStatus != 0) {
error "❌ Les tests ont échoué - Le déploiement est bloqué"
error "❌ Les tests ont échoué"
}
echo "✅ Tests et lint passés avec succès"
echo "✅ Tests et lint passés"
}
}
}
stage('SonarQube Analysis') {
stage('SonarQube') {
agent {
docker {
image 'sonarsource/sonar-scanner-cli:latest'
@ -94,43 +108,11 @@ pipeline {
-Dsonar.projectKey=Th-Tip-Top-Frontend \
-Dsonar.projectName='Thé Tip Top Frontend' \
-Dsonar.sources=. \
-Dsonar.exclusions=node_modules/**,.next/**,coverage/**,out/** \
-Dsonar.javascript.lcov.reportPaths=coverage/lcov.info
-Dsonar.exclusions=node_modules/**,.next/**,coverage/**,out/**
"""
}
}
}
stage('Build Frontend') {
agent {
docker {
image 'node:20'
args '-u root'
}
}
steps {
echo "⚙️ Build de l'application Next.js..."
script {
// Nettoyer le cache Next.js pour forcer une reconstruction complète
sh 'rm -rf .next node_modules/.cache'
// Next.js peut échouer avec des erreurs SSR mais générer quand même un build fonctionnel
def buildStatus = sh(script: 'npm ci && npm run build', returnStatus: true)
// Vérifier que le build a été généré même si des erreurs SSR sont survenues
def nextExists = sh(script: '[ -d .next ] && echo "true" || echo "false"', returnStdout: true).trim()
if (nextExists == "false") {
error "❌ Le build Next.js a complètement échoué - pas de dossier .next généré"
}
if (buildStatus != 0) {
echo "⚠️ Avertissement: Des erreurs SSR sont survenues mais le build .next a été généré"
echo " Ces erreurs n'affectent pas le fonctionnement en production (pages client-side)"
} else {
echo "✅ Build Next.js réussi sans erreurs"
}
}
}
}
@ -138,11 +120,9 @@ pipeline {
steps {
echo "🐳 Construction de l'image Docker frontend..."
script {
// Charger les variables d'environnement selon l'environnement
def envFile = ".env.${env.ENV}"
def envVars = sh(script: "cat ${envFile} | grep -E '^NEXT_PUBLIC_' | xargs", returnStdout: true).trim()
// Construire les arguments de build
def buildArgs = ""
envVars.split().each { envVar ->
def parts = envVar.split('=', 2)
@ -152,7 +132,7 @@ pipeline {
}
sh """
docker build --no-cache ${buildArgs} -t ${REGISTRY_URL}/${IMAGE_NAME}:${env.TAG} .
docker build ${buildArgs} -t ${REGISTRY_URL}/${IMAGE_NAME}:${env.TAG} .
docker tag ${REGISTRY_URL}/${IMAGE_NAME}:${env.TAG} ${REGISTRY_URL}/${IMAGE_NAME}:latest
"""
}
@ -161,7 +141,7 @@ pipeline {
stage('Push to Registry') {
steps {
echo "📤 Envoi de limage vers le registre Docker..."
echo "📤 Envoi de l'image vers le registre Docker..."
withCredentials([usernamePassword(credentialsId: 'registry-credentials', usernameVariable: 'REG_USER', passwordVariable: 'REG_PASS')]) {
sh """
echo "$REG_PASS" | docker login ${REGISTRY_URL} -u "$REG_USER" --password-stdin
@ -172,22 +152,6 @@ pipeline {
}
}
stage('Backup before deploy') {
steps {
echo "💾 Sauvegarde avant déploiement (${env.ENV})..."
sh '''
BACKUP_DIR="/srv/backups/the-tip-top/${ENV}/$(date +%F_%H-%M-%S)"
mkdir -p $BACKUP_DIR
echo "📦 Sauvegarde du docker-compose et logs..."
cp -r ${DEPLOY_PATH}/docker-compose.yml $BACKUP_DIR/ 2>/dev/null || true
cp -r ${DEPLOY_PATH}/logs $BACKUP_DIR/ 2>/dev/null || true
tar -czf ${BACKUP_DIR}.tar.gz -C $(dirname $BACKUP_DIR) $(basename $BACKUP_DIR)
rm -rf $BACKUP_DIR
echo "✅ Sauvegarde compressée : ${BACKUP_DIR}.tar.gz"
'''
}
}
stage('Deploy') {
steps {
echo "🚀 Déploiement du frontend sur ${env.ENV}..."