2026-07-07 23:21:18 +01:00
# deploy-test.ps1 - Ed's test-deploy. proj\remsound\default sounds is the AUTHORITATIVE sound master.
#
# As of 2026-06-13 the shipped DEFAULT cue sounds live in a "default sounds\" folder next to the exe
# (AppConfig.SoundsDirectory) - they're part of the install, not per-user state, so an update (or a
# republish) always overwrites them and a tweaked default always lands. The user's OWN custom sounds
# are NOT here: they're explicit file paths set via the Preferences "Browse" picker, kept in the
# user's own location, which nothing here touches.
#
# Every run of THIS script force-copies the ENTIRE source "default sounds\" folder over BOTH test
# locations' copies, overwriting every file regardless of timestamp/size (/IS /IT). Ed can tweak any
# number of sounds, with any timestamps, without telling anyone which changed - the next deploy
# always takes them all. (A running app reads each WAV fresh on every play, so a sound tweak even
# takes effect live, no restart needed.) Binaries + program files go out too, skipped automatically
# if RemSound is open and has them locked.
#
# Run: powershell -ExecutionPolicy Bypass -File deploy-test.ps1
2026-07-12 20:06:34 +01:00
# Add -SkipGate to skip the build-and-test gate (e.g. when you just ran it) - by default a binary
# deploy runs run-tests.ps1 first and refuses to deploy a build that didn't pass.
param ([ switch ] $SkipGate )
2026-07-07 23:21:18 +01:00
$ErrorActionPreference = 'Stop'
$repo = $PSScriptRoot
$proj = Join-Path $repo 'src\RemSound.App\RemSound.App.csproj'
$srcSounds = Join-Path $repo 'default sounds'
$publish = Join-Path $repo 'publish'
# The TWO test run-locations. Each has its own 'default sounds\' copy that must be kept current.
$runLocations = @ ( $publish , 'D:\Dropbox\remsound' )
function Invoke-Robocopy([string[]]$rcArgs ) {
& robocopy @rcArgs / NFL / NDL / NJH / NJS / NP / R: 3 / W: 1 | Out-Null
if ( $LASTEXITCODE -ge 8 ) { throw "robocopy failed ( $LASTEXITCODE ): $( $rcArgs -join ' ' ) " }
}
2026-07-17 14:38:24 +01:00
# Only a RemSound process running FROM the publish folder locks its binaries. The send-only Windows
# service runs from its own copy under ProgramData (...\service\bin) and an installed app runs from
# %LocalAppData%\Programs\RemSound - neither locks publish, so neither should force a sounds-only deploy.
# (This is the bug that silently skipped binary deploys while the service was running - 2026-07-17.)
$publishFull = ( Resolve-Path -LiteralPath $publish -ErrorAction SilentlyContinue ). Path
$locking = @ ( Get-Process RemSound -ErrorAction SilentlyContinue | Where-Object {
try { $_ . Path -and $publishFull -and $_ . Path . StartsWith ( $publishFull , [ System.StringComparison ]:: OrdinalIgnoreCase ) }
catch { $false } # .Path throws for the SYSTEM service (access denied) - it's not in publish, so ignore it
})
$soundOnly = $locking . Count -gt 0
2026-07-07 23:21:18 +01:00
if ( $soundOnly ) {
2026-07-17 14:38:24 +01:00
Write-Host "A RemSound is running FROM the publish folder - refreshing SOUNDS only (its binaries are locked; close that copy to update them)." -ForegroundColor Yellow
2026-07-07 23:21:18 +01:00
}
else {
2026-07-12 20:06:34 +01:00
# Never deploy a build to test that hasn't passed the tests. The gate publishes + tests its own
# throwaway copy, so it doesn't touch the publish\ folder below. -SkipGate overrides (e.g. when the
# gate was just run in this session). Sound-only refreshes above skip it - they change no code.
if ( -not $SkipGate ) {
$gate = Join-Path $repo 'run-tests.ps1'
if ( Test-Path -LiteralPath $gate ) {
Write-Host "Running the build-and-test gate before deploying..." -ForegroundColor Cyan
& $gate
if ( $LASTEXITCODE -ne 0 ) { throw "build-and-test gate FAILED - not deploying. Fix the failures above, or re-run with -SkipGate to override." }
}
else { Write-Host "WARNING: run-tests.ps1 not found - deploying WITHOUT the test gate." -ForegroundColor Yellow }
}
2026-07-07 23:21:18 +01:00
Write-Host "Publishing (Release) -> $publish ..." -ForegroundColor Cyan
& dotnet publish $proj -c Release -o $publish - -nologo -v q
if ( $LASTEXITCODE -ne 0 ) { throw "dotnet publish failed ( $LASTEXITCODE )" }
}
foreach ( $loc in $runLocations ) {
# Binaries: publish\ already has them from the publish above; copy them to the other location(s).
if ( -not $soundOnly -and $loc -ne $publish ) {
Write-Host "Deploying program + binaries -> $loc (preserving user settings/logs) ..." -ForegroundColor Cyan
2026-07-12 19:56:34 +01:00
# /E copies the program + binaries; NO /MIR so we never DELETE the user's data. The /XD
# excludes make the copy incapable of OVERWRITING it either: if publish\ ever accumulated a
# user-data folder (a stray run from there), it must never land on Ed's real Dropbox profiles/
# config/logs. The binary sync only ever carries program files, never user state, both ways.
Invoke-Robocopy @ ( $publish , $loc , '/E' ,
'/XD' , 'user settings and logs' , 'recordings' , 'logs' , 'profiles' , 'config' ,
'/XF' , 'global config.json' , 'remsound.config.json' )
2026-07-07 23:21:18 +01:00
}
# THE point of this script: the whole source 'default sounds' folder, force-copied over THIS
# location's copy, every time. /IS = copy even files robocopy thinks are identical; /IT = copy
# "tweaked" files. No /XO (don't skip on timestamp) and no /MIR (don't delete files).
$locSounds = Join-Path $loc 'default sounds'
Write-Host "Force-syncing 'default sounds' -> $locSounds (source wins, every time) ..." -ForegroundColor Cyan
New-Item -ItemType Directory -Path $locSounds -Force | Out-Null
Invoke-Robocopy @ ( $srcSounds , $locSounds , '*.wav' , '/IS' , '/IT' )
# One-time tidy: drop the orphaned pre-2026-06-13 program 'sounds\' folder and the defunct old
# per-user sounds folder if they're lingering from before the move (the running app also deletes
# the per-user one on launch). Idempotent - a no-op once gone.
foreach ( $orphan in @ (( Join-Path $loc 'sounds' ), ( Join-Path $loc 'user settings and logs\sounds' ))) {
if ( Test-Path -LiteralPath $orphan ) { Remove-Item -LiteralPath $orphan -Recurse -Force -ErrorAction SilentlyContinue }
}
}
$count = @ ( Get-ChildItem $srcSounds -Filter *. wav ). Count
Write-Host "Done. $count default sounds force-synced to BOTH test locations. Tweak away - the next run always takes them all." -ForegroundColor Green