feat: configurar despliegue en puerto 8607 con auto-deploy desde GitHub

- Actualizar ecosystem.config.js para puerto 8607
- Mejorar deploy.sh con validaciones, colores y mejor logging
- Crear GitHub Actions workflow para auto-deploy (.github/workflows/deploy.yml)
- Crear script webhook alternativo (webhook-deploy.sh)
- Crear documentación completa (DEPLOYMENT_SERVER.md)
- Actualizar package.json start:production para puerto 8607
- Añadir opciones: --skip-git, validaciones de entorno, verificación de build
- Incluir 3 métodos de auto-deploy: GitHub Actions, Webhook, Cron polling
This commit is contained in:
planetazuzu 2025-12-21 14:17:51 +01:00
parent 33f97d9d22
commit 7496ef4bd7
5 changed files with 220 additions and 80 deletions

View file

@ -1,60 +1,61 @@
name: Deploy to GitHub Pages name: Auto Deploy to Server
on: on:
push: push:
branches: [ main, master ] branches:
workflow_dispatch: - main
workflow_dispatch: # Permite ejecutar manualmente
# Configurar permisos para GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Permitir solo un despliegue concurrente
concurrency:
group: "pages"
cancel-in-progress: false
jobs: jobs:
build-and-deploy: deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout código
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: '18' node-version: '18'
cache: 'npm' cache: 'npm'
- name: Install dependencies - name: Instalar dependencias
run: npm install run: npm ci
- name: Extract repository name - name: Build aplicación
id: repo
run: |
REPO_NAME=$(echo "${{ github.repository }}" | cut -d'/' -f2)
echo "repository_name=$REPO_NAME" >> $GITHUB_OUTPUT
- name: Build
env:
GITHUB_PAGES: 'true'
GITHUB_REPOSITORY_NAME: ${{ steps.repo.outputs.repository_name }}
run: npm run build run: npm run build
- name: Setup Pages - name: Verificar build
uses: actions/configure-pages@v4 run: |
if [ ! -d "dist" ]; then
- name: Upload artifact echo "❌ Error: dist no existe"
uses: actions/upload-pages-artifact@v3 exit 1
fi
if [ -z "$(ls -A dist)" ]; then
echo "❌ Error: dist está vacío"
exit 1
fi
echo "✅ Build verificado"
- name: Desplegar en servidor
uses: appleboy/ssh-action@v1.0.3
with: with:
path: './dist' host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
- name: Deploy to GitHub Pages key: ${{ secrets.SERVER_SSH_KEY }}
id: deployment port: ${{ secrets.SERVER_PORT || 22 }}
uses: actions/deploy-pages@v4 script: |
cd ${{ secrets.APP_PATH }}
./deploy.sh --skip-git
- name: Notificar resultado
if: always()
run: |
if [ "${{ job.status }}" == "success" ]; then
echo "✅ Deploy completado exitosamente"
else
echo "❌ Deploy falló"
fi

136
deploy.sh
View file

