<# .SYNOPSIS CSM Release Build Script .DESCRIPTION Builds all release artifacts: server binary with embedded frontend, client binary, and packages them for distribution. .USAGE .\scripts\build-release.ps1 [-Version "0.2.0"] [-SkipFrontend] [-SkipInstaller] #> param( [string]$Version = "", [switch]$SkipFrontend, [switch]$SkipInstaller ) $ErrorActionPreference = "Stop" # Determine project root (parent of scripts/ directory) $projectRoot = if ($PSScriptRoot) { Split-Path $PSScriptRoot -Parent } else { $PWD.Path } Write-Host "" Write-Host "======================================" -ForegroundColor Cyan Write-Host " CSM Release Builder" -ForegroundColor Cyan Write-Host "======================================" -ForegroundColor Cyan Write-Host "" # --- Determine version --- if (-not $Version) { $cargoToml = Get-Content "$projectRoot\Cargo.toml" -Raw if ($cargoToml -match 'version\s*=\s*"([^"]+)"') { $Version = $Matches[1] } else { $Version = "0.1.0" } } Write-Host "Building version: $Version" -ForegroundColor White # --- Prerequisites check --- function Check-Command { param([string]$Name) try { Get-Command $Name -ErrorAction Stop | Out-Null; return $true } catch { return $false } } if (-not (Check-Command "cargo")) { Write-Host "[ERROR] cargo not found in PATH" -ForegroundColor Red; exit 1 } if (-not (Check-Command "npm")) { Write-Host "[ERROR] npm not found in PATH" -ForegroundColor Red; exit 1 } # --- Step 1: Build frontend --- if (-not $SkipFrontend) { Write-Host "[1/4] Building frontend..." -ForegroundColor Yellow Push-Location "$projectRoot\web" npm install --prefer-offline 2>&1 | Out-Null npm run build 2>&1 | ForEach-Object { Write-Host $_ } if ($LASTEXITCODE -ne 0) { Write-Host "[ERROR] Frontend build failed" -ForegroundColor Red Pop-Location; exit 1 } Pop-Location Write-Host "[1/4] Frontend build OK" -ForegroundColor Green } else { Write-Host "[1/4] Skipping frontend build" -ForegroundColor DarkGray } # --- Step 2: Build Rust workspace --- Write-Host "[2/4] Building Rust workspace (release)..." -ForegroundColor Yellow cargo build --release --workspace 2>&1 | ForEach-Object { Write-Host $_ } if ($LASTEXITCODE -ne 0) { Write-Host "[ERROR] Rust build failed" -ForegroundColor Red; exit 1 } Write-Host "[2/4] Rust build OK" -ForegroundColor Green # --- Step 3: Package server --- Write-Host "[3/4] Packaging server..." -ForegroundColor Yellow $releaseDir = "$projectRoot\release\v$Version" if (Test-Path $releaseDir) { Remove-Item $releaseDir -Recurse -Force } New-Item -ItemType Directory -Path $releaseDir -Force | Out-Null # Server package $serverDir = "$releaseDir\csm-server-$Version" New-Item -ItemType Directory -Path $serverDir -Force | Out-Null Copy-Item "$projectRoot\target\release\csm-server.exe" "$serverDir\" if (Test-Path "$projectRoot\config.toml.example") { Copy-Item "$projectRoot\config.toml.example" "$serverDir\" } else { # Generate a default config example @" [server] http_addr = "0.0.0.0:9998" tcp_addr = "0.0.0.0:9999" cors_origins = [] [database] path = "./csm.db" [auth] jwt_secret = "" access_token_ttl_secs = 1800 refresh_token_ttl_secs = 604800 registration_token = "" [retention] status_history_days = 7 usb_events_days = 90 asset_changes_days = 365 alert_records_days = 90 audit_log_days = 365 "@ | Out-File "$serverDir\config.toml.example" -Encoding utf8 } # README for server @" CSM Server v$Version ================== Quick Start: 1. Copy config.toml.example to config.toml 2. Edit config.toml (set jwt_secret and registration_token) 3. Run: csm-server.exe 4. Default admin credentials printed on first run 5. Open http://localhost:9998 in browser Ports: HTTP/WebSocket: 9998 TCP (client): 9999 Files: csm-server.exe - Server binary (includes embedded web UI) config.toml.example - Configuration template "@ | Out-File "$serverDir\README.txt" -Encoding utf8 # Create server ZIP Compress-Archive -Path "$serverDir\*" -DestinationPath "$releaseDir\csm-server-$Version.zip" -Force Remove-Item $serverDir -Recurse -Force Write-Host "[3/4] Server packaged: csm-server-$Version.zip" -ForegroundColor Green # --- Step 4: Prepare client for installer --- Write-Host "[4/4] Preparing client..." -ForegroundColor Yellow $clientExe = "$projectRoot\target\release\csm-client.exe" if (-not (Test-Path $clientExe)) { Write-Host "[ERROR] csm-client.exe not found" -ForegroundColor Red; exit 1 } # Copy client exe to release dir for NSIS Copy-Item $clientExe "$releaseDir\csm-client-$Version.exe" Write-Host "[4/4] Client binary ready: csm-client-$Version.exe" -ForegroundColor Green # --- Generate checksums --- Write-Host "" Write-Host "Generating SHA256 checksums..." -ForegroundColor Yellow $hashes = @() foreach ($file in (Get-ChildItem "$releaseDir\*" -File)) { $hash = (Get-FileHash $file.FullName -Algorithm SHA256).Hash.ToLower() $hashes += "$hash $($file.Name)" } $hashes | Out-File "$releaseDir\SHA256SUMS.txt" -Encoding utf8 # --- Summary --- Write-Host "" Write-Host "======================================" -ForegroundColor Green Write-Host " Release v$Version built successfully!" -ForegroundColor Green Write-Host "======================================" -ForegroundColor Green Write-Host "" Write-Host "Output directory: $releaseDir" -ForegroundColor White Write-Host "" Get-ChildItem "$releaseDir\*" -File | ForEach-Object { $size = [math]::Round($_.Length / 1MB, 2) Write-Host (" {0,-40} {1,8} MB" -f $_.Name, $size) -ForegroundColor White } Write-Host "" Write-Host "Next steps:" -ForegroundColor Cyan Write-Host " 1. Test csm-server by extracting the ZIP and running" -ForegroundColor White if (Check-Command "makensis") { Write-Host " 2. Run NSIS: makensis /DVERSION=$Version installer\client.nsi" -ForegroundColor White } else { Write-Host " 2. Install NSIS (https://nsis.sourceforge.io) to build client installer" -ForegroundColor White } Write-Host " 3. Tag release: git tag -a v$Version -m `"Release v$Version`"" -ForegroundColor White Write-Host ""