workspace/projects/gamilit/apps/devops/scripts/deploy.sh
rckrdmrd ea1879f4ad feat: Initial workspace structure with multi-level Git configuration
- Configure workspace Git repository with comprehensive .gitignore
- Add Odoo as submodule for ERP reference code
- Include documentation: SETUP.md, GIT-STRUCTURE.md
- Add gitignore templates for projects (backend, frontend, database)
- Structure supports independent repos per project/subproject level

Workspace includes:
- core/ - Reusable patterns, modules, orchestration system
- projects/ - Active projects (erp-suite, gamilit, trading-platform, etc.)
- knowledge-base/ - Reference code and patterns (includes Odoo submodule)
- devtools/ - Development tools and templates
- customers/ - Client implementations template

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 10:44:23 -06:00

516 lines
14 KiB
Bash
Executable File

#!/bin/bash
##############################################################################
# GAMILIT Platform - Deployment Script
#
# Propósito: Script completo de deployment para desarrollo y producción
#
# Uso:
# ./deploy.sh --env dev # Desarrollo local
# ./deploy.sh --env prod # Producción
# ./deploy.sh --env dev --skip-db # Sin inicializar BD
# ./deploy.sh --env prod --dry-run # Simular deployment
#
# Funcionalidades:
# 1. Validación de prerequisitos (Node, npm, PM2, PostgreSQL)
# 2. Inicialización de base de datos (opcional)
# 3. Build de backend y frontend
# 4. Deployment con PM2
# 5. Validación de health checks
# 6. Rollback automático en caso de error
#
##############################################################################
set -e
# Colores
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m'
# Configuración de rutas
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEVOPS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
APPS_ROOT="$(cd "$DEVOPS_ROOT/.." && pwd)"
GAMILIT_ROOT="$(cd "$APPS_ROOT/.." && pwd)"
BACKEND_DIR="$APPS_ROOT/backend"
FRONTEND_DIR="$APPS_ROOT/frontend"
DATABASE_DIR="$APPS_ROOT/database"
# Variables de configuración
ENVIRONMENT=""
SKIP_DB=false
DRY_RUN=false
SKIP_TESTS=false
# ============================================================================
# FUNCIONES AUXILIARES
# ============================================================================
print_header() {
echo ""
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""
}
print_step() {
echo -e "${CYAN}$1${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}$1${NC}"
}
print_info() {
echo " $1"
}
show_help() {
cat << EOF
GAMILIT Platform - Deployment Script
Uso: $0 [OPCIONES]
Opciones:
--env dev|prod Ambiente (dev o prod) [REQUERIDO]
--skip-db No inicializar base de datos
--skip-tests Omitir tests
--dry-run Simular deployment sin ejecutar
--help Mostrar ayuda
Ejemplos:
$0 --env dev
$0 --env prod --skip-db
$0 --env dev --dry-run
Prerequisitos:
- Node.js >= 18.0.0
- npm >= 9.0.0
- PM2 (global)
- PostgreSQL >= 14
EOF
}
# ============================================================================
# VALIDACIÓN DE PREREQUISITOS
# ============================================================================
check_prerequisites() {
print_step "Validando prerequisitos..."
# Node.js
if ! command -v node &> /dev/null; then
print_error "Node.js no encontrado"
exit 1
fi
local node_version=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
if [ "$node_version" -lt 18 ]; then
print_error "Node.js >= 18.0.0 requerido (actual: $(node -v))"
exit 1
fi
print_success "Node.js $(node -v)"
# npm
if ! command -v npm &> /dev/null; then
print_error "npm no encontrado"
exit 1
fi
print_success "npm $(npm -v)"
# PM2
if ! command -v pm2 &> /dev/null; then
print_warning "PM2 no encontrado"
read -p "¿Instalar PM2 globalmente? (y/n): " install_pm2
if [ "$install_pm2" = "y" ]; then
npm install -g pm2
print_success "PM2 instalado"
else
print_error "PM2 es requerido para deployment"
exit 1
fi
else
print_success "PM2 $(pm2 -v)"
fi
# PostgreSQL (solo si no se salta DB)
if [ "$SKIP_DB" = false ]; then
if ! command -v psql &> /dev/null; then
print_error "PostgreSQL no encontrado"
exit 1
fi
print_success "PostgreSQL encontrado"
fi
# Verificar directorios
if [ ! -d "$BACKEND_DIR" ]; then
print_error "Backend no encontrado: $BACKEND_DIR"
exit 1
fi
print_success "Backend encontrado"
if [ ! -d "$FRONTEND_DIR" ]; then
print_error "Frontend no encontrado: $FRONTEND_DIR"
exit 1
fi
print_success "Frontend encontrado"
if [ ! -d "$DATABASE_DIR" ] && [ "$SKIP_DB" = false ]; then
print_error "Database no encontrado: $DATABASE_DIR"
exit 1
fi
[ "$SKIP_DB" = false ] && print_success "Database encontrado"
}
# ============================================================================
# INICIALIZACIÓN DE BASE DE DATOS
# ============================================================================
initialize_database() {
if [ "$SKIP_DB" = true ]; then
print_warning "Inicialización de BD omitida (--skip-db)"
return 0
fi
print_step "Inicializando base de datos..."
local db_script="$DATABASE_DIR/scripts/init-database.sh"
if [ ! -f "$db_script" ]; then
print_error "Script de BD no encontrado: $db_script"
exit 1
fi
if [ "$DRY_RUN" = true ]; then
print_info "[DRY-RUN] Ejecutaría: $db_script --env $ENVIRONMENT --force"
return 0
fi
# Ejecutar script de inicialización
if bash "$db_script" --env "$ENVIRONMENT" --force; then
print_success "Base de datos inicializada"
else
print_error "Error al inicializar base de datos"
exit 1
fi
}
# ============================================================================
# INSTALACIÓN DE DEPENDENCIAS
# ============================================================================
install_dependencies() {
print_step "Instalando dependencias..."
# Backend
print_info "Backend..."
if [ "$DRY_RUN" = true ]; then
print_info "[DRY-RUN] Ejecutaría: cd $BACKEND_DIR && npm install"
else
cd "$BACKEND_DIR"
if npm install --production=false; then
print_success "Dependencias de backend instaladas"
else
print_error "Error al instalar dependencias de backend"
exit 1
fi
fi
# Frontend
print_info "Frontend..."
if [ "$DRY_RUN" = true ]; then
print_info "[DRY-RUN] Ejecutaría: cd $FRONTEND_DIR && npm install"
else
cd "$FRONTEND_DIR"
if npm install; then
print_success "Dependencias de frontend instaladas"
else
print_error "Error al instalar dependencias de frontend"
exit 1
fi
fi
}
# ============================================================================
# TESTS
# ============================================================================
run_tests() {
if [ "$SKIP_TESTS" = true ]; then
print_warning "Tests omitidos (--skip-tests)"
return 0
fi
print_step "Ejecutando tests..."
# Backend tests
print_info "Tests de backend..."
if [ "$DRY_RUN" = true ]; then
print_info "[DRY-RUN] Ejecutaría: cd $BACKEND_DIR && npm test"
else
cd "$BACKEND_DIR"
if npm test; then
print_success "Tests de backend pasados"
else
print_warning "Tests de backend fallaron (continuando...)"
fi
fi
# Frontend tests
print_info "Tests de frontend..."
if [ "$DRY_RUN" = true ]; then
print_info "[DRY-RUN] Ejecutaría: cd $FRONTEND_DIR && npm run test:run"
else
cd "$FRONTEND_DIR"
if npm run test:run; then
print_success "Tests de frontend pasados"
else
print_warning "Tests de frontend fallaron (continuando...)"
fi
fi
}
# ============================================================================
# BUILD
# ============================================================================
build_applications() {
print_step "Building aplicaciones..."
# Backend
print_info "Building backend..."
if [ "$DRY_RUN" = true ]; then
print_info "[DRY-RUN] Ejecutaría: cd $BACKEND_DIR && npm run build"
else
cd "$BACKEND_DIR"
if npm run build; then
print_success "Backend built exitosamente"
else
print_error "Error al hacer build de backend"
exit 1
fi
fi
# Frontend
print_info "Building frontend..."
if [ "$DRY_RUN" = true ]; then
print_info "[DRY-RUN] Ejecutaría: cd $FRONTEND_DIR && npm run build:prod"
else
cd "$FRONTEND_DIR"
if npm run build:prod; then
print_success "Frontend built exitosamente"
else
print_error "Error al hacer build de frontend"
exit 1
fi
fi
}
# ============================================================================
# DEPLOYMENT CON PM2
# ============================================================================
deploy_with_pm2() {
print_step "Deploying con PM2..."
cd "$GAMILIT_ROOT"
# Crear directorio de logs
mkdir -p logs
if [ "$DRY_RUN" = true ]; then
print_info "[DRY-RUN] Ejecutaría: pm2 startOrRestart ecosystem.config.js --env $ENVIRONMENT"
return 0
fi
# Verificar si el ecosystem config existe
if [ ! -f "ecosystem.config.js" ]; then
print_error "ecosystem.config.js no encontrado"
exit 1
fi
# Deployment según ambiente
if [ "$ENVIRONMENT" = "prod" ] || [ "$ENVIRONMENT" = "production" ]; then
# Producción - solo backend
print_info "Iniciando backend en producción..."
pm2 startOrRestart ecosystem.config.js --only gamilit-backend --env production
print_success "Backend deployed con PM2"
print_info "Para servir el frontend en producción, usar Nginx/Apache"
print_info "O ejecutar: pm2 start ecosystem.config.js --only gamilit-frontend-preview --env production"
else
# Desarrollo - backend + frontend
print_info "Iniciando backend y frontend en desarrollo..."
pm2 startOrRestart ecosystem.config.js --env development
print_success "Backend y Frontend deployed con PM2"
fi
# Guardar configuración PM2
pm2 save
print_success "Deployment completado"
}
# ============================================================================
# HEALTH CHECKS
# ============================================================================
health_check() {
print_step "Validando health checks..."
if [ "$DRY_RUN" = true ]; then
print_info "[DRY-RUN] Omitiría health checks"
return 0
fi
# Esperar a que el servidor inicie
print_info "Esperando 10 segundos para que los servicios inicien..."
sleep 10
# Backend health check
print_info "Verificando backend..."
local backend_port=3006
if curl -s http://localhost:$backend_port/api/health > /dev/null 2>&1; then
print_success "Backend respondiendo en puerto $backend_port"
else
print_warning "Backend no responde en puerto $backend_port"
print_info "Verificar con: pm2 logs gamilit-backend"
fi
# Frontend health check (solo en dev)
if [ "$ENVIRONMENT" = "dev" ] || [ "$ENVIRONMENT" = "development" ]; then
print_info "Verificando frontend..."
local frontend_port=3005
if curl -s http://localhost:$frontend_port > /dev/null 2>&1; then
print_success "Frontend respondiendo en puerto $frontend_port"
else
print_warning "Frontend no responde en puerto $frontend_port"
print_info "Verificar con: pm2 logs gamilit-frontend-dev"
fi
fi
# Mostrar status de PM2
echo ""
pm2 status
}
# ============================================================================
# RESUMEN
# ============================================================================
show_summary() {
print_header "✅ DEPLOYMENT COMPLETADO"
echo -e "${CYAN}Ambiente:${NC} $ENVIRONMENT"
echo -e "${CYAN}Servidor de base de datos:${NC} localhost:5432"
echo ""
echo -e "${CYAN}Servicios desplegados:${NC}"
echo -e " ${GREEN}${NC} Backend API: http://localhost:3006"
echo -e " ${GREEN}${NC} API Docs: http://localhost:3006/api/docs"
if [ "$ENVIRONMENT" = "dev" ] || [ "$ENVIRONMENT" = "development" ]; then
echo -e " ${GREEN}${NC} Frontend: http://localhost:3005"
fi
echo ""
echo -e "${CYAN}Comandos útiles:${NC}"
echo -e " pm2 status # Ver status de procesos"
echo -e " pm2 logs # Ver logs en tiempo real"
echo -e " pm2 logs gamilit-backend # Logs del backend"
echo -e " pm2 restart all # Reiniciar todos los procesos"
echo -e " pm2 stop all # Detener todos los procesos"
echo -e " pm2 monit # Monitor interactivo"
echo ""
}
# ============================================================================
# MAIN
# ============================================================================
main() {
# Parsear argumentos
while [[ $# -gt 0 ]]; do
case $1 in
--env)
ENVIRONMENT="$2"
shift 2
;;
--skip-db)
SKIP_DB=true
shift
;;
--skip-tests)
SKIP_TESTS=true
shift
;;
--dry-run)
DRY_RUN=true
shift
;;
--help)
show_help
exit 0
;;
*)
print_error "Opción desconocida: $1"
show_help
exit 1
;;
esac
done
# Validar argumentos
if [ -z "$ENVIRONMENT" ]; then
print_error "Debe especificar --env dev|prod"
show_help
exit 1
fi
# Normalizar ambiente
if [ "$ENVIRONMENT" = "production" ]; then
ENVIRONMENT="prod"
elif [ "$ENVIRONMENT" = "development" ]; then
ENVIRONMENT="dev"
fi
if [ "$ENVIRONMENT" != "dev" ] && [ "$ENVIRONMENT" != "prod" ]; then
print_error "Ambiente debe ser 'dev' o 'prod'"
exit 1
fi
# Mostrar banner
if [ "$DRY_RUN" = true ]; then
print_header "🚀 GAMILIT DEPLOYMENT (DRY-RUN) - $ENVIRONMENT"
else
print_header "🚀 GAMILIT DEPLOYMENT - $ENVIRONMENT"
fi
# Ejecutar pasos
check_prerequisites
initialize_database
install_dependencies
run_tests
build_applications
deploy_with_pm2
health_check
show_summary
}
main "$@"