wip: Windows desktop app scaffold (WinUI 3/.NET 8) + NSIS installer + docs
Owner decision pending (STATE.md DC-100 tick): adopt/ship/park. Preserved from fragile git stash to named branch 2026-08-23. NOTE: requires a Windows build machine (WinUI XAML compiler + MSIX do not cross-build on Linux) — see WINDOWS_APP_BUILD.md in this tree. Secret-scanned clean 2026-08-23 (no keys/tokens/PEM in tree).
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Build script for DashCaddy Windows Desktop App
|
||||
|
||||
.DESCRIPTION
|
||||
This script:
|
||||
1. Builds the WinUI 3 desktop app (Release)
|
||||
2. Packages as MSIX
|
||||
3. Creates NSIS installer
|
||||
4. Outputs: DashCaddy-Setup-1.15.0.exe
|
||||
|
||||
.REQUIREMENTS
|
||||
- Visual Studio 2022 with Windows App SDK workload
|
||||
- NSIS 3.08+
|
||||
- .NET 8 SDK
|
||||
#>
|
||||
|
||||
param(
|
||||
[string]$Version = "1.15.0",
|
||||
[string]$Configuration = "Release",
|
||||
[string]$Platform = "x64"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$RootDir = Split-Path $PSScriptRoot -Parent
|
||||
$DesktopDir = Join-Path $RootDir 'desktop'
|
||||
$InstallerDir = Join-Path $RootDir 'installer\windows'
|
||||
$OutputDir = Join-Path $RootDir 'artifacts'
|
||||
$BuildDir = Join-Path $OutputDir 'build'
|
||||
|
||||
Write-Host "=== DashCaddy Windows Build v$Version ===" -ForegroundColor Cyan
|
||||
Write-Host "Configuration: $Configuration"
|
||||
Write-Host "Platform: $Platform"
|
||||
|
||||
# ─── Clean ───
|
||||
if (Test-Path $OutputDir) {
|
||||
Write-Host "Cleaning previous build..."
|
||||
Remove-Item -Recurse -Force $OutputDir
|
||||
}
|
||||
New-Item -ItemType Directory -Path $BuildDir -Force | Out-Null
|
||||
|
||||
# ─── Build .NET App ───
|
||||
Write-Host "`n[1/5] Building WinUI 3 Desktop App..." -ForegroundColor Green
|
||||
$csproj = Join-Path $DesktopDir 'DashCaddy.Desktop.csproj'
|
||||
$publishDir = Join-Path $BuildDir 'app'
|
||||
|
||||
dotnet publish $csproj `
|
||||
-c $Configuration `
|
||||
-r win10-$Platform `
|
||||
--self-contained true `
|
||||
-p:PublishSingleFile=true `
|
||||
-p:PublishTrimmed=true `
|
||||
-p:TrimMode=partial `
|
||||
-p:EnableMsixTooling=true `
|
||||
-p:AppxPackageDir=$OutputDir `
|
||||
-o $publishDir
|
||||
|
||||
if (-not (Test-Path (Join-Path $publishDir 'DashCaddy.exe'))) {
|
||||
throw "Build failed - DashCaddy.exe not found"
|
||||
}
|
||||
Write-Host "App built to: $publishDir"
|
||||
|
||||
# ─── Copy Assets ───
|
||||
Write-Host "`n[2/5] Copying assets..." -ForegroundColor Green
|
||||
$assetsSrc = Join-Path $InstallerDir 'assets'
|
||||
$assetsDst = Join-Path $BuildDir 'assets'
|
||||
if (Test-Path $assetsSrc) {
|
||||
Copy-Item -Recurse $assetsSrc $assetsDst
|
||||
} else {
|
||||
# Create minimal assets
|
||||
New-Item -ItemType Directory -Path $assetsDst -Force | Out-Null
|
||||
# Create a simple icon placeholder
|
||||
Write-Host "Warning: No assets found, creating placeholders"
|
||||
}
|
||||
|
||||
# ─── Copy Bootstrap ───
|
||||
Write-Host "`n[3/5] Copying bootstrap script..." -ForegroundColor Green
|
||||
Copy-Item (Join-Path $InstallerDir 'bootstrap.ps1') (Join-Path $BuildDir 'bootstrap.ps1')
|
||||
|
||||
# ─── Create docker-compose.yml for installer ───
|
||||
Write-Host "`n[4/5] Creating installer docker-compose.yml..." -ForegroundColor Green
|
||||
$composeContent = @"
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
dashcaddy-api:
|
||||
image: dashcaddy/dashcaddy-api:latest
|
||||
container_name: dashcaddy-api
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:3001:3001"
|
||||
volumes:
|
||||
- \${DATA_DIR}:/opt/dashcaddy/data
|
||||
- \${APPDATA_DIR}/config.yaml:/opt/dashcaddy/config.yaml:ro
|
||||
- //./pipe/docker_engine:/var/run/docker.sock:ro
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- DATA_DIR=/opt/dashcaddy/data
|
||||
- CONFIG_FILE=/opt/dashcaddy/config.yaml
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3001/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1); }).on('error', () => process.exit(1))"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
networks:
|
||||
- dashcaddy-net
|
||||
|
||||
caddy:
|
||||
image: caddy:2.10-alpine
|
||||
container_name: dashcaddy-caddy
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- \${DATA_DIR}/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- \${DATA_DIR}/caddy/data:/data
|
||||
- \${DATA_DIR}/caddy/config:/config
|
||||
networks:
|
||||
- dashcaddy-net
|
||||
depends_on:
|
||||
- dashcaddy-api
|
||||
|
||||
coredns:
|
||||
image: coredns/coredns:latest
|
||||
container_name: dashcaddy-coredns
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "53:53/udp"
|
||||
- "53:53/tcp"
|
||||
volumes:
|
||||
- \${DATA_DIR}/coredns/Corefile:/etc/coredns/Corefile:ro
|
||||
networks:
|
||||
- dashcaddy-net
|
||||
|
||||
networks:
|
||||
dashcaddy-net:
|
||||
driver: bridge
|
||||
"@
|
||||
|
||||
$composeContent | Set-Content -Path (Join-Path $BuildDir 'docker-compose.yml') -Encoding UTF8
|
||||
|
||||
# ─── Build NSIS Installer ───
|
||||
Write-Host "`n[5/5] Building NSIS Installer..." -ForegroundColor Green
|
||||
|
||||
$nsisPath = "C:\Program Files (x86)\NSIS\makensis.exe"
|
||||
if (-not (Test-Path $nsisPath)) {
|
||||
$nsisPath = "C:\Program Files\NSIS\makensis.exe"
|
||||
}
|
||||
if (-not (Test-Path $nsisPath)) {
|
||||
throw "NSIS not found. Install NSIS 3.08+ from https://nsis.sourceforge.io/"
|
||||
}
|
||||
|
||||
$nsiFile = Join-Path $InstallerDir 'dashcaddy.nsi'
|
||||
$installerOutput = Join-Path $OutputDir "DashCaddy-Setup-$Version.exe"
|
||||
|
||||
& $nsisPath `
|
||||
"/DVERSION=$Version" `
|
||||
"/DOUTPUT=$installerOutput" `
|
||||
"/DINSTALLER_DIR=$BuildDir" `
|
||||
$nsiFile
|
||||
|
||||
if (Test-Path $installerOutput) {
|
||||
$size = [math]::Round((Get-Item $installerOutput).Length / 1MB, 1)
|
||||
Write-Host "`n✅ Build Complete!" -ForegroundColor Green
|
||||
Write-Host "Installer: $installerOutput ($size MB)"
|
||||
Write-Host ""
|
||||
Write-Host "Next steps:"
|
||||
Write-Host " 1. Test installer on clean Windows VM"
|
||||
Write-Host " 2. Code sign: signtool sign /fd sha256 /tr http://timestamp.digicert.com $installerOutput"
|
||||
Write-Host " 3. Upload to dashcaddy.net/downloads"
|
||||
} else {
|
||||
throw "NSIS build failed - installer not created"
|
||||
}
|
||||
Reference in New Issue
Block a user