Initial commit: ROA2WEB - FastAPI + Vue.js + Telegram Bot
Modern ERP Reports Application with microservices architecture Tech Stack: - Backend: FastAPI + python-oracledb (Oracle DB integration) - Frontend: Vue.js 3 + PrimeVue + Vite - Telegram Bot: python-telegram-bot + SQLite - Infrastructure: Shared database pool, JWT authentication, SSH tunnel Features: - FastAPI backend with async Oracle connection pool - Vue.js 3 responsive frontend with PrimeVue components - Telegram bot alternative interface - Microservices architecture with shared components - Complete deployment support (Linux Docker + Windows IIS) - Comprehensive testing (Playwright E2E + pytest) Repository Structure: - reports-app/ - Main application (backend, frontend, telegram-bot) - shared/ - Shared components (database pool, auth, utils) - deployment/ - Deployment scripts (Linux & Windows) - docs/ - Project documentation - security/ - Security scanning and git hooks
This commit is contained in:
585
deployment/windows/scripts/Build-Frontend.ps1
Normal file
585
deployment/windows/scripts/Build-Frontend.ps1
Normal file
@@ -0,0 +1,585 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Build ROA2WEB Frontend for Production Deployment
|
||||
|
||||
.DESCRIPTION
|
||||
This script builds the Vue.js frontend for Windows Server deployment:
|
||||
- Checks for Node.js installation
|
||||
- Installs npm dependencies
|
||||
- Builds production-optimized static files
|
||||
- Creates deployment package with backend files
|
||||
- Optionally transfers to remote server
|
||||
|
||||
.PARAMETER BackendSource
|
||||
Path to backend source (default: ../../reports-app/backend)
|
||||
|
||||
.PARAMETER FrontendSource
|
||||
Path to frontend source (default: ../../reports-app/frontend)
|
||||
|
||||
.PARAMETER OutputPath
|
||||
Output path for deployment package (default: ./deploy-package)
|
||||
|
||||
.PARAMETER ServerPath
|
||||
Remote server path for automatic deployment (optional)
|
||||
|
||||
.PARAMETER ServerHost
|
||||
Remote server hostname/IP for automatic deployment (optional)
|
||||
|
||||
.EXAMPLE
|
||||
.\Build-Frontend.ps1
|
||||
Build with defaults, output to ./deploy-package
|
||||
|
||||
.EXAMPLE
|
||||
.\Build-Frontend.ps1 -OutputPath "D:\deployments\roa2web-$(Get-Date -Format 'yyyyMMdd')"
|
||||
Build to custom output path
|
||||
|
||||
.EXAMPLE
|
||||
.\Build-Frontend.ps1 -ServerHost "10.0.20.170" -ServerPath "C:\Temp\roa2web-deploy"
|
||||
Build and transfer to remote server
|
||||
|
||||
.NOTES
|
||||
Author: ROA2WEB Team
|
||||
Requires: Node.js 16+, npm
|
||||
Can run on: WSL, Windows, Linux
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$BackendSource = "../../reports-app/backend",
|
||||
[string]$FrontendSource = "../../reports-app/frontend",
|
||||
[string]$OutputPath = "./deploy-package",
|
||||
[string]$ServerHost = "",
|
||||
[string]$ServerPath = ""
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# =============================================================================
|
||||
# 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 Test-NodeJS {
|
||||
Write-Step "Checking Node.js installation..."
|
||||
|
||||
try {
|
||||
$nodeVersion = node --version 2>&1
|
||||
$npmVersion = npm --version 2>&1
|
||||
|
||||
Write-Success "Node.js: $nodeVersion"
|
||||
Write-Success "npm: $npmVersion"
|
||||
|
||||
# Check minimum version (16.x)
|
||||
if ($nodeVersion -match "v(\d+)\.") {
|
||||
$major = [int]$matches[1]
|
||||
if ($major -lt 16) {
|
||||
throw "Node.js version 16+ required (found: $nodeVersion)"
|
||||
}
|
||||
}
|
||||
|
||||
return $true
|
||||
} catch {
|
||||
Write-Error "Node.js not found or version too old"
|
||||
Write-Host "`n Install Node.js from: https://nodejs.org/" -ForegroundColor Yellow
|
||||
Write-Host " Minimum version: 16.x" -ForegroundColor Yellow
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
function Resolve-FullPath {
|
||||
param([string]$Path)
|
||||
|
||||
$scriptDir = Split-Path -Parent $PSScriptRoot
|
||||
$fullPath = Join-Path $scriptDir $Path
|
||||
|
||||
# Convert to absolute path and resolve .. and . properly
|
||||
$fullPath = [System.IO.Path]::GetFullPath($fullPath)
|
||||
|
||||
return $fullPath
|
||||
}
|
||||
|
||||
function Build-Frontend {
|
||||
param([string]$SourcePath)
|
||||
|
||||
Write-Step "Building Vue.js frontend..."
|
||||
|
||||
if (-not (Test-Path $SourcePath)) {
|
||||
throw "Frontend source path not found: $SourcePath"
|
||||
}
|
||||
|
||||
Push-Location $SourcePath
|
||||
try {
|
||||
# Clean node_modules if it exists (to avoid EPERM errors)
|
||||
$nodeModulesPath = Join-Path $SourcePath "node_modules"
|
||||
if (Test-Path $nodeModulesPath) {
|
||||
Write-Step "Cleaning existing node_modules..."
|
||||
try {
|
||||
Remove-Item -Path $nodeModulesPath -Recurse -Force -ErrorAction Stop
|
||||
Write-Success "Cleaned node_modules"
|
||||
} catch {
|
||||
Write-Warning "Could not remove node_modules: $_"
|
||||
Write-Warning "Please close VS Code/IDE and try again, or run as Administrator"
|
||||
throw "Cannot proceed with locked node_modules. Close all IDEs and retry."
|
||||
}
|
||||
}
|
||||
|
||||
# Install dependencies
|
||||
Write-Step "Installing npm dependencies (this may take a minute)..."
|
||||
|
||||
# Show npm output for transparency, redirect to host to prevent capture
|
||||
npm install | Out-Default
|
||||
|
||||
# Verify node_modules was created
|
||||
if (-not (Test-Path $nodeModulesPath)) {
|
||||
throw "npm install failed: node_modules not created. Check errors above."
|
||||
}
|
||||
Write-Success "Dependencies installed"
|
||||
|
||||
# Build for production
|
||||
Write-Step "Building for production (this may take a minute)..."
|
||||
$env:NODE_ENV = "production"
|
||||
|
||||
# Show build output for transparency, redirect to host to prevent capture
|
||||
npm run build | Out-Default
|
||||
|
||||
Write-Success "Build completed"
|
||||
|
||||
# Verify dist folder
|
||||
$distPath = Join-Path $SourcePath "dist"
|
||||
if (-not (Test-Path $distPath)) {
|
||||
throw "Build failed: dist folder not found"
|
||||
}
|
||||
|
||||
$distFiles = Get-ChildItem -Path $distPath -Recurse -File
|
||||
$totalSize = ($distFiles | Measure-Object -Property Length -Sum).Sum / 1MB
|
||||
Write-Success "Generated $(($distFiles).Count) files (Total: $([math]::Round($totalSize, 2)) MB)"
|
||||
|
||||
return $distPath
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
function Copy-BackendFiles {
|
||||
param(
|
||||
[string]$SourcePath,
|
||||
[string]$DestPath
|
||||
)
|
||||
|
||||
Write-Step "Copying backend files..."
|
||||
|
||||
if (-not (Test-Path $SourcePath)) {
|
||||
throw "Backend source path not found: $SourcePath"
|
||||
}
|
||||
|
||||
# Ensure destination exists
|
||||
if (-not (Test-Path $DestPath)) {
|
||||
New-Item -ItemType Directory -Path $DestPath -Force | Out-Null
|
||||
}
|
||||
|
||||
# Exclude directory names (will skip entire directory trees)
|
||||
$excludeDirs = @(
|
||||
"venv",
|
||||
"__pycache__",
|
||||
".pytest_cache",
|
||||
"logs",
|
||||
"temp",
|
||||
"node_modules"
|
||||
)
|
||||
|
||||
# Exclude file patterns
|
||||
$excludeFiles = @(
|
||||
"*.pyc",
|
||||
"*.pyo",
|
||||
"*.log",
|
||||
".env",
|
||||
".env.local"
|
||||
)
|
||||
|
||||
# Normalize source path (ensure trailing backslash for proper substring calculation)
|
||||
$normalizedSourcePath = $SourcePath.TrimEnd('\', '/') + '\'
|
||||
|
||||
# Helper function to check if path should be excluded (using script: scope to access parent variables)
|
||||
$testExclude = {
|
||||
param([string]$RelativePath, [bool]$IsDirectory, [array]$ExcludeDirs, [array]$ExcludeFiles)
|
||||
|
||||
# Check directory exclusions (match directory name exactly)
|
||||
if ($IsDirectory) {
|
||||
$dirName = Split-Path $RelativePath -Leaf
|
||||
if ($ExcludeDirs -contains $dirName) {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
# Check if any parent directory should be excluded
|
||||
$pathParts = $RelativePath -split '[\\/]'
|
||||
foreach ($part in $pathParts) {
|
||||
if ($ExcludeDirs -contains $part) {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
# Check file patterns
|
||||
if (-not $IsDirectory) {
|
||||
foreach ($pattern in $ExcludeFiles) {
|
||||
if ($RelativePath -like $pattern) {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
# Copy files
|
||||
Get-ChildItem -Path $SourcePath -Recurse | ForEach-Object {
|
||||
# Calculate relative path safely
|
||||
if ($_.FullName.Length -le $normalizedSourcePath.Length) {
|
||||
return # Skip if path is too short (shouldn't happen, but safety check)
|
||||
}
|
||||
$relativePath = $_.FullName.Substring($normalizedSourcePath.Length)
|
||||
|
||||
# Check if should be excluded
|
||||
$shouldExclude = & $testExclude -RelativePath $relativePath -IsDirectory $_.PSIsContainer -ExcludeDirs $excludeDirs -ExcludeFiles $excludeFiles
|
||||
if ($shouldExclude) {
|
||||
return
|
||||
}
|
||||
|
||||
$destFile = Join-Path $DestPath $relativePath
|
||||
|
||||
if ($_.PSIsContainer) {
|
||||
if (-not (Test-Path $destFile)) {
|
||||
New-Item -ItemType Directory -Path $destFile -Force | Out-Null
|
||||
}
|
||||
} else {
|
||||
$destDir = Split-Path $destFile -Parent
|
||||
if (-not (Test-Path $destDir)) {
|
||||
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
|
||||
}
|
||||
Copy-Item -Path $_.FullName -Destination $destFile -Force
|
||||
}
|
||||
}
|
||||
|
||||
$backendFiles = Get-ChildItem -Path $DestPath -Recurse -File
|
||||
Write-Success "Copied $(($backendFiles).Count) backend files"
|
||||
}
|
||||
|
||||
function New-DeploymentPackage {
|
||||
param(
|
||||
[string]$FrontendDistPath,
|
||||
[string]$BackendSourcePath,
|
||||
[string]$OutputPath
|
||||
)
|
||||
|
||||
Write-Step "Creating deployment package..."
|
||||
|
||||
# Create output directory
|
||||
if (Test-Path $OutputPath) {
|
||||
Write-Warning "Output path exists, cleaning..."
|
||||
Remove-Item -Path $OutputPath -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null
|
||||
|
||||
# Create structure
|
||||
$frontendDest = Join-Path $OutputPath "frontend"
|
||||
$backendDest = Join-Path $OutputPath "backend"
|
||||
|
||||
New-Item -ItemType Directory -Path $frontendDest -Force | Out-Null
|
||||
New-Item -ItemType Directory -Path $backendDest -Force | Out-Null
|
||||
|
||||
# Copy frontend dist
|
||||
Write-Step "Copying frontend files..."
|
||||
Copy-Item -Path "$FrontendDistPath\*" -Destination $frontendDest -Recurse -Force
|
||||
Write-Success "Frontend files copied"
|
||||
|
||||
# Copy backend files
|
||||
Copy-BackendFiles -SourcePath $BackendSourcePath -DestPath $backendDest
|
||||
|
||||
# Copy shared modules (database, auth, utils)
|
||||
Write-Step "Copying shared modules..."
|
||||
$sharedSource = Join-Path (Split-Path (Split-Path $BackendSourcePath -Parent) -Parent) "shared"
|
||||
$sharedDest = Join-Path $OutputPath "shared"
|
||||
|
||||
if (Test-Path $sharedSource) {
|
||||
Copy-Item -Path $sharedSource -Destination $sharedDest -Recurse -Force -Exclude @("__pycache__", "*.pyc", "tests")
|
||||
Write-Success "Shared modules copied"
|
||||
} else {
|
||||
Write-Warning "Shared modules not found at: $sharedSource"
|
||||
}
|
||||
|
||||
# Copy deployment config
|
||||
$configSource = Join-Path (Split-Path -Parent $PSScriptRoot) "config"
|
||||
$configDest = Join-Path $OutputPath "config"
|
||||
|
||||
if (Test-Path $configSource) {
|
||||
Copy-Item -Path $configSource -Destination $configDest -Recurse -Force
|
||||
Write-Success "Config files copied"
|
||||
}
|
||||
|
||||
# Copy deployment scripts
|
||||
Write-Step "Copying deployment scripts..."
|
||||
$scriptsSource = $PSScriptRoot
|
||||
$scriptsDest = Join-Path $OutputPath "scripts"
|
||||
New-Item -ItemType Directory -Path $scriptsDest -Force | Out-Null
|
||||
|
||||
# List of scripts to include in deployment package
|
||||
$deploymentScripts = @(
|
||||
"Install-ROA2WEB.ps1",
|
||||
"Deploy-ROA2WEB.ps1",
|
||||
"Start-ROA2WEB.ps1",
|
||||
"Stop-ROA2WEB.ps1",
|
||||
"Restart-ROA2WEB.ps1"
|
||||
)
|
||||
|
||||
$copiedScripts = 0
|
||||
foreach ($script in $deploymentScripts) {
|
||||
$scriptPath = Join-Path $scriptsSource $script
|
||||
if (Test-Path $scriptPath) {
|
||||
Copy-Item -Path $scriptPath -Destination $scriptsDest -Force
|
||||
$copiedScripts++
|
||||
}
|
||||
}
|
||||
Write-Success "Copied $copiedScripts deployment scripts"
|
||||
|
||||
# Create README
|
||||
$readmePath = Join-Path $OutputPath "README.txt"
|
||||
$readme = @"
|
||||
================================================================================
|
||||
ROA2WEB DEPLOYMENT PACKAGE
|
||||
Generated: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
|
||||
================================================================================
|
||||
|
||||
CONTENTS:
|
||||
---------
|
||||
backend/ FastAPI backend application files (Python)
|
||||
frontend/ Vue.js static files (built for production)
|
||||
config/ IIS configuration files (.env template, web.config)
|
||||
scripts/ PowerShell management scripts
|
||||
|
||||
DEPLOYMENT SCRIPTS:
|
||||
-------------------
|
||||
Install-ROA2WEB.ps1 First-time setup (Python venv, IIS site)
|
||||
Deploy-ROA2WEB.ps1 Update application files (auto-detects source)
|
||||
Start-ROA2WEB.ps1 Start backend service + IIS
|
||||
Stop-ROA2WEB.ps1 Stop backend service + IIS
|
||||
Restart-ROA2WEB.ps1 Quick restart
|
||||
|
||||
================================================================================
|
||||
DEPLOYMENT WORKFLOW
|
||||
================================================================================
|
||||
|
||||
>> FIRST TIME INSTALLATION:
|
||||
---------------------------
|
||||
1. Copy this entire folder to server (e.g., C:\Deploy\ROA2WEB-v1)
|
||||
|
||||
2. Open PowerShell as Administrator:
|
||||
cd C:\Deploy\ROA2WEB-v1\scripts
|
||||
.\Install-ROA2WEB.ps1
|
||||
|
||||
3. Configure environment:
|
||||
notepad C:\inetpub\wwwroot\roa2web\backend\.env
|
||||
|
||||
4. Start services:
|
||||
.\Start-ROA2WEB.ps1
|
||||
|
||||
5. Access: http://localhost:8080
|
||||
|
||||
|
||||
>> UPDATES (New code version):
|
||||
-------------------------------
|
||||
1. Copy new deployment package to server (e.g., C:\Deploy\ROA2WEB-v2)
|
||||
|
||||
2. Open PowerShell as Administrator:
|
||||
cd C:\Deploy\ROA2WEB-v2\scripts
|
||||
|
||||
3. Deploy (automatically stops, updates, and starts):
|
||||
.\Stop-ROA2WEB.ps1
|
||||
.\Deploy-ROA2WEB.ps1
|
||||
.\Start-ROA2WEB.ps1
|
||||
|
||||
Note: Deploy-ROA2WEB.ps1 auto-detects source path (no parameters needed!)
|
||||
|
||||
4. Done! Application updated with new code.
|
||||
|
||||
|
||||
>> QUICK OPERATIONS:
|
||||
--------------------
|
||||
Restart app: .\Restart-ROA2WEB.ps1
|
||||
Stop app: .\Stop-ROA2WEB.ps1
|
||||
Start app: .\Start-ROA2WEB.ps1
|
||||
|
||||
================================================================================
|
||||
REQUIREMENTS
|
||||
================================================================================
|
||||
- Windows Server 2016+ or Windows 10/11
|
||||
- IIS already installed (with ASP.NET Core Hosting Bundle)
|
||||
- Python 3.8+ installed
|
||||
- PowerShell 5.1+ (run as Administrator)
|
||||
|
||||
NOTES:
|
||||
------
|
||||
• Backend files do NOT include venv (virtual environment)
|
||||
• Install-ROA2WEB.ps1 creates venv and installs dependencies automatically
|
||||
• Deploy-ROA2WEB.ps1 creates backup before updating
|
||||
• .env files are preserved during updates
|
||||
• Application installs to: C:\inetpub\wwwroot\roa2web\
|
||||
|
||||
TROUBLESHOOTING:
|
||||
----------------
|
||||
Check logs: C:\inetpub\wwwroot\roa2web\logs\
|
||||
Backend logs: C:\inetpub\wwwroot\roa2web\backend\backend.log
|
||||
IIS logs: C:\inetpub\logs\LogFiles\
|
||||
|
||||
For detailed documentation, see: WINDOWS_DEPLOYMENT.md
|
||||
|
||||
================================================================================
|
||||
"@
|
||||
Set-Content -Path $readmePath -Value $readme -Force
|
||||
|
||||
# Calculate package size
|
||||
$packageFiles = Get-ChildItem -Path $OutputPath -Recurse -File
|
||||
$packageSize = ($packageFiles | Measure-Object -Property Length -Sum).Sum / 1MB
|
||||
|
||||
Write-Success "Deployment package created: $OutputPath"
|
||||
Write-Success "Total files: $(($packageFiles).Count)"
|
||||
Write-Success "Total size: $([math]::Round($packageSize, 2)) MB"
|
||||
|
||||
return $OutputPath
|
||||
}
|
||||
|
||||
function Copy-ToRemoteServer {
|
||||
param(
|
||||
[string]$LocalPath,
|
||||
[string]$ServerHost,
|
||||
[string]$ServerPath
|
||||
)
|
||||
|
||||
Write-Step "Transferring to remote server..."
|
||||
|
||||
try {
|
||||
# Check if remote server is accessible
|
||||
$pingResult = Test-Connection -ComputerName $ServerHost -Count 1 -Quiet
|
||||
|
||||
if (-not $pingResult) {
|
||||
Write-Warning "Server $ServerHost not reachable"
|
||||
return $false
|
||||
}
|
||||
|
||||
# Use robocopy for efficient transfer (Windows)
|
||||
if ($IsWindows -or $env:OS -match "Windows") {
|
||||
$remotePath = "\\$ServerHost\$($ServerPath -replace ':', '$')"
|
||||
|
||||
Write-Host " [*] Copying to: $remotePath" -ForegroundColor Yellow
|
||||
|
||||
robocopy $LocalPath $remotePath /E /Z /R:3 /W:5 /MT:8 /NFL /NDL /NP
|
||||
|
||||
if ($LASTEXITCODE -le 7) {
|
||||
Write-Success "Files transferred successfully"
|
||||
return $true
|
||||
} else {
|
||||
Write-Error "Transfer failed with code: $LASTEXITCODE"
|
||||
return $false
|
||||
}
|
||||
} else {
|
||||
# Use scp for Unix/WSL
|
||||
Write-Warning "Remote copy via SCP not yet implemented"
|
||||
Write-Host " Manual transfer required to: $ServerHost`:$ServerPath" -ForegroundColor Yellow
|
||||
return $false
|
||||
}
|
||||
} catch {
|
||||
Write-Error "Failed to transfer to server: $_"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# MAIN BUILD FLOW
|
||||
# =============================================================================
|
||||
|
||||
function Main {
|
||||
Write-Host @"
|
||||
|
||||
====================================================================
|
||||
ROA2WEB - Frontend Build Script
|
||||
Build Vue.js frontend and create deployment package
|
||||
====================================================================
|
||||
|
||||
"@ -ForegroundColor Cyan
|
||||
|
||||
try {
|
||||
# Resolve paths
|
||||
$backendSourcePath = Resolve-FullPath -Path $BackendSource
|
||||
$frontendSourcePath = Resolve-FullPath -Path $FrontendSource
|
||||
$outputPath = if ([System.IO.Path]::IsPathRooted($OutputPath)) { $OutputPath } else { Resolve-FullPath -Path $OutputPath }
|
||||
|
||||
Write-Host "`nPaths:" -ForegroundColor Yellow
|
||||
Write-Host " Backend Source: $backendSourcePath"
|
||||
Write-Host " Frontend Source: $frontendSourcePath"
|
||||
Write-Host " Output Path: $outputPath"
|
||||
|
||||
# Check Node.js
|
||||
Test-NodeJS
|
||||
|
||||
# Build frontend
|
||||
$distPath = Build-Frontend -SourcePath $frontendSourcePath
|
||||
|
||||
# Create deployment package
|
||||
$packagePath = New-DeploymentPackage `
|
||||
-FrontendDistPath $distPath `
|
||||
-BackendSourcePath $backendSourcePath `
|
||||
-OutputPath $outputPath
|
||||
|
||||
# Transfer to server if specified
|
||||
if ($ServerHost -and $ServerPath) {
|
||||
$transferred = Copy-ToRemoteServer `
|
||||
-LocalPath $packagePath `
|
||||
-ServerHost $ServerHost `
|
||||
-ServerPath $ServerPath
|
||||
}
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " BUILD COMPLETED SUCCESSFULLY" -ForegroundColor Green
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
Write-Host "`nDeployment Package: $packagePath" -ForegroundColor Yellow
|
||||
|
||||
if ($ServerHost) {
|
||||
Write-Host "`nNext Steps (on server $ServerHost):" -ForegroundColor Yellow
|
||||
Write-Host " cd $ServerPath"
|
||||
Write-Host " .\Deploy-ROA2WEB.ps1 -SourcePath ."
|
||||
} else {
|
||||
Write-Host "`nNext Steps:" -ForegroundColor Yellow
|
||||
Write-Host " 1. Transfer '$packagePath' to your Windows Server"
|
||||
Write-Host " 2. On the server, run: Deploy-ROA2WEB.ps1 -SourcePath '<transferred-path>'"
|
||||
}
|
||||
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
|
||||
} catch {
|
||||
Write-Host "`n[FATAL ERROR] Build failed: $_" -ForegroundColor Red
|
||||
Write-Host $_.ScriptStackTrace -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Run main build
|
||||
Main
|
||||
Reference in New Issue
Block a user