Local checkpoint - NOT for public release. Produces a zip that mirrors the publish folder (every current code fix, program files, pdb, all runtimes, sounds, readme, Tolk, install scripts) with NONE of the developer's personal state (no profiles/config/logs/recordings). Same safety approach as build-release.ps1: publishes into a fresh never-run folder, then scans both the staged files AND the finished zip and aborts if any personal data is present. Not a public release (no tag/notes/GitHub) - a private portable copy for external testers. Runs the build-and-test gate first by default (don't ship testers a broken build); -SkipGate to bypass, -Output to pick the path (defaults to D:\Dropbox\remsound.zip). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
93 lines
4.8 KiB
PowerShell
93 lines
4.8 KiB
PowerShell
# make-tester-zip.ps1 - build a clean, portable RemSound copy to hand to external testers.
|
|
#
|
|
# What it produces
|
|
# ----------------
|
|
# A zip that MIRRORS the publish folder (every current code fix, the program files, pdb symbols,
|
|
# all runtimes, default sounds, readme, Tolk, install scripts) but with NONE of your personal state -
|
|
# no profiles, config, logs or recordings. A tester unzips it, runs RemSound.exe, and it builds its own
|
|
# fresh config on first launch.
|
|
#
|
|
# How it stays clean
|
|
# ------------------
|
|
# * It ALWAYS publishes into a fresh, empty folder the app has never run in, so there is nothing
|
|
# personal to leak (same principle as build-release.ps1).
|
|
# * It then SCANS the staged files AND the finished zip and ABORTS (deletes the zip, exits non-zero)
|
|
# if anything that could carry personal data is present.
|
|
# Unlike build-release.ps1 this is NOT a public release: no tag, no version/notes checks, no GitHub -
|
|
# it's a private portable copy for a couple of testers. Nothing is stripped, so it matches exactly what
|
|
# you test with locally.
|
|
#
|
|
# Usage:
|
|
# powershell -ExecutionPolicy Bypass -File make-tester-zip.ps1 # -> D:\Dropbox\remsound.zip, runs the test gate first
|
|
# powershell -ExecutionPolicy Bypass -File make-tester-zip.ps1 -Output C:\path\to\build.zip
|
|
# powershell -ExecutionPolicy Bypass -File make-tester-zip.ps1 -SkipGate # skip the build-and-test gate (faster; use when you just ran it)
|
|
|
|
param(
|
|
[string]$Output = 'D:\Dropbox\remsound.zip',
|
|
[switch]$SkipGate
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$repo = $PSScriptRoot
|
|
$proj = Join-Path $repo 'src\RemSound.App\RemSound.App.csproj'
|
|
$staging = Join-Path ([System.IO.Path]::GetTempPath()) ("remsound-testers-" + [guid]::NewGuid().ToString('N'))
|
|
|
|
# 0. Don't hand testers a broken build - run the build-and-test gate first (unless told to skip). The
|
|
# gate publishes + tests its OWN throwaway copy, so it doesn't touch the clean staging folder below.
|
|
$gate = Join-Path $repo 'run-tests.ps1'
|
|
if (-not $SkipGate -and (Test-Path $gate)) {
|
|
Write-Host "Running the build-and-test gate first..." -ForegroundColor Cyan
|
|
& $gate
|
|
if ($LASTEXITCODE -ne 0) { throw "build-and-test gate FAILED - not making a tester zip. Fix the failures, or re-run with -SkipGate to override." }
|
|
}
|
|
|
|
# 1. Fresh Release publish = exactly what deploy-test puts in the publish folder (program files, pdb,
|
|
# all runtimes, default sounds, readme, Tolk, install scripts). Fresh = never run = no user state.
|
|
Write-Host "Publishing Release to a fresh folder: $staging" -ForegroundColor Cyan
|
|
& dotnet publish $proj -c Release -o $staging --nologo -v q
|
|
if ($LASTEXITCODE -ne 0) { throw "dotnet publish failed ($LASTEXITCODE)" }
|
|
|
|
# 2. SAFETY SCAN - the same rule build-release.ps1 uses. Nothing that could carry personal data may ship.
|
|
$forbiddenFolders = @('logs','profiles','recordings','config','user settings and logs')
|
|
function Test-Forbidden([string]$path) {
|
|
$p = $path.Replace('\','/')
|
|
foreach ($f in $forbiddenFolders) { if ($p -match "(^|/)$f/") { return $true } }
|
|
if ($p -match '\.log$') { return $true }
|
|
if ($p -match '(^|/)(remsound\.config\.json|global config\.json)$') { return $true }
|
|
return $false
|
|
}
|
|
$bad = @()
|
|
Get-ChildItem -Path $staging -Recurse -Force | ForEach-Object {
|
|
$rel = $_.FullName.Substring($staging.Length).TrimStart('\','/')
|
|
if (Test-Forbidden $rel) { $bad += $rel }
|
|
}
|
|
if ($bad.Count -gt 0) {
|
|
Remove-Item -LiteralPath $staging -Recurse -Force
|
|
throw "ABORT - staged copy contains files that must not ship: $($bad -join ', ')"
|
|
}
|
|
Write-Host "Scan clean: no profiles / config / logs / recordings present." -ForegroundColor Green
|
|
|
|
# 3. Zip it.
|
|
$outDir = Split-Path -Parent $Output
|
|
if ($outDir -and -not (Test-Path -LiteralPath $outDir)) { New-Item -ItemType Directory -Path $outDir -Force | Out-Null }
|
|
if (Test-Path -LiteralPath $Output) { Remove-Item -LiteralPath $Output -Force }
|
|
Compress-Archive -Path (Join-Path $staging '*') -DestinationPath $Output -CompressionLevel Optimal -Force
|
|
|
|
# 4. SAFETY SCAN again, on the finished zip - belt and braces.
|
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
$zip = [System.IO.Compression.ZipFile]::OpenRead($Output)
|
|
try {
|
|
$leaked = @($zip.Entries | Where-Object { Test-Forbidden $_.FullName })
|
|
$entryCount = $zip.Entries.Count
|
|
} finally { $zip.Dispose() }
|
|
Remove-Item -LiteralPath $staging -Recurse -Force
|
|
if ($leaked.Count -gt 0) {
|
|
Remove-Item -LiteralPath $Output -Force
|
|
throw "ABORT - finished zip contains forbidden entries: $($leaked.FullName -join ', ')"
|
|
}
|
|
|
|
$mb = [math]::Round((Get-Item -LiteralPath $Output).Length / 1MB, 2)
|
|
Write-Host ""
|
|
Write-Host "OK - tester zip ready: $Output ($mb MB, $entryCount entries)." -ForegroundColor Green
|
|
Write-Host " Mirrors the publish folder; verified no profiles / config / logs / recordings." -ForegroundColor Green
|