#!/usr/bin/env groovy def PROTECTED_BRANCH def BRANCH_ENV = [ test: 'test', master: 'production', beta: 'production' ] node { stage('Setup') { env.FRONT_REPLICAS = 1 env.NODE_ENV = BRANCH_ENV[env.BRANCH_NAME] ?: 'dev' PROTECTED_BRANCH = [ 'dev', 'test', 'master', 'beta' ].contains(env.BRANCH_NAME) // https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables echo "NODE_NAME: ${env.NODE_NAME}" echo "WORKSPACE: ${env.WORKSPACE}" configFileProvider([ configFile(fileId: 'salix-front.properties', variable: 'PROPS_FILE') ]) { def props = readProperties file: PROPS_FILE props.each {key, value -> env."${key}" = value } props.each {key, value -> echo "${key}: ${value}" } } if (PROTECTED_BRANCH) { configFileProvider([ configFile(fileId: "salix-front.branch.${env.BRANCH_NAME}", variable: 'BRANCH_PROPS_FILE') ]) { def props = readProperties file: BRANCH_PROPS_FILE props.each {key, value -> env."${key}" = value } props.each {key, value -> echo "${key}: ${value}" } } } } } pipeline { agent any options { disableConcurrentBuilds() } tools { nodejs 'node-v18' } environment { PROJECT_NAME = 'lilium' } stages { stage('Install') { environment { NODE_ENV = "" } steps { sh 'pnpm install --prefer-offline' } } // stage('Test: Unit') { // when { // expression { !PROTECTED_BRANCH } // } // environment { // NODE_ENV = "" // } // steps { // sh 'pnpm run test:unit:ci' // } // post { // always { // junit( // testResults: 'junitresults.xml', // allowEmptyResults: true // ) // } // } // } stage('Test: E2E') { when { expression { !PROTECTED_BRANCH } } environment { NODE_ENV = "" CREDENTIALS = credentials('docker-registry') } stages { stage('Setup') { steps { script { def packageJson = readJSON file: 'package.json' env.VERSION = "${packageJson.version}-build${env.BUILD_ID}" env.NETWORK = "${PROJECT_NAME}-${env.BRANCH_NAME}-${env.BUILD_ID}" cleanDockerE2E() sh "pnpm exec cypress install" sh "docker build -t cypress-setup:latest -f ./test/cypress/Dockerfile ." // sh "docker network create ${env.NETWORK} || true" } } } stage('Run') { steps { script { sh "docker-compose -p ${env.NETWORK} -f docker-compose.e2e.yml up -d back" sh "docker-compose -p ${env.NETWORK} -f docker-compose.e2e.yml up -d front" sh "docker-compose -p ${env.NETWORK} -f docker-compose.e2e.yml up e2e" checkErrors(folderName) } } } } post { always { cleanDockerE2E() } } } stage('Build') { when { expression { PROTECTED_BRANCH } } environment { CREDENTIALS = credentials('docker-registry') } steps { sh 'quasar build' script { def packageJson = readJSON file: 'package.json' env.VERSION = "${packageJson.version}-build${env.BUILD_ID}" } dockerBuild() } } stage('Deploy') { when { expression { PROTECTED_BRANCH } } steps { script { def packageJson = readJSON file: 'package.json' env.VERSION = "${packageJson.version}-build${env.BUILD_ID}" } withKubeConfig([ serverUrl: "$KUBERNETES_API", credentialsId: 'kubernetes', namespace: 'lilium' ]) { sh 'kubectl set image deployment/lilium-$BRANCH_NAME lilium-$BRANCH_NAME=$REGISTRY/salix-frontend:$VERSION' } } } } } def cleanDockerE2E() { script { def projectBranch = "${PROJECT_NAME}-${env.BRANCH_NAME}".toLowerCase() // STOP AND REMOVE sh """ docker ps -a --filter 'name=^${projectBranch}' | awk 'NR>1 {print \"\$1\"}' | xargs -r -I {} sh -c 'docker stop {} && docker rm -v {}' || true """ sh """ docker network ls --filter 'name=^${projectBranch}' | awk 'NR>1 {print \"\$1\"}' | xargs -r docker network rm || true """ } } // def runTestsInParallel(int numParallelGroups) { // def folders = sh(script: "ls -d test/cypress/integration/*/ || echo ''", returnStdout: true).trim().split('\n').findAll { it } // if (folders.isEmpty()) { // echo "No se encontraron carpetas de pruebas." // return // } // // Divide las carpetas en grupos para paralelizar // def groupSize = Math.ceil((folders.size() as double) / numParallelGroups).toInteger() // def groups = folders.collate(groupSize) // def tasks = [:] // groups.eachWithIndex { group, index -> // tasks["parallel_group_${index + 1}"] = { // stage("Parallel Group ${index + 1}") { // script { // group.each { testFolder -> // def folderName = testFolder.replaceAll('test/cypress/integration/', '').replaceAll('/', '') // folderName = folderName.replaceAll('[^a-zA-Z0-9_-]', '') // SanitizaciĆ³n de nombres // stage("Run ${folderName}") { // try { // env.CYPRESS_SPEC = "test/cypress/integration/${folderName}/**/*.spec.js" // sh "docker-compose -p ${env.NETWORK}_${folderName} -f docker-compose.e2e.yml up -d back" // sh "docker-compose -p ${env.NETWORK}_${folderName} -f docker-compose.e2e.yml up -d front" // sh "CYPRESS_SPEC=test/cypress/integration/${folderName}/**/*.spec.js docker-compose -p ${env.NETWORK}_${folderName} -f docker-compose.e2e.yml up e2e" // checkErrors(folderName) // } catch (Exception e) { // echo "Error en la ejecuciĆ³n de ${folderName}: ${e.message}" // currentBuild.result = 'UNSTABLE' // } finally { // sh "docker-compose -p ${env.NETWORK}_${folderName} -f docker-compose.e2e.yml down || true" // } // } // } // } // } // } // } // parallel tasks // } def checkErrors(String folderName){ def containerId = sh(script: "docker-compose -p ${env.NETWORK}_${folderName} -f docker-compose.e2e.yml ps -q e2e", returnStdout: true).trim() if (containerId) { def exitCode = sh(script: "docker inspect -f '{{.State.ExitCode}}' ${containerId}", returnStdout: true).trim() // sh "sudo docker cp ${containerId}:/app/test/cypress/reports ./test/cypress/" if (exitCode != '0') { def logs = sh(script: "docker logs ${containerId}", returnStdout: true).trim() error("Cypress E2E tests failed with exit code: ${exitCode}\nLogs:\n${logs}") } } else { error("The Docker container for E2E tests could not be created") } }