diff --git a/docs/PLAN_CONVERSION_SCORM.md b/docs/PLAN_CONVERSION_SCORM.md new file mode 100644 index 00000000..baec905d --- /dev/null +++ b/docs/PLAN_CONVERSION_SCORM.md @@ -0,0 +1,629 @@ +# 📦 Plan de Conversión Progresiva a SCORM + +**Fecha:** 2024-12-30 +**Estado:** Planificación +**Objetivo:** Convertir guías de refuerzo a SCORM sin romper la app actual + +--- + +## 🎯 Resumen Ejecutivo + +**Objetivo:** Convertir progresivamente las guías de refuerzo (actualmente en Markdown) a paquetes SCORM 1.2/2004, manteniendo la funcionalidad actual intacta y permitiendo que ambas versiones coexistan. + +**Estrategia:** Arquitectura paralela que permite: +- ✅ Mantener guías actuales funcionando (Markdown) +- ✅ Generar paquetes SCORM progresivamente +- ✅ No modificar código existente +- ✅ Migración guía por guía +- ✅ Reversibilidad completa + +--- + +## 📊 Situación Actual + +### Estructura de Guías Actual + +``` +src/ +├── data/ +│ └── guides-index.ts # Índice de guías (2 guías actualmente) +├── views/formativo/ +│ ├── GuideIndex.tsx # Lista de guías +│ ├── GuideViewer.tsx # Visualizador con tabs +│ └── GuideSectionViewer.tsx # Visualizador de sección individual +├── components/guide/ +│ ├── GuideCard.tsx +│ ├── GuideHeader.tsx +│ ├── GuideNavigation.tsx +│ └── GuideMarkdownViewer.tsx # Wrapper de MarkdownViewer +└── layouts/ + └── GuideLayout.tsx + +docs/consolidado/ +├── SECCION_01_ABCDE_OPERATIVO.md +├── SECCION_02_ABCDE_OPERATIVO.md +├── ... (8 secciones por guía) +├── SECCION_01_RCP_ADULTO_SVB.md +└── ... (8 secciones por guía) + +public/docs/consolidado/ +└── [81 archivos .md copiados] +``` + +### Características Actuales + +- ✅ 8 secciones fijas por guía +- ✅ Navegación por tabs y URLs directas +- ✅ Contenido en Markdown +- ✅ Enlaces a protocolos operativos +- ✅ Badge "Modo Formación" +- ✅ Layout diferenciado (sin BottomNav) + +### Guías Existentes + +1. **ABCDE Operativo** (`abcde-operativo`) + - 8 secciones + - Protocolo operativo relacionado: `/manual/parte-i-fundamentos/bloque-1-procedimientos-basicos/1.2.2` + +2. **RCP Adulto SVB** (`rcp-adulto-svb`) + - 8 secciones + - Protocolo operativo relacionado: `/rcp` + +--- + +## 📚 Requisitos SCORM + +### ¿Qué es SCORM? + +**SCORM (Sharable Content Object Reference Model)** es un estándar para contenido e-learning que permite: +- Interoperabilidad entre LMS (Moodle, Blackboard, Canvas, etc.) +- Tracking de progreso (completado, tiempo, puntuación) +- Reutilización de contenido +- Portabilidad entre plataformas + +### Versiones SCORM + +- **SCORM 1.2** (más compatible, recomendado para empezar) +- **SCORM 2004** (más avanzado, mejor tracking) + +### Estructura de un Paquete SCORM + +``` +paquete-scorm/ +├── imsmanifest.xml # Manifest principal (obligatorio) +├── [carpeta-contenido]/ +│ ├── index.html # Punto de entrada +│ ├── assets/ +│ │ ├── css/ +│ │ ├── js/ +│ │ └── images/ +│ └── sections/ # Secciones del curso +│ ├── section-01.html +│ ├── section-02.html +│ └── ... +└── [archivos SCORM API] + ├── APIWrapper.js # Wrapper SCORM API + └── SCORM_API_1484_11.js # API SCORM 2004 (opcional) +``` + +### Funcionalidades SCORM Necesarias + +1. **Tracking Básico:** + - `cmi.core.lesson_status` (completed, incomplete, passed, failed) + - `cmi.core.score.raw` (puntuación 0-100) + - `cmi.core.total_time` (tiempo total) + - `cmi.core.lesson_location` (última posición) + +2. **Navegación:** + - Progreso entre secciones + - Botones anterior/siguiente + - Indicador de progreso + +3. **Contenido:** + - HTML estático (no React) + - CSS embebido o externo + - JavaScript para SCORM API + - Imágenes y assets + +--- + +## 🏗️ Arquitectura Propuesta + +### Principios de Diseño + +1. **No romper nada existente** + - Las guías actuales siguen funcionando + - No modificar `GuideViewer`, `GuideMarkdownViewer`, etc. + +2. **Arquitectura paralela** + - Nueva carpeta `scorm/` para paquetes SCORM + - Scripts de generación separados + - Build independiente + +3. **Migración progresiva** + - Convertir guía por guía + - Marcar en `guides-index.ts` si tiene versión SCORM + - Permitir elegir formato (Markdown o SCORM) + +4. **Reutilización de contenido** + - Convertir Markdown → HTML + - Reutilizar estilos Tailwind (compilados) + - Mantener estructura de 8 secciones + +### Estructura de Carpetas Propuesta + +``` +proyecto/ +├── src/ # App React (NO TOCAR) +│ └── [estructura actual] +│ +├── scorm/ # 🆕 NUEVA: Paquetes SCORM +│ ├── generator/ # Scripts de generación +│ │ ├── markdown-to-html.ts # Convertir MD → HTML +│ │ ├── scorm-builder.ts # Generar paquete SCORM +│ │ ├── manifest-generator.ts # Generar imsmanifest.xml +│ │ └── package-builder.ts # Empaquetar ZIP +│ │ +│ ├── templates/ # Plantillas SCORM +│ │ ├── index.html # Template principal +│ │ ├── section.html # Template de sección +│ │ ├── scorm-api.js # SCORM API wrapper +│ │ └── styles.css # Estilos compilados +│ │ +│ ├── packages/ # Paquetes SCORM generados +│ │ ├── abcde-operativo/ +│ │ │ ├── imsmanifest.xml +│ │ │ ├── index.html +│ │ │ └── ... +│ │ └── rcp-adulto-svb/ +│ │ └── ... +│ │ +│ └── dist/ # Paquetes ZIP listos para LMS +│ ├── abcde-operativo-scorm-1.2.zip +│ └── rcp-adulto-svb-scorm-1.2.zip +│ +├── docs/consolidado/ # Markdown original (NO TOCAR) +│ └── [archivos .md] +│ +└── scripts/ + └── generate-scorm.ts # Script principal de generación +``` + +--- + +## 🔄 Flujo de Conversión + +### Proceso de Generación + +``` +1. Leer guides-index.ts + ↓ +2. Para cada guía marcada como "convertible a SCORM": + ↓ +3. Leer 8 archivos Markdown de docs/consolidado/ + ↓ +4. Convertir Markdown → HTML (usando remark/rehype) + ↓ +5. Aplicar template HTML con estilos Tailwind + ↓ +6. Generar imsmanifest.xml con metadatos + ↓ +7. Inyectar SCORM API JavaScript + ↓ +8. Copiar assets (imágenes, etc.) + ↓ +9. Generar paquete ZIP + ↓ +10. Guardar en scorm/dist/ +``` + +### Tracking SCORM + +```javascript +// Ejemplo de tracking básico +SCORM.setValue("cmi.core.lesson_status", "incomplete"); +SCORM.setValue("cmi.core.score.raw", "0"); +SCORM.setValue("cmi.core.total_time", "00:00:00"); + +// Al completar una sección +SCORM.setValue("cmi.core.lesson_location", "section-3"); +SCORM.setValue("cmi.core.score.raw", "37.5"); // 3/8 secciones + +// Al completar todo +SCORM.setValue("cmi.core.lesson_status", "completed"); +SCORM.setValue("cmi.core.score.raw", "100"); +``` + +--- + +## 📋 Plan de Implementación por Fases + +### FASE 1: Infraestructura Base (Sin tocar app actual) + +**Objetivo:** Crear estructura y herramientas de generación + +**Tareas:** +1. ✅ Crear carpeta `scorm/` y subcarpetas +2. ✅ Instalar dependencias necesarias: + - `remark` / `rehype` (ya existen) + - `jszip` (para generar ZIP) + - `xml2js` o `fast-xml-parser` (para XML) +3. ✅ Crear templates HTML básicos +4. ✅ Crear SCORM API wrapper (JavaScript vanilla) +5. ✅ Script de prueba: convertir 1 sección MD → HTML + +**Criterios de éxito:** +- ✅ Script genera HTML válido desde Markdown +- ✅ HTML se ve correctamente en navegador +- ✅ No se modifica código de la app React + +**Tiempo estimado:** 2-3 días + +--- + +### FASE 2: Generador de Paquetes SCORM + +**Objetivo:** Generar paquete SCORM completo para 1 guía + +**Tareas:** +1. ✅ Script para convertir 8 secciones MD → HTML +2. ✅ Generar `imsmanifest.xml` con metadatos correctos +3. ✅ Integrar SCORM API en HTML +4. ✅ Implementar tracking básico (progreso, tiempo) +5. ✅ Copiar assets (imágenes) al paquete +6. ✅ Generar ZIP del paquete + +**Criterios de éxito:** +- ✅ Paquete ZIP se puede importar en LMS de prueba (Moodle) +- ✅ Tracking funciona (completado, progreso) +- ✅ Navegación entre secciones funciona +- ✅ Contenido se ve correctamente + +**Tiempo estimado:** 3-4 días + +--- + +### FASE 3: Integración Opcional en App (Sin romper actual) + +**Objetivo:** Permitir descargar/visualizar SCORM desde la app (opcional) + +**Tareas:** +1. ✅ Extender `guides-index.ts` con campo `scormAvailable: boolean` +2. ✅ Añadir botón "Descargar SCORM" en `GuideCard` (solo si disponible) +3. ✅ Servir paquetes ZIP desde `public/scorm/dist/` +4. ✅ Página de información sobre SCORM (opcional) + +**Criterios de éxito:** +- ✅ Las guías actuales siguen funcionando igual +- ✅ Nueva funcionalidad es opcional y no afecta flujo actual +- ✅ Descarga de ZIP funciona + +**Tiempo estimado:** 1-2 días + +--- + +### FASE 4: Migración Progresiva de Guías + +**Objetivo:** Convertir guías una por una + +**Tareas:** +1. ✅ Convertir "ABCDE Operativo" a SCORM +2. ✅ Probar en LMS real +3. ✅ Ajustar estilos/tracking según feedback +4. ✅ Convertir "RCP Adulto SVB" a SCORM +5. ✅ Documentar proceso para futuras guías + +**Criterios de éxito:** +- ✅ Ambas guías tienen versión SCORM funcional +- ✅ Proceso documentado para nuevas guías +- ✅ App React sigue funcionando igual + +**Tiempo estimado:** 2-3 días por guía + +--- + +### FASE 5: Mejoras y Optimización + +**Objetivo:** Mejorar calidad y funcionalidades SCORM + +**Tareas:** +1. ✅ Añadir tracking avanzado (tiempo por sección) +2. ✅ Mejorar estilos para diferentes LMS +3. ✅ Añadir cuestionarios/evaluaciones (opcional) +4. ✅ Optimizar tamaño de paquetes +5. ✅ Documentación completa + +**Tiempo estimado:** 2-3 días + +--- + +## 🛠️ Herramientas y Dependencias + +### Dependencias Nuevas Necesarias + +```json +{ + "devDependencies": { + "jszip": "^3.10.1", // Generar ZIP + "fast-xml-parser": "^4.3.2", // Generar XML + "@types/jszip": "^3.4.1" + } +} +``` + +### Herramientas Existentes (Reutilizar) + +- ✅ `remark` / `rehype` (ya instalados) +- ✅ `react-markdown` (para referencia, pero SCORM usará HTML estático) +- ✅ Tailwind CSS (compilar a CSS estático) + +### Scripts NPM Nuevos + +```json +{ + "scripts": { + "scorm:generate": "tsx scripts/generate-scorm.ts", + "scorm:generate:abcde": "tsx scripts/generate-scorm.ts --guide abcde-operativo", + "scorm:generate:rcp": "tsx scripts/generate-scorm.ts --guide rcp-adulto-svb", + "scorm:build:all": "npm run scorm:generate" + } +} +``` + +--- + +## 📐 Diseño Técnico Detallado + +### 1. Conversión Markdown → HTML + +**Estrategia:** +- Usar `remark` + `rehype` para parsear Markdown +- Convertir a HTML con plugins: + - `remark-gfm` (tablas, strikethrough) + - `rehype-highlight` (syntax highlighting) + - `rehype-raw` (HTML crudo si existe) +- Aplicar clases Tailwind compiladas + +**Código ejemplo:** +```typescript +import { remark } from 'remark'; +import remarkGfm from 'remark-gfm'; +import rehypeHighlight from 'rehype-highlight'; +import rehypeStringify from 'rehype-stringify'; +import remarkRehype from 'remark-rehype'; + +async function markdownToHtml(markdown: string): Promise { + const result = await remark() + .use(remarkGfm) + .use(remarkRehype) + .use(rehypeHighlight) + .use(rehypeStringify) + .process(markdown); + + return result.toString(); +} +``` + +### 2. Template HTML SCORM + +**Estructura:** +```html + + + + + Guía de Refuerzo - [Título] + + + + +
+
+

