# Setup completo de Git para GobTech # ============================================================ # ErrorActionPreference se mantiene en Continue para evitar que # comandos nativos (gpg, ssh, git) que escriben a stderr causen # errores fatales en PowerShell. Los errores reales se controlan # comprobando $LASTEXITCODE tras cada comando nativo. # ============================================================ $ErrorActionPreference = "Continue" # ============================================================ # CONSTANTES # ============================================================ $DEFAULT_DOMAIN = "gitlks.gobtech.lksnext.com" $DEFAULT_SSH_HOST = "gitssh.gobtech.lksnext.com" # ============================================================ # LOGGING # ============================================================ $_logDir = if ($PSScriptRoot) { $PSScriptRoot } else { $HOME } $LOG_FILE = Join-Path $_logDir "setup-git.log" function Write-Log { param( [string]$Message, [ValidateSet("INFO", "WARN", "ERROR", "DEBUG")] [string]$Level = "INFO" ) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $entry = "[$timestamp] [$Level] $Message" Add-Content -Path $LOG_FILE -Value $entry -Encoding utf8 } function Invoke-NativeCommand { <# .SYNOPSIS Ejecuta un comando nativo, loguea stdout+stderr al fichero de log, y devuelve stdout como string (o array de strings). Lanza excepcion si el exit code no es 0 y $ThrowOnError es $true. #> param( [string]$Command, [string[]]$Arguments, [string]$StdinText, [switch]$ThrowOnError, [switch]$PassThru # si se activa, devuelve stdout al caller ) $argString = $Arguments -join " " Write-Log "CMD: $Command $argString" -Level DEBUG if ($StdinText) { Write-Log "STDIN: $StdinText" -Level DEBUG } # Construir process info $psi = New-Object System.Diagnostics.ProcessStartInfo $psi.FileName = $Command $psi.Arguments = $argString $psi.RedirectStandardOutput = $true $psi.RedirectStandardError = $true $psi.RedirectStandardInput = [bool]$StdinText $psi.UseShellExecute = $false $psi.CreateNoWindow = $true $proc = New-Object System.Diagnostics.Process $proc.StartInfo = $psi $proc.Start() | Out-Null if ($StdinText) { $proc.StandardInput.Write($StdinText) $proc.StandardInput.Close() } $stdout = $proc.StandardOutput.ReadToEnd() $stderr = $proc.StandardError.ReadToEnd() $proc.WaitForExit() $exitCode = $proc.ExitCode if ($stdout.Trim()) { Write-Log "STDOUT:`n$($stdout.TrimEnd())" -Level DEBUG } if ($stderr.Trim()) { Write-Log "STDERR:`n$($stderr.TrimEnd())" -Level DEBUG } Write-Log "EXIT_CODE: $exitCode" -Level DEBUG if ($ThrowOnError -and $exitCode -ne 0) { $errMsg = if ($stderr.Trim()) { $stderr.Trim() } else { "exit code $exitCode" } throw "$Command fallo: $errMsg" } if ($PassThru) { return $stdout } return $exitCode } # ============================================================ # VARIABLES DE ESTADO (para resumen final) # ============================================================ $summary = @{ GitInstalled = $false NameSource = "" # "existente" | "nuevo" EmailSource = "" # "existente" | "nuevo" GitName = "" GitEmail = "" Domain = "" ConnectionMethod = "" # "SSH" | "HTTPS" | "Ambos" GpgGenerated = $false SshGenerated = $false PatConfigured = $false } # ============================================================ # FUNCIONES # ============================================================ function Exit-WithError($msg) { Write-Log $msg -Level ERROR Write-Host "`n[ERROR] $msg" -ForegroundColor Red Read-Host "`nPulsa Enter para salir" exit 1 } function Invoke-Prerequisites { param([string]$ConnectionMethod) Write-Host "`n--- Verificando requisitos previos ---" Write-Log "Verificando requisitos previos (metodo: $ConnectionMethod)" # winget (obligatorio) if (-not (Get-Command winget -ErrorAction SilentlyContinue)) { Exit-WithError "winget no disponible. Instala 'App Installer' desde la Microsoft Store y vuelve a ejecutar." } Write-Host " [OK] winget" Write-Log "winget: OK" # SSH (solo si se necesita) if ($ConnectionMethod -ne "HTTPS") { if (-not (Get-Command ssh -ErrorAction SilentlyContinue)) { Exit-WithError "ssh no disponible. Instalalo manualmente y vuelve a ejecutar." } Write-Host " [OK] ssh" Write-Log "ssh: OK" } else { Write-Log "ssh: no requerido (metodo HTTPS)" } # GPG (siempre) if (-not (Get-Command gpg -ErrorAction SilentlyContinue)) { Write-Host " [!] gpg no encontrado. Instalando..." Write-Log "gpg: no encontrado, instalando..." winget install --id GnuPG.GnuPG -e --source winget --accept-package-agreements --accept-source-agreements $env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("PATH", "User") + ";" + "C:\Program Files (x86)\GnuPG\bin" + ";" + "C:\Program Files\GnuPG\bin" if (-not (Get-Command gpg -ErrorAction SilentlyContinue)) { Exit-WithError "gpg instalado pero no encontrado en PATH. Reinicia la terminal y vuelve a ejecutar." } Write-Host " [OK] gpg instalado" Write-Log "gpg: instalado correctamente" } else { $gpgVersion = (gpg --version 2>&1 | Select-Object -First 1) Write-Host " [OK] gpg" Write-Log "gpg: OK ($gpgVersion)" } } function Install-GitIfNeeded { Write-Log "Comprobando si Git esta instalado..." if (Get-Command git -ErrorAction SilentlyContinue) { $gitVersion = (git --version 2>&1) Write-Host "`n [OK] Git ya instalado" Write-Log "Git: ya instalado ($gitVersion)" return $false } Write-Host "`n--- Instalando Git ---" Write-Log "Git: no encontrado, instalando..." winget install --id Git.Git -e --source winget --accept-package-agreements --accept-source-agreements $env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("PATH", "User") if (-not (Get-Command git -ErrorAction SilentlyContinue)) { Exit-WithError "Git instalado pero no encontrado en PATH. Reinicia la terminal y vuelve a ejecutar." } $gitVersion = (git --version 2>&1) Write-Log "Git: instalado correctamente ($gitVersion)" return $true } function Read-ValidEmail { param([string]$Prompt = "Email") do { $email = Read-Host $Prompt if ($email -notmatch '^[^@\s]+@[^@\s]+\.[^@\s]+$') { Write-Host " [!] Formato de email invalido. Intentalo de nuevo." -ForegroundColor Yellow Write-Log "Email invalido introducido: '$email'" -Level WARN } } while ($email -notmatch '^[^@\s]+@[^@\s]+\.[^@\s]+$') return $email } function Read-ConnectionMethod { Write-Host "`n--- Metodo de conexion ---" Write-Host " [1] SSH" Write-Host " [2] HTTPS" Write-Host " [3] Ambos" do { $choice = Read-Host "Selecciona (1/2/3)" } while ($choice -notin @("1", "2", "3")) switch ($choice) { "1" { return "SSH" } "2" { return "HTTPS" } "3" { return "Ambos" } } } function Set-BaseGitConfig { param($Name, $Mail) Write-Host "`n--- Configurando Git global ---" Write-Log "Configurando Git global: name='$Name', email='$Mail'" git config --global user.name "$Name" git config --global user.email "$Mail" git config --global core.editor "code --wait" git config --global init.defaultBranch develop Write-Log "Git global configurado correctamente" } function Set-GpgConfig { param($Name, $Mail, $Domain) Write-Host "`n--- Configurando GPG ---" Write-Log "Iniciando configuracion GPG: name='$Name', email='$Mail', domain='$Domain'" # Listar claves existentes $listOutput = Invoke-NativeCommand -Command "gpg" -Arguments @("--list-secret-keys", "--with-colons") -PassThru Write-Log "gpg --list-secret-keys raw output length: $($listOutput.Length) chars" $KEY_ID = ($listOutput -split "`n" | Where-Object { $_ -match "^sec:" } | ForEach-Object { ($_ -split ":")[4] } | Select-Object -First 1) Write-Log "KEY_ID encontrado en listado inicial: '$KEY_ID'" $gpgGenerated = $false if (-not $KEY_ID) { Write-Host " Generando clave GPG..." Write-Log "No hay clave GPG existente, generando nueva..." $batchContent = @( "%no-protection", "Key-Type: RSA", "Key-Length: 4096", "Name-Real: $Name", "Name-Email: $Mail", "Expire-Date: 0", "%commit" ) -join "`n" Write-Log "GPG batch content:`n$batchContent" $batchFile = Join-Path $env:TEMP "gpg-batch-$(Get-Date -Format 'yyyyMMddHHmmss').txt" [System.IO.File]::WriteAllText($batchFile, $batchContent) Write-Log "Batch file escrito en: $batchFile" # Verificar que el fichero se escribio bien $batchVerify = [System.IO.File]::ReadAllText($batchFile) Write-Log "Batch file verificacion (bytes: $($batchVerify.Length)):`n$batchVerify" $genExitCode = Invoke-NativeCommand -Command "gpg" -Arguments @("--batch", "--gen-key", $batchFile) Remove-Item $batchFile -ErrorAction SilentlyContinue if ($genExitCode -ne 0) { throw "Error al generar la clave GPG (exit code: $genExitCode). Consulta $LOG_FILE para mas detalles." } Write-Log "gpg --batch --gen-key finalizado con exit code 0, buscando KEY_ID..." $listOutput2 = Invoke-NativeCommand -Command "gpg" -Arguments @("--list-secret-keys", "--with-colons") -PassThru Write-Log "gpg --list-secret-keys (post-gen) raw output length: $($listOutput2.Length) chars" $KEY_ID = ($listOutput2 -split "`n" | Where-Object { $_ -match "^sec:" } | ForEach-Object { ($_ -split ":")[4] } | Select-Object -First 1) Write-Log "KEY_ID encontrado post-generacion: '$KEY_ID'" if (-not $KEY_ID) { throw "No se pudo obtener el ID de la clave GPG. Consulta $LOG_FILE para mas detalles." } $gpgGenerated = $true Write-Log "Clave GPG generada correctamente: $KEY_ID" } else { Write-Host " [OK] Clave GPG existente: $KEY_ID" Write-Log "Usando clave GPG existente: $KEY_ID" } $GPG_PATH = (Get-Command gpg).Source Write-Log "GPG path: $GPG_PATH" git config --global gpg.program "$GPG_PATH" git config --global user.signingkey "$KEY_ID" git config --global commit.gpgsign true Write-Log "Git config GPG aplicado (signingkey=$KEY_ID)" Write-Host " [OK] Clave GPG configurada: $KEY_ID" Write-Host "`n=== Clave GPG (pegar en GitLab > GPG Keys si no esta) ===`n" $gpgPublic = Invoke-NativeCommand -Command "gpg" -Arguments @("--armor", "--export", $KEY_ID) -PassThru Write-Log "gpg --armor --export output length: $($gpgPublic.Length) chars" if ($gpgPublic.Trim()) { Write-Host $gpgPublic.Trim() } else { Write-Host " [!] No se pudo exportar la clave publica GPG. Consulta $LOG_FILE" -ForegroundColor Yellow Write-Log "WARN: gpg --armor --export no devolvio contenido" -Level WARN } Start-Process "https://$Domain/-/user_settings/gpg_keys" Read-Host "`nPulsa Enter para continuar" return $gpgGenerated } function Set-GpgAgentAutoStart { Write-Host "`n--- Configurando arranque automatico de gpg-agent ---" Write-Log "Configurando arranque automatico de gpg-agent via Task Scheduler" # Localizar gpg-connect-agent (comando correcto para arranque idempotente del agente) # gpg-agent --daemon no funciona bien en Windows (T3337); gpg-connect-agent /bye si $_cmd = Get-Command "gpg-connect-agent.exe" -ErrorAction SilentlyContinue $gpgConnectAgent = if ($_cmd) { $_cmd.Source } else { $null } if (-not $gpgConnectAgent) { foreach ($candidate in @( "C:\Program Files (x86)\GnuPG\bin\gpg-connect-agent.exe", "C:\Program Files\GnuPG\bin\gpg-connect-agent.exe" )) { if (Test-Path $candidate) { $gpgConnectAgent = $candidate; break } } } if (-not $gpgConnectAgent) { Write-Host " [!] gpg-connect-agent.exe no encontrado. Autostart no configurado." -ForegroundColor Yellow Write-Log "gpg-connect-agent.exe no encontrado, autostart omitido" -Level WARN return } Write-Log "gpg-connect-agent: $gpgConnectAgent" # Crear gpg-agent.conf si no existe (tiempos de cache de jornada laboral) $gnupgHome = if ($env:GNUPGHOME) { $env:GNUPGHOME } else { "$env:APPDATA\gnupg" } if (-not (Test-Path $gnupgHome)) { New-Item -ItemType Directory -Path $gnupgHome -Force | Out-Null Write-Log "Directorio $gnupgHome creado" } $agentConf = Join-Path $gnupgHome "gpg-agent.conf" if (-not (Test-Path $agentConf)) { $utf8NoBom = New-Object System.Text.UTF8Encoding($false) [System.IO.File]::WriteAllLines($agentConf, @( "default-cache-ttl 34560000", "max-cache-ttl 34560000" ), $utf8NoBom) Write-Host " [OK] gpg-agent.conf creado ($agentConf)" Write-Log "gpg-agent.conf creado en: $agentConf" } else { Write-Host " [OK] gpg-agent.conf ya existe" Write-Log "gpg-agent.conf ya existe: $agentConf" } # Crear VBScript launcher: wscript.exe + WindowStyle=0 es la unica forma 100% fiable # de arrancar un proceso sin que aparezca ninguna ventana en una tarea programada. # powershell -WindowStyle Hidden sigue mostrando la ventana brevemente en algunos casos. $vbsPath = Join-Path $gnupgHome "launch-gpg-agent.vbs" $utf8NoBom = New-Object System.Text.UTF8Encoding($false) # bWaitOnReturn=True: el VBScript espera a que gpg-connect-agent confirme que el # agente esta listo antes de devolver el control. La doble llamada es el workaround # documentado del bug T4978 de GnuPG: la primera puede fallar mientras el agente # arranca su socket; la segunda siempre lo encuentra operativo. $vbsContent = @" Set WshShell = CreateObject("WScript.Shell") WshShell.Run """$gpgConnectAgent"" /bye", 0, True WshShell.Run """$gpgConnectAgent"" /bye", 0, True "@ [System.IO.File]::WriteAllText($vbsPath, $vbsContent, $utf8NoBom) Write-Log "VBScript launcher escrito en: $vbsPath" # Registrar tarea en Programador de tareas Windows (AtLogOn, sin privilegios elevados) try { $action = New-ScheduledTaskAction -Execute "wscript.exe" -Argument "`"$vbsPath`"" $trigger = New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME $settings = New-ScheduledTaskSettingsSet ` -AllowStartIfOnBatteries ` -DontStopIfGoingOnBatteries ` -ExecutionTimeLimit ([TimeSpan]::Zero) ` -StartWhenAvailable $principal = New-ScheduledTaskPrincipal ` -UserId $env:USERNAME ` -LogonType Interactive ` -RunLevel Limited Register-ScheduledTask ` -TaskName "GpgAgentAutoStart" ` -TaskPath "\GobTech\" ` -Action $action -Trigger $trigger ` -Settings $settings -Principal $principal ` -Description "Arranca gpg-agent al iniciar sesion para firmado de commits (GobTech)" ` -Force -ErrorAction Stop | Out-Null Write-Host " [OK] Tarea '\GobTech\GpgAgentAutoStart' registrada en Programador de tareas" Write-Log "Tarea '\GobTech\GpgAgentAutoStart' registrada correctamente" } catch { Write-Host " [!] No se pudo registrar en Programador de tareas: $_" -ForegroundColor Yellow Write-Log "Error registrando tarea programada: $_" -Level WARN } # Arrancar el agente en la sesion actual (doble llamada, workaround T4978) & "$gpgConnectAgent" /bye 2>$null & "$gpgConnectAgent" /bye 2>$null Write-Host " [OK] gpg-agent activo en la sesion actual" Write-Log "gpg-agent iniciado en sesion actual (doble gpg-connect-agent /bye, exit code: $LASTEXITCODE)" } function Set-SshConfig { param($Mail, $Domain, $SshHost) Write-Host "`n--- Configurando SSH ---" Write-Log "Iniciando configuracion SSH: email='$Mail', domain='$Domain', sshHost='$SshHost'" $sshGenerated = $false if (-not (Test-Path "$HOME\.ssh\id_ed25519")) { Write-Host " Generando clave SSH..." Write-Log "No existe $HOME\.ssh\id_ed25519, generando..." if (-not (Test-Path "$HOME\.ssh")) { New-Item -ItemType Directory "$HOME\.ssh" | Out-Null Write-Log "Directorio $HOME\.ssh creado" } Invoke-NativeCommand -Command "ssh-keygen" -Arguments @("-t", "ed25519", "-C", $Mail, "-f", "$HOME\.ssh\id_ed25519", "-N", '""') -ThrowOnError $sshGenerated = $true Write-Log "Clave SSH generada" } else { Write-Host " [OK] Clave SSH existente" Write-Log "Clave SSH ya existe en $HOME\.ssh\id_ed25519" } Write-Host "`n=== Clave SSH (pegar en GitLab > SSH Keys si no esta) ===`n" $sshPub = Get-Content "$HOME\.ssh\id_ed25519.pub" Write-Host $sshPub Write-Log "Clave SSH publica: $sshPub" Start-Process "https://$Domain/-/user_settings/ssh_keys" Read-Host "`nPulsa Enter para continuar" Write-Host " Probando conexion SSH con $SshHost..." Write-Log "Probando conexion SSH: ssh -T -o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 git@$SshHost" # Se ejecuta directamente (no via Invoke-NativeCommand) porque SSH puede # necesitar interaccion con el usuario (confirmacion de host key, etc.) ssh -T -o StrictHostKeyChecking=accept-new -o ConnectTimeout=15 "git@$SshHost" Write-Log "SSH test exit code: $LASTEXITCODE" return $sshGenerated } function Set-HttpsConfig { param($User, $Domain) Write-Host "`n--- Configurando HTTPS (credential.helper + PAT) ---" Write-Log "Iniciando configuracion HTTPS: user='$User', domain='$Domain'" # Suprimir GCM del sistema (credential.helper=manager en system gitconfig de Git for Windows). # Git encadena helpers de todos los niveles; GCM aparece primero y muestra un dialogo. # Una entrada vacia antes de store resetea la lista heredada del sistema. # git config no escribe valores vacios en PowerShell (los trata como "borrar clave"), # por eso manipulamos el fichero directamente. git config --global --unset-all credential.helper 2>$null $utf8NoBom = New-Object System.Text.UTF8Encoding($false) $configPath = "$HOME\.gitconfig" $lines = [System.Collections.Generic.List[string]]::new() $credFound = $false foreach ($ln in [System.IO.File]::ReadAllLines($configPath, [System.Text.Encoding]::UTF8)) { $lines.Add($ln) if ($ln -match '^\[credential\]') { $lines.Add("`thelper = ") # entrada vacia: resetea lista del sistema $lines.Add("`thelper = store") $credFound = $true } } if (-not $credFound) { $lines.Add("[credential]") $lines.Add("`thelper = ") $lines.Add("`thelper = store") } [System.IO.File]::WriteAllLines($configPath, $lines, $utf8NoBom) Write-Log "credential.helper configurado: '' + store (GCM del sistema suprimido)" Write-Host "`n=== PAT (Personal Access Token) ===" Write-Host "Genera un token con los scopes: read_user, read_repository, write_repository, api" Start-Process "https://$Domain/-/user_settings/personal_access_tokens" $isDefaultDomain = ($Domain -eq $DEFAULT_DOMAIN) do { $PAT = Read-Host "`nIntroduce el PAT generado" if ([string]::IsNullOrWhiteSpace($PAT)) { Write-Host " [!] El PAT no puede estar vacio." -ForegroundColor Yellow $valid = $false } elseif ($isDefaultDomain -and $PAT -notmatch "^gobtech-") { Write-Host " [!] PAT invalido. Debe empezar por 'gobtech-'" -ForegroundColor Yellow $valid = $false } else { $valid = $true } } while (-not $valid) Write-Log "PAT recibido (longitud: $($PAT.Length), prefijo: $($PAT.Substring(0, [Math]::Min(8, $PAT.Length)))...)" $escapedDomain = [regex]::Escape($Domain) $credFile = "$HOME\.git-credentials" $newEntry = "https://${User}:${PAT}@${Domain}" # Requisitos del fichero .git-credentials: # 1. Sin BOM: PowerShell 5.x escribe BOM con -Encoding utf8; git-credential-store lo # interpreta como parte de la URL y la primera entrada nunca hace match. # 2. Sin CRLF: WriteAllLines usa Environment.NewLine (\r\n en Windows); git lee el # fichero con strbuf_getline_lf() que solo elimina \n y deja \r en la URL, por lo # que "https://host\r" nunca coincide con "https://host". Se usa WriteAllText con # saltos de linea Unix (\n) explicitos, igual que escribe el propio git desde MINGW. $utf8NoBom = New-Object System.Text.UTF8Encoding($false) if (Test-Path $credFile) { # Get-Content normaliza los saltos de linea al leer, asi que las lineas existentes # quedan limpias independientemente del formato original del fichero. $lines = @(Get-Content $credFile -Encoding UTF8 | Where-Object { $_ -notmatch $escapedDomain }) $content = (($lines + $newEntry) -join "`n") + "`n" [System.IO.File]::WriteAllText($credFile, $content, $utf8NoBom) Write-Log "Credenciales actualizadas en $credFile (sin BOM, LF Unix)" } else { [System.IO.File]::WriteAllText($credFile, $newEntry + "`n", $utf8NoBom) Write-Log "Credenciales escritas en $credFile (fichero nuevo, sin BOM, LF Unix)" } return $true } function Show-Summary { param($summary) Write-Host "`n" Write-Host "============================================================" -ForegroundColor Cyan Write-Host " RESUMEN DE CONFIGURACION " -ForegroundColor Cyan Write-Host "============================================================" -ForegroundColor Cyan Write-Host "`n Git:" -ForegroundColor White if ($summary.GitInstalled) { Write-Host " Instalacion: Git instalado en esta sesion" } else { Write-Host " Instalacion: Ya estaba instalado" } Write-Host " Nombre: $($summary.GitName) ($($summary.NameSource))" Write-Host " Email: $($summary.GitEmail) ($($summary.EmailSource))" Write-Host "`n GitLab:" -ForegroundColor White Write-Host " Dominio: $($summary.Domain)" Write-Host " Conexion: $($summary.ConnectionMethod)" Write-Host "`n Seguridad:" -ForegroundColor White if ($summary.GpgGenerated) { Write-Host " GPG: Clave generada en esta sesion" } else { Write-Host " GPG: Se uso clave existente" } Write-Host " GPG-Agent: Autostart configurado (Programador de tareas Windows)" if ($summary.ConnectionMethod -in @("SSH", "Ambos")) { if ($summary.SshGenerated) { Write-Host " SSH: Clave generada en esta sesion" } else { Write-Host " SSH: Se uso clave existente" } } if ($summary.ConnectionMethod -in @("HTTPS", "Ambos")) { if ($summary.PatConfigured) { Write-Host " PAT: Configurado en esta sesion" } } Write-Host "`n============================================================" -ForegroundColor Cyan Write-Host " Log detallado: $LOG_FILE" -ForegroundColor DarkGray } # ============================================================ # MAIN # ============================================================ try { # Iniciar log "=" * 60 | Out-File -FilePath $LOG_FILE -Encoding utf8 Write-Log "Inicio de setup-git.ps1" Write-Log "PowerShell version: $($PSVersionTable.PSVersion)" Write-Log "OS: $([System.Environment]::OSVersion.VersionString)" Write-Log "Usuario Windows: $env:USERNAME" Write-Log "HOME: $HOME" Write-Log "TEMP: $env:TEMP" Write-Log "PATH: $env:PATH" Write-Host "============================================================" -ForegroundColor Cyan Write-Host " Setup de Git para GobTech " -ForegroundColor Cyan Write-Host "============================================================" -ForegroundColor Cyan # --- Paso 1-2: Instalar Git --- $summary.GitInstalled = Install-GitIfNeeded # --- Paso 3: Comprobar nombre/email existentes --- Write-Log "Comprobando git config existente..." $existingName = git config --global user.name 2>$null $existingMail = git config --global user.email 2>$null Write-Log "Existing name: '$existingName'" Write-Log "Existing mail: '$existingMail'" if ($existingName -and $existingMail) { Write-Host "`n [OK] Configuracion Git existente detectada:" Write-Host " Nombre: $existingName" Write-Host " Email: $existingMail" $GIT_NAME = $existingName $GIT_MAIL = $existingMail $summary.NameSource = "existente" $summary.EmailSource = "existente" } else { if ($existingName) { Write-Host "`n [OK] Nombre existente: $existingName" $GIT_NAME = $existingName $summary.NameSource = "existente" } else { $GIT_NAME = Read-Host "`nNombre completo" $summary.NameSource = "nuevo" } if ($existingMail) { Write-Host " [OK] Email existente: $existingMail" $GIT_MAIL = $existingMail $summary.EmailSource = "existente" } else { $GIT_MAIL = Read-ValidEmail -Prompt "Email" $summary.EmailSource = "nuevo" } } $summary.GitName = $GIT_NAME $summary.GitEmail = $GIT_MAIL Write-Log "Datos usuario: name='$GIT_NAME', email='$GIT_MAIL'" # --- Paso 4: Usuario GitLab --- $GIT_USER = Read-Host "Usuario de GitLab (ej: xabier.gabina)" Write-Log "Usuario GitLab: '$GIT_USER'" # --- Paso 5: Dominio GitLab --- $domainInput = Read-Host "Dominio GitLab (Enter para '$DEFAULT_DOMAIN')" if ([string]::IsNullOrWhiteSpace($domainInput)) { $GIT_DOMAIN = $DEFAULT_DOMAIN } else { $GIT_DOMAIN = $domainInput.Trim() } $summary.Domain = $GIT_DOMAIN $isDefaultDomain = ($GIT_DOMAIN -eq $DEFAULT_DOMAIN) Write-Log "Dominio GitLab: '$GIT_DOMAIN' (default: $isDefaultDomain)" # --- Paso 6: Metodo de conexion --- $connMethod = Read-ConnectionMethod $summary.ConnectionMethod = $connMethod Write-Log "Metodo de conexion: $connMethod" # --- Paso 7: Host SSH (si aplica) --- $SSH_HOST = $null if ($connMethod -ne "HTTPS") { if ($isDefaultDomain) { $sshInput = Read-Host "Host SSH (Enter para '$DEFAULT_SSH_HOST')" if ([string]::IsNullOrWhiteSpace($sshInput)) { $SSH_HOST = $DEFAULT_SSH_HOST } else { $SSH_HOST = $sshInput.Trim() } } else { do { $SSH_HOST = Read-Host "Host SSH (obligatorio para conexion SSH)" } while ([string]::IsNullOrWhiteSpace($SSH_HOST)) $SSH_HOST = $SSH_HOST.Trim() } Write-Log "Host SSH: '$SSH_HOST'" } # --- Prerequisites (ahora sabemos si necesitamos SSH) --- Invoke-Prerequisites -ConnectionMethod $connMethod # --- Paso 8: Configurar Git global --- Set-BaseGitConfig -Name $GIT_NAME -Mail $GIT_MAIL # --- Paso 9: GPG (siempre) --- $summary.GpgGenerated = Set-GpgConfig -Name $GIT_NAME -Mail $GIT_MAIL -Domain $GIT_DOMAIN # --- Paso 9b: Autostart de gpg-agent (siempre) --- Set-GpgAgentAutoStart # --- Paso 10: SSH (si aplica) --- if ($connMethod -ne "HTTPS") { $summary.SshGenerated = Set-SshConfig -Mail $GIT_MAIL -Domain $GIT_DOMAIN -SshHost $SSH_HOST } # --- Paso 11: HTTPS (si aplica) --- if ($connMethod -ne "SSH") { $summary.PatConfigured = Set-HttpsConfig -User $GIT_USER -Domain $GIT_DOMAIN } # --- Paso 12: Resumen final --- Show-Summary -summary $summary Write-Log "Setup completado correctamente" Write-Host "`nSetup completado." -ForegroundColor Green } catch { Write-Log "EXCEPCION: $_" -Level ERROR Write-Log "Stack trace: $($_.ScriptStackTrace)" -Level ERROR Write-Host "`n[ERROR] $_" -ForegroundColor Red Write-Host " Log detallado: $LOG_FILE" -ForegroundColor DarkGray } finally { Write-Log "Fin de ejecucion" Read-Host "`nPulsa Enter para salir" }