feat(ci): validar imagen nueva en E2E antes del deploy a dev
El stage E2E corría contra A76_URL (versión viva en dev), así que detectaba regresiones un build tarde: el código roto ya estaba desplegado cuando el siguiente pipeline lo encontraba. Ahora E2E levanta un stack efímero con la imagen del backend recién pusheada a Harbor y una imagen del frontend buildeada localmente con VITE_API_URL=http://localhost:8000/api/ (la imagen de prod tiene la URL de dev bakeada en el bundle). Si E2E falla, el deploy no ocurre — el guardrail actúa sobre lo que se va a desplegar. Cambios: - docker-compose.e2e.yml (nuevo): postgres + minio + valkey + backend + frontend efímeros, sin volúmenes persistidos, image tags vía env vars. - Jenkinsfile: stage E2E reescrito. Build temp frontend en paralelo con startup DB+alembic; preparación Playwright en paralelo con health wait de backend/frontend. --cache-from de la imagen prod para reusar layer de pnpm install. Cleanup garantizado vía trap EXIT. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
179
Jenkinsfile
vendored
179
Jenkinsfile
vendored
@@ -293,15 +293,17 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── E2E (Playwright) — contra la versión actualmente desplegada ─────────
|
// ── E2E (Playwright) — contra la imagen recién buildeada ────────────────
|
||||||
// Corre ANTES del deploy con la imagen ya en Harbor pero aún no desplegada.
|
// Levanta un stack efímero (docker-compose.e2e.yml) con la imagen del backend
|
||||||
// Playwright apunta a A76_URL (versión viva anterior) — dominio de confianza
|
// recién pusheada a Harbor y una imagen del frontend buildeada localmente con
|
||||||
// para Workspace. Si E2E falla, el deploy no ocurre.
|
// VITE_API_URL=http://localhost:8000/api/ (la imagen de prod tiene la URL de dev
|
||||||
|
// bakeada en el bundle, ver Dockerfile.prod:19-20). Si E2E falla, el deploy
|
||||||
|
// no ocurre — el guardrail actúa sobre el código que se va a desplegar,
|
||||||
|
// no sobre la versión viva.
|
||||||
stage('E2E (Playwright)') {
|
stage('E2E (Playwright)') {
|
||||||
when { branch 'development' }
|
when { branch 'development' }
|
||||||
steps {
|
steps {
|
||||||
withCredentials([
|
withCredentials([
|
||||||
string(credentialsId: 'a76-public-url-dev', variable: 'A76_URL'),
|
|
||||||
usernamePassword(
|
usernamePassword(
|
||||||
credentialsId: 'a76-e2e-credentials',
|
credentialsId: 'a76-e2e-credentials',
|
||||||
usernameVariable: 'E2E_USER',
|
usernameVariable: 'E2E_USER',
|
||||||
@@ -310,43 +312,164 @@ pipeline {
|
|||||||
]) {
|
]) {
|
||||||
sh '''
|
sh '''
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
C="a76-test-e2e-${BUILD_NUMBER}"
|
export DOCKER_BUILDKIT=1
|
||||||
cleanup() { docker rm -f "$C" >/dev/null 2>&1 || true; }
|
PROJECT="a76-e2e-${BUILD_NUMBER}"
|
||||||
|
FE_IMAGE_E2E="${IMAGE_FRONTEND}:e2e-${BUILD_NUMBER}"
|
||||||
|
BE_IMAGE_E2E="${IMAGE_BACKEND}:${APP_VERSION}"
|
||||||
|
PLAYWRIGHT_C="a76-test-e2e-${BUILD_NUMBER}"
|
||||||
|
BUILD_LOG="${WORKSPACE}/e2e-frontend-build.log"
|
||||||
|
PREP_LOG="${WORKSPACE}/e2e-playwright-prep.log"
|
||||||
|
|
||||||
|
export E2E_BACKEND_IMAGE="$BE_IMAGE_E2E"
|
||||||
|
export E2E_FRONTEND_IMAGE="$FE_IMAGE_E2E"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
echo "=== E2E cleanup ==="
|
||||||
|
docker rm -f "$PLAYWRIGHT_C" >/dev/null 2>&1 || true
|
||||||
|
docker compose -p "$PROJECT" -f docker-compose.e2e.yml down -v --remove-orphans >/dev/null 2>&1 || true
|
||||||
|
docker rmi -f "$FE_IMAGE_E2E" >/dev/null 2>&1 || true
|
||||||
|
rm -f "$BUILD_LOG" "$PREP_LOG" || true
|
||||||
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
docker rm -f "$C" >/dev/null 2>&1 || true
|
# ── PARALELO #1 ─────────────────────────────────────────────────
|
||||||
docker run -d --name "$C" "$PLAYWRIGHT_IMAGE" sleep infinity
|
# Lanzar en background el build del frontend temporal Y el stack
|
||||||
docker exec "$C" mkdir -p /workspace
|
# de dependencias. El build es lo más lento (~2-4 min); mientras
|
||||||
docker cp "$WORKSPACE/." "$C:/workspace"
|
# corre, levantamos postgres+minio+valkey y aplicamos migraciones.
|
||||||
|
# ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Build temporal del frontend con VITE_API_URL=localhost.
|
||||||
|
# --cache-from reusa la layer de pnpm install de la imagen de prod
|
||||||
|
# recién buildeada (las deps son idénticas, solo cambia VITE_API_URL).
|
||||||
|
# No se pushea a Harbor; solo existe en este agente durante el stage.
|
||||||
|
( docker build --progress=plain \
|
||||||
|
--cache-from "${IMAGE_FRONTEND}:latest" \
|
||||||
|
--build-arg BUILDKIT_INLINE_CACHE=1 \
|
||||||
|
--build-arg VITE_API_URL=http://localhost:8000/api/ \
|
||||||
|
--build-arg VITE_KEYCLOAK_URL=${KC_URL} \
|
||||||
|
--build-arg VITE_KEYCLOAK_CLIENT_ID=anexo76-frontend \
|
||||||
|
--build-arg INTERNAL_API_URL=http://backend:8000/api/ \
|
||||||
|
-t "$FE_IMAGE_E2E" \
|
||||||
|
-f frontend/Dockerfile.prod \
|
||||||
|
frontend/ ) > "$BUILD_LOG" 2>&1 &
|
||||||
|
BUILD_PID=$!
|
||||||
|
|
||||||
|
# En foreground: levantar dependencias y correr migraciones
|
||||||
|
docker compose -p "$PROJECT" -f docker-compose.e2e.yml up -d postgres-a76 minio valkey
|
||||||
|
|
||||||
|
# Esperar postgres healthy (timeout 60s)
|
||||||
|
READY=0
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
STATUS=$(docker inspect -f '{{.State.Health.Status}}' \
|
||||||
|
"$(docker compose -p "$PROJECT" -f docker-compose.e2e.yml ps -q postgres-a76)" 2>/dev/null || echo "starting")
|
||||||
|
if [ "$STATUS" = "healthy" ]; then READY=1; break; fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
if [ "$READY" != "1" ]; then
|
||||||
|
echo "ERROR: Postgres no quedó healthy en 60s"
|
||||||
|
docker compose -p "$PROJECT" -f docker-compose.e2e.yml logs postgres-a76 || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Crear schemas que el backend espera (mismo patrón que Test — Backend)
|
||||||
|
DB_C=$(docker compose -p "$PROJECT" -f docker-compose.e2e.yml ps -q postgres-a76)
|
||||||
|
docker exec "$DB_C" psql -U postgres -d anexo76_core -v ON_ERROR_STOP=1 -c "
|
||||||
|
CREATE SCHEMA IF NOT EXISTS core;
|
||||||
|
CREATE SCHEMA IF NOT EXISTS a24;
|
||||||
|
CREATE SCHEMA IF NOT EXISTS a76;
|
||||||
|
CREATE SCHEMA IF NOT EXISTS public;
|
||||||
|
"
|
||||||
|
|
||||||
|
# `run --rm --no-deps` ejecuta alembic con la imagen del backend SIN
|
||||||
|
# arrancar los servicios dependientes (ya están corriendo).
|
||||||
|
docker compose -p "$PROJECT" -f docker-compose.e2e.yml run --rm --no-deps \
|
||||||
|
--entrypoint "" backend alembic upgrade head
|
||||||
|
|
||||||
|
# Esperar a que termine el build del frontend (si no terminó ya)
|
||||||
|
echo "Esperando build temporal del frontend..."
|
||||||
|
if ! wait "$BUILD_PID"; then
|
||||||
|
echo "ERROR: build del frontend E2E falló — log:"
|
||||||
|
cat "$BUILD_LOG" || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✓ Build temporal del frontend completado"
|
||||||
|
|
||||||
|
# ── Arrancar backend y frontend ─────────────────────────────────
|
||||||
|
docker compose -p "$PROJECT" -f docker-compose.e2e.yml up -d backend frontend
|
||||||
|
|
||||||
|
# ── PARALELO #2 ─────────────────────────────────────────────────
|
||||||
|
# Mientras backend+frontend se vuelven healthy (~40-80s),
|
||||||
|
# preparar el contenedor Playwright en background.
|
||||||
|
# ────────────────────────────────────────────────────────────────
|
||||||
|
docker rm -f "$PLAYWRIGHT_C" >/dev/null 2>&1 || true
|
||||||
|
# --network host: para que "localhost:5173" dentro del contenedor
|
||||||
|
# de Playwright resuelva a los puertos publicados por el stack.
|
||||||
|
# Necesario porque ORIGIN=http://localhost:5173 y el callback de
|
||||||
|
# Keycloak redirige a esa URL exacta.
|
||||||
|
docker run -d --name "$PLAYWRIGHT_C" --network host "$PLAYWRIGHT_IMAGE" sleep infinity
|
||||||
|
docker exec "$PLAYWRIGHT_C" mkdir -p /workspace
|
||||||
|
docker cp "$WORKSPACE/." "$PLAYWRIGHT_C:/workspace"
|
||||||
|
|
||||||
|
( docker exec -w /workspace/frontend "$PLAYWRIGHT_C" bash -lc '
|
||||||
|
set -euxo pipefail
|
||||||
|
npm install -g pnpm@9 --quiet
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
pnpm run i18n:compile
|
||||||
|
' ) > "$PREP_LOG" 2>&1 &
|
||||||
|
PREP_PID=$!
|
||||||
|
|
||||||
|
# En foreground: esperar backend y frontend healthy
|
||||||
|
for SVC in backend frontend; do
|
||||||
|
READY=0
|
||||||
|
for i in $(seq 1 60); do
|
||||||
|
CID=$(docker compose -p "$PROJECT" -f docker-compose.e2e.yml ps -q "$SVC" 2>/dev/null)
|
||||||
|
if [ -n "$CID" ]; then
|
||||||
|
STATUS=$(docker inspect -f '{{.State.Health.Status}}' "$CID" 2>/dev/null || echo "starting")
|
||||||
|
if [ "$STATUS" = "healthy" ]; then READY=1; break; fi
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
if [ "$READY" != "1" ]; then
|
||||||
|
echo "ERROR: $SVC no quedó healthy en 120s"
|
||||||
|
docker compose -p "$PROJECT" -f docker-compose.e2e.yml logs "$SVC" || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Esperar a que termine la preparación de Playwright
|
||||||
|
echo "Esperando preparación de Playwright..."
|
||||||
|
if ! wait "$PREP_PID"; then
|
||||||
|
echo "ERROR: preparación de Playwright falló — log:"
|
||||||
|
cat "$PREP_LOG" || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✓ Playwright listo"
|
||||||
|
|
||||||
|
# ── Correr tests ────────────────────────────────────────────────
|
||||||
|
E2E_EXIT=0
|
||||||
docker exec \
|
docker exec \
|
||||||
-e CI=true \
|
-e CI=true \
|
||||||
-e "JENKINS_URL=${JENKINS_URL}" \
|
-e "JENKINS_URL=${JENKINS_URL}" \
|
||||||
-e "PLAYWRIGHT_TEST_BASE_URL=${A76_URL}" \
|
-e "PLAYWRIGHT_TEST_BASE_URL=http://localhost:5173" \
|
||||||
-e "E2E_TEST_USER=${E2E_USER}" \
|
-e "E2E_TEST_USER=${E2E_USER}" \
|
||||||
-e "E2E_TEST_PASSWORD=${E2E_PASS}" \
|
-e "E2E_TEST_PASSWORD=${E2E_PASS}" \
|
||||||
|
-e "PLAYWRIGHT_JUNIT_OUTPUT_NAME=playwright-results.xml" \
|
||||||
-w /workspace/frontend \
|
-w /workspace/frontend \
|
||||||
"$C" bash -lc '
|
"$PLAYWRIGHT_C" \
|
||||||
set -euxo pipefail
|
pnpm exec playwright test \
|
||||||
npm install -g pnpm@9 --quiet
|
--reporter=junit,html \
|
||||||
pnpm install --frozen-lockfile
|
--trace=retain-on-failure || E2E_EXIT=$?
|
||||||
pnpm run i18n:compile
|
|
||||||
|
|
||||||
E2E_EXIT=0
|
# Copiar artefactos antes de salir (pase o falle)
|
||||||
PLAYWRIGHT_JUNIT_OUTPUT_NAME=playwright-results.xml \
|
docker cp "$PLAYWRIGHT_C:/workspace/frontend/playwright-results.xml" \
|
||||||
pnpm exec playwright test \
|
|
||||||
--reporter=junit,html \
|
|
||||||
--trace=retain-on-failure || E2E_EXIT=$?
|
|
||||||
|
|
||||||
exit "$E2E_EXIT"
|
|
||||||
'
|
|
||||||
docker cp "$C:/workspace/frontend/playwright-results.xml" \
|
|
||||||
"$WORKSPACE/frontend/playwright-results.xml" 2>/dev/null || true
|
"$WORKSPACE/frontend/playwright-results.xml" 2>/dev/null || true
|
||||||
docker cp "$C:/workspace/frontend/playwright-report" \
|
docker cp "$PLAYWRIGHT_C:/workspace/frontend/playwright-report" \
|
||||||
"$WORKSPACE/frontend/playwright-report" 2>/dev/null || true
|
"$WORKSPACE/frontend/playwright-report" 2>/dev/null || true
|
||||||
# test-results contiene trace.zip + error-context.md + screenshots por test fallido
|
# test-results contiene trace.zip + error-context.md + screenshots por test fallido
|
||||||
docker cp "$C:/workspace/frontend/test-results" \
|
docker cp "$PLAYWRIGHT_C:/workspace/frontend/test-results" \
|
||||||
"$WORKSPACE/frontend/test-results" 2>/dev/null || true
|
"$WORKSPACE/frontend/test-results" 2>/dev/null || true
|
||||||
|
|
||||||
|
exit "$E2E_EXIT"
|
||||||
'''
|
'''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
157
docker-compose.e2e.yml
Normal file
157
docker-compose.e2e.yml
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
# Stack efímero para pruebas E2E (Playwright) en CI.
|
||||||
|
# Levantado por Jenkinsfile (stage "E2E (Playwright)") ANTES del deploy a dev,
|
||||||
|
# para validar la imagen recién buildeada contra una DB limpia y servicios aislados.
|
||||||
|
#
|
||||||
|
# Diferencias clave vs docker-compose.prod.yml:
|
||||||
|
# - Sin volúmenes persistidos (todo se descarta en `down -v`).
|
||||||
|
# - Sin `container_name` ni `restart` (efímero, COMPOSE_PROJECT_NAME aísla los nombres).
|
||||||
|
# - Sin `celery_worker` / `celery_beat` (no se ejercitan en los specs actuales).
|
||||||
|
# - Imágenes vía env vars: la del frontend se rebuildea localmente con
|
||||||
|
# VITE_API_URL=http://localhost:8000/api/ (la prod tiene la URL de dev bakeada).
|
||||||
|
# - Puertos fijos: frontend 5173 / backend 8000 (URIs ya registradas en Workspace).
|
||||||
|
#
|
||||||
|
# Variables requeridas en el entorno al invocar docker compose:
|
||||||
|
# E2E_BACKEND_IMAGE — imagen del backend recién pusheada a Harbor
|
||||||
|
# E2E_FRONTEND_IMAGE — imagen temporal del frontend con VITE_API_URL=localhost
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres-a76:
|
||||||
|
image: postgres:18-alpine
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: anexo76_core
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
POSTGRES_INITDB_ARGS: "--encoding=UTF8"
|
||||||
|
networks:
|
||||||
|
- e2e-net
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres -d anexo76_core || exit 1"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 10
|
||||||
|
start_period: 20s
|
||||||
|
tmpfs:
|
||||||
|
- /var/lib/postgresql/data
|
||||||
|
|
||||||
|
minio:
|
||||||
|
image: minio/minio:RELEASE.2025-09-07T16-13-09Z
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
environment:
|
||||||
|
MINIO_ROOT_USER: minioadmin
|
||||||
|
MINIO_ROOT_PASSWORD: minioadmin
|
||||||
|
networks:
|
||||||
|
- e2e-net
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -f http://127.0.0.1:9000/minio/health/live || exit 1"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 15s
|
||||||
|
tmpfs:
|
||||||
|
- /data
|
||||||
|
|
||||||
|
valkey:
|
||||||
|
image: valkey/valkey:7.2
|
||||||
|
networks:
|
||||||
|
- e2e-net
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image: ${E2E_BACKEND_IMAGE}
|
||||||
|
environment:
|
||||||
|
- DEBUG=False
|
||||||
|
- ENVIRONMENT=e2e
|
||||||
|
- PYTHONUNBUFFERED=1
|
||||||
|
- PYTHONDONTWRITEBYTECODE=1
|
||||||
|
- CORE_DB_HOST=postgres-a76
|
||||||
|
- CORE_DB_PORT=5432
|
||||||
|
- CORE_DB_NAME=anexo76_core
|
||||||
|
- CORE_DB_USER=postgres
|
||||||
|
- CORE_DB_PASSWORD=postgres
|
||||||
|
# Keycloak — apunta a Workspace real; el cliente anexo76-frontend ya
|
||||||
|
# tiene http://localhost:5173/auth/callback como redirect URI permitida.
|
||||||
|
- KEYCLOAK_SERVER_URL=https://workspace.aduanasoft.com/kcauth
|
||||||
|
- KEYCLOAK_REALM=master
|
||||||
|
- KEYCLOAK_CLIENT_ID=anexo76-frontend
|
||||||
|
- KEYCLOAK_CLIENT_SECRET=${KEYCLOAK_CLIENT_SECRET:-}
|
||||||
|
- CORS_ORIGINS=http://localhost:5173
|
||||||
|
- VALKEY_URL=redis://valkey:6379/0
|
||||||
|
- HUB_URL=https://workspace.aduanasoft.com
|
||||||
|
- APP_PUBLIC_URL=http://localhost:5173
|
||||||
|
- CSV_IMPORT_STORAGE=minio
|
||||||
|
- S3_ENDPOINT_URL=http://minio:9000
|
||||||
|
- S3_ACCESS_KEY=minioadmin
|
||||||
|
- S3_SECRET_KEY=minioadmin
|
||||||
|
- S3_BUCKET=anexo76
|
||||||
|
- S3_REGION=us-east-1
|
||||||
|
- S3_USE_SSL=false
|
||||||
|
- S3_FILE_STORAGE=true
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
depends_on:
|
||||||
|
postgres-a76:
|
||||||
|
condition: service_healthy
|
||||||
|
minio:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- e2e-net
|
||||||
|
# Replica el comando de prod (gunicorn) para que el test ejerza el mismo runtime
|
||||||
|
# que se desplegará. El CMD del Dockerfile usa uvicorn --reload (modo dev).
|
||||||
|
command:
|
||||||
|
- gunicorn
|
||||||
|
- main:app
|
||||||
|
- -k
|
||||||
|
- uvicorn.workers.UvicornWorker
|
||||||
|
- -w
|
||||||
|
- "1"
|
||||||
|
- -b
|
||||||
|
- 0.0.0.0:8000
|
||||||
|
- --log-level
|
||||||
|
- info
|
||||||
|
- --forwarded-allow-ips
|
||||||
|
- "*"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -f http://localhost:8000/api/health || exit 1"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image: ${E2E_FRONTEND_IMAGE}
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
# VITE_API_URL ya está bakeada en E2E_FRONTEND_IMAGE; este valor solo sirve
|
||||||
|
# para fallback server-side en frontend/src/lib/server/api.ts.
|
||||||
|
- VITE_API_URL=http://localhost:8000/api/
|
||||||
|
- INTERNAL_API_URL=http://backend:8000/api/
|
||||||
|
- INTERNAL_HUB_URL=https://workspace.aduanasoft.com
|
||||||
|
- HUB_URL=https://workspace.aduanasoft.com
|
||||||
|
- VITE_HUB_URL=https://workspace.aduanasoft.com
|
||||||
|
- VITE_KEYCLOAK_URL=https://workspace.aduanasoft.com/kcauth
|
||||||
|
- VITE_KEYCLOAK_REALM=master
|
||||||
|
- VITE_KEYCLOAK_CLIENT_ID=anexo76-frontend
|
||||||
|
- KEYCLOAK_URL=https://workspace.aduanasoft.com/kcauth
|
||||||
|
- KEYCLOAK_REALM=master
|
||||||
|
- KEYCLOAK_CLIENT_ID=anexo76-frontend
|
||||||
|
- KEYCLOAK_CLIENT_SECRET=${KEYCLOAK_CLIENT_SECRET:-}
|
||||||
|
# ORIGIN controla url.origin y el flag secure de cookies — debe coincidir con la URL
|
||||||
|
# registrada en Workspace para que el callback de Keycloak resuelva correctamente.
|
||||||
|
- ORIGIN=http://localhost:5173
|
||||||
|
- SITE_URL=http://localhost:5173
|
||||||
|
ports:
|
||||||
|
- "5173:5173"
|
||||||
|
depends_on:
|
||||||
|
backend:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- e2e-net
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:5173/ || exit 1"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
networks:
|
||||||
|
e2e-net:
|
||||||
|
driver: bridge
|
||||||
Reference in New Issue
Block a user