<# .SYNOPSIS ROA2WEB - Interactive Build & Publish Console .DESCRIPTION Build deployment packages locally and transfer to Windows Server: - Build locally (Frontend, Backend, Telegram Bot, or All) - Transfer via Windows Share (LAN) or SSH/SCP (remote) - Auto-detect best transfer method - Interactive menu or command-line operation - Server auto-deploys when new package detected .PARAMETER NonInteractive Run in non-interactive mode with specific action .PARAMETER Action Action to perform in non-interactive mode: - Build: Build and publish package - TestConnections: Test Windows Share and SSH connectivity - Configure: Edit configuration (interactive only) - ViewConfig: Display current configuration .PARAMETER Component Component to build (All, Frontend, Backend) .PARAMETER TransferMethod Transfer method (Auto, WindowsShare, SSH) .PARAMETER ConfigFile Path to configuration file (default: deploy-config.json) .EXAMPLE .\Publish-And-Deploy.ps1 Launch interactive menu .EXAMPLE .\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All Build all components and publish (auto-detect transfer method) .EXAMPLE .\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component Frontend -TransferMethod SSH Build frontend and publish via SSH .EXAMPLE .\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component DataEntryApp Build Data Entry App (frontend + backend) and publish .NOTES Author: ROA2WEB Team Version: 1.1 (Added Data Entry App support) Requires: PowerShell 5.1+, SSH key configured for remote access #> [CmdletBinding()] param( [switch]$NonInteractive, [ValidateSet("Build", "TestConnections", "ViewConfig")] [string]$Action = "", [ValidateSet("All", "Frontend", "Backend")] [string]$Component = "", [ValidateSet("Auto", "WindowsShare", "SSH")] [string]$TransferMethod = "", [string]$ConfigFile = "" ) $ErrorActionPreference = "Stop" # ============================================================================= # CONFIGURATION LOADING # ============================================================================= $script:ConfigFilePath = if ($ConfigFile) { $ConfigFile } else { Join-Path $PSScriptRoot "deploy-config.json" } function Load-Configuration { Write-Host "`nLoading configuration from: $script:ConfigFilePath" -ForegroundColor Gray if (-not (Test-Path $script:ConfigFilePath)) { Write-Host "[ERROR] Configuration file not found: $script:ConfigFilePath" -ForegroundColor Red Write-Host "Creating default configuration..." -ForegroundColor Yellow $defaultConfig = @{ server = @{ host = "10.0.20.36" sshPort = 22122 sshUser = "Administrator" sshKeyPath = "~/.ssh/roa2web_deploy" windowsShare = "\\10.0.20.36\ROA2WEB-Deploy" deployPath = "C:\ROA2WEB-Deploy" } build = @{ defaultComponent = "All" outputPath = "../deploy-package" } transfer = @{ defaultMethod = "Auto" scpRemotePath = "/cygdrive/c/ROA2WEB-Deploy" retryAttempts = 3 timeout = 300 } deployment = @{ autoDeployEnabled = $true checkIntervalMinutes = 5 } } $defaultConfig | ConvertTo-Json -Depth 10 | Set-Content -Path $script:ConfigFilePath Write-Host "Default configuration created. Please review and edit as needed." -ForegroundColor Green } try { $script:Config = Get-Content -Path $script:ConfigFilePath -Raw | ConvertFrom-Json Write-Host "[OK] Configuration loaded successfully" -ForegroundColor Green return $true } catch { Write-Host "[ERROR] Failed to load configuration: $_" -ForegroundColor Red return $false } } function Save-Configuration { try { $script:Config | ConvertTo-Json -Depth 10 | Set-Content -Path $script:ConfigFilePath Write-Host "[OK] Configuration saved successfully" -ForegroundColor Green return $true } catch { Write-Host "[ERROR] Failed to save configuration: $_" -ForegroundColor Red return $false } } # ============================================================================= # HELPER FUNCTIONS # ============================================================================= function Write-Step { param([string]$Message) Write-Host "`n[*] $Message" -ForegroundColor Cyan } function Write-Success { param([string]$Message) Write-Host " [OK] $Message" -ForegroundColor Green } function Write-Error { param([string]$Message) Write-Host " [ERROR] $Message" -ForegroundColor Red } function Write-Warning { param([string]$Message) Write-Host " [WARN] $Message" -ForegroundColor Yellow } function Write-Info { param([string]$Message) Write-Host " [*] $Message" -ForegroundColor Yellow } function Resolve-FullPath { param([string]$Path) # Resolve relative paths from the parent of the scripts directory # This matches the resolution logic in Build-ROA2WEB.ps1 $scriptDir = Split-Path -Parent $PSScriptRoot $fullPath = Join-Path $scriptDir $Path $fullPath = [System.IO.Path]::GetFullPath($fullPath) return $fullPath } function Wait-ForKeyPress { Write-Host "`nPress any key to continue..." -ForegroundColor Gray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") } # ============================================================================= # CONNECTION TESTING # ============================================================================= function Test-WindowsShare { Write-Step "Testing Windows Share access..." $sharePath = $script:Config.server.windowsShare Write-Info "Share: $sharePath" try { if (Test-Path $sharePath) { Write-Success "Windows Share is accessible" # Try to write test file $testFile = Join-Path $sharePath ".test-$(Get-Date -Format 'yyyyMMddHHmmss')" "test" | Out-File -FilePath $testFile -Force if (Test-Path $testFile) { Remove-Item -Path $testFile -Force Write-Success "Write permissions verified" return $true } else { Write-Warning "Share is readable but write test failed" return $false } } else { Write-Error "Windows Share is not accessible" Write-Info "Ensure network share is configured and accessible" return $false } } catch { Write-Error "Failed to access Windows Share: $_" return $false } } function Test-SSHConnection { Write-Step "Testing SSH connection..." $serverHost = $script:Config.server.host $port = $script:Config.server.sshPort $user = $script:Config.server.sshUser $keyPath = $script:Config.server.sshKeyPath Write-Info "Host: ${serverHost}:${port}" Write-Info "User: $user" Write-Info "Key: $keyPath" # Expand tilde in key path (support both Unix / and Windows \ styles) if ($keyPath -like "~/*" -or $keyPath -like "~\*") { $keyPath = $keyPath -replace "^~", $env:USERPROFILE } if (-not (Test-Path $keyPath)) { Write-Error "SSH key not found: $keyPath" return $false } try { # Test SSH connection $sshTest = ssh -i "$keyPath" -p $port -o ConnectTimeout=10 -o StrictHostKeyChecking=no "${user}@${serverHost}" "echo 'Connection successful'" 2>&1 if ($LASTEXITCODE -eq 0 -and $sshTest -like "*Connection successful*") { Write-Success "SSH connection established" return $true } else { Write-Error "SSH connection failed" Write-Info "Output: $sshTest" return $false } } catch { Write-Error "Failed to test SSH connection: $_" return $false } } function Test-AllConnections { Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan Write-Host " Connection Testing" -ForegroundColor Cyan Write-Host ("=" * 70) -ForegroundColor Cyan $shareOk = Test-WindowsShare $sshOk = Test-SSHConnection Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan Write-Host " Test Results" -ForegroundColor Cyan Write-Host ("=" * 70) -ForegroundColor Cyan Write-Host "`n Windows Share: " -NoNewline if ($shareOk) { Write-Host "[OK] Available" -ForegroundColor Green } else { Write-Host "[X] Not Available" -ForegroundColor Red } Write-Host " SSH Connection: " -NoNewline if ($sshOk) { Write-Host "[OK] Available" -ForegroundColor Green } else { Write-Host "[X] Not Available" -ForegroundColor Red } Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan return @{ WindowsShare = $shareOk SSH = $sshOk } } # ============================================================================= # BUILD & TRANSFER FUNCTIONS # ============================================================================= function Invoke-Build { param( [Parameter(Mandatory)] [ValidateSet("All", "Frontend", "Backend")] [string]$Component ) Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan Write-Host " Building Component: $Component" -ForegroundColor Cyan Write-Host ("=" * 70) -ForegroundColor Cyan $buildScript = Join-Path $PSScriptRoot "Build-ROA2WEB.ps1" if (-not (Test-Path $buildScript)) { Write-Error "Build script not found: $buildScript" return $false } try { $outputPath = $script:Config.build.outputPath # Resolve the output path using the same logic as Build-ROA2WEB.ps1 $resolvedOutputPath = if ([System.IO.Path]::IsPathRooted($outputPath)) { $outputPath } else { Resolve-FullPath -Path $outputPath } Write-Step "Building deployment package..." & $buildScript -Component $Component -OutputPath $outputPath if ($LASTEXITCODE -ne 0) { throw "Build script returned error code: $LASTEXITCODE" } if (-not (Test-Path $resolvedOutputPath)) { throw "Build output not found: $resolvedOutputPath" } Write-Success "Build completed successfully" return $true } catch { Write-Error "Build failed: $_" return $false } } function Copy-ViaWindowsShare { param([string]$SourcePath) Write-Step "Transferring via Windows Share..." $sharePath = $script:Config.server.windowsShare $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $deployFolder = "deploy-$timestamp" $destPath = Join-Path $sharePath $deployFolder try { Write-Info "Destination: $destPath" Copy-Item -Path $SourcePath -Destination $destPath -Recurse -Force if (Test-Path $destPath) { Write-Success "Files transferred successfully" Write-Success "Server will auto-deploy within $($script:Config.deployment.checkIntervalMinutes) minutes" return $true } else { Write-Error "Transfer failed - destination folder not found" return $false } } catch { Write-Error "Windows Share transfer failed: $_" return $false } } function Copy-ViaSSH { param([string]$SourcePath) Write-Step "Transferring via SSH/SCP..." $serverHost = $script:Config.server.host $port = $script:Config.server.sshPort $user = $script:Config.server.sshUser $keyPath = $script:Config.server.sshKeyPath $remotePath = $script:Config.transfer.scpRemotePath $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $deployFolder = "deploy-$timestamp" # Expand tilde in key path (support both Unix / and Windows \ styles) if ($keyPath -like "~/*" -or $keyPath -like "~\*") { $keyPath = $keyPath -replace "^~", $env:USERPROFILE } try { Write-Info "Host: ${serverHost}:${port}" Write-Info "Destination: ${remotePath}/${deployFolder}" # Create remote directory Write-Info "Creating remote directory..." $createDir = ssh -i "$keyPath" -p $port "${user}@${serverHost}" "mkdir -p '${remotePath}/${deployFolder}'" 2>&1 if ($LASTEXITCODE -ne 0) { throw "Failed to create remote directory: $createDir" } # Transfer files via SCP Write-Info "Transferring files (this may take a few minutes)..." $scpResult = scp -i "$keyPath" -P $port -r "${SourcePath}/*" "${user}@${serverHost}:${remotePath}/${deployFolder}/" 2>&1 if ($LASTEXITCODE -ne 0) { throw "SCP transfer failed: $scpResult" } Write-Success "Files transferred successfully" Write-Success "Server will auto-deploy within $($script:Config.deployment.checkIntervalMinutes) minutes" return $true } catch { Write-Error "SSH transfer failed: $_" return $false } } function Invoke-Transfer { param( [Parameter(Mandatory)] [ValidateSet("Auto", "WindowsShare", "SSH")] [string]$Method, [Parameter(Mandatory)] [string]$SourcePath ) Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan Write-Host " Transfer Method: $Method" -ForegroundColor Cyan Write-Host ("=" * 70) -ForegroundColor Cyan if ($Method -eq "Auto") { Write-Info "Auto-detecting best transfer method..." # Try Windows Share first (faster for LAN) Write-Info "Checking Windows Share availability..." if (Test-Path $script:Config.server.windowsShare) { Write-Success "Windows Share accessible - using Windows Share" return Copy-ViaWindowsShare -SourcePath $SourcePath } else { Write-Warning "Windows Share not accessible - falling back to SSH" return Copy-ViaSSH -SourcePath $SourcePath } } elseif ($Method -eq "WindowsShare") { return Copy-ViaWindowsShare -SourcePath $SourcePath } else { return Copy-ViaSSH -SourcePath $SourcePath } } # ============================================================================= # CONFIGURATION MANAGEMENT # ============================================================================= function Show-CurrentConfig { Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan Write-Host " Current Configuration" -ForegroundColor Cyan Write-Host ("=" * 70) -ForegroundColor Cyan Write-Host "" Write-Host " Server Settings:" -ForegroundColor Yellow Write-Host " Host: $($script:Config.server.host)" -ForegroundColor Gray Write-Host " SSH Port: $($script:Config.server.sshPort)" -ForegroundColor Gray Write-Host " SSH User: $($script:Config.server.sshUser)" -ForegroundColor Gray Write-Host " SSH Key: $($script:Config.server.sshKeyPath)" -ForegroundColor Gray Write-Host " Windows Share: $($script:Config.server.windowsShare)" -ForegroundColor Gray Write-Host " Deploy Path: $($script:Config.server.deployPath)" -ForegroundColor Gray Write-Host "" Write-Host " Build Settings:" -ForegroundColor Yellow Write-Host " Default Component: $($script:Config.build.defaultComponent)" -ForegroundColor Gray Write-Host " Output Path: $($script:Config.build.outputPath)" -ForegroundColor Gray Write-Host "" Write-Host " Transfer Settings:" -ForegroundColor Yellow Write-Host " Default Method: $($script:Config.transfer.defaultMethod)" -ForegroundColor Gray Write-Host " SCP Remote Path: $($script:Config.transfer.scpRemotePath)" -ForegroundColor Gray Write-Host " Retry Attempts: $($script:Config.transfer.retryAttempts)" -ForegroundColor Gray Write-Host " Timeout (sec): $($script:Config.transfer.timeout)" -ForegroundColor Gray Write-Host "" Write-Host " Deployment Settings:" -ForegroundColor Yellow Write-Host " Auto-Deploy: $($script:Config.deployment.autoDeployEnabled)" -ForegroundColor Gray Write-Host " Check Interval: $($script:Config.deployment.checkIntervalMinutes) minutes" -ForegroundColor Gray Write-Host "" Write-Host " Config File: $script:ConfigFilePath" -ForegroundColor Gray Write-Host ("=" * 70) -ForegroundColor Cyan } function Edit-Configuration { Clear-Host Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan Write-Host " Configuration Editor" -ForegroundColor Cyan Write-Host ("=" * 70) -ForegroundColor Cyan Write-Host "" Write-Host " Current Settings:" -ForegroundColor Yellow Write-Host " Server Host: $($script:Config.server.host)" -ForegroundColor Gray Write-Host " SSH Port: $($script:Config.server.sshPort)" -ForegroundColor Gray Write-Host " SSH User: $($script:Config.server.sshUser)" -ForegroundColor Gray Write-Host " SSH Key: $($script:Config.server.sshKeyPath)" -ForegroundColor Gray Write-Host " Windows Share: $($script:Config.server.windowsShare)" -ForegroundColor Gray Write-Host " Server Deploy Path: $($script:Config.server.deployPath)" -ForegroundColor Gray Write-Host "" Write-Host " [1] Edit SSH Connection Settings" -ForegroundColor White Write-Host " [2] Edit Windows Share Path" -ForegroundColor White Write-Host " [3] Edit Server Deploy Path" -ForegroundColor White Write-Host " [4] Edit Build Settings" -ForegroundColor White Write-Host " [5] Edit Transfer Settings" -ForegroundColor White Write-Host " [S] Save Configuration" -ForegroundColor Green Write-Host " [R] Reset to Defaults" -ForegroundColor Yellow Write-Host " [B] Back (discard changes)" -ForegroundColor Red Write-Host "" Write-Host ("=" * 70) -ForegroundColor Cyan do { Write-Host "`nYour choice: " -ForegroundColor Yellow -NoNewline $choice = Read-Host switch ($choice.ToUpper()) { "1" { Write-Host "`nEdit SSH Connection Settings:" -ForegroundColor Yellow Write-Host "Server Host [current: $($script:Config.server.host)]: " -NoNewline $newHost = Read-Host if ($newHost) { $script:Config.server.host = $newHost } Write-Host "SSH Port [current: $($script:Config.server.sshPort)]: " -NoNewline $newPort = Read-Host if ($newPort) { $script:Config.server.sshPort = [int]$newPort } Write-Host "SSH User [current: $($script:Config.server.sshUser)]: " -NoNewline $newUser = Read-Host if ($newUser) { $script:Config.server.sshUser = $newUser } Write-Host "SSH Key Path [current: $($script:Config.server.sshKeyPath)]: " -NoNewline $newKey = Read-Host if ($newKey) { $script:Config.server.sshKeyPath = $newKey } Write-Success "SSH settings updated (not saved yet)" return Edit-Configuration } "2" { Write-Host "`nEdit Windows Share Path:" -ForegroundColor Yellow Write-Host "Windows Share [current: $($script:Config.server.windowsShare)]: " -NoNewline $newShare = Read-Host if ($newShare) { $script:Config.server.windowsShare = $newShare } Write-Success "Windows Share updated (not saved yet)" return Edit-Configuration } "3" { Write-Host "`nEdit Server Deploy Path:" -ForegroundColor Yellow Write-Host "Deploy Path [current: $($script:Config.server.deployPath)]: " -NoNewline $newPath = Read-Host if ($newPath) { $script:Config.server.deployPath = $newPath } Write-Success "Deploy path updated (not saved yet)" return Edit-Configuration } "4" { Write-Host "`nEdit Build Settings:" -ForegroundColor Yellow Write-Host "Default Component (All/Frontend/Backend)" -ForegroundColor Gray Write-Host "[current: $($script:Config.build.defaultComponent)]: " -NoNewline $newComp = Read-Host if ($newComp) { $script:Config.build.defaultComponent = $newComp } Write-Host "Output Path [current: $($script:Config.build.outputPath)]: " -NoNewline $newOut = Read-Host if ($newOut) { $script:Config.build.outputPath = $newOut } Write-Success "Build settings updated (not saved yet)" return Edit-Configuration } "5" { Write-Host "`nEdit Transfer Settings:" -ForegroundColor Yellow Write-Host "Default Method (Auto/WindowsShare/SSH) [current: $($script:Config.transfer.defaultMethod)]: " -NoNewline $newMethod = Read-Host if ($newMethod) { $script:Config.transfer.defaultMethod = $newMethod } Write-Host "SCP Remote Path [current: $($script:Config.transfer.scpRemotePath)]: " -NoNewline $newScp = Read-Host if ($newScp) { $script:Config.transfer.scpRemotePath = $newScp } Write-Success "Transfer settings updated (not saved yet)" return Edit-Configuration } "S" { if (Save-Configuration) { Write-Host "`nConfiguration saved successfully!" -ForegroundColor Green Wait-ForKeyPress return } } "R" { Write-Host "`nAre you sure you want to reset to defaults? [Y/N]: " -ForegroundColor Yellow -NoNewline $confirm = Read-Host if ($confirm.ToUpper() -eq "Y") { Load-Configuration Write-Success "Configuration reset to defaults" return Edit-Configuration } } "B" { Write-Host "`nChanges discarded" -ForegroundColor Yellow Load-Configuration # Reload from file return } default { Write-Host "Invalid choice. Please select 1-5, S, R, or B." -ForegroundColor Red } } } while ($true) } # ============================================================================= # MENU FUNCTIONS # ============================================================================= function Show-MainMenu { Clear-Host Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan Write-Host " ROA2WEB - Interactive Build & Publish Console" -ForegroundColor Cyan Write-Host ("=" * 70) -ForegroundColor Cyan Write-Host "" Write-Host " Main Menu:" -ForegroundColor Yellow Write-Host "" Write-Host " [1] Build & Publish Package" -ForegroundColor White Write-Host " (Build locally and transfer to server)" -ForegroundColor Gray Write-Host "" Write-Host " [2] Test Connections" -ForegroundColor White Write-Host " (Verify Windows Share and SSH access)" -ForegroundColor Gray Write-Host "" Write-Host " [3] Configure Settings" -ForegroundColor White Write-Host " (Edit deployment configuration)" -ForegroundColor Gray Write-Host "" Write-Host " [4] View Current Configuration" -ForegroundColor White Write-Host " (Display active settings)" -ForegroundColor Gray Write-Host "" Write-Host " [Q] Quit" -ForegroundColor Red Write-Host "" Write-Host ("=" * 70) -ForegroundColor Cyan do { Write-Host "`nYour choice: " -ForegroundColor Yellow -NoNewline $choice = Read-Host switch ($choice.ToUpper()) { "1" { return "BuildPublish" } "2" { return "TestConnections" } "3" { return "Configure" } "4" { return "ViewConfig" } "Q" { return "Quit" } default { Write-Host "Invalid choice. Please select 1-4 or Q." -ForegroundColor Red } } } while ($true) } function Show-ComponentMenu { Clear-Host Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan Write-Host " Select Component to Build" -ForegroundColor Cyan Write-Host " Ultrathin Monolith Architecture" -ForegroundColor Cyan Write-Host ("=" * 70) -ForegroundColor Cyan Write-Host "" Write-Host " [1] All Components" -ForegroundColor White Write-Host " (Unified Backend + Frontend)" -ForegroundColor Gray Write-Host " Includes: Reports, Data Entry, and Telegram modules" -ForegroundColor DarkGray Write-Host "" Write-Host " [2] Frontend + Backend" -ForegroundColor White Write-Host " (Vue.js SPA build + Unified FastAPI backend)" -ForegroundColor Gray Write-Host "" Write-Host " [3] Backend Only" -ForegroundColor White Write-Host " (Unified FastAPI backend + shared modules)" -ForegroundColor Gray Write-Host " All modules included - control via MODULE_*_ENABLED flags" -ForegroundColor DarkGray Write-Host "" Write-Host " [B] Back to Main Menu" -ForegroundColor Yellow Write-Host "" Write-Host ("=" * 70) -ForegroundColor Cyan do { Write-Host "`nYour choice: " -ForegroundColor Yellow -NoNewline $choice = Read-Host switch ($choice.ToUpper()) { "1" { return "All" } "2" { return "Frontend" } "3" { return "Backend" } "B" { return "Back" } default { Write-Host "Invalid choice. Please select 1-3 or B." -ForegroundColor Red } } } while ($true) } function Show-TransferMenu { Clear-Host Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan Write-Host " Select Transfer Method" -ForegroundColor Cyan Write-Host ("=" * 70) -ForegroundColor Cyan Write-Host "" Write-Host " [1] Auto-detect (Recommended)" -ForegroundColor White Write-Host " Try Windows Share first, fallback to SSH" -ForegroundColor Gray Write-Host "" Write-Host " [2] Windows Share (LAN)" -ForegroundColor White Write-Host " Fast transfer via network share ($($script:Config.server.windowsShare))" -ForegroundColor Gray Write-Host "" Write-Host " [3] SSH/SCP (Remote)" -ForegroundColor White Write-Host " Secure transfer via SSH (port $($script:Config.server.sshPort))" -ForegroundColor Gray Write-Host "" Write-Host " [B] Back" -ForegroundColor Yellow Write-Host "" Write-Host ("=" * 70) -ForegroundColor Cyan do { Write-Host "`nYour choice: " -ForegroundColor Yellow -NoNewline $choice = Read-Host switch ($choice.ToUpper()) { "1" { return "Auto" } "2" { return "WindowsShare" } "3" { return "SSH" } "B" { return "Back" } default { Write-Host "Invalid choice. Please select 1-3 or B." -ForegroundColor Red } } } while ($true) } # ============================================================================= # ACTION HANDLERS # ============================================================================= function Invoke-BuildAndPublish { param( [string]$Component = "", [string]$TransferMethod = "" ) # Get component if not provided if (-not $Component) { $Component = Show-ComponentMenu if ($Component -eq "Back") { return } } # Get transfer method if not provided if (-not $TransferMethod) { $TransferMethod = Show-TransferMenu if ($TransferMethod -eq "Back") { return } } # Build $buildSuccess = Invoke-Build -Component $Component if (-not $buildSuccess) { Write-Host "`n[BUILD FAILED] Cannot proceed with transfer" -ForegroundColor Red if (-not $NonInteractive) { Wait-ForKeyPress } return } # Transfer $outputPath = $script:Config.build.outputPath # Resolve the output path for transfer $resolvedOutputPath = if ([System.IO.Path]::IsPathRooted($outputPath)) { $outputPath } else { Resolve-FullPath -Path $outputPath } $transferSuccess = Invoke-Transfer -Method $TransferMethod -SourcePath $resolvedOutputPath if ($transferSuccess) { Write-Host "`n" + ("=" * 70) -ForegroundColor Green Write-Host " BUILD & PUBLISH COMPLETED SUCCESSFULLY" -ForegroundColor Green Write-Host ("=" * 70) -ForegroundColor Green Write-Host "`nPackage published to server: $($script:Config.server.host)" -ForegroundColor Gray Write-Host "Server will auto-deploy within $($script:Config.deployment.checkIntervalMinutes) minutes" -ForegroundColor Gray Write-Host ("=" * 70) -ForegroundColor Green } else { Write-Host "`n[TRANSFER FAILED] Package built but transfer failed" -ForegroundColor Red } if (-not $NonInteractive) { Wait-ForKeyPress } } # ============================================================================= # MAIN EXECUTION FLOW # ============================================================================= function Main { # Load configuration if (-not (Load-Configuration)) { Write-Host "`nPress any key to exit..." -ForegroundColor Gray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit 1 } # Non-interactive mode if ($NonInteractive -and $Action) { switch ($Action) { "Build" { $comp = if ($Component) { $Component } else { $script:Config.build.defaultComponent } $method = if ($TransferMethod) { $TransferMethod } else { $script:Config.transfer.defaultMethod } Invoke-BuildAndPublish -Component $comp -TransferMethod $method } "TestConnections" { Test-AllConnections | Out-Null } "ViewConfig" { Show-CurrentConfig } } return } # Interactive mode - main loop do { $mainChoice = Show-MainMenu switch ($mainChoice) { "BuildPublish" { Invoke-BuildAndPublish } "TestConnections" { Test-AllConnections | Out-Null Wait-ForKeyPress } "Configure" { Edit-Configuration } "ViewConfig" { Show-CurrentConfig Wait-ForKeyPress } "Quit" { Write-Host "`nGoodbye!`n" -ForegroundColor Cyan return } } } while ($true) } # Run main Main