refactor(jenkins): mover E2E a después del deploy, contra URL desplegada
Workspace rechaza redirigir a localhost por seguridad. Solución: E2E corre contra A76_URL (dominio de confianza) después del deploy. - E2E stage movido después de Deploy — Dev (solo en branch development) - Eliminado arranque de dev server (pnpm run dev, wait 90s) - PLAYWRIGHT_TEST_BASE_URL = A76_URL en lugar de localhost:5173 - Test — Frontend queda solo con Vitest (tests unitarios) - Pipeline más limpio y correcto: E2E valida lo que está realmente desplegado Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
223
Jenkinsfile
vendored
223
Jenkinsfile
vendored
@@ -1,13 +1,13 @@
|
||||
// Pipeline CI/CD — Aduanasoft Anexo76
|
||||
// Ejecuta: tests (backend + frontend en paralelo) → security scan → docker build/push → deploy dev → smoke test
|
||||
// Ejecuta: tests → security scan → docker build/push → deploy dev → E2E → smoke test
|
||||
//
|
||||
// Credenciales requeridas en Jenkins:
|
||||
// - harbor-credentials : username/password para dev.aduanasoft.com
|
||||
// - a76-public-url-dev : Secret Text — URL pública base (ej. https://anexo76-dev.aduanasoft.com)
|
||||
// Se usa para construir VITE_API_URL y VITE_KEYCLOAK_URL en el build del frontend
|
||||
// - dev-server-user : Secret Text — usuario SSH del servidor dev
|
||||
// - dev-server-host : Secret Text — hostname/IP del servidor dev
|
||||
// - dev-server-ssh : SSH Username with Private Key — llave privada para deploy
|
||||
// - a76-e2e-credentials : Username with password — usuario de prueba en Workspace
|
||||
//
|
||||
// El agente Jenkins solo necesita: Docker CLI
|
||||
|
||||
@@ -22,8 +22,7 @@ pipeline {
|
||||
// Debe coincidir con @playwright/test del frontend (ver frontend/pnpm-lock.yaml)
|
||||
PLAYWRIGHT_IMAGE = 'mcr.microsoft.com/playwright:v1.56.1-noble'
|
||||
DEPLOY_PATH = '~/projects/anexo76'
|
||||
// URL de Keycloak/Workspace accesible desde el agente Jenkins.
|
||||
// Difiere de A76_URL/kcauth porque Keycloak vive en Workspace, no en el servidor de Anexo76.
|
||||
// URL de Keycloak/Workspace — Keycloak vive en Workspace, no en el servidor de Anexo76
|
||||
KC_URL = 'https://workspace.aduanasoft.com/kcauth'
|
||||
}
|
||||
|
||||
@@ -36,7 +35,7 @@ pipeline {
|
||||
|
||||
stages {
|
||||
|
||||
// ── Paso 5b — Tests (backend y frontend en paralelo) ──────────────────
|
||||
// ── Tests (backend y frontend unit en paralelo) ───────────────────────
|
||||
stage('Tests') {
|
||||
parallel {
|
||||
|
||||
@@ -134,138 +133,40 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
stage('Test — Frontend') {
|
||||
stages {
|
||||
stage('Test — Frontend (Vitest)') {
|
||||
steps {
|
||||
sh '''
|
||||
set -euo pipefail
|
||||
C="a76-test-fe-${BUILD_NUMBER}"
|
||||
cleanup() { docker rm -f "$C" >/dev/null 2>&1 || true; }
|
||||
trap cleanup EXIT
|
||||
|
||||
stage('Unit Tests (Vitest)') {
|
||||
steps {
|
||||
sh '''
|
||||
set -euo pipefail
|
||||
C="a76-test-fe-${BUILD_NUMBER}"
|
||||
cleanup() { docker rm -f "$C" >/dev/null 2>&1 || true; }
|
||||
trap cleanup EXIT
|
||||
|
||||
docker rm -f "$C" >/dev/null 2>&1 || true
|
||||
docker run -d --name "$C" "$PLAYWRIGHT_IMAGE" sleep infinity
|
||||
docker exec "$C" mkdir -p /workspace
|
||||
docker cp "$WORKSPACE/." "$C:/workspace"
|
||||
|
||||
docker exec \
|
||||
-e CI=true \
|
||||
-e NODE_ENV=test \
|
||||
-e "JENKINS_URL=${JENKINS_URL}" \
|
||||
-e JENKINS_VITEST_FULL=1 \
|
||||
-w /workspace/frontend \
|
||||
"$C" bash -lc '
|
||||
set -euxo pipefail
|
||||
npm install -g pnpm@9 --quiet
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm run i18n:compile
|
||||
pnpm run test:unit -- --run
|
||||
'
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('E2E (Playwright)') {
|
||||
steps {
|
||||
// auth.setup.ts navega a /login → Workspace → llena form → /dashboard
|
||||
// y guarda storageState para los tests dependientes.
|
||||
//
|
||||
// Credenciales requeridas en Jenkins:
|
||||
// a76-public-url-dev : URL pública base de Anexo76
|
||||
// a76-e2e-credentials : Username with password — usuario de prueba en Workspace
|
||||
withCredentials([
|
||||
string(credentialsId: 'a76-public-url-dev', variable: 'A76_URL'),
|
||||
usernamePassword(
|
||||
credentialsId: 'a76-e2e-credentials',
|
||||
usernameVariable: 'E2E_USER',
|
||||
passwordVariable: 'E2E_PASS'
|
||||
)
|
||||
]) {
|
||||
sh '''
|
||||
set -euo pipefail
|
||||
C="a76-test-e2e-${BUILD_NUMBER}"
|
||||
cleanup() { docker rm -f "$C" >/dev/null 2>&1 || true; }
|
||||
trap cleanup EXIT
|
||||
|
||||
docker rm -f "$C" >/dev/null 2>&1 || true
|
||||
docker run -d --name "$C" "$PLAYWRIGHT_IMAGE" sleep infinity
|
||||
docker exec "$C" mkdir -p /workspace
|
||||
docker cp "$WORKSPACE/." "$C:/workspace"
|
||||
|
||||
docker exec \
|
||||
-e CI=true \
|
||||
-e NODE_ENV=test \
|
||||
-e "JENKINS_URL=${JENKINS_URL}" \
|
||||
-e PLAYWRIGHT_TEST_BASE_URL=http://localhost:5173 \
|
||||
-e "VITE_API_URL=${A76_URL}/api/" \
|
||||
-e "INTERNAL_API_URL=${A76_URL}/api/" \
|
||||
-e "VITE_KEYCLOAK_URL=${KC_URL}" \
|
||||
-e "KEYCLOAK_URL=${KC_URL}" \
|
||||
-e VITE_KEYCLOAK_REALM=master \
|
||||
-e KEYCLOAK_REALM=master \
|
||||
-e VITE_KEYCLOAK_CLIENT_ID=hub-frontend \
|
||||
-e KEYCLOAK_CLIENT_ID=hub-frontend \
|
||||
-e ORIGIN=http://localhost:5173 \
|
||||
-e "KC_URL=${KC_URL}" \
|
||||
-e "E2E_TEST_USER=${E2E_USER}" \
|
||||
-e "E2E_TEST_PASSWORD=${E2E_PASS}" \
|
||||
-w /workspace/frontend \
|
||||
"$C" bash -lc '
|
||||
set -euxo pipefail
|
||||
npm install -g pnpm@9 --quiet
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm run i18n:compile
|
||||
|
||||
# Arrancar dev server
|
||||
pnpm run dev &
|
||||
DEV_PID=$!
|
||||
|
||||
# Esperar a que el dev server esté listo (máx 90s, primer request lento por compilación)
|
||||
READY=0
|
||||
for i in $(seq 1 45); do
|
||||
if curl -sf --max-time 5 http://localhost:5173 >/dev/null 2>&1; then
|
||||
READY=1; break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
if [ "$READY" != "1" ]; then
|
||||
echo "ERROR: Dev server no arrancó en 90s."
|
||||
kill "$DEV_PID" 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ejecutar E2E; capturar exit code para no perder el reporte
|
||||
E2E_EXIT=0
|
||||
PLAYWRIGHT_JUNIT_OUTPUT_NAME=playwright-results.xml \
|
||||
pnpm exec playwright test --reporter=junit,html || E2E_EXIT=$?
|
||||
|
||||
kill "$DEV_PID" 2>/dev/null || true
|
||||
exit "$E2E_EXIT"
|
||||
'
|
||||
docker cp "$C:/workspace/frontend/playwright-results.xml" \
|
||||
"$WORKSPACE/frontend/playwright-results.xml" 2>/dev/null || true
|
||||
docker cp "$C:/workspace/frontend/playwright-report" \
|
||||
"$WORKSPACE/frontend/playwright-report" 2>/dev/null || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit allowEmptyResults: true, testResults: 'frontend/playwright-results.xml'
|
||||
archiveArtifacts artifacts: 'frontend/playwright-report/**', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
}
|
||||
docker rm -f "$C" >/dev/null 2>&1 || true
|
||||
docker run -d --name "$C" "$PLAYWRIGHT_IMAGE" sleep infinity
|
||||
docker exec "$C" mkdir -p /workspace
|
||||
docker cp "$WORKSPACE/." "$C:/workspace"
|
||||
|
||||
docker exec \
|
||||
-e CI=true \
|
||||
-e NODE_ENV=test \
|
||||
-e "JENKINS_URL=${JENKINS_URL}" \
|
||||
-e JENKINS_VITEST_FULL=1 \
|
||||
-w /workspace/frontend \
|
||||
"$C" bash -lc '
|
||||
set -euxo pipefail
|
||||
npm install -g pnpm@9 --quiet
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm run i18n:compile
|
||||
pnpm run test:unit -- --run
|
||||
'
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// ── Pasos 5c-5d — Escaneo de vulnerabilidades ────────────────────────
|
||||
// ── Escaneo de vulnerabilidades ───────────────────────────────────────
|
||||
stage('Security Scan') {
|
||||
parallel {
|
||||
stage('pip-audit') {
|
||||
@@ -340,7 +241,7 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Paso 5e — Docker Build + Push ─────────────────────────────────────
|
||||
// ── Docker Build + Push ───────────────────────────────────────────────
|
||||
stage('Docker Build') {
|
||||
when {
|
||||
anyOf { branch 'main'; branch 'development' }
|
||||
@@ -391,7 +292,7 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Paso 5f — Deploy Dev ───────────────────────────────────────────────
|
||||
// ── Deploy Dev ────────────────────────────────────────────────────────
|
||||
stage('Deploy — Dev') {
|
||||
when { branch 'development' }
|
||||
steps {
|
||||
@@ -441,6 +342,66 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
// ── E2E (Playwright) — contra la URL desplegada ───────────────────────
|
||||
// Corre después del deploy para que Workspace confíe en el dominio de retorno.
|
||||
// No levanta dev server — Playwright apunta directamente a A76_URL.
|
||||
stage('E2E (Playwright)') {
|
||||
when { branch 'development' }
|
||||
steps {
|
||||
withCredentials([
|
||||
string(credentialsId: 'a76-public-url-dev', variable: 'A76_URL'),
|
||||
usernamePassword(
|
||||
credentialsId: 'a76-e2e-credentials',
|
||||
usernameVariable: 'E2E_USER',
|
||||
passwordVariable: 'E2E_PASS'
|
||||
)
|
||||
]) {
|
||||
sh '''
|
||||
set -euo pipefail
|
||||
C="a76-test-e2e-${BUILD_NUMBER}"
|
||||
cleanup() { docker rm -f "$C" >/dev/null 2>&1 || true; }
|
||||
trap cleanup EXIT
|
||||
|
||||
docker rm -f "$C" >/dev/null 2>&1 || true
|
||||
docker run -d --name "$C" "$PLAYWRIGHT_IMAGE" sleep infinity
|
||||
docker exec "$C" mkdir -p /workspace
|
||||
docker cp "$WORKSPACE/." "$C:/workspace"
|
||||
|
||||
docker exec \
|
||||
-e CI=true \
|
||||
-e "JENKINS_URL=${JENKINS_URL}" \
|
||||
-e "PLAYWRIGHT_TEST_BASE_URL=${A76_URL}" \
|
||||
-e "E2E_TEST_USER=${E2E_USER}" \
|
||||
-e "E2E_TEST_PASSWORD=${E2E_PASS}" \
|
||||
-w /workspace/frontend \
|
||||
"$C" bash -lc '
|
||||
set -euxo pipefail
|
||||
npm install -g pnpm@9 --quiet
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm run i18n:compile
|
||||
|
||||
# Ejecutar E2E contra la URL desplegada
|
||||
E2E_EXIT=0
|
||||
PLAYWRIGHT_JUNIT_OUTPUT_NAME=playwright-results.xml \
|
||||
pnpm exec playwright test --reporter=junit,html || E2E_EXIT=$?
|
||||
|
||||
exit "$E2E_EXIT"
|
||||
'
|
||||
docker cp "$C:/workspace/frontend/playwright-results.xml" \
|
||||
"$WORKSPACE/frontend/playwright-results.xml" 2>/dev/null || true
|
||||
docker cp "$C:/workspace/frontend/playwright-report" \
|
||||
"$WORKSPACE/frontend/playwright-report" 2>/dev/null || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit allowEmptyResults: true, testResults: 'frontend/playwright-results.xml'
|
||||
archiveArtifacts artifacts: 'frontend/playwright-report/**', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Smoke Test ────────────────────────────────────────────────────────
|
||||
stage('Smoke Test') {
|
||||
when { branch 'development' }
|
||||
|
||||
Reference in New Issue
Block a user