Refactor Windows deployment scripts: unify build and management tools
Major improvements to deployment workflow with unified scripts and interactive menus. New unified scripts: - Build-ROA2WEB.ps1: Interactive menu for building all components * Isolated temp directory for frontend builds (prevents WSL node_modules corruption) * Automatic devDependencies installation (fixes Vite not found issue) * Auto-cleanup after build * Supports both interactive menu and non-interactive CLI - ROA2WEB-Console.ps1: All-in-one deployment and management console * Interactive menus for deploy, manage services, and status checks * Automatic backups before deployment * Smart dependency updates (only if requirements.txt changed) * Health checks after service operations * Color-coded status output * Both interactive and non-interactive modes Removed deprecated scripts (replaced by unified tools): - Build-Frontend.ps1 → Use Build-ROA2WEB.ps1 -Component Frontend - Build-TelegramBot.ps1 → Use Build-ROA2WEB.ps1 -Component TelegramBot - Deploy-ROA2WEB.ps1 → Use ROA2WEB-Console.ps1 [Deploy menu] - Deploy-TelegramBot.ps1 → Use ROA2WEB-Console.ps1 [Deploy menu] - Manage-ROA2WEB.ps1 → Use ROA2WEB-Console.ps1 [Manage menu] Updated documentation: - Complete rewrite of scripts/README.md - Clear workflow guides for first-time deployment and updates - Comparison table v1.0 vs v2.0 - Updated best practices and troubleshooting Benefits: ✅ Reduced from 13 to 8 scripts (better maintainability) ✅ Interactive menus for better UX ✅ Fixed WSL node_modules corruption issue ✅ Smart dependency management (faster deployments) ✅ Unified interface reduces learning curve ✅ Better error handling and health checks 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -14,11 +14,12 @@
|
||||
- Supports automatic server transfer
|
||||
|
||||
.PARAMETER Component
|
||||
Component(s) to build:
|
||||
- All (default): Build complete package (frontend + backend + telegram bot)
|
||||
Component(s) to build (optional - shows interactive menu if not specified):
|
||||
- All: Build complete package (frontend + backend + telegram bot)
|
||||
- Frontend: Build frontend + backend files only
|
||||
- Backend: Copy backend files only (no frontend build)
|
||||
- TelegramBot: Build telegram bot package only
|
||||
- If omitted: Interactive menu will be displayed
|
||||
|
||||
.PARAMETER OutputPath
|
||||
Output path for deployment package (default: ./deploy-package)
|
||||
@@ -34,7 +35,11 @@
|
||||
|
||||
.EXAMPLE
|
||||
.\Build-ROA2WEB.ps1
|
||||
Build complete deployment package (all components)
|
||||
Shows interactive menu to select components to build
|
||||
|
||||
.EXAMPLE
|
||||
.\Build-ROA2WEB.ps1 -Component All
|
||||
Build complete deployment package (all components) without menu
|
||||
|
||||
.EXAMPLE
|
||||
.\Build-ROA2WEB.ps1 -Component Frontend
|
||||
@@ -57,7 +62,7 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[ValidateSet("All", "Frontend", "Backend", "TelegramBot")]
|
||||
[string]$Component = "All",
|
||||
[string]$Component = "",
|
||||
|
||||
[string]$OutputPath = "./deploy-package",
|
||||
[string]$ServerHost = "",
|
||||
@@ -74,7 +79,7 @@ $ErrorActionPreference = "Stop"
|
||||
$config = @{
|
||||
BackendSource = "../../reports-app/backend"
|
||||
FrontendSource = "../../reports-app/frontend"
|
||||
TelegramBotSource = "../../../reports-app/telegram-bot"
|
||||
TelegramBotSource = "../../reports-app/telegram-bot"
|
||||
SharedSource = "../../shared"
|
||||
ConfigSource = "../config"
|
||||
RequiredNodeVersion = 16
|
||||
@@ -114,6 +119,49 @@ function Resolve-FullPath {
|
||||
return $fullPath
|
||||
}
|
||||
|
||||
function Show-BuildMenu {
|
||||
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host " ROA2WEB - Build Component Selection Menu" -ForegroundColor Cyan
|
||||
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " Select components to build:" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host " [1] All Components" -ForegroundColor White
|
||||
Write-Host " (Frontend + Backend + Telegram Bot)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [2] Frontend + Backend" -ForegroundColor White
|
||||
Write-Host " (Vue.js build + FastAPI backend files)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [3] Backend Only" -ForegroundColor White
|
||||
Write-Host " (FastAPI backend files + shared modules)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " [4] Telegram Bot Only" -ForegroundColor White
|
||||
Write-Host " (Telegram bot standalone package)" -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 "All" }
|
||||
"2" { return "Frontend" }
|
||||
"3" { return "Backend" }
|
||||
"4" { return "TelegramBot" }
|
||||
"Q" {
|
||||
Write-Host "`nBuild cancelled by user." -ForegroundColor Yellow
|
||||
exit 0
|
||||
}
|
||||
default {
|
||||
Write-Host "Invalid choice. Please select 1-4 or Q." -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
} while ($true)
|
||||
}
|
||||
|
||||
function Test-NodeJS {
|
||||
Write-Step "Checking Node.js installation..."
|
||||
|
||||
@@ -142,37 +190,90 @@ function Test-NodeJS {
|
||||
}
|
||||
|
||||
function Build-Frontend {
|
||||
param([string]$SourcePath)
|
||||
param(
|
||||
[string]$SourcePath,
|
||||
[string]$OutputPath
|
||||
)
|
||||
|
||||
Write-Step "Building Vue.js frontend..."
|
||||
Write-Step "Building Vue.js frontend in isolated environment..."
|
||||
|
||||
if (-not (Test-Path $SourcePath)) {
|
||||
throw "Frontend source path not found: $SourcePath"
|
||||
}
|
||||
|
||||
Push-Location $SourcePath
|
||||
try {
|
||||
# Clean node_modules if it exists
|
||||
$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: $_"
|
||||
throw "Cannot proceed with locked node_modules. Close all IDEs and retry."
|
||||
# Create temporary build directory
|
||||
$tempBuildDir = Join-Path $OutputPath ".temp-frontend-build"
|
||||
if (Test-Path $tempBuildDir) {
|
||||
Write-Step "Cleaning existing temp build directory..."
|
||||
Remove-Item -Path $tempBuildDir -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Path $tempBuildDir -Force | Out-Null
|
||||
Write-Success "Created temp build directory (isolated from WSL)"
|
||||
|
||||
# Copy frontend sources to temp (exclude node_modules, dist, .git)
|
||||
Write-Step "Copying frontend sources to temp directory..."
|
||||
$excludeDirs = @("node_modules", "dist", ".git", "__pycache__", ".vscode", ".idea")
|
||||
$excludeFiles = @(".env", ".env.local", "*.log")
|
||||
|
||||
Get-ChildItem -Path $SourcePath -Recurse | ForEach-Object {
|
||||
$relativePath = $_.FullName.Substring($SourcePath.Length).TrimStart('\', '/')
|
||||
|
||||
# Check if in excluded directory
|
||||
$inExcludedDir = $false
|
||||
foreach ($excludeDir in $excludeDirs) {
|
||||
if ($relativePath -match "^$excludeDir" -or $relativePath -match "[\\/]$excludeDir[\\/]") {
|
||||
$inExcludedDir = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
if ($inExcludedDir) { return }
|
||||
|
||||
# Install dependencies
|
||||
Write-Step "Installing npm dependencies..."
|
||||
# Check if excluded file
|
||||
$isExcludedFile = $false
|
||||
foreach ($pattern in $excludeFiles) {
|
||||
if ($_.Name -like $pattern) {
|
||||
$isExcludedFile = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
if ($isExcludedFile) { return }
|
||||
|
||||
$destPath = Join-Path $tempBuildDir $relativePath
|
||||
|
||||
if ($_.PSIsContainer) {
|
||||
if (-not (Test-Path $destPath)) {
|
||||
New-Item -ItemType Directory -Path $destPath -Force | Out-Null
|
||||
}
|
||||
} else {
|
||||
$destDir = Split-Path $destPath -Parent
|
||||
if (-not (Test-Path $destDir)) {
|
||||
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
|
||||
}
|
||||
Copy-Item -Path $_.FullName -Destination $destPath -Force
|
||||
}
|
||||
}
|
||||
Write-Success "Frontend sources copied to temp"
|
||||
|
||||
# Build in temp directory
|
||||
Push-Location $tempBuildDir
|
||||
try {
|
||||
# Install dependencies (including devDependencies for Vite)
|
||||
Write-Step "Installing npm dependencies (Windows binaries)..."
|
||||
# Clear NODE_ENV to ensure devDependencies (vite, etc.) are installed
|
||||
Remove-Item Env:\NODE_ENV -ErrorAction SilentlyContinue
|
||||
npm install | Out-Default
|
||||
|
||||
$nodeModulesPath = Join-Path $tempBuildDir "node_modules"
|
||||
if (-not (Test-Path $nodeModulesPath)) {
|
||||
throw "npm install failed: node_modules not created"
|
||||
}
|
||||
Write-Success "Dependencies installed"
|
||||
Write-Success "Dependencies installed in temp"
|
||||
|
||||
# Verify Vite is installed
|
||||
$vitePath = Join-Path $nodeModulesPath ".bin\vite.cmd"
|
||||
if (-not (Test-Path $vitePath)) {
|
||||
throw "Vite not found in node_modules - devDependencies not installed"
|
||||
}
|
||||
|
||||
# Build for production
|
||||
Write-Step "Building for production..."
|
||||
@@ -181,7 +282,7 @@ function Build-Frontend {
|
||||
Write-Success "Build completed"
|
||||
|
||||
# Verify dist folder
|
||||
$distPath = Join-Path $SourcePath "dist"
|
||||
$distPath = Join-Path $tempBuildDir "dist"
|
||||
if (-not (Test-Path $distPath)) {
|
||||
throw "Build failed: dist folder not found"
|
||||
}
|
||||
@@ -417,6 +518,26 @@ function Copy-ConfigTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
function Remove-TempDirectories {
|
||||
param([string]$OutputPath)
|
||||
|
||||
Write-Step "Cleaning up temporary build directories..."
|
||||
|
||||
$tempBuildDir = Join-Path $OutputPath ".temp-frontend-build"
|
||||
|
||||
if (Test-Path $tempBuildDir) {
|
||||
try {
|
||||
Remove-Item -Path $tempBuildDir -Recurse -Force -ErrorAction Stop
|
||||
Write-Success "Temporary build directory cleaned"
|
||||
} catch {
|
||||
Write-Warning "Could not remove temp directory: $_"
|
||||
Write-Warning "You may need to manually delete: $tempBuildDir"
|
||||
}
|
||||
} else {
|
||||
Write-Success "No temporary directories to clean"
|
||||
}
|
||||
}
|
||||
|
||||
function Copy-DeploymentScripts {
|
||||
param(
|
||||
[string]$ScriptsSourcePath,
|
||||
@@ -652,7 +773,7 @@ function New-DeploymentPackage {
|
||||
switch ($ComponentType) {
|
||||
"All" {
|
||||
# Frontend
|
||||
$frontendDistPath = Build-Frontend -SourcePath $Paths.FrontendSource
|
||||
$frontendDistPath = Build-Frontend -SourcePath $Paths.FrontendSource -OutputPath $OutputPath
|
||||
$frontendDest = Join-Path $OutputPath "frontend"
|
||||
New-Item -ItemType Directory -Path $frontendDest -Force | Out-Null
|
||||
Write-Step "Copying frontend files..."
|
||||
@@ -678,7 +799,7 @@ function New-DeploymentPackage {
|
||||
|
||||
"Frontend" {
|
||||
# Frontend build
|
||||
$frontendDistPath = Build-Frontend -SourcePath $Paths.FrontendSource
|
||||
$frontendDistPath = Build-Frontend -SourcePath $Paths.FrontendSource -OutputPath $OutputPath
|
||||
$frontendDest = Join-Path $OutputPath "frontend"
|
||||
New-Item -ItemType Directory -Path $frontendDest -Force | Out-Null
|
||||
Write-Step "Copying frontend files..."
|
||||
@@ -719,6 +840,11 @@ function New-DeploymentPackage {
|
||||
}
|
||||
}
|
||||
|
||||
# Cleanup temporary directories
|
||||
if ($ComponentType -eq "All" -or $ComponentType -eq "Frontend") {
|
||||
Remove-TempDirectories -OutputPath $OutputPath
|
||||
}
|
||||
|
||||
# Copy deployment scripts
|
||||
Copy-DeploymentScripts -ScriptsSourcePath $PSScriptRoot -DestPath $OutputPath -ComponentType $ComponentType
|
||||
|
||||
@@ -741,6 +867,11 @@ function New-DeploymentPackage {
|
||||
# =============================================================================
|
||||
|
||||
function Main {
|
||||
# Show interactive menu if no component specified
|
||||
if ([string]::IsNullOrWhiteSpace($Component)) {
|
||||
$script:Component = Show-BuildMenu
|
||||
}
|
||||
|
||||
$banner = @"
|
||||
|
||||
====================================================================
|
||||
|
||||
Reference in New Issue
Block a user