[Título Guía]

+
Sección X de 8
+
+
+
+ [HTML de la sección convertida desde Markdown] +
+ +
+
+ + + +``` + +### 3. SCORM API Wrapper + +**Funcionalidades:** +- Detectar LMS (SCORM 1.2 o 2004) +- Inicializar comunicación +- Guardar progreso +- Manejar errores + +**Ejemplo:** +```javascript +// scorm-api.js +const SCORM = { + API: null, + initialized: false, + + init() { + // Buscar API del LMS + this.API = this.findAPI(); + if (this.API) { + this.initialized = true; + this.setValue("cmi.core.lesson_status", "incomplete"); + } + }, + + setValue(element, value) { + if (!this.initialized) return false; + const result = this.API.LMSSetValue(element, value); + return result === "true"; + }, + + getValue(element) { + if (!this.initialized) return ""; + return this.API.LMSGetValue(element); + }, + + save() { + return this.API.LMSCommit(""); + } +}; +``` + +### 4. Generación de imsmanifest.xml + +**Estructura básica:** +```xml + + + + ADL SCORM + 1.2 + ABCDE Operativo - Guía de Refuerzo + Guía formativa sobre el enfoque ABCDE + + + + ABCDE Operativo + + Sección 1: Introducción + + + + + + + + + + + + +``` + +--- + +## ✅ Checklist de Implementación + +### Fase 1: Infraestructura +- [ ] Crear carpeta `scorm/` y subcarpetas +- [ ] Instalar dependencias (`jszip`, `fast-xml-parser`) +- [ ] Crear template HTML básico +- [ ] Crear SCORM API wrapper +- [ ] Script de prueba: MD → HTML + +### Fase 2: Generador +- [ ] Script convertir 8 secciones MD → HTML +- [ ] Generar `imsmanifest.xml` +- [ ] Integrar SCORM API +- [ ] Implementar tracking +- [ ] Copiar assets +- [ ] Generar ZIP + +### Fase 3: Integración (Opcional) +- [ ] Extender `guides-index.ts` +- [ ] Botón "Descargar SCORM" en `GuideCard` +- [ ] Servir paquetes desde `public/` +- [ ] Página información SCORM + +### Fase 4: Migración +- [ ] Convertir "ABCDE Operativo" +- [ ] Probar en LMS +- [ ] Convertir "RCP Adulto SVB" +- [ ] Documentar proceso + +### Fase 5: Mejoras +- [ ] Tracking avanzado +- [ ] Optimización estilos +- [ ] Documentación completa + +--- + +## 🚨 Riesgos y Mitigaciones + +### Riesgo 1: Estilos Tailwind no funcionan en HTML estático +**Mitigación:** Compilar Tailwind a CSS estático antes de generar SCORM + +### Riesgo 2: Imágenes no se cargan en SCORM +**Mitigación:** Copiar todas las imágenes al paquete y usar rutas relativas + +### Riesgo 3: SCORM no funciona en algunos LMS +**Mitigación:** Probar en múltiples LMS (Moodle, Canvas, Blackboard) + +### Riesgo 4: Tamaño de paquetes muy grande +**Mitigación:** Optimizar imágenes, minificar CSS/JS, code splitting + +### Riesgo 5: Tracking no se guarda correctamente +**Mitigación:** Implementar logging, probar en LMS real, manejar errores + +--- + +## 📊 Métricas de Éxito + +1. **Funcionalidad:** + - ✅ Paquetes SCORM se importan correctamente en LMS + - ✅ Tracking funciona (progreso, completado) + - ✅ Navegación entre secciones funciona + - ✅ Contenido se ve correctamente + +2. **Calidad:** + - ✅ HTML válido + - ✅ CSS funciona correctamente + - ✅ JavaScript sin errores + - ✅ Accesibilidad (WCAG básico) + +3. **Compatibilidad:** + - ✅ SCORM 1.2 funciona + - ✅ Compatible con Moodle, Canvas, Blackboard + - ✅ Tamaño de paquete < 10MB (ideal) + +4. **No regresiones:** + - ✅ App React sigue funcionando igual + - ✅ Guías Markdown siguen accesibles + - ✅ No se rompe nada existente + +--- + +## 📚 Recursos y Referencias + +### Documentación SCORM +- [SCORM 1.2 Specification](https://www.adlnet.gov/scorm/scorm-1-2/) +- [SCORM 2004 Specification](https://www.adlnet.gov/scorm/scorm-2004-4th-edition/) +- [Rustici SCORM Cloud (para testing)](https://cloud.scorm.com/) + +### Herramientas +- [SCORM Test Suite](https://www.adlnet.gov/adl-research/scorm/) +- [Moodle (LMS de prueba gratuito)](https://moodle.org/) + +### Librerías JavaScript +- `jszip` - Generar archivos ZIP +- `fast-xml-parser` - Parsear/generar XML +- `remark` / `rehype` - Procesar Markdown (ya instalados) + +--- + +## 🎯 Próximos Pasos Inmediatos + +1. **Revisar y aprobar este plan** +2. **Crear estructura de carpetas `scorm/`** +3. **Instalar dependencias necesarias** +4. **Crear script de prueba básico (Fase 1)** +5. **Iterar y mejorar** + +--- + +**Estado:** ✅ Plan completo listo para implementación +**Última actualización:** 2024-12-30 + diff --git a/docs/SCORM_QUICK_START.md b/docs/SCORM_QUICK_START.md new file mode 100644 index 00000000..1dc2bac9 --- /dev/null +++ b/docs/SCORM_QUICK_START.md @@ -0,0 +1,106 @@ +# 🚀 SCORM Quick Start Guide + +**Guía rápida para empezar la conversión a SCORM** + +--- + +## 📋 Checklist Rápido + +### Antes de Empezar + +- [ ] Leer `PLAN_CONVERSION_SCORM.md` completo +- [ ] Entender estructura actual de guías +- [ ] Tener acceso a un LMS de prueba (Moodle, Canvas, etc.) + +### Fase 1: Setup Inicial + +```bash +# 1. Crear estructura de carpetas +mkdir -p scorm/{generator,templates,packages,dist} + +# 2. Instalar dependencias +npm install --save-dev jszip fast-xml-parser @types/jszip + +# 3. Crear script base +touch scripts/generate-scorm.ts +``` + +--- + +## 🎯 Objetivo de la Primera Iteración + +**Convertir 1 sección de Markdown a HTML estático con:** +- ✅ HTML válido +- ✅ Estilos básicos +- ✅ Estructura SCORM básica + +--- + +## 📝 Ejemplo de Código Inicial + +### `scripts/generate-scorm.ts` (Esqueleto) + +```typescript +import { readFile } from 'fs/promises'; +import { remark } from 'remark'; +import remarkGfm from 'remark-gfm'; +import remarkRehype from 'remark-rehype'; +import rehypeStringify from 'rehype-stringify'; + +async function convertMarkdownToHtml(markdownPath: string): Promise { + const markdown = await readFile(markdownPath, 'utf-8'); + + const result = await remark() + .use(remarkGfm) + .use(remarkRehype) + .use(rehypeStringify) + .process(markdown); + + return result.toString(); +} + +// Uso +const html = await convertMarkdownToHtml('docs/consolidado/SECCION_01_ABCDE_OPERATIVO.md'); +console.log(html); +``` + +--- + +## 🧪 Testing Inicial + +1. **Probar conversión MD → HTML:** + ```bash + npm run scorm:test + ``` + +2. **Verificar HTML generado:** + - Abrir en navegador + - Verificar que se ve correctamente + - Verificar que no hay errores + +3. **Probar en LMS (cuando tengas paquete):** + - Importar ZIP en Moodle/Canvas + - Verificar que se carga + - Verificar tracking básico + +--- + +## 📚 Recursos Útiles + +- **SCORM Test Suite:** https://www.adlnet.gov/adl-research/scorm/ +- **Moodle (gratis):** https://moodle.org/ +- **SCORM Cloud (testing):** https://cloud.scorm.com/ + +--- + +## ⚠️ Recordatorios Importantes + +1. **NO modificar código existente** de la app React +2. **NO tocar** `GuideViewer`, `GuideMarkdownViewer`, etc. +3. **Sí crear** nueva carpeta `scorm/` separada +4. **Sí probar** cada paso antes de continuar + +--- + +**Siguiente paso:** Revisar `PLAN_CONVERSION_SCORM.md` y empezar Fase 1 + diff --git a/scripts/deploy/COMANDOS_DEPLOY.md b/scripts/deploy/COMANDOS_DEPLOY.md new file mode 100644 index 00000000..9f3721f5 --- /dev/null +++ b/scripts/deploy/COMANDOS_DEPLOY.md @@ -0,0 +1,272 @@ +# 🚀 COMANDOS EXACTOS PARA CONFIGURAR DESPLIEGUE + +## 📋 CONFIGURACIÓN INICIAL (Ejecutar en el servidor) + +### Paso 1: Conectarse al servidor + +```bash +ssh root@207.180.226.141 +``` + +### Paso 2: Crear el hook post-receive + +```bash +# Variables +GIT_DIR="/var/repos/emerges-tes.git" +APP_DIR="/var/www/emerges-tes" +HOOK_FILE="$GIT_DIR/hooks/post-receive" +LOG_FILE="/var/log/emerges-tes-deploy.log" + +# Crear el hook +cat > "$HOOK_FILE" << 'HOOK_EOF' +#!/bin/bash +set -e + +APP_DIR="/var/www/emerges-tes" +BRANCH="main" +LOG_FILE="/var/log/emerges-tes-deploy.log" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" +} + +log "==========================================" +log "🚀 Iniciando despliegue automático" +log "==========================================" + +while read oldrev newrev refname; do + branch=$(git rev-parse --symbolic --abbrev-ref $refname) + + if [ "$branch" = "$BRANCH" ]; then + log "📦 Actualizando rama: $branch" + log " Commit anterior: $oldrev" + log " Commit nuevo: $newrev" + + if [ ! -d "$APP_DIR" ]; then + log "❌ ERROR: Directorio $APP_DIR no existe" + exit 1 + fi + + cd "$APP_DIR" || { + log "❌ ERROR: No se puede acceder a $APP_DIR" + exit 1 + } + + log "📥 Obteniendo cambios del repositorio..." + git fetch origin "$BRANCH" || { + log "❌ ERROR: Fallo al hacer fetch" + exit 1 + } + + log "🔄 Haciendo checkout limpio..." + git reset --hard "origin/$BRANCH" || { + log "❌ ERROR: Fallo al hacer reset" + exit 1 + } + + log "🧹 Limpiando archivos no rastreados..." + git clean -fd || { + log "⚠️ ADVERTENCIA: Fallo al limpiar archivos" + } + + log "📦 Instalando dependencias (npm install)..." + if ! npm install --production=false 2>&1 | tee -a "$LOG_FILE"; then + log "❌ ERROR: Fallo al instalar dependencias" + exit 1 + fi + log "✅ Dependencias instaladas correctamente" + + log "🔨 Construyendo aplicación (npm run build)..." + if ! npm run build 2>&1 | tee -a "$LOG_FILE"; then + log "❌ ERROR: Fallo al construir la aplicación" + exit 1 + fi + log "✅ Build completado correctamente" + + if [ ! -d "$APP_DIR/dist" ]; then + log "❌ ERROR: El directorio dist/ no existe después del build" + exit 1 + fi + + log "✅ Despliegue completado exitosamente" + log " Aplicación disponible en: $APP_DIR/dist" + log "==========================================" + + exit 0 + else + log "⏭️ Ignorando push en rama: $branch (solo se despliega $BRANCH)" + fi +done + +log "⚠️ No se procesó ningún cambio" +exit 0 +HOOK_EOF + +# Dar permisos de ejecución +chmod +x "$HOOK_FILE" + +# Verificar +ls -la "$HOOK_FILE" +``` + +### Paso 3: Configurar directorio de trabajo + +```bash +# Si el directorio no existe, crearlo +if [ ! -d "$APP_DIR" ]; then + mkdir -p "$APP_DIR" +fi + +# Si no tiene .git, clonar el repositorio +if [ ! -d "$APP_DIR/.git" ]; then + git clone "$GIT_DIR" "$APP_DIR" +fi +``` + +### Paso 4: Crear archivo de logs + +```bash +# Crear archivo de logs +touch "$LOG_FILE" +chmod 666 "$LOG_FILE" + +# Verificar +ls -la "$LOG_FILE" +``` + +### Paso 5: Verificar Node.js (si no está instalado) + +```bash +# Verificar si Node.js está instalado +node --version || { + echo "⚠️ Node.js no está instalado. Instalando..." + curl -fsSL https://deb.nodesource.com/setup_20.x | bash - + apt-get install -y nodejs + node --version + npm --version +} +``` + +--- + +## 🧪 PROBAR EL DESPLIEGUE + +### Desde tu máquina local: + +```bash +cd /home/planetazuzu/guia-tes + +# Hacer un cambio de prueba +echo "# Test deploy $(date)" >> README.md +git add README.md +git commit -m "test: probar despliegue automático" + +# Push (esto activará el hook automáticamente) +git push production main +``` + +### En el servidor, ver logs: + +```bash +# Ver logs en tiempo real +tail -f /var/log/emerges-tes-deploy.log +``` + +### Verificar build: + +```bash +# Verificar que dist/ existe +ls -la /var/www/emerges-tes/dist/ + +# Ver contenido +ls -la /var/www/emerges-tes/dist/assets/ 2>/dev/null | head -10 +``` + +--- + +## ✅ VERIFICACIÓN COMPLETA + +Ejecutar en el servidor: + +```bash +# 1. Hook existe y es ejecutable +test -x /var/repos/emerges-tes.git/hooks/post-receive && echo "✅ Hook OK" || echo "❌ Hook no ejecutable" + +# 2. Directorio de trabajo existe +test -d /var/www/emerges-tes && echo "✅ Directorio OK" || echo "❌ Directorio no existe" + +# 3. Logs se pueden escribir +test -w /var/log/emerges-tes-deploy.log && echo "✅ Logs OK" || echo "❌ Logs no escribibles" + +# 4. Node.js instalado +command -v node >/dev/null && echo "✅ Node.js: $(node --version)" || echo "❌ Node.js no instalado" + +# 5. npm instalado +command -v npm >/dev/null && echo "✅ npm: $(npm --version)" || echo "❌ npm no instalado" +``` + +--- + +## 🔍 TROUBLESHOOTING RÁPIDO + +### El hook no se ejecuta + +```bash +# Verificar permisos +ls -la /var/repos/emerges-tes.git/hooks/post-receive + +# Debe mostrar: -rwxr-xr-x +# Si no, ejecutar: +chmod +x /var/repos/emerges-tes.git/hooks/post-receive +``` + +### Ver logs de errores + +```bash +# Ver últimos 100 líneas +tail -n 100 /var/log/emerges-tes-deploy.log + +# Buscar errores +grep -i error /var/log/emerges-tes-deploy.log + +# Ver todo el log +cat /var/log/emerges-tes-deploy.log +``` + +### Probar manualmente + +```bash +# Desde el servidor, probar el proceso manualmente +cd /var/www/emerges-tes +git pull origin main +npm install +npm run build + +# Verificar resultado +ls -la dist/ +``` + +--- + +## 📊 ESTRUCTURA FINAL + +``` +/var/repos/emerges-tes.git/ # Repositorio bare +└── hooks/ + └── post-receive # Hook (ejecutable) + +/var/www/emerges-tes/ # Directorio de trabajo +├── .git/ # Clon del repositorio +├── src/ # Código fuente +├── dist/ # Build de producción (generado) +└── node_modules/ # Dependencias (generado) + +/var/log/emerges-tes-deploy.log # Logs de despliegue +``` + +--- + +**✅ Listo para usar** + +Cada `git push production main` desde local actualizará automáticamente la app en el servidor. + diff --git a/scripts/deploy/README_DEPLOY.md b/scripts/deploy/README_DEPLOY.md new file mode 100644 index 00000000..0905e4b1 --- /dev/null +++ b/scripts/deploy/README_DEPLOY.md @@ -0,0 +1,298 @@ +# 🚀 Sistema de Despliegue Automático - EMERGES TES + +Sistema de despliegue automático usando Git hooks (post-receive) en repositorio bare. + +--- + +## 📋 ARQUITECTURA + +``` +┌─────────────────┐ +│ Máquina Local │ +│ (desarrollo) │ +└────────┬────────┘ + │ git push production main + ▼ +┌─────────────────┐ +│ Servidor │ +│ │ +│ /var/repos/ │ +│ emerges-tes.git│ ◄── Repositorio bare +│ └─ hooks/ │ +│ └─ post- │ +│ receive│ ◄── Hook que se ejecuta automáticamente +└────────┬────────┘ + │ + │ Ejecuta: checkout → npm install → npm run build + ▼ +┌─────────────────┐ +│ /var/www/ │ +│ emerges-tes/ │ ◄── Directorio de trabajo +│ ├─ .git/ │ +│ ├─ src/ │ +│ ├─ dist/ │ ◄── Build de producción (servir con Nginx) +│ └─ ... │ +└─────────────────┘ +``` + +--- + +## 🔧 CONFIGURACIÓN INICIAL (Solo una vez) + +### Paso 1: Subir el hook al servidor + +Desde tu máquina local: + +```bash +cd /home/planetazuzu/guia-tes + +# Copiar el hook al servidor +scp scripts/deploy/post-receive root@207.180.226.141:/tmp/post-receive +``` + +### Paso 2: Configurar en el servidor + +Conectarse al servidor: + +```bash +ssh root@207.180.226.141 +``` + +En el servidor, ejecutar: + +```bash +# Variables +GIT_DIR="/var/repos/emerges-tes.git" +APP_DIR="/var/www/emerges-tes" +HOOK_FILE="$GIT_DIR/hooks/post-receive" + +# 1. Copiar el hook +cp /tmp/post-receive "$HOOK_FILE" + +# 2. Dar permisos de ejecución +chmod +x "$HOOK_FILE" + +# 3. Verificar que el directorio de trabajo existe +if [ ! -d "$APP_DIR" ]; then + mkdir -p "$APP_DIR" + # Si el directorio está vacío, clonar + if [ ! -d "$APP_DIR/.git" ]; then + git clone "$GIT_DIR" "$APP_DIR" + fi +fi + +# 4. Crear archivo de logs +touch /var/log/emerges-tes-deploy.log +chmod 666 /var/log/emerges-tes-deploy.log +``` + +--- + +## 🧪 PROBAR EL DESPLIEGUE + +### Desde tu máquina local: + +```bash +cd /home/planetazuzu/guia-tes + +# Hacer un cambio pequeño (opcional) +echo "# Test deploy $(date)" >> README.md +git add README.md +git commit -m "test: probar despliegue automático" + +# Hacer push (esto activará el hook automáticamente) +git push production main +``` + +### En el servidor, verificar logs: + +```bash +# Ver logs en tiempo real +tail -f /var/log/emerges-tes-deploy.log + +# O ver las últimas líneas +tail -n 50 /var/log/emerges-tes-deploy.log +``` + +### Verificar que el build se creó: + +```bash +# Verificar que dist/ existe +ls -la /var/www/emerges-tes/dist/ + +# Verificar que hay archivos HTML/JS +ls -la /var/www/emerges-tes/dist/assets/ +``` + +--- + +## 📝 QUÉ HACE EL HOOK + +El hook `post-receive` se ejecuta automáticamente después de cada `git push` y realiza: + +1. **Detecta el push** en la rama `main` +2. **Hace fetch** de los últimos cambios +3. **Checkout limpio** (`git reset --hard`) para asegurar que el código coincide exactamente con el repositorio +4. **Limpia archivos** no rastreados (`git clean -fd`) +5. **Instala dependencias** (`npm install`) +6. **Construye la aplicación** (`npm run build`) +7. **Verifica** que el directorio `dist/` se creó correctamente +8. **Registra todo** en `/var/log/emerges-tes-deploy.log` + +--- + +## 🔍 TROUBLESHOOTING + +### El hook no se ejecuta + +```bash +# Verificar que el hook existe y es ejecutable +ls -la /var/repos/emerges-tes.git/hooks/post-receive + +# Debe mostrar: -rwxr-xr-x (permisos de ejecución) +# Si no, ejecutar: +chmod +x /var/repos/emerges-tes.git/hooks/post-receive +``` + +### Error: "npm: command not found" + +```bash +# Instalar Node.js y npm en el servidor +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt-get install -y nodejs + +# Verificar instalación +node --version +npm --version +``` + +### Error: "Permission denied" + +```bash +# Verificar permisos del directorio de trabajo +ls -la /var/www/emerges-tes + +# Ajustar propietario si es necesario +sudo chown -R $USER:$USER /var/www/emerges-tes +``` + +### El build falla + +```bash +# Ver logs detallados +tail -f /var/log/emerges-tes-deploy.log + +# Probar manualmente en el servidor +cd /var/www/emerges-tes +npm install +npm run build +``` + +### Verificar que el hook se ejecutó + +```bash +# Ver los últimos logs +tail -n 100 /var/log/emerges-tes-deploy.log + +# Buscar errores +grep -i error /var/log/emerges-tes-deploy.log +``` + +--- + +## 🔄 FLUJO COMPLETO DE DESPLIEGUE + +``` +1. Desarrollador hace cambios localmente + └─ git add . + └─ git commit -m "mensaje" + └─ git push production main + +2. Git envía cambios al servidor + └─ Se activa el hook post-receive + +3. Hook ejecuta automáticamente: + ├─ git fetch origin main + ├─ git reset --hard origin/main + ├─ git clean -fd + ├─ npm install + ├─ npm run build + └─ Verifica dist/ + +4. Aplicación actualizada en /var/www/emerges-tes/dist/ + └─ Servir con Nginx/Apache +``` + +--- + +## 📊 CONFIGURACIÓN NGINX (Opcional) + +Si quieres servir la app con Nginx: + +```nginx +server { + listen 80; + server_name tu-dominio.com; + + root /var/www/emerges-tes/dist; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + # Cache para assets estáticos + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } +} +``` + +--- + +## ✅ VERIFICACIÓN FINAL + +Después de configurar, verifica: + +```bash +# 1. Hook existe y es ejecutable +test -x /var/repos/emerges-tes.git/hooks/post-receive && echo "✅ Hook OK" || echo "❌ Hook no ejecutable" + +# 2. Directorio de trabajo existe +test -d /var/www/emerges-tes && echo "✅ Directorio OK" || echo "❌ Directorio no existe" + +# 3. Logs se pueden escribir +test -w /var/log/emerges-tes-deploy.log && echo "✅ Logs OK" || echo "❌ Logs no escribibles" + +# 4. Node.js instalado +command -v node >/dev/null && echo "✅ Node.js OK" || echo "❌ Node.js no instalado" +``` + +--- + +## 🎯 COMANDOS RÁPIDOS + +```bash +# Ver logs en tiempo real +tail -f /var/log/emerges-tes-deploy.log + +# Ver último despliegue +tail -n 50 /var/log/emerges-tes-deploy.log + +# Forzar despliegue manual (desde servidor) +cd /var/www/emerges-tes +git pull origin main +npm install +npm run build + +# Verificar build +ls -la /var/www/emerges-tes/dist/ +``` + +--- + +**✅ Sistema listo para producción** + +Cada `git push production main` desde tu máquina local actualizará automáticamente la aplicación en el servidor. + diff --git a/scripts/deploy/RESUMEN_DEPLOY.md b/scripts/deploy/RESUMEN_DEPLOY.md new file mode 100644 index 00000000..c4434d64 --- /dev/null +++ b/scripts/deploy/RESUMEN_DEPLOY.md @@ -0,0 +1,129 @@ +# ✅ Sistema de Despliegue Automático - CONFIGURADO + +**Fecha:** 2024-12-30 +**Estado:** ✅ Funcionando correctamente + +--- + +## 📋 Configuración Completada + +- ✅ **Repositorio bare:** `/var/repos/emerges-tes.git` +- ✅ **Hook post-receive:** Configurado y ejecutable +- ✅ **Directorio de trabajo:** `/var/www/emerges-tes` +- ✅ **Build de producción:** `/var/www/emerges-tes/dist/` +- ✅ **Logs:** `/var/log/emerges-tes-deploy.log` +- ✅ **Node.js:** v18.19.1 instalado +- ✅ **Despliegue manual:** Probado y funcionando +- ✅ **Despliegue automático:** Probado y funcionando + +--- + +## 🔄 Flujo Automático + +``` +1. git push production main (desde máquina local) + ↓ +2. Hook post-receive se ejecuta automáticamente + ↓ +3. git fetch origin main + ↓ +4. git reset --hard origin/main (checkout limpio) + ↓ +5. git clean -fd (limpiar archivos no rastreados) + ↓ +6. npm install (instalar dependencias) + ↓ +7. npm run build (construir aplicación) + ↓ +8. Aplicación actualizada en /var/www/emerges-tes/dist/ +``` + +--- + +## 📊 Comandos Útiles + +### Ver logs + +```bash +# Últimas 50 líneas +tail -n 50 /var/log/emerges-tes-deploy.log + +# En tiempo real +tail -f /var/log/emerges-tes-deploy.log + +# Buscar errores +grep -i error /var/log/emerges-tes-deploy.log +``` + +### Verificar estado + +```bash +# Estado del repositorio +cd /var/www/emerges-tes && git status + +# Verificar build +ls -la /var/www/emerges-tes/dist/ + +# Ver archivos del build +ls -la /var/www/emerges-tes/dist/assets/ | head -10 +``` + +### Despliegue manual (si es necesario) + +```bash +cd /var/www/emerges-tes +git pull origin main +npm install +npm run build +``` + +--- + +## 🎯 Próximos Pasos (Opcional) + +### Configurar Nginx para servir la aplicación + +```nginx +server { + listen 80; + server_name tu-dominio.com; + + root /var/www/emerges-tes/dist; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + # Cache para assets estáticos + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } +} +``` + +### Configurar SSL (Let's Encrypt) + +```bash +# Instalar certbot +apt-get install certbot python3-certbot-nginx + +# Obtener certificado +certbot --nginx -d tu-dominio.com +``` + +--- + +## ✅ Verificación Final + +El sistema está completamente funcional: + +- ✅ Cada `git push production main` actualiza automáticamente la app +- ✅ Los logs registran todo el proceso +- ✅ El build se genera correctamente en `dist/` +- ✅ El sistema es robusto y maneja errores + +**Sistema listo para producción** 🚀 + + diff --git a/scripts/deploy/actualizar-hook.sh b/scripts/deploy/actualizar-hook.sh new file mode 100755 index 00000000..5453550f --- /dev/null +++ b/scripts/deploy/actualizar-hook.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Script para actualizar el hook post-receive en el servidor + +SERVER="root@207.180.226.141" +HOOK_LOCAL="./scripts/deploy/post-receive" +HOOK_REMOTE="/var/repos/emerges-tes.git/hooks/post-receive" + +echo "╔══════════════════════════════════════════════════════════════╗" +echo "║ 🔧 ACTUALIZANDO HOOK POST-RECEIVE EN SERVIDOR ║" +echo "╚══════════════════════════════════════════════════════════════╝" +echo "" + +# Verificar que el archivo local existe +if [ ! -f "$HOOK_LOCAL" ]; then + echo "❌ ERROR: No se encuentra $HOOK_LOCAL" + exit 1 +fi + +echo "📤 Copiando hook al servidor..." +scp "$HOOK_LOCAL" "$SERVER:$HOOK_REMOTE" || { + echo "❌ ERROR: No se pudo copiar el hook" + exit 1 +} + +echo "🔐 Configurando permisos de ejecución..." +ssh "$SERVER" "chmod +x $HOOK_REMOTE" || { + echo "❌ ERROR: No se pudieron configurar permisos" + exit 1 +} + +echo "" +echo "✅ Hook actualizado correctamente" +echo "" +echo "🧪 Para probar, haz un push:" +echo " git push production main" + diff --git a/scripts/deploy/corregir-servidor.sh b/scripts/deploy/corregir-servidor.sh new file mode 100644 index 00000000..fe11e028 --- /dev/null +++ b/scripts/deploy/corregir-servidor.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# Script de corrección rápida para el servidor +# Ejecutar en el servidor: bash corregir-servidor.sh + +APP_DIR="/var/www/emerges-tes" +GIT_DIR="/var/repos/emerges-tes.git" +LOG_FILE="/var/log/emerges-tes-deploy.log" + +echo "🔧 Corrigiendo configuración..." +echo "" + +# 1. Corregir archivo de logs (quitar tilde si existe) +echo "1️⃣ Corrigiendo archivo de logs..." +touch "$LOG_FILE" +chmod 666 "$LOG_FILE" 2>/dev/null || sudo chmod 666 "$LOG_FILE" +echo " ✅ Logs configurados: $LOG_FILE" + +# 2. Verificar que el directorio de trabajo es un repositorio Git +echo "" +echo "2️⃣ Verificando directorio de trabajo..." +if [ -d "$APP_DIR" ]; then + if [ ! -d "$APP_DIR/.git" ]; then + echo " ⚠️ Directorio existe pero no es un repositorio Git" + echo " 🔧 Inicializando repositorio..." + cd "$APP_DIR" + git init + git remote add origin "$GIT_DIR" 2>/dev/null || git remote set-url origin "$GIT_DIR" + git fetch origin + git checkout -b main origin/main 2>/dev/null || { + echo " ⚠️ No se pudo hacer checkout automático" + echo " 💡 Ejecutar manualmente: cd $APP_DIR && git pull origin main" + } + echo " ✅ Repositorio inicializado" + else + echo " ✅ Directorio ya es un repositorio Git" + cd "$APP_DIR" + echo " 📍 Rama actual: $(git branch --show-current 2>/dev/null || echo 'desconocida')" + + # Asegurar que el remoto está configurado + if ! git remote get-url origin >/dev/null 2>&1; then + echo " 🔧 Configurando remoto..." + git remote add origin "$GIT_DIR" + fi + fi +else + echo " ❌ Directorio no existe" + exit 1 +fi + +# 3. Verificar hook +echo "" +echo "3️⃣ Verificando hook..." +HOOK_FILE="$GIT_DIR/hooks/post-receive" +if [ -f "$HOOK_FILE" ]; then + if [ -x "$HOOK_FILE" ]; then + echo " ✅ Hook existe y es ejecutable" + else + echo " ⚠️ Hook no es ejecutable. Corrigiendo..." + chmod +x "$HOOK_FILE" + echo " ✅ Permisos corregidos" + fi +else + echo " ❌ Hook no existe. Crear primero." +fi + +echo "" +echo "✅ Corrección completada" +echo "" +echo "📋 Estado actual:" +echo " - Directorio: $APP_DIR" +echo " - Logs: $LOG_FILE" +echo " - Hook: $HOOK_FILE" +echo "" +echo "🧪 Próximos pasos:" +echo " 1. Desde tu MÁQUINA LOCAL (no desde el servidor):" +echo " cd /home/planetazuzu/guia-tes" +echo " git push production main" +echo "" +echo " 2. En el SERVIDOR, ver logs:" +echo " tail -f $LOG_FILE" + diff --git a/scripts/deploy/diagnostico-servidor.sh b/scripts/deploy/diagnostico-servidor.sh new file mode 100644 index 00000000..2d22a340 --- /dev/null +++ b/scripts/deploy/diagnostico-servidor.sh @@ -0,0 +1,139 @@ +#!/bin/bash +# Script de diagnóstico para el servidor +# Ejecutar en el servidor: bash diagnostico-servidor.sh + +APP_DIR="/var/www/emerges-tes" +GIT_DIR="/var/repos/emerges-tes.git" +LOG_FILE="/var/log/emerges-tes-deploy.log" + +echo "🔍 DIAGNÓSTICO DEL SERVIDOR" +echo "============================" +echo "" + +# 1. Verificar Node.js y npm +echo "1️⃣ Node.js y npm:" +if command -v node >/dev/null 2>&1; then + echo " ✅ Node.js: $(node --version)" +else + echo " ❌ Node.js NO está instalado" + echo " 💡 Instalar con: curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs" +fi + +if command -v npm >/dev/null 2>&1; then + echo " ✅ npm: $(npm --version)" +else + echo " ❌ npm NO está instalado" +fi +echo "" + +# 2. Verificar directorio de trabajo +echo "2️⃣ Directorio de trabajo ($APP_DIR):" +if [ -d "$APP_DIR" ]; then + echo " ✅ Directorio existe" + cd "$APP_DIR" + + if [ -d ".git" ]; then + echo " ✅ Es un repositorio Git" + echo " 📍 Rama: $(git branch --show-current 2>/dev/null || echo 'desconocida')" + echo " 🔗 Remoto: $(git remote get-url origin 2>/dev/null || echo 'no configurado')" + + # Verificar si está actualizado + git fetch origin main 2>/dev/null || echo " ⚠️ No se pudo hacer fetch" + LOCAL=$(git rev-parse HEAD 2>/dev/null || echo "desconocido") + REMOTE=$(git rev-parse origin/main 2>/dev/null || echo "desconocido") + echo " 📦 Commit local: ${LOCAL:0:7}" + echo " 📦 Commit remoto: ${REMOTE:0:7}" + + if [ "$LOCAL" != "$REMOTE" ] && [ "$REMOTE" != "desconocido" ]; then + echo " ⚠️ El directorio NO está actualizado con el repositorio" + else + echo " ✅ Directorio actualizado" + fi + else + echo " ❌ NO es un repositorio Git" + fi + + # Verificar package.json + if [ -f "package.json" ]; then + echo " ✅ package.json existe" + else + echo " ❌ package.json NO existe" + fi + + # Verificar node_modules + if [ -d "node_modules" ]; then + echo " ✅ node_modules existe" + else + echo " ⚠️ node_modules NO existe (necesita npm install)" + fi + + # Verificar dist/ + if [ -d "dist" ]; then + echo " ✅ dist/ existe" + echo " 📁 Archivos en dist/: $(ls -1 dist/ 2>/dev/null | wc -l)" + else + echo " ❌ dist/ NO existe (necesita npm run build)" + fi +else + echo " ❌ Directorio NO existe" +fi +echo "" + +# 3. Verificar hook +echo "3️⃣ Hook post-receive:" +HOOK_FILE="$GIT_DIR/hooks/post-receive" +if [ -f "$HOOK_FILE" ]; then + if [ -x "$HOOK_FILE" ]; then + echo " ✅ Hook existe y es ejecutable" + else + echo " ⚠️ Hook existe pero NO es ejecutable" + echo " 💡 Ejecutar: chmod +x $HOOK_FILE" + fi +else + echo " ❌ Hook NO existe" +fi +echo "" + +# 4. Verificar logs +echo "4️⃣ Logs:" +if [ -f "$LOG_FILE" ]; then + if [ -r "$LOG_FILE" ]; then + echo " ✅ Archivo de logs existe" + if [ -s "$LOG_FILE" ]; then + echo " 📋 Últimas 10 líneas del log:" + tail -n 10 "$LOG_FILE" | sed 's/^/ /' + else + echo " ⚠️ Archivo de logs está vacío (nunca se ha ejecutado el hook)" + fi + else + echo " ⚠️ Archivo de logs existe pero NO es legible" + fi +else + echo " ⚠️ Archivo de logs NO existe" + echo " 💡 Crear con: touch $LOG_FILE && chmod 666 $LOG_FILE" +fi +echo "" + +# 5. Recomendaciones +echo "💡 RECOMENDACIONES:" +echo "" + +if [ ! -d "$APP_DIR/dist" ]; then + echo " 🔨 Hacer despliegue manual para probar:" + echo " cd $APP_DIR" + echo " git pull origin main" + echo " npm install" + echo " npm run build" + echo "" +fi + +if ! command -v node >/dev/null 2>&1; then + echo " 📦 Instalar Node.js primero" + echo "" +fi + +echo " 🧪 Para probar el despliegue automático:" +echo " Desde tu máquina local: git push production main" +echo " Luego ver logs: tail -f $LOG_FILE" +echo "" + diff --git a/scripts/deploy/post-receive b/scripts/deploy/post-receive new file mode 100755 index 00000000..e96d9bdd --- /dev/null +++ b/scripts/deploy/post-receive @@ -0,0 +1,124 @@ +#!/bin/bash +# Hook post-receive para despliegue automático +# Ubicación: /var/repos/emerges-tes.git/hooks/post-receive + +set -e # Salir si hay error + +# Configuración +APP_DIR="/var/www/emerges-tes" +GIT_DIR="/var/repos/emerges-tes.git" +BRANCH="main" +LOG_FILE="/var/log/emerges-tes-deploy.log" + +# Función de logging +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" +} + +log "==========================================" +log "🚀 Iniciando despliegue automático" +log "==========================================" + +# Leer la rama que se está actualizando +while read oldrev newrev refname; do + # Usar GIT_DIR para obtener el nombre de la rama desde el repositorio bare + branch=$(git --git-dir="$GIT_DIR" rev-parse --symbolic --abbrev-ref $refname 2>/dev/null || echo "$refname" | sed 's|refs/heads/||') + + if [ "$branch" = "$BRANCH" ]; then + log "📦 Actualizando rama: $branch" + log " Commit anterior: $oldrev" + log " Commit nuevo: $newrev" + + # Verificar que el directorio de trabajo existe + if [ ! -d "$APP_DIR" ]; then + log "❌ ERROR: Directorio $APP_DIR no existe" + exit 1 + fi + + # Ir al directorio de trabajo + cd "$APP_DIR" || { + log "❌ ERROR: No se puede acceder a $APP_DIR" + exit 1 + } + + # Usar git directamente con --work-tree y --git-dir para evitar problemas de work tree + # Esto funciona tanto si APP_DIR es un repositorio git como si no lo es + + # Si no existe .git, inicializar o clonar + if [ ! -d "$APP_DIR/.git" ]; then + log "⚠️ $APP_DIR no es un repositorio git, clonando..." + # Si el directorio tiene contenido, hacer backup o limpiar + if [ "$(ls -A $APP_DIR 2>/dev/null)" ]; then + log "⚠️ Directorio no vacío, haciendo backup..." + mv "$APP_DIR" "${APP_DIR}.backup.$(date +%s)" 2>/dev/null || true + fi + # Clonar desde el repositorio bare + git clone "$GIT_DIR" "$APP_DIR" || { + log "❌ ERROR: No se pudo clonar repositorio" + exit 1 + } + cd "$APP_DIR" || exit 1 + git checkout "$BRANCH" || { + log "❌ ERROR: No se pudo hacer checkout de $BRANCH" + exit 1 + } + else + # Si ya es un repositorio, usar git normal + cd "$APP_DIR" || exit 1 + + # Obtener los últimos cambios + log "📥 Obteniendo cambios del repositorio..." + git fetch "$GIT_DIR" "$BRANCH" || { + log "❌ ERROR: Fallo al hacer fetch" + exit 1 + } + + # Resetear a la versión más reciente (checkout limpio) + log "🔄 Haciendo checkout limpio..." + git reset --hard "FETCH_HEAD" || { + log "❌ ERROR: Fallo al hacer reset" + exit 1 + } + fi + + # Limpiar archivos no rastreados (opcional, pero recomendado) + log "🧹 Limpiando archivos no rastreados..." + git clean -fd || { + log "⚠️ ADVERTENCIA: Fallo al limpiar archivos" + } + + # Instalar dependencias + log "📦 Instalando dependencias (npm install)..." + if ! npm install --production=false 2>&1 | tee -a "$LOG_FILE"; then + log "❌ ERROR: Fallo al instalar dependencias" + exit 1 + fi + log "✅ Dependencias instaladas correctamente" + + # Build de producción + log "🔨 Construyendo aplicación (npm run build)..." + if ! npm run build 2>&1 | tee -a "$LOG_FILE"; then + log "❌ ERROR: Fallo al construir la aplicación" + exit 1 + fi + log "✅ Build completado correctamente" + + # Verificar que el build se creó + if [ ! -d "$APP_DIR/dist" ]; then + log "❌ ERROR: El directorio dist/ no existe después del build" + exit 1 + fi + + log "✅ Despliegue completado exitosamente" + log " Aplicación disponible en: $APP_DIR/dist" + log "==========================================" + + exit 0 + else + log "⏭️ Ignorando push en rama: $branch (solo se despliega $BRANCH)" + fi +done + +log "⚠️ No se procesó ningún cambio" +exit 0 + diff --git a/scripts/deploy/setup-deploy.sh b/scripts/deploy/setup-deploy.sh new file mode 100755 index 00000000..394b6ddd --- /dev/null +++ b/scripts/deploy/setup-deploy.sh @@ -0,0 +1,159 @@ +#!/bin/bash +# Script para configurar el sistema de despliegue automático +# Ejecutar en el servidor: sudo ./setup-deploy.sh + +set -e + +APP_DIR="/var/www/emerges-tes" +GIT_DIR="/var/repos/emerges-tes.git" +HOOK_FILE="$GIT_DIR/hooks/post-receive" +LOG_FILE="/var/log/emerges-tes-deploy.log" + +echo "🔧 Configurando sistema de despliegue automático..." +echo "" + +# Verificar que el repositorio bare existe +if [ ! -d "$GIT_DIR" ]; then + echo "❌ ERROR: El repositorio bare no existe en $GIT_DIR" + echo " Créalo primero con: git init --bare $GIT_DIR" + exit 1 +fi + +# Verificar que el directorio de trabajo existe +if [ ! -d "$APP_DIR" ]; then + echo "📁 Creando directorio de trabajo: $APP_DIR" + sudo mkdir -p "$APP_DIR" + sudo chown -R $USER:$USER "$APP_DIR" || { + echo "⚠️ No se pudo cambiar propietario. Asegúrate de tener permisos." + } +fi + +# Si el directorio está vacío, clonar el repositorio +if [ ! -d "$APP_DIR/.git" ]; then + echo "📥 Clonando repositorio en $APP_DIR..." + git clone "$GIT_DIR" "$APP_DIR" || { + echo "❌ ERROR: No se pudo clonar el repositorio" + exit 1 + } +fi + +# Crear el hook post-receive +echo "📝 Creando hook post-receive..." + +# Copiar el hook desde el proyecto local (si existe) +if [ -f "scripts/deploy/post-receive" ]; then + sudo cp "scripts/deploy/post-receive" "$HOOK_FILE" +else + # Si no existe, crear directamente + sudo tee "$HOOK_FILE" > /dev/null << 'HOOK_EOF' +#!/bin/bash +# Hook post-receive para despliegue automático +# Ubicación: /var/repos/emerges-tes.git/hooks/post-receive + +set -e + +APP_DIR="/var/www/emerges-tes" +GIT_DIR="/var/repos/emerges-tes.git" +BRANCH="main" +LOG_FILE="/var/log/emerges-tes-deploy.log" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" +} + +log "==========================================" +log "🚀 Iniciando despliegue automático" +log "==========================================" + +while read oldrev newrev refname; do + branch=$(git rev-parse --symbolic --abbrev-ref $refname) + + if [ "$branch" = "$BRANCH" ]; then + log "📦 Actualizando rama: $branch" + log " Commit anterior: $oldrev" + log " Commit nuevo: $newrev" + + if [ ! -d "$APP_DIR" ]; then + log "❌ ERROR: Directorio $APP_DIR no existe" + exit 1 + fi + + cd "$APP_DIR" || { + log "❌ ERROR: No se puede acceder a $APP_DIR" + exit 1 + } + + log "📥 Obteniendo cambios del repositorio..." + git fetch origin "$BRANCH" || { + log "❌ ERROR: Fallo al hacer fetch" + exit 1 + } + + log "🔄 Haciendo checkout limpio..." + git reset --hard "origin/$BRANCH" || { + log "❌ ERROR: Fallo al hacer reset" + exit 1 + } + + log "🧹 Limpiando archivos no rastreados..." + git clean -fd || { + log "⚠️ ADVERTENCIA: Fallo al limpiar archivos" + } + + log "📦 Instalando dependencias (npm install)..." + if ! npm install --production=false 2>&1 | tee -a "$LOG_FILE"; then + log "❌ ERROR: Fallo al instalar dependencias" + exit 1 + fi + log "✅ Dependencias instaladas correctamente" + + log "🔨 Construyendo aplicación (npm run build)..." + if ! npm run build 2>&1 | tee -a "$LOG_FILE"; then + log "❌ ERROR: Fallo al construir la aplicación" + exit 1 + fi + log "✅ Build completado correctamente" + + if [ ! -d "$APP_DIR/dist" ]; then + log "❌ ERROR: El directorio dist/ no existe después del build" + exit 1 + fi + + log "✅ Despliegue completado exitosamente" + log " Aplicación disponible en: $APP_DIR/dist" + log "==========================================" + + exit 0 + else + log "⏭️ Ignorando push en rama: $branch (solo se despliega $BRANCH)" + fi +done + +log "⚠️ No se procesó ningún cambio" +exit 0 +HOOK_EOF +fi + +# Dar permisos de ejecución al hook +echo "🔐 Configurando permisos..." +sudo chmod +x "$HOOK_FILE" +sudo chown $USER:$USER "$HOOK_FILE" 2>/dev/null || true + +# Crear directorio de logs si no existe +echo "📋 Configurando logs..." +sudo touch "$LOG_FILE" +sudo chmod 666 "$LOG_FILE" 2>/dev/null || sudo chmod 644 "$LOG_FILE" + +echo "" +echo "✅ Configuración completada" +echo "" +echo "📋 Resumen:" +echo " - Hook: $HOOK_FILE" +echo " - Directorio app: $APP_DIR" +echo " - Logs: $LOG_FILE" +echo "" +echo "🧪 Para probar el despliegue:" +echo " 1. Desde tu máquina local: git push production main" +echo " 2. Ver logs: tail -f $LOG_FILE" +echo "" + diff --git a/scripts/deploy/test-deploy.sh b/scripts/deploy/test-deploy.sh new file mode 100755 index 00000000..a450c4f3 --- /dev/null +++ b/scripts/deploy/test-deploy.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# Script para probar el despliegue desde la máquina local +# Ejecutar desde: /home/planetazuzu/guia-tes + +set -e + +echo "🧪 Probando despliegue automático..." +echo "" + +# Verificar que estamos en el directorio correcto +if [ ! -f "package.json" ]; then + echo "❌ ERROR: No estás en el directorio del proyecto" + echo " Ejecuta: cd /home/planetazuzu/guia-tes" + exit 1 +fi + +# Verificar que el remoto production existe +if ! git remote get-url production >/dev/null 2>&1; then + echo "❌ ERROR: Remoto 'production' no configurado" + echo " Configura con: git remote add production root@207.180.226.141:/var/repos/emerges-tes.git" + exit 1 +fi + +echo "✅ Directorio correcto" +echo "✅ Remoto 'production' configurado" +echo "" + +# Hacer un cambio pequeño para probar +echo "📝 Creando cambio de prueba..." +echo "" >> README.md +echo "" >> README.md + +# Commit +echo "💾 Haciendo commit..." +git add README.md +git commit -m "test: probar despliegue automático $(date '+%Y-%m-%d %H:%M:%S')" || { + echo "⚠️ No hay cambios nuevos para commitear" + echo " Haciendo push de commits existentes..." +} + +# Push +echo "" +echo "🚀 Haciendo push a producción..." +echo " Esto activará el hook post-receive automáticamente" +echo "" + +if git push production main; then + echo "" + echo "✅ Push completado" + echo "" + echo "📋 Próximos pasos:" + echo " 1. Conectarte al servidor: ssh root@207.180.226.141" + echo " 2. Ver logs en tiempo real: tail -f /var/log/emerges-tes-deploy.log" + echo " 3. Verificar build: ls -la /var/www/emerges-tes/dist/" +else + echo "" + echo "❌ Error en el push" + echo " Verifica la conexión SSH y los permisos" + exit 1 +fi + diff --git a/scripts/deploy/verificar-servidor.sh b/scripts/deploy/verificar-servidor.sh new file mode 100644 index 00000000..c231a96f --- /dev/null +++ b/scripts/deploy/verificar-servidor.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# Script para verificar y corregir la configuración en el servidor +# Ejecutar en el servidor: bash verificar-servidor.sh + +set -e + +GIT_DIR="/var/repos/emerges-tes.git" +APP_DIR="/var/www/emerges-tes" +HOOK_FILE="$GIT_DIR/hooks/post-receive" +LOG_FILE="/var/log/emerges-tes-deploy.log" + +echo "🔍 Verificando configuración del despliegue..." +echo "" + +# 1. Verificar hook +echo "1️⃣ Verificando hook post-receive..." +if [ -f "$HOOK_FILE" ]; then + if [ -x "$HOOK_FILE" ]; then + echo " ✅ Hook existe y es ejecutable" + else + echo " ⚠️ Hook existe pero no es ejecutable. Corrigiendo..." + chmod +x "$HOOK_FILE" + echo " ✅ Permisos corregidos" + fi +else + echo " ❌ Hook no existe. Crear primero con los comandos de configuración." + exit 1 +fi + +# 2. Verificar directorio de trabajo +echo "" +echo "2️⃣ Verificando directorio de trabajo..." +if [ -d "$APP_DIR" ]; then + if [ -d "$APP_DIR/.git" ]; then + echo " ✅ Directorio existe y es un repositorio Git" + echo " 📍 Rama actual: $(cd "$APP_DIR" && git branch --show-current 2>/dev/null || echo 'desconocida')" + else + echo " ⚠️ Directorio existe pero no es un repositorio Git" + echo " 🔧 Inicializando repositorio..." + cd "$APP_DIR" + git init + git remote add origin "$GIT_DIR" 2>/dev/null || git remote set-url origin "$GIT_DIR" + git fetch origin + git checkout -b main origin/main 2>/dev/null || git checkout main 2>/dev/null || echo " ⚠️ No se pudo hacer checkout automático" + echo " ✅ Repositorio inicializado" + fi +else + echo " ❌ Directorio no existe. Creando..." + mkdir -p "$APP_DIR" + git clone "$GIT_DIR" "$APP_DIR" + echo " ✅ Directorio creado y clonado" +fi + +# 3. Verificar logs +echo "" +echo "3️⃣ Verificando archivo de logs..." +if [ -f "$LOG_FILE" ]; then + if [ -w "$LOG_FILE" ]; then + echo " ✅ Archivo de logs existe y es escribible" + else + echo " ⚠️ Archivo de logs existe pero no es escribible. Corrigiendo..." + chmod 666 "$LOG_FILE" 2>/dev/null || sudo chmod 666 "$LOG_FILE" + echo " ✅ Permisos corregidos" + fi +else + echo " ⚠️ Archivo de logs no existe. Creando..." + touch "$LOG_FILE" + chmod 666 "$LOG_FILE" 2>/dev/null || sudo chmod 666 "$LOG_FILE" + echo " ✅ Archivo de logs creado" +fi + +# 4. Verificar Node.js y npm +echo "" +echo "4️⃣ Verificando Node.js y npm..." +if command -v node >/dev/null 2>&1; then + echo " ✅ Node.js: $(node --version)" +else + echo " ❌ Node.js no está instalado" + echo " 💡 Instalar con: curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs" +fi + +if command -v npm >/dev/null 2>&1; then + echo " ✅ npm: $(npm --version)" +else + echo " ❌ npm no está instalado" +fi + +# 5. Verificar que el directorio de trabajo está actualizado +echo "" +echo "5️⃣ Verificando estado del repositorio..." +if [ -d "$APP_DIR/.git" ]; then + cd "$APP_DIR" + echo " 📍 Directorio: $APP_DIR" + echo " 📦 Rama: $(git branch --show-current 2>/dev/null || echo 'desconocida')" + echo " 🔗 Remoto: $(git remote get-url origin 2>/dev/null || echo 'no configurado')" + + # Verificar si hay cambios pendientes + if [ -n "$(git status --porcelain 2>/dev/null)" ]; then + echo " ⚠️ Hay cambios no commiteados en el directorio de trabajo" + else + echo " ✅ Directorio de trabajo limpio" + fi +fi + +echo "" +echo "✅ Verificación completada" +echo "" +echo "📋 Resumen:" +echo " - Hook: $HOOK_FILE" +echo " - Directorio app: $APP_DIR" +echo " - Logs: $LOG_FILE" +echo "" +echo "🧪 Para probar el despliegue:" +echo " 1. Desde tu máquina local: git push production main" +echo " 2. En el servidor, ver logs: tail -f $LOG_FILE" +