Optimize Windows deployment scripts: build cache, console integration, and .env.example handling

Build-ROA2WEB.ps1 improvements:
- Add intelligent npm node_modules caching (saves 2-5 minutes on repeated builds)
- Cache stored outside deploy-package in .build-cache/ directory
- Add Clean Cache menu option ([C]) and -CleanCache parameter
- Include ROA2WEB-Console.ps1 in deployment package
- Update README workflow to use unified console (interactive and CLI modes)
- Remove obsolete script references (Manage-ROA2WEB.ps1, Deploy-*.ps1)
- Fix .env.example copying for backend and telegram-bot (copy from source instead of hardcoded template)

ROA2WEB-Console.ps1 improvements:
- Fix PowerShell parsing error: ${ComponentName}: instead of $ComponentName:
- Add .env.example copying in Update-BackendFiles function
- Add .env.example copying in Update-TelegramBotFiles function
- Keep .env.example synchronized with development templates

.gitignore:
- Add .build-cache/ to prevent committing npm cache directory

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-12 02:04:31 +02:00
parent 1832684aca
commit 016c309d70
3 changed files with 214 additions and 61 deletions

5
.gitignore vendored
View File

@@ -354,6 +354,11 @@ deployment/windows/deploy-package/
deploy-package/
**/deploy-package/
# Build cache (npm node_modules cache for faster builds)
deployment/windows/.build-cache/
.build-cache/
**/.build-cache/
# Deployment logs and temporary files
deployment/windows/scripts/*.log
deployment/windows/temp/

View File

@@ -33,6 +33,9 @@
.PARAMETER Clean
Clean output directory before building (default: true)
.PARAMETER CleanCache
Clean build cache (cached node_modules) and exit
.EXAMPLE
.\Build-ROA2WEB.ps1
Shows interactive menu to select components to build
@@ -53,6 +56,10 @@
.\Build-ROA2WEB.ps1 -Component All -OutputPath "D:\deployments\roa2web-$(Get-Date -Format 'yyyyMMdd')"
Build complete package to custom output path
.EXAMPLE
.\Build-ROA2WEB.ps1 -CleanCache
Clean build cache to free disk space
.NOTES
Author: ROA2WEB Team
Version: 2.0 (Unified Build Script)
@@ -67,7 +74,8 @@ param(
[string]$OutputPath = "./deploy-package",
[string]$ServerHost = "",
[string]$ServerPath = "",
[bool]$Clean = $true
[bool]$Clean = $true,
[switch]$CleanCache
)
$ErrorActionPreference = "Stop"
@@ -119,6 +127,46 @@ function Resolve-FullPath {
return $fullPath
}
function Clear-BuildCache {
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
Write-Host " CLEAN BUILD CACHE" -ForegroundColor Cyan
Write-Host ("=" * 70) -ForegroundColor Cyan
$scriptDir = Split-Path -Parent $PSScriptRoot
$cacheDir = Join-Path $scriptDir ".build-cache"
if (-not (Test-Path $cacheDir)) {
Write-Warning "No build cache found at: $cacheDir"
Write-Host "`nNothing to clean." -ForegroundColor Gray
return
}
try {
# Calculate cache size
$cacheFiles = Get-ChildItem -Path $cacheDir -Recurse -File -ErrorAction SilentlyContinue
$cacheSize = ($cacheFiles | Measure-Object -Property Length -Sum).Sum / 1MB
Write-Host "`nCache location: $cacheDir" -ForegroundColor Gray
Write-Host "Cache size: $([math]::Round($cacheSize, 2)) MB" -ForegroundColor Gray
Write-Host "Files: $(($cacheFiles).Count)" -ForegroundColor Gray
Write-Host ""
Write-Host "Are you sure you want to delete the build cache? [Y/N]: " -ForegroundColor Yellow -NoNewline
$confirmation = Read-Host
if ($confirmation.ToUpper() -eq "Y") {
Write-Step "Removing build cache..."
Remove-Item -Path $cacheDir -Recurse -Force -ErrorAction Stop
Write-Success "Build cache cleared successfully"
Write-Success "Freed $([math]::Round($cacheSize, 2)) MB of disk space"
} else {
Write-Host "`nCache cleanup cancelled." -ForegroundColor Yellow
}
} catch {
Write-Host "`n[ERROR] Failed to clear cache: $_" -ForegroundColor Red
}
}
function Show-BuildMenu {
Write-Host "`n" + ("=" * 70) -ForegroundColor Cyan
Write-Host " ROA2WEB - Build Component Selection Menu" -ForegroundColor Cyan
@@ -138,6 +186,9 @@ function Show-BuildMenu {
Write-Host " [4] Telegram Bot Only" -ForegroundColor White
Write-Host " (Telegram bot standalone package)" -ForegroundColor Gray
Write-Host ""
Write-Host " [C] Clean Build Cache" -ForegroundColor Yellow
Write-Host " (Remove cached node_modules to free disk space)" -ForegroundColor Gray
Write-Host ""
Write-Host " [Q] Quit" -ForegroundColor Red
Write-Host ""
Write-Host ("=" * 70) -ForegroundColor Cyan
@@ -151,12 +202,18 @@ function Show-BuildMenu {
"2" { return "Frontend" }
"3" { return "Backend" }
"4" { return "TelegramBot" }
"C" {
Clear-BuildCache
Write-Host "`nPress any key to return to menu..." -ForegroundColor Gray
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
return Show-BuildMenu
}
"Q" {
Write-Host "`nBuild cancelled by user." -ForegroundColor Yellow
exit 0
}
default {
Write-Host "Invalid choice. Please select 1-4 or Q." -ForegroundColor Red
Write-Host "Invalid choice. Please select 1-4, C or Q." -ForegroundColor Red
}
}
} while ($true)
@@ -210,6 +267,13 @@ function Build-Frontend {
New-Item -ItemType Directory -Path $tempBuildDir -Force | Out-Null
Write-Success "Created temp build directory (isolated from WSL)"
# Create cache directory for node_modules (OUTSIDE deploy-package)
$scriptDir = Split-Path -Parent $PSScriptRoot
$cacheDir = Join-Path $scriptDir ".build-cache"
if (-not (Test-Path $cacheDir)) {
New-Item -ItemType Directory -Path $cacheDir -Force | Out-Null
}
# 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")
@@ -257,19 +321,66 @@ function Build-Frontend {
# 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
# Check if dependencies need to be reinstalled
$needsInstall = $true
$cachedNodeModules = Join-Path $cacheDir "node_modules"
$cachedPackageJson = Join-Path $cacheDir "package.json"
$cachedPackageLock = Join-Path $cacheDir "package-lock.json"
$nodeModulesPath = Join-Path $tempBuildDir "node_modules"
if (-not (Test-Path $nodeModulesPath)) {
throw "npm install failed: node_modules not created"
$currentPackageJson = Join-Path $tempBuildDir "package.json"
$currentPackageLock = Join-Path $tempBuildDir "package-lock.json"
if ((Test-Path $cachedNodeModules) -and (Test-Path $cachedPackageJson)) {
# Compare package.json hashes
$currentHash = (Get-FileHash $currentPackageJson -Algorithm SHA256).Hash
$cachedHash = (Get-FileHash $cachedPackageJson -Algorithm SHA256).Hash
# Also compare package-lock.json if it exists
$lockMatches = $true
if ((Test-Path $currentPackageLock) -and (Test-Path $cachedPackageLock)) {
$currentLockHash = (Get-FileHash $currentPackageLock -Algorithm SHA256).Hash
$cachedLockHash = (Get-FileHash $cachedPackageLock -Algorithm SHA256).Hash
$lockMatches = ($currentLockHash -eq $cachedLockHash)
}
if (($currentHash -eq $cachedHash) -and $lockMatches) {
Write-Step "Reusing cached node_modules (dependencies unchanged)..."
Copy-Item -Path $cachedNodeModules -Destination $tempBuildDir -Recurse -Force
$needsInstall = $false
Write-Success "Dependencies restored from cache (saved 2-5 minutes!)"
} else {
Write-Info "Dependencies changed, will reinstall"
}
}
if ($needsInstall) {
# 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 in temp"
# Update cache
Write-Step "Caching node_modules for future builds..."
if (Test-Path $cachedNodeModules) {
Remove-Item -Path $cachedNodeModules -Recurse -Force
}
Copy-Item -Path $nodeModulesPath -Destination $cachedNodeModules -Recurse -Force
Copy-Item -Path $currentPackageJson -Destination $cachedPackageJson -Force
if (Test-Path $currentPackageLock) {
Copy-Item -Path $currentPackageLock -Destination $cachedPackageLock -Force
}
Write-Success "Cache updated for next build"
}
Write-Success "Dependencies installed in temp"
# Verify Vite is installed
$nodeModulesPath = Join-Path $tempBuildDir "node_modules"
$vitePath = Join-Path $nodeModulesPath ".bin\vite.cmd"
if (-not (Test-Path $vitePath)) {
throw "Vite not found in node_modules - devDependencies not installed"
@@ -376,6 +487,16 @@ function Copy-BackendFiles {
$backendFiles = Get-ChildItem -Path $DestPath -Recurse -File
Write-Success "Copied $(($backendFiles).Count) backend files"
# Copy .env.example explicitly (excluded from recursive copy)
$sourceEnvExample = Join-Path $SourcePath ".env.example"
$destEnvExample = Join-Path $DestPath ".env.example"
if (Test-Path $sourceEnvExample) {
Copy-Item -Path $sourceEnvExample -Destination $destEnvExample -Force
Write-Success ".env.example template copied"
} else {
Write-Warning ".env.example not found in source - manual configuration required"
}
# Verify requirements.txt
$requirementsTxt = Join-Path $DestPath "requirements.txt"
if (-not (Test-Path $requirementsTxt)) {
@@ -464,28 +585,15 @@ function Copy-TelegramBotFiles {
Write-Success "requirements.txt copied"
}
# Create .env.example
$envTemplate = @"
# ROA2WEB Telegram Bot - Production Configuration
TELEGRAM_BOT_TOKEN=your_bot_token_from_BotFather
CLAUDE_API_KEY=your_claude_api_key
BACKEND_URL=http://localhost:8000
BACKEND_TIMEOUT=30
SQLITE_DB_PATH=C:\inetpub\wwwroot\roa2web\telegram-bot\data\telegram_bot.db
INTERNAL_API_HOST=127.0.0.1
INTERNAL_API_PORT=8002
LOG_LEVEL=INFO
LOG_FILE=C:\inetpub\wwwroot\roa2web\telegram-bot\logs\bot.log
ENVIRONMENT=production
AUTH_CODE_EXPIRY_MINUTES=15
JWT_REFRESH_THRESHOLD_MINUTES=5
SESSION_TIMEOUT_MINUTES=60
MAX_CONVERSATION_HISTORY=20
"@
$envPath = Join-Path $DestPath ".env.example"
Set-Content -Path $envPath -Value $envTemplate -Encoding UTF8
Write-Success ".env.example template created"
# Copy .env.example from source (keeps it synchronized with development)
$sourceEnvExample = Join-Path $SourcePath ".env.example"
$destEnvExample = Join-Path $DestPath ".env.example"
if (Test-Path $sourceEnvExample) {
Copy-Item -Path $sourceEnvExample -Destination $destEnvExample -Force
Write-Success ".env.example template copied"
} else {
Write-Warning ".env.example not found in source - manual configuration required"
}
}
function Copy-SharedModules {
@@ -552,11 +660,9 @@ function Copy-DeploymentScripts {
# Essential scripts for all deployments
$scripts = @(
"ROA2WEB-Console.ps1", # Unified deployment & management console
"Install-ROA2WEB.ps1",
"Install-TelegramBot.ps1",
"Deploy-ROA2WEB.ps1",
"Deploy-TelegramBot.ps1",
"Manage-ROA2WEB.ps1"
"Install-TelegramBot.ps1"
)
# Add utility scripts for complete deployments
@@ -637,11 +743,13 @@ CONTENTS:
DEPLOYMENT SCRIPTS:
-------------------
ROA2WEB-Console.ps1 Unified deployment & management console
- Deploy components (Backend/Frontend/TelegramBot)
- Manage services (Start/Stop/Restart)
- Check system status and health
Install-ROA2WEB.ps1 First-time backend + frontend setup
Install-TelegramBot.ps1 First-time Telegram bot setup
Deploy-ROA2WEB.ps1 Update backend + frontend
Deploy-TelegramBot.ps1 Update Telegram bot
Manage-ROA2WEB.ps1 Unified service management (start/stop/restart)
"@
if ($ComponentType -eq "All" -or $ComponentType -eq "TelegramBot") {
@@ -653,6 +761,13 @@ DEPLOYMENT SCRIPTS:
"@
}
if ($ComponentType -eq "All" -or $ComponentType -eq "Frontend") {
$readme += @"
Enable-HTTPS.ps1 Configure HTTPS/SSL certificates
"@
}
$readme += @"
@@ -674,8 +789,9 @@ DEPLOYMENT WORKFLOW
2. Configure environment:
notepad C:\inetpub\wwwroot\roa2web\backend\.env
3. Start services:
.\Manage-ROA2WEB.ps1 -Action Start -Component Backend
3. Start services using the unified console:
.\ROA2WEB-Console.ps1
(Select: Manage Services > Start All)
"@
}
@@ -690,34 +806,44 @@ DEPLOYMENT WORKFLOW
notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env
6. Start Telegram bot:
.\Manage-ROA2WEB.ps1 -Action Start -Component TelegramBot
.\ROA2WEB-Console.ps1
(Select: Manage Services > Start Telegram Bot)
"@
}
$readme += @"
>> UPDATES:
-----------
>> UPDATES (Interactive Console):
----------------------------------
cd scripts
.\Manage-ROA2WEB.ps1 -Action Stop
.\Deploy-ROA2WEB.ps1 # Updates backend + frontend
.\Deploy-TelegramBot.ps1 # Updates Telegram bot
.\Manage-ROA2WEB.ps1 -Action Start
.\ROA2WEB-Console.ps1
(Select: Deploy Components > choose what to update)
>> SERVICE MANAGEMENT:
----------------------
>> UPDATES (Command Line):
---------------------------
.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployBackend # Update backend + frontend
.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployTelegramBot # Update Telegram bot
.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployAll # Update everything
>> SERVICE MANAGEMENT (Interactive):
-------------------------------------
.\ROA2WEB-Console.ps1
(Select: Manage Services > choose action)
>> SERVICE MANAGEMENT (Command Line):
--------------------------------------
# Start all services
.\Manage-ROA2WEB.ps1 -Action Start
.\ROA2WEB-Console.ps1 -NonInteractive -Action StartAll
# Stop all services
.\Manage-ROA2WEB.ps1 -Action Stop
.\ROA2WEB-Console.ps1 -NonInteractive -Action StopAll
# Restart backend only
.\Manage-ROA2WEB.ps1 -Action Restart -Component Backend
# Restart all services
.\ROA2WEB-Console.ps1 -NonInteractive -Action RestartAll
# Check status
.\Manage-ROA2WEB.ps1 -Action Status
.\ROA2WEB-Console.ps1 -NonInteractive -Action Status
================================================================================
REQUIREMENTS
@@ -733,6 +859,7 @@ NOTES:
- .env files preserved during updates
- Automatic backup before each update
- Default install location: C:\inetpub\wwwroot\roa2web\
- Build cache NOT included in this package (stays on build machine)
TROUBLESHOOTING:
----------------
@@ -867,6 +994,12 @@ function New-DeploymentPackage {
# =============================================================================
function Main {
# Handle -CleanCache parameter
if ($CleanCache) {
Clear-BuildCache
exit 0
}
# Show interactive menu if no component specified
if ([string]::IsNullOrWhiteSpace($Component)) {
$script:Component = Show-BuildMenu

View File

@@ -459,7 +459,7 @@ function Show-ServiceStatus {
$service = Get-ServiceSafe -ServiceName $ServiceName
Write-Host "`n$ComponentName:" -ForegroundColor Cyan
Write-Host "`n${ComponentName}:" -ForegroundColor Cyan
Write-Host " Service Name: $ServiceName" -ForegroundColor Gray
if ($service) {
@@ -633,6 +633,14 @@ function Update-BackendFiles {
Write-Success "Backend files updated"
# Copy .env.example explicitly (excluded from recursive copy)
$sourceEnvExample = Join-Path $sourceBackend ".env.example"
$destEnvExample = Join-Path $Config.BackendPath ".env.example"
if (Test-Path $sourceEnvExample) {
Copy-Item -Path $sourceEnvExample -Destination $destEnvExample -Force
Write-Success ".env.example template updated"
}
# Check if requirements.txt changed
$sourceReq = Join-Path $sourceBackend "requirements.txt"
$destReq = Join-Path $Config.BackendPath "requirements.txt"
@@ -743,12 +751,19 @@ function Update-TelegramBotFiles {
}
}
# Preserve .env file
# Copy .env.example template (always update to keep in sync)
$sourceEnvExample = Join-Path $Config.SourcePath ".env.example"
$destEnvExample = Join-Path $Config.TelegramBotPath ".env.example"
if (Test-Path $sourceEnvExample) {
Copy-Item -Path $sourceEnvExample -Destination $destEnvExample -Force
Write-Success ".env.example template updated"
}
# Preserve .env file (or create from .env.example if missing)
$envFile = Join-Path $Config.TelegramBotPath ".env"
if (-not (Test-Path $envFile)) {
$sourceEnv = Join-Path $Config.SourcePath ".env.example"
if (Test-Path $sourceEnv) {
Copy-Item -Path $sourceEnv -Destination $envFile -Force
if (Test-Path $sourceEnvExample) {
Copy-Item -Path $sourceEnvExample -Destination $envFile -Force
Write-Warning "Created .env from .env.example - PLEASE CONFIGURE"
}
} else {