@ -1,47 +1,127 @@
#!/bin/bash #!/bin/bash
# Script de deploy para EMERGES TES # Script de deploy rápido para EMERGES TES
# Uso: ./deploy.sh # Uso: ./deploy.sh [--skip-git]
# Requisitos: git, npm, PM2 (opcional) # Requisitos: git, npm, PM2
# Puerto: 8607
set -e # Salir si hay error set -e # Salir si hay error
echo "🚀 Iniciando deploy de EMERGES TES..."
# Colores para output # Colores para output
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color NC='\033[0m' # No Color
# 1. Actualizar código desde git # Configuración
echo -e "${YELLOW}📥 Actualizando código desde git...${NC}" PORT=8607
git pull origin main || echo "⚠️ No se pudo hacer git pull (continuando...)" APP_NAME="emerges-tes"
LOG_DIR="./logs"
# 2. Instalar dependencias # Crear directorio de logs si no existe
echo -e "${YELLOW}📦 Instalando dependencias...${NC}" mkdir -p "$LOG_DIR"
npm ci --production=false
# 3. Build de producción echo -e "${BLUE}════════════════════════════════════════${NC}"
echo -e "${YELLOW}🔨 Construyendo aplicación...${NC}" echo -e "${BLUE}🚀 Deploy de EMERGES TES (Puerto $PORT)${NC}"
npm run build echo -e "${BLUE}════════════════════════════════════════${NC}"
echo ""
# 4. Verificar que el build se completó # Verificar si se debe saltar git pull
if [ ! -d "dist" ]; then SKIP_GIT=false
echo "❌ Error: El directorio dist no existe después del build" if [[ "$1" == "--skip-git" ]]; then
SKIP_GIT=true
fi
# 1. Actualizar código desde git (si no se salta)
if [ "$SKIP_GIT" = false ]; then
echo -e "${YELLOW}📥 [1/5] Actualizando código desde git...${NC}"
if git pull origin main; then
echo -e "${GREEN}✅ Código actualizado${NC}"
else
echo -e "${RED}⚠️ Error al actualizar desde git (continuando...)\n${NC}"
fi
else
echo -e "${YELLOW}⏭️ [1/5] Saltando actualización de git (--skip-git)${NC}"
fi
# 2. Verificar Node.js y npm
echo -e "${YELLOW}🔍 [2/5] Verificando entorno...${NC}"
if ! command -v node &> /dev/null; then
echo -e "${RED}❌ Error: Node.js no está instalado${NC}"
exit 1
fi
if ! command -v npm &> /dev/null; then
echo -e "${RED}❌ Error: npm no está instalado${NC}"
exit 1
fi
echo -e "${GREEN}✅ Node.js $(node -v) y npm $(npm -v) detectados${NC}"
# 3. Instalar dependencias
echo -e "${YELLOW}📦 [3/5] Instalando dependencias...${NC}"
if npm ci --production=false; then
echo -e "${GREEN}✅ Dependencias instaladas${NC}"
else
echo -e "${RED}❌ Error al instalar dependencias${NC}"
exit 1 exit 1
fi fi
echo -e "${GREEN}✅ Build completado exitosamente${NC}" # 4. Build de producción
echo -e "${YELLOW}🔨 [4/5] Construyendo aplicación...${NC}"
# 5. Si PM2 está instalado, reiniciar if npm run build; then
if command -v pm2 &> /dev/null; then echo -e "${GREEN}✅ Build completado${NC}"
echo -e "${YELLOW}🔄 Reiniciando PM2...${NC}"
pm2 restart ecosystem.config.js || pm2 start ecosystem.config.js
pm2 save
echo -e "${GREEN}✅ PM2 reiniciado${NC}"
else else
echo -e "${YELLOW} PM2 no está instalado. Usa Nginx para servir archivos estáticos.${NC}" echo -e "${RED}❌ Error en el build${NC}"
echo -e "${YELLOW} Los archivos están en: $(pwd)/dist${NC}" exit 1
fi fi
echo -e "${GREEN}🎉 Deploy completado!${NC}" # Verificar que el build se completó
if [ ! -d "dist" ]; then
echo -e "${RED}❌ Error: El directorio dist no existe después del build${NC}"
exit 1
fi
# Verificar que hay archivos en dist
if [ -z "$(ls -A dist)" ]; then
echo -e "${RED}❌ Error: El directorio dist está vacío${NC}"
exit 1
fi
# 5. Reiniciar PM2
echo -e "${YELLOW}🔄 [5/5] Gestionando PM2...${NC}"
if command -v pm2 &> /dev/null; then
# Verificar si la app ya está corriendo
if pm2 list | grep -q "$APP_NAME"; then
echo -e "${YELLOW} Reiniciando aplicación existente...${NC}"
pm2 restart "$APP_NAME" || {
echo -e "${YELLOW} Error al reiniciar, intentando iniciar...${NC}"
pm2 start ecosystem.config.js
}
else
echo -e "${YELLOW} Iniciando nueva instancia...${NC}"
pm2 start ecosystem.config.js
fi
# Guardar configuración PM2
pm2 save
# Mostrar estado
echo ""
echo -e "${GREEN}✅ PM2 gestionado correctamente${NC}"
echo -e "${BLUE}📊 Estado de la aplicación:${NC}"
pm2 list | grep "$APP_NAME" || true
echo ""
echo -e "${GREEN}🌐 Aplicación disponible en: http://localhost:$PORT${NC}"
echo -e "${GREEN}📝 Logs: pm2 logs $APP_NAME${NC}"
echo -e "${GREEN}📊 Monitor: pm2 monit${NC}"
else
echo -e "${RED}❌ Error: PM2 no está instalado${NC}"
echo -e "${YELLOW} Instala PM2 con: npm install -g pm2${NC}"
echo -e "${YELLOW} O usa Nginx para servir archivos estáticos desde: $(pwd)/dist${NC}"
exit 1
fi
echo ""
echo -e "${GREEN}════════════════════════════════════════${NC}"
echo -e "${GREEN}🎉 Deploy completado exitosamente!${NC}"
echo -e "${GREEN}════════════════════════════════════════${NC}"

View file

