diff --git a/Jenkinsfile b/Jenkinsfile index 6512be28..8a5be402 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,7 @@ pipeline { - agent any + agent { + label 'docker' + } options { timestamps() disableConcurrentBuilds() @@ -57,7 +59,6 @@ pipeline { DB_NAME="anexo76_test" DB_USER="anexo76" DB_PASS="anexo76" - DB_PORT="55432" export TEST_DATABASE_URL="postgresql://${DB_USER}:${DB_PASS}@${DB_CONTAINER}:5432/${DB_NAME}" PY_CONTAINER="anexo76-test-py-${BUILD_NUMBER}" TEST_NETWORK="anexo76-test-net-${BUILD_NUMBER}" @@ -80,13 +81,19 @@ pipeline { -e POSTGRES_PASSWORD="$DB_PASS" \ postgres:16-alpine - # Espera a que Postgres acepte conexiones + # Espera a que Postgres acepte conexiones (hasta ~60s) + READY=0 for i in $(seq 1 30); do if docker exec "$DB_CONTAINER" pg_isready -U "$DB_USER" -d "$DB_NAME" >/dev/null 2>&1; then + READY=1 break fi sleep 2 done + if [ "$READY" != "1" ]; then + echo "ERROR: Postgres no quedó listo a tiempo (30 intentos × 2s)." + exit 1 + fi docker exec "$DB_CONTAINER" pg_isready -U "$DB_USER" -d "$DB_NAME" docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -v ON_ERROR_STOP=1 -c " CREATE SCHEMA IF NOT EXISTS core; @@ -165,33 +172,47 @@ pipeline { stage('Build + push backend') { steps { - sh ''' - set -euo pipefail - docker build \ - --build-arg APP_VERSION="${APP_VERSION}" \ - -t "${REGISTRY}/${IMAGE_NAMESPACE}/backend:latest" \ - -f ./backend/Dockerfile \ - ./backend + script { + retry(3) { + sh ''' + set -euo pipefail + export DOCKER_BUILDKIT=1 + docker build \ + --build-arg APP_VERSION="${APP_VERSION}" \ + -t "${REGISTRY}/${IMAGE_NAMESPACE}/backend:${APP_VERSION}" \ + -t "${REGISTRY}/${IMAGE_NAMESPACE}/backend:latest" \ + -f ./backend/Dockerfile \ + ./backend - docker push "${REGISTRY}/${IMAGE_NAMESPACE}/backend:latest" - ''' + docker push "${REGISTRY}/${IMAGE_NAMESPACE}/backend:${APP_VERSION}" + docker push "${REGISTRY}/${IMAGE_NAMESPACE}/backend:latest" + ''' + } + } } } stage('Build + push frontend') { steps { - sh ''' - set -euo pipefail - docker build \ - --build-arg VITE_API_URL=https://anexo76-dev.aduanasoft.com/api/ \ - --build-arg VITE_KEYCLOAK_URL=https://anexo76-dev.aduanasoft.com/kcauth/ \ - --build-arg INTERNAL_API_URL=http://backend:3467/api/ \ - -t "${REGISTRY}/${IMAGE_NAMESPACE}/frontend:latest" \ - -f ./frontend/Dockerfile.prod \ - ./frontend + script { + retry(3) { + sh ''' + set -euo pipefail + export DOCKER_BUILDKIT=1 + docker build \ + --build-arg VITE_API_URL=https://anexo76-dev.aduanasoft.com/api/ \ + --build-arg VITE_KEYCLOAK_URL=https://anexo76-dev.aduanasoft.com/kcauth/ \ + --build-arg INTERNAL_API_URL=http://backend:3467/api/ \ + -t "${REGISTRY}/${IMAGE_NAMESPACE}/frontend:${APP_VERSION}" \ + -t "${REGISTRY}/${IMAGE_NAMESPACE}/frontend:latest" \ + -f ./frontend/Dockerfile.prod \ + ./frontend - docker push "${REGISTRY}/${IMAGE_NAMESPACE}/frontend:latest" - ''' + docker push "${REGISTRY}/${IMAGE_NAMESPACE}/frontend:${APP_VERSION}" + docker push "${REGISTRY}/${IMAGE_NAMESPACE}/frontend:latest" + ''' + } + } } } @@ -229,13 +250,19 @@ pipeline { ) ]) { script { + sh """ + set -euo pipefail + mkdir -p ~/.ssh + chmod 700 ~/.ssh + ssh-keyscan -T 15 -H '${env.DEV_SERVER_HOST}' >> ~/.ssh/known_hosts + """ def remote = [ name: 'dev-server', host: env.DEV_SERVER_HOST, user: env.DEV_SERVER_USER ?: env.DEV_SERVER_SSH_USER, identityFile: env.DEV_SERVER_KEY, passphrase: env.DEV_SERVER_KEY_PASSPHRASE, - allowAnyHosts: true + allowAnyHosts: false ] sshCommand remote: remote, command: ''' set -euo pipefail @@ -243,6 +270,7 @@ pipeline { # Asume docker login ya configurado en el host destino para evitar exponer secretos por interpolación. docker compose -f docker-compose.prod.yml pull docker compose -f docker-compose.prod.yml up -d + # Solo imágenes colgantes (sin tag); no borra imágenes en uso por otros contenedores. docker image prune -f ''' }