From d6e973c3cee1927ed13f09dc11ed07b7fba167e7 Mon Sep 17 00:00:00 2001 From: Torben Nehmer Date: Thu, 1 Oct 2026 13:46:51 +0200 Subject: [PATCH] fix: preflight.ps1 asset-mode helper renamed to Exit-Asset so PSScriptAnalyzer passes (#151, C) Files changed: - CHANGES.md - VERSION - tools/preflight.ps1 --- CHANGES.md | 15 ++++++++++++--- VERSION | 2 +- tools/preflight.ps1 | 26 +++++++++++++------------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 746281e..21be69b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -59,7 +59,7 @@ concern - readable here, never shipped as something to parse. --- -## 8.0.0-beta.16 - 2026-10-01 - Preflight as a release asset: download, verify and unpack the stack, then run the tree preflight +## 8.0.0-beta.17 - 2026-10-01 - preflight.ps1: the asset-mode error helper is Exit-Asset, so PSScriptAnalyzer passes **Author:** Torben Nehmer @@ -125,8 +125,16 @@ concern - readable here, never shipped as something to parse. - bug-report instruction: step 1 no longer calls every bundle unpseudonymised - setup-instance step 15 names --no-push for a local-only first publish; gates.md and a docstring follow #159 - raw/CONTRACT.md points at the path budget for a name accepted from incoming/ +- preflight.ps1: the asset-mode error helper is Exit-Asset, so PSScriptAnalyzer passes +### preflight.ps1: the asset-mode error helper is Exit-Asset, so PSScriptAnalyzer passes + +The helper that ends asset mode with exit 1 was called `Stop-Asset`. `Stop` is one of the verbs +PSScriptAnalyzer reads as changing system state, so `PSUseShouldProcessForStateChangingFunctions` +failed the CI `pwsh` job on the previous bump. It is now `Exit-Asset`, beside `Exit-WithGuide`; +behaviour is unchanged. + ### Preflight as a release asset: download, verify and unpack the stack, then run the tree preflight Section C of #151, the first install. Until now a new user had to get the stack onto the machine @@ -148,8 +156,9 @@ script with empty placeholders and no `--archive` exits 1 saying it does not com for a machine that cannot download, and is the entry point the tests use. On POSIX asset mode needs `curl`, `tar` and `sha256sum` (or `shasum`) and stops with exit 42 and -the usual guidance block when one is missing; the PowerShell script uses what Windows ships plus -`tar`. On Windows with long paths off, the 95-character folder limit is judged at the final +the usual guidance block when one is missing; the PowerShell script uses what Windows 10 and 11 +ship (`Invoke-WebRequest`, `Get-FileHash`, `tar.exe`) and stops the same way only when `tar` is +gone. On Windows with long paths off, the 95-character folder limit is judged at the final target before anything is unpacked, so a too-long `--into` stops with exit 42 and the fix is a shorter folder. Git Bash gets the target and archive converted with `cygpath -u`, because GNU tar would read `C:` as a host. diff --git a/VERSION b/VERSION index f2a3fb1..598636c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.0.0-beta.16 +8.0.0-beta.17 diff --git a/tools/preflight.ps1 b/tools/preflight.ps1 index 38f7b37..fb5977f 100644 --- a/tools/preflight.ps1 +++ b/tools/preflight.ps1 @@ -221,7 +221,7 @@ function Test-LongPathsEnabled { } } -function Stop-Asset { +function Exit-Asset { param([string]$Message) Write-ErrorLine "preflight: $Message" exit 1 @@ -238,19 +238,19 @@ function Resolve-AssetPath { function Invoke-AssetMode { $target = if ($Into) { Resolve-AssetPath $Into } else { Join-Path $Dir 'chemenu' } if ($null -ne (Get-Item -LiteralPath $target -Force -ErrorAction SilentlyContinue)) { - Stop-Asset "$target already exists - nothing was unpacked. Choose another folder with --into , or move the existing one away." + Exit-Asset "$target already exists - nothing was unpacked. Choose another folder with --into , or move the existing one away." } if (-not $Archive -and (-not $ReleaseArchiveUrl -or -not $ReleaseChecksumUrl)) { - Stop-Asset 'this copy of the script does not come from a release (it has no download address). Download preflight.ps1 from the release page, or pass --archive .' + Exit-Asset 'this copy of the script does not come from a release (it has no download address). Download preflight.ps1 from the release page, or pass --archive .' } if ($Archive) { $Archive = Resolve-AssetPath $Archive if (-not (Test-Path -LiteralPath $Archive -PathType Leaf)) { - Stop-Asset "--archive: $Archive is not a file." + Exit-Asset "--archive: $Archive is not a file." } if (-not (Test-Path -LiteralPath "$Archive.sha256" -PathType Leaf)) { - Stop-Asset "--archive: $Archive.sha256 is missing - the checksum file has to lie next to the tarball." + Exit-Asset "--archive: $Archive.sha256 is missing - the checksum file has to lie next to the tarball." } } @@ -278,7 +278,7 @@ function Invoke-AssetMode { try { Invoke-WebRequest -Uri $pair[0] -OutFile $pair[1] } catch { - Stop-Asset "the download failed: $($pair[0]) ($($_.Exception.Message)) - check the internet connection, then run this again." + Exit-Asset "the download failed: $($pair[0]) ($($_.Exception.Message)) - check the internet connection, then run this again." } } } @@ -286,18 +286,18 @@ function Invoke-AssetMode { $first = Get-Content -LiteralPath $checksumPath -TotalCount 1 -Encoding utf8 $match = [regex]::Match("$first", '^([0-9A-Fa-f]{64})') if (-not $match.Success) { - Stop-Asset 'the checksum file holds no sha256 in its first line - nothing was unpacked.' + Exit-Asset 'the checksum file holds no sha256 in its first line - nothing was unpacked.' } $want = $match.Groups[1].Value.ToLowerInvariant() $have = (Get-FileHash -LiteralPath $archivePath -Algorithm SHA256).Hash.ToLowerInvariant() if ($want -ne $have) { - Stop-Asset "the sha256 of the archive does not match its checksum file (expected $want, got $have) - nothing was unpacked. Delete the download and run this again." + Exit-Asset "the sha256 of the archive does not match its checksum file (expected $want, got $have) - nothing was unpacked. Delete the download and run this again." } Write-Line 'sha256 OK' $listing = Invoke-Native $tar.Source @('-tzf', $archivePath) if ($null -eq $listing) { - Stop-Asset 'the archive could not be read - nothing was unpacked.' + Exit-Asset 'the archive could not be read - nothing was unpacked.' } $tops = @( $listing -split "`n" | @@ -306,13 +306,13 @@ function Invoke-AssetMode { Select-Object -Unique ) if ($tops.Count -ne 1) { - Stop-Asset 'the archive does not hold exactly one top-level folder - nothing was unpacked.' + Exit-Asset 'the archive does not hold exactly one top-level folder - nothing was unpacked.' } $top = $tops[0] $manifestText = Invoke-Native $tar.Source @('-xOzf', $archivePath, "$top/tools/prerequisites.txt") if ($null -eq $manifestText) { - Stop-Asset "the archive holds no $top/tools/prerequisites.txt - nothing was unpacked." + Exit-Asset "the archive holds no $top/tools/prerequisites.txt - nothing was unpacked." } $limit = 0 foreach ($line in ($manifestText -split "`n")) { @@ -338,7 +338,7 @@ function Invoke-AssetMode { $null = New-Item -ItemType Directory -Path $unpack $null = Invoke-NativeVerbose $tar.Source @('-xzf', $archivePath, '-C', $unpack) if (-not (Test-Path -LiteralPath (Join-Path $unpack $top) -PathType Container)) { - Stop-Asset "unpacking failed - the target was not created." + Exit-Asset "unpacking failed - the target was not created." } Move-Item -LiteralPath (Join-Path $unpack $top) -Destination $target } finally { @@ -351,7 +351,7 @@ function Invoke-AssetMode { $treeScript = Join-Path $target 'tools/preflight.ps1' if (-not (Test-Path -LiteralPath $treeScript -PathType Leaf)) { - Stop-Asset 'the unpacked stack has no tools/preflight.ps1.' + Exit-Asset 'the unpacked stack has no tools/preflight.ps1.' } Write-Line "Unpacked into $target." Write-Line 'If a later step stops, run tools/preflight.ps1 from inside that folder.'