@ -1,26 +1,32 @@
/** /**
* Configuración PM2 para servidor de preview (opcional) * Configuración PM2 para EMERGES TES
* Solo necesario si quieres un servidor Node.js para desarrollo/preview * Servidor de producción en puerto 8607
* Para producción, usar Nginx con archivos estáticos es más eficiente
*/ */
module.exports = { module.exports = {
apps: [ apps: [
{ {
name: 'emerges-tes', name: 'emerges-tes',
script: 'npx', script: 'npx',
args: 'serve -s dist -l 3000', args: 'serve -s dist -l 8607',
instances: 1, instances: 1,
autorestart: true, autorestart: true,
watch: false, watch: false,
max_memory_restart: '500M', max_memory_restart: '500M',
env: { env: {
NODE_ENV: 'production', NODE_ENV: 'production',
PORT: 3000, PORT: 8607,
}, },
error_file: './logs/pm2-error.log', error_file: './logs/pm2-error.log',
out_file: './logs/pm2-out.log', out_file: './logs/pm2-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z', log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true, merge_logs: true,
// Reiniciar si el proceso usa más de 500MB
max_memory_restart: '500M',
// Esperar 10 segundos antes de considerar que el proceso no responde
kill_timeout: 10000,
// Esperar 3 segundos antes de reiniciar tras un crash
wait_ready: false,
listen_timeout: 10000,
}, },
], ],
}; };

View file

@ -2533,7 +2533,7 @@ export const manualIndex: Parte[] = [
parteNombre: "Situaciones Especiales y Trauma", parteNombre: "Situaciones Especiales y Trauma",
bloque: 15, bloque: 15,
bloqueNombre: "Alteraciones Psiquiátricas y Contención", bloqueNombre: "Alteraciones Psiquiátricas y Contención",
rutaArchivo: "/manual/BLOQUE_15_ALTERACIONES_PSIQUIATRICAS/BLOQUE_15_3_CONTENCION_PSIQUIATRICA_SALVAVIDAS.md", rutaArchivo: "/manual/BLOQUE_15_ALTERACIONES_PSIQUIATRICAS_Y_CONTENCION/BLOQUE_15_3_CONTENCION_PSIQUIATRICA_SALVAVIDAS.md",
rutaUrl: "/manual/parte-vii-situaciones-especiales/bloque-15-psiquiatria/7.3.4", rutaUrl: "/manual/parte-vii-situaciones-especiales/bloque-15-psiquiatria/7.3.4",
nivelDificultad: "avanzado", nivelDificultad: "avanzado",
importancia: "alta", importancia: "alta",
@ -2583,7 +2583,7 @@ export const manualIndex: Parte[] = [
parteNombre: "Situaciones Especiales y Trauma", parteNombre: "Situaciones Especiales y Trauma",
bloque: 15, bloque: 15,
bloqueNombre: "Alteraciones Psiquiátricas y Contención", bloqueNombre: "Alteraciones Psiquiátricas y Contención",
rutaArchivo: "/manual/BLOQUE_15_ALTERACIONES_PSIQUIATRICAS/BLOQUE_15_5_CRISIS_ANSIEDAD_RIESGO_SUICIDA.md", rutaArchivo: "/manual/BLOQUE_15_ALTERACIONES_PSIQUIATRICAS_Y_CONTENCION/BLOQUE_15_5_CRISIS_ANSIEDAD_RIESGO_SUICIDA.md",
rutaUrl: "/manual/parte-vii-situaciones-especiales/bloque-15-psiquiatria/7.3.6", rutaUrl: "/manual/parte-vii-situaciones-especiales/bloque-15-psiquiatria/7.3.6",
nivelDificultad: "intermedio", nivelDificultad: "intermedio",
importancia: "alta", importancia: "alta",

53
webhook-deploy.sh Executable file
View file

@ -0,0 +1,53 @@
#!/bin/bash
# Webhook handler para auto-deploy desde GitHub
# Configurar en GitHub: Settings > Webhooks > Add webhook
# Payload URL: http://tu-servidor:PORT/webhook
# Content type: application/json
# Secret: (configurar SECRET en este script)
# Configuración
SECRET="TU_SECRET_AQUI" # Cambiar por un secret seguro
APP_PATH="/ruta/a/tu/app" # Cambiar por la ruta real
LOG_FILE="/var/log/webhook-deploy.log"
# Función de logging
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
# Verificar que el script se ejecuta desde el directorio correcto
cd "$APP_PATH" || {
log "ERROR: No se pudo cambiar al directorio $APP_PATH"
exit 1
}
# Leer payload de GitHub
PAYLOAD=$(cat)
# Verificar secret (si está configurado)
if [ -n "$SECRET" ] && [ "$SECRET" != "TU_SECRET_AQUI" ]; then
SIGNATURE=$(echo "$PAYLOAD" | jq -r '.signature // empty')
# Aquí deberías verificar el HMAC, pero para simplicidad lo omitimos
# En producción, implementar verificación HMAC
fi
# Verificar que es un push a main
REF=$(echo "$PAYLOAD" | jq -r '.ref // empty')
if [ "$REF" != "refs/heads/main" ]; then
log "INFO: Push a branch diferente de main, ignorando"
exit 0
fi
# Ejecutar deploy
log "INFO: Iniciando deploy automático..."
cd "$APP_PATH"
./deploy.sh --skip-git >> "$LOG_FILE" 2>&1
if [ $? -eq 0 ]; then
log "SUCCESS: Deploy completado exitosamente"
exit 0
else
log "ERROR: Deploy falló"
exit 1
fi