#!/usr/bin/env ruby # frozen_string_literal: true # tools/orquestador/migrar_ids_hitos.rb # ====================================== # Script de migración para actualizar IDs de hitos al nuevo formato fNNNNN # Migra IDs antiguos como BKP02, DB02, etc. a f05001, f05002, etc. require 'fileutils' class MigradorIDsHitos # Mapeo de IDs antiguos a nuevos (Fase 5) MAPEO_IDS = { # Fase 5 'BKP02' => 'f05001', 'DB02' => 'f05002', 'MON01' => 'f05003', 'DOC01' => 'f05004', 'PERF01' => 'f05005', # IDs genéricos para migración automática 'BKP' => 'f05', # Patrón para backups 'DB' => 'f05', # Patrón para bases de datos 'MON' => 'f05', # Patrón para monitoreo 'DOC' => 'f05', # Patrón para documentación 'PERF' => 'f05', # Patrón para performance }.freeze def initialize(dashboard_path = nil) @dashboard_path = dashboard_path || default_dashboard_path @backup_dir = File.join(File.dirname(@dashboard_path), 'backups') @contador_migrados = 0 @contador_errores = 0 @ids_migrados = [] end def default_dashboard_path File.expand_path('../../../dashboard/index.html', __FILE__) end def migrar_ids puts "🔄 MIGRANDO IDs DE HITOS AL NUEVO FORMATO" puts "=" * 60 unless File.exist?(@dashboard_path) puts "❌ Error: No se encuentra el dashboard en #{@dashboard_path}" return false end # Crear backup crear_backup_migracion # Leer contenido puts "📖 Leyendo dashboard..." contenido = File.read(@dashboard_path) contenido_original = contenido.dup # Extraer todos los hitos para análisis hitos = extraer_hitos_con_ids(contenido) puts "🔍 Encontrados #{hitos.size} hitos para analizar" # Mostrar IDs actuales mostrar_ids_actuales(hitos) # Preguntar confirmación unless confirmar_migracion(hitos.size) puts "❌ Migración cancelada por el usuario" return false end # Realizar migración puts "\n🔄 Realizando migración..." contenido_migrado = migrar_contenido(contenido) # Verificar cambios if contenido_migrado == contenido_original puts "ℹ️ No se realizaron cambios (posiblemente ya están migrados)" return true end # Guardar cambios puts "💾 Guardando dashboard migrado..." File.write(@dashboard_path, contenido_migrado) # Mostrar resultados mostrar_resultados_migracion # Verificar integridad verificar_integridad_migracion(contenido_migrado) true end def simular_migracion puts "🔍 SIMULACIÓN DE MIGRACIÓN (MODO DRY RUN)" puts "=" * 60 unless File.exist?(@dashboard_path) puts "❌ Error: No se encuentra el dashboard" return false end contenido = File.read(@dashboard_path) hitos = extraer_hitos_con_ids(contenido) puts "📊 ANÁLISIS DE MIGRACIÓN:" puts " • Total de hitos encontrados: #{hitos.size}" puts " • IDs que requieren migración: #{hitos.count { |h| requiere_migracion?(h[:id]) }}" puts " • IDs ya en formato nuevo: #{hitos.count { |h| !requiere_migracion?(h[:id]) }}" puts "\n📋 DETALLE DE MIGRACIÓN:" hitos.each do |hito| if requiere_migracion?(hito[:id]) nuevo_id = generar_nuevo_id(hito[:id]) puts " • #{hito[:id]} → #{nuevo_id} (#{hito[:titulo][0..50]}...)" else puts " • #{hito[:id]} (ya migrado)" end end puts "\n💡 RECOMENDACIONES:" if hitos.any? { |h| requiere_migracion?(h[:id]) } puts " • Ejecutar migración completa: ./migrar_ids_hitos.rb migrar" puts " • Revisar mapeo de IDs antes de proceder" else puts " • Todos los IDs ya están en formato nuevo" puts " • No se requiere migración" end true end def verificar_estado_migracion puts "🔍 VERIFICANDO ESTADO DE MIGRACIÓN" puts "=" * 60 unless File.exist?(@dashboard_path) puts "❌ Error: No se encuentra el dashboard" return false end contenido = File.read(@dashboard_path) hitos = extraer_hitos_con_ids(contenido) puts "📊 ESTADO ACTUAL:" # Contar por tipo de ID ids_antiguos = hitos.select { |h| requiere_migracion?(h[:id]) } ids_nuevos = hitos.select { |h| !requiere_migracion?(h[:id]) } puts " • IDs en formato antiguo: #{ids_antiguos.size}" puts " • IDs en formato nuevo: #{ids_nuevos.size}" puts " • Total de hitos: #{hitos.size}" if ids_antiguos.any? puts "\n⚠️ IDs QUE REQUIEREN MIGRACIÓN:" ids_antiguos.each do |hito| nuevo_id = generar_nuevo_id(hito[:id]) puts " • #{hito[:id]} → #{nuevo_id}" end end if ids_nuevos.any? puts "\n✅ IDs YA MIGRADOS:" ids_nuevos.each do |hito| puts " • #{hito[:id]}" end end # Verificar formato de IDs nuevos puts "\n🔍 VALIDACIÓN DE FORMATOS:" ids_nuevos.each do |hito| if formato_valido_nuevo?(hito[:id]) puts " • #{hito[:id]}: ✅ Formato válido" else puts " • #{hito[:id]}: ❌ Formato inválido" end end puts "\n💡 RECOMENDACIONES:" if ids_antiguos.any? puts " • Ejecutar migración para estandarizar IDs" puts " • Usar: ./migrar_ids_hitos.rb migrar" else puts " • Todos los IDs están en formato nuevo" puts " • Sistema listo para usar módulos optimizados" end true end private def crear_backup_migracion FileUtils.mkdir_p(@backup_dir) unless Dir.exist?(@backup_dir) timestamp = Time.now.strftime('%Y%m%d_%H%M%S') backup_file = File.join(@backup_dir, "dashboard_pre_migracion_#{timestamp}.html") puts "💾 Creando backup pre-migración: #{backup_file}" FileUtils.cp(@dashboard_path, backup_file) puts "✅ Backup creado" end def extraer_hitos_con_ids(contenido) hitos = [] contenido.scan(/
([\s\S]*?)<\/div>\s*<\/div>\s*<\/div>/m) do |hito_html| hito = hito_html[0] # Extraer ID id_match = hito.match(/([^<]+)<\/span>/) titulo_match = hito.match(/
([^<]+)<\/div>/) if id_match && titulo_match hitos << { id: id_match[1], titulo: titulo_match[1], html_completo: hito_html[0] } end end hitos.uniq { |h| h[:id] } end def mostrar_ids_actuales(hitos) puts "\n📋 IDs ACTUALES ENCONTRADOS:" hitos.each_with_index do |hito, i| requiere = requiere_migracion?(hito[:id]) ? "⚠️ Requiere migración" : "✅ Ya migrado" puts " #{i + 1}. #{hito[:id]}: #{hito[:titulo][0..40]}... (#{requiere})" end end def confirmar_migracion(total_hitos) puts "\n⚠️ ADVERTENCIA: Esta operación modificará el dashboard" puts " • Total de hitos a analizar: #{total_hitos}" puts " • Se creará un backup automático" puts " • Los cambios no se pueden deshacer automáticamente" # Para ejecución automática, siempre confirmar puts "\n✅ Confirmación automática para migración" true end def requiere_migracion?(id) # Un ID requiere migración si no sigue el formato fNNNNN !id.match(/^f\d{5}$/) end def formato_valido_nuevo?(id) id.match(/^f\d{5}$/) end def generar_nuevo_id(id_antiguo) # Buscar mapeo directo return MAPEO_IDS[id_antiguo] if MAPEO_IDS.key?(id_antiguo) # Buscar por prefijo MAPEO_IDS.each do |prefijo, nuevo_base| if id_antiguo.start_with?(prefijo) # Extraer número del ID antiguo numero_match = id_antiguo.match(/\d+/) numero = numero_match ? numero_match[0].to_i : 1 # Generar nuevo ID con secuencia return "#{nuevo_base}#{numero.to_s.rjust(3, '0')}" end end # ID genérico para fase 5 "f05#{(@contador_migrados + 1).to_s.rjust(3, '0')}" end def migrar_contenido(contenido) nuevo_contenido = contenido.dup # Extraer todos los hitos hitos = extraer_hitos_con_ids(contenido) hitos.each do |hito| if requiere_migracion?(hito[:id]) nuevo_id = generar_nuevo_id(hito[:id]) # Reemplazar en el contenido nuevo_contenido = nuevo_contenido.gsub( /#{Regexp.escape(hito[:id])}<\/span>/, "#{nuevo_id}" ) @contador_migrados += 1 @ids_migrados << { antiguo: hito[:id], nuevo: nuevo_id } puts " • #{hito[:id]} → #{nuevo_id}" end end nuevo_contenido end def mostrar_resultados_migracion puts "\n📊 RESULTADOS DE LA MIGRACIÓN:" puts "=" * 60 puts "✅ Migración completada exitosamente" puts " • IDs migrados: #{@contador_migrados}" puts " • Errores: #{@contador_errores}" if @ids_migrados.any? puts "\n📋 DETALLE DE MIGRACIONES:" @ids_migrados.each do |migracion| puts " • #{migracion[:antiguo]} → #{migracion[:nuevo]}" end end puts "\n💡 RECOMENDACIONES POST-MIGRACIÓN:" puts " 1. Verificar dashboard en producción" puts " 2. Actualizar referencias en documentación" puts " 3. Usar nuevos módulos optimizados" puts " 4. Backup disponible en: #{@backup_dir}" end def verificar_integridad_migracion(contenido_migrado) puts "\n🔍 VERIFICANDO INTEGRIDAD POST-MIGRACIÓN" hitos = extraer_hitos_con_ids(contenido_migrado) ids_invalidos = hitos.select { |h| requiere_migracion?(h[:id]) } if ids_invalidos.empty? puts "✅ Todos los IDs están en formato nuevo" else puts "⚠️ Se encontraron IDs aún en formato antiguo:" ids_invalidos.each do |hito| puts " • #{hito[:id]}" end end # Verificar duplicados ids = hitos.map { |h| h[:id] } duplicados = ids.select { |id| ids.count(id) > 1 }.uniq if duplicados.empty? puts "✅ No hay IDs duplicados" else puts "❌ IDs duplicados encontrados:" duplicados.each do |id| puts " • #{id}" end end end end # Interfaz de línea de comandos if __FILE__ == $0 begin migrador = MigradorIDsHitos.new # Parsear argumentos command = ARGV[0] || 'verificar' case command when 'migrar', 'migrate' success = migrador.migrar_ids when 'simular', 'simulate', 'dry-run' success = migrador.simular_migracion when 'verificar', 'check', 'status' success = migrador.verificar_estado_migracion when 'help', '--help', '-h' puts "📖 MIGRADOR DE IDs DE HITOS - Dashboard P2601" puts "=" * 60 puts puts "DESCRIPCIÓN:" puts " Migra IDs de hitos del formato antiguo (BKP02, DB02, etc.)" puts " al nuevo formato estandarizado (f05001, f05002, etc.)" puts puts "USO:" puts " #{$0} [comando]" puts puts "COMANDOS:" puts " migrar, migrate - Realizar migración completa (con backup)" puts " simular, simulate - Simular migración (modo dry-run)" puts " verificar, check - Verificar estado actual de migración" puts " help - Mostrar esta ayuda" puts puts "MAFEO DE IDs (Fase 5):" puts " • BKP02 → f05001 (Backup Automático de VMs)" puts " • DB02 → f05002 (Backup Automático de Base de Datos)" puts " • MON01 → f05003 (Monitoreo de Recursos)" puts " • DOC01 → f05004 (Documentación Operativa)" puts " • PERF01 → f05005 (Pruebas de Rendimiento)" puts puts "CARACTERÍSTICAS:" puts " • Backup automático pre-migración" puts " • Confirmación interactiva" puts " • Verificación de integridad post-migración" puts " • Modo dry-run para pruebas" puts puts "EJEMPLOS:" puts " #{$0} verificar # Verificar estado actual" puts " #{$0} simular # Simular migración" puts " #{$0} migrar # Realizar migración completa" puts success = true else puts "❌ Comando '#{command}' no reconocido" puts " Use '#{$0} help' para ver la ayuda" success = false end if success puts "\n🚀 PRÓXIMOS PASOS:" puts " 1. Usar nuevos módulos optimizados en tools/orquestador/lib/" puts " 2. Consultar README_OPTIMIZADO.md para documentación" puts " 3. Verificar dashboard: https://ns8.frlr.utn.edu.ar/bitacoras/p2601" puts puts "📅 #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}" puts "=" * 60 else exit 1 end rescue => e puts "❌ Error: #{e.message}" puts e.backtrace if ENV['DEBUG'] exit 1 end end