pipeline { agent none options { timestamps() } parameters { string( name: 'JENKINS_BASE_URL', defaultValue: 'https://openbokeron.org/jenkins', description: 'Base URL del Jenkins objetivo' ) string( name: 'JENKINS_JOB_NAME', defaultValue: 'TallerCiCd', description: 'Nombre del job que se consulta en Jenkins' ) string( name: 'VITE_API_BASE', defaultValue: '/taller/api', description: 'Base path/API para el frontend (build time)' ) } environment { NODE_OPTIONS = '--max_old_space_size=2048' APP_VERSION = "1.0.${BUILD_NUMBER}" DOCKER_BUILDKIT = '1' JENKINS_BASE_URL = "${params.JENKINS_BASE_URL}" JENKINS_JOB_NAME = "${params.JENKINS_JOB_NAME}" VITE_API_BASE = "${params.VITE_API_BASE}" PYTHONDONTWRITEBYTECODE = 1 } stages { /* ========================= TESTS ========================= */ stage('Backend: test (main)') { agent { docker { image 'python:3.11-slim' args '-u root' } } steps { dir('backend') { sh ''' set -e python -m venv .venv . .venv/bin/activate pip install --upgrade pip pip install -r requirements-dev.txt pytest ''' } } } /* ========================= DOCKER BUILD ========================= */ stage('Docker: build images') { agent any steps { script { env.COMMIT_SHORT = sh( script: "git rev-parse --short HEAD", returnStdout: true ).trim() env.COMMIT_AUTHOR = sh( script: "git show -s --format=%an HEAD", returnStdout: true ).trim() } sh ''' set -e OLD_BACKEND_LATEST_ID=$(docker images -q cafeteria-backend:latest || true) OLD_BACKEND_PREVIOUS_ID=$(docker images -q cafeteria-backend:previous || true) OLD_FRONTEND_LATEST_ID=$(docker images -q cafeteria-frontend:latest || true) OLD_FRONTEND_PREVIOUS_ID=$(docker images -q cafeteria-frontend:previous || true) docker build \ --build-arg APP_VERSION=${APP_VERSION} \ --build-arg GIT_COMMIT=${COMMIT_SHORT} \ --build-arg COMMIT_AUTHOR="${COMMIT_AUTHOR}" \ --build-arg BUILD_NUMBER=${BUILD_NUMBER} \ -t cafeteria-backend:latest \ ./backend docker build \ --build-arg VITE_API_BASE=${VITE_API_BASE} \ -t cafeteria-frontend:latest \ ./frontend NEW_BACKEND_LATEST_ID=$(docker images -q cafeteria-backend:latest || true) NEW_FRONTEND_LATEST_ID=$(docker images -q cafeteria-frontend:latest || true) if [ -n "$OLD_BACKEND_LATEST_ID" ]; then docker tag "$OLD_BACKEND_LATEST_ID" cafeteria-backend:previous fi if [ -n "$OLD_FRONTEND_LATEST_ID" ]; then docker tag "$OLD_FRONTEND_LATEST_ID" cafeteria-frontend:previous fi if [ -n "$OLD_BACKEND_PREVIOUS_ID" ] && \ [ "$OLD_BACKEND_PREVIOUS_ID" != "$OLD_BACKEND_LATEST_ID" ] && \ [ "$OLD_BACKEND_PREVIOUS_ID" != "$NEW_BACKEND_LATEST_ID" ]; then docker rmi "$OLD_BACKEND_PREVIOUS_ID" || true fi if [ -n "$OLD_FRONTEND_PREVIOUS_ID" ] && \ [ "$OLD_FRONTEND_PREVIOUS_ID" != "$OLD_FRONTEND_LATEST_ID" ] && \ [ "$OLD_FRONTEND_PREVIOUS_ID" != "$NEW_FRONTEND_LATEST_ID" ]; then docker rmi "$OLD_FRONTEND_PREVIOUS_ID" || true fi cleanup_tags() { repo="$1" docker images --format "{{.Repository}}:{{.Tag}}" \ | awk -v repo="$repo" '$0 ~ "^"repo":" && $0 !~ /:latest$|:previous$/' \ | xargs -r docker rmi || true } cleanup_tags cafeteria-backend cleanup_tags cafeteria-frontend ''' } } /* ========================= DEPLOY ========================= */ stage('Deploy (docker compose)') { agent any steps { withCredentials([ usernamePassword( credentialsId: 'jenkins-api-token', usernameVariable: 'JENKINS_USER', passwordVariable: 'JENKINS_TOKEN' ) ]) { sh ''' set -e echo "Deploying backend ${BUILD_NUMBER}" BACKEND_TAG=latest FRONTEND_TAG=latest docker compose up -d ''' } } } stage('Cleanup') { agent any steps { cleanWs() } } } }