diff --git a/bdt.sh b/bdt.sh index a6bb6c4..b6b9304 100755 --- a/bdt.sh +++ b/bdt.sh @@ -20,7 +20,7 @@ set -euo pipefail # CONFIGURACION #=============================================================================== -SCRIPT_VERSION="2.1.0" +SCRIPT_VERSION="2.2.0" SCRIPT_NAME="$(basename "$0")" # Directorios - resolver symlinks para encontrar la ruta real @@ -334,6 +334,7 @@ cmd_install() { # (canales-* lo tienen en apps//Dockerfile, contexto = raíz del monorepo canales) _docker_build_local() { local svc="$1" + local nocache="${2:-}" local dir dockerfile dockerfile_path dir="$(repo_dir "$svc")" [[ -z "$dir" ]] && { err "Servicio desconocido: ${svc}"; return 1; } @@ -342,9 +343,14 @@ _docker_build_local() { [[ ! -f "$dockerfile_path" ]] && { err "Sin Dockerfile: ${svc} (${dockerfile_path})"; return 1; } local args=(-t "bdt-${svc}:latest") + if [[ "$nocache" == "nocache" || "$nocache" == "--no-cache" ]]; then + args=(--no-cache "${args[@]}") + info "Construyendo bdt-${svc}:latest ${YELLOW}(sin caché)${NC}..." + else + info "Construyendo bdt-${svc}:latest..." + fi [[ -n "$dockerfile" ]] && args+=(-f "$dockerfile_path") args+=("$dir") - info "Construyendo bdt-${svc}:latest..." if docker build "${args[@]}" > "${LOG_DIR}/${svc}-docker-build.log" 2>&1; then ok "bdt-${svc}: imagen construida" else @@ -356,18 +362,114 @@ _docker_build_local() { cmd_build() { banner - local svc="${1:-all}" - step "BUILD" "Construyendo imágenes Docker" + local svc="all" nocache="" a + # Soporta: bdt build [servicio|all] [--no-cache] + for a in "$@"; do + case "$a" in + --no-cache|nocache) nocache="nocache" ;; + *) svc="$a" ;; + esac + done + step "BUILD" "Construyendo imágenes Docker${nocache:+ (sin caché)}" if [[ "$svc" == "all" ]]; then for s in $APP_SERVICES; do - _docker_build_local "$s" || true + _docker_build_local "$s" "$nocache" || true done else - _docker_build_local "$svc" + _docker_build_local "$svc" "$nocache" fi } +#=============================================================================== +# COMANDO: rebuild - Interactivo: elegir docker → build --no-cache → up +# La idea del shell: seleccionar CUÁL docker reconstruir SIN CACHÉ y levantarlo. +#=============================================================================== + +cmd_rebuild() { + banner + step "REBUILD" "Reconstruir un servicio SIN CACHÉ y levantarlo (--force-recreate)" + echo "" + + # 1. Elegir servicio (lista numerada con estado del contenedor) + local options=() i=1 s + for s in $APP_SERVICES; do + options+=("$s") + local cname st + cname="$(docker_name "$s")" + st="$(docker inspect --format='{{.State.Status}}' "$cname" 2>/dev/null | tr -d '[:space:]' || true)" + [[ -z "$st" ]] && st="sin contenedor" + echo -e " ${WHITE}${i}${NC}) ${WHITE}${s}${NC} — $(svc_desc "$s") ${GRAY}[contenedor: ${st}]${NC}" + i=$((i+1)) + done + echo -e " ${WHITE}a${NC}) TODOS los servicios de aplicación" + echo "" + echo -ne " ${O3}¿Qué docker reconstruir sin caché? (1-${#options[@]}, 'a'=todos, nombre, Enter=cancelar):${NC} " + read -r choice + [[ -z "$choice" ]] && { warn "Cancelado"; return 0; } + + local targets=() + if [[ "$choice" == "a" || "$choice" == "all" ]]; then + targets=($APP_SERVICES) + elif [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= ${#options[@]} )); then + targets=("${options[$((choice-1))]}") + else + for s in "${options[@]}"; do [[ "$s" == "$choice" ]] && targets=("$s"); done + fi + [[ ${#targets[@]} -eq 0 ]] && { err "Opción inválida: ${choice}"; return 1; } + + # 2. Servicios Java: el Dockerfile copia build/libs/*.jar — ofrecer recompilar el JAR + local recompile="" + for s in "${targets[@]}"; do + case "$s" in + gateway|service-bus) + echo -ne " ${O3}¿Recompilar el JAR (gradle bootJar) antes del build? (s/N):${NC} " + read -r recompile + break + ;; + esac + done + + # 3. Por cada target: (gradle) → docker build --no-cache → up --force-recreate → health + for s in "${targets[@]}"; do + echo "" + step "REBUILD ${s}" "$(svc_desc "$s")" + + if [[ "$recompile" =~ ^[sSyY] ]]; then + case "$s" in + gateway|service-bus) + local jdir; jdir="$(repo_dir "$s")" + info "Compilando ${s} (bootJar, sin tests)..." + ( cd "$jdir" && ./gradlew clean bootJar -x test > "${LOG_DIR}/${s}-rebuild-gradle.log" 2>&1 ) \ + && ok "JAR: $(ls "${jdir}"/build/libs/*.jar 2>/dev/null | head -1)" \ + || { err "Gradle falló (ver ${LOG_DIR}/${s}-rebuild-gradle.log)"; continue; } + ;; + esac + fi + + _docker_build_local "$s" nocache || { err "Build de ${s} falló — sigo con el resto"; continue; } + + info "Recreando contenedor ${s}..." + ( cd "$INFRA_DIR" && $COMPOSE_CMD --profile apps --profile tools up -d --force-recreate "$s" 2>&1 \ + | while read -r l; do echo -e " ${GRAY}${l}${NC}"; done ) + + local url; url="$(svc_health_url "$s")" + if [[ -n "$url" ]]; then + info "Esperando salud de ${s} (hasta 120s)..." + local tries=0 code="000" + while (( tries < 24 )); do + code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 3 "$url" 2>/dev/null || echo "000") + [[ "$code" =~ ^(200|302|401)$ ]] && break + sleep 5; tries=$((tries+1)) + done + [[ "$code" =~ ^(200|302|401)$ ]] && ok "${s} saludable (HTTP ${code})" || warn "${s}: sin health OK (HTTP ${code}) — revisá logs" + else + ok "${s} recreado" + fi + done + cd "$BDT_ROOT" 2>/dev/null || true +} + #=============================================================================== # COMANDO: up - Levantar servicios #=============================================================================== @@ -1028,7 +1130,7 @@ _bdt_completions() { local cur="${COMP_WORDS[COMP_CWORD]}" local prev="${COMP_WORDS[COMP_CWORD-1]}" - local commands="clone pull install build up down restart status logs health verify-db verify-api deploy construir publish env update creds clean setup menu help image-login image-build image-push image-pull image-deploy image-build-amd64 server-deploy" + local commands="clone pull install build rebuild up down restart status logs health verify-db verify-api deploy construir publish env update creds clean setup menu help image-login image-build image-push image-pull image-deploy image-build-amd64 server-deploy" local services="frontend gateway service-bus canales-admin-web canales-worker apibank infrastructure database" local up_targets="all infra apps tools frontend gateway canales-admin-web canales-worker service-bus postgres redis keycloak" local envs="desarrollo calidad demo produccion" @@ -1180,6 +1282,7 @@ _menu_dispatch() { d) cmd_deploy ;; e) cmd_install ;; f) cmd_build all ;; + n) cmd_rebuild ;; g) cmd_clone ;; h) cmd_pull ;; i) @@ -1211,6 +1314,7 @@ cmd_menu() { while true; do banner echo -e " ${O1}${BOLD}0) CONSTRUIR SERVICIO${NC} ${GRAY}— asistente: git banco → build → docker → up${NC}" + echo -e " ${O1}${BOLD}n) REBUILD SIN CACHÉ${NC} ${GRAY}— elegir docker → build --no-cache → up --force-recreate${NC}" echo "" echo -e " ${O2}${BOLD}SERVICIOS${NC} ${O3}${BOLD}MONITOREO${NC} ${O1}${BOLD}VERIFICACION${NC}" echo -e " ${GRAY}$(printf '%.0s─' {1..60})${NC}" @@ -1711,7 +1815,8 @@ cmd_help() { echo "" echo -e " ${O2}${BOLD}COMPILACIÓN${NC}" echo -e " ${WHITE}install${NC} Instalar dependencias + compilar todo" - echo -e " ${WHITE}build${NC} [servicio|all] Construir imágenes Docker" + echo -e " ${WHITE}build${NC} [servicio|all] [--no-cache] Construir imágenes Docker (opcional sin caché)" + echo -e " ${WHITE}rebuild${NC} Interactivo: elegir docker → build --no-cache → up --force-recreate" echo "" echo -e " ${O2}${BOLD}SERVICIOS${NC}" echo -e " ${WHITE}up${NC} [all|infra|apps|tools|nombre] Levantar servicios" @@ -1780,6 +1885,7 @@ case "$cmd" in pull) cmd_pull "$@" ;; install) cmd_install "$@" ;; build) cmd_build "$@" ;; + rebuild|rebuild-nc) cmd_rebuild "$@" ;; up|start) cmd_up "$@" ;; down|stop) cmd_down "$@" ;; restart) cmd_restart "$@" ;;