Repository navigation
fix(cli): make temporary directory cleanup non-fatal in the Windows install script - #135
Conversation
…nstall script The installer deleted its download directory with Remove-Item -Recurse inside a finally block. On machines where TEMP resolves to an 8.3 short path (a user profile such as C:\Users\USERNA~1.EXT), Windows PowerShell's filesystem provider fails that delete with "An object at the specified path ... does not exist", and the throw was reported as "Installation failed" after the binary and PATH were already in place. Resolve TEMP to its long path before building the temporary directory, delete it through System.IO.Directory.Delete, and downgrade any cleanup error to a warning so a leftover temporary folder never masks a completed install.
There was a problem hiding this comment.
All reported issues were addressed across 4 files
Shadow auto-approve: would not auto-approve because issues were found.
View guided diff | Turn on auto-fix | Re-trigger cubic
…EMP path Resolving TEMP through Get-Item threw before the cleanup guard when the directory did not exist, and its FullName does not reliably expand 8.3 short names. The guarded Directory.Delete already tolerates short paths.
There was a problem hiding this comment.
0 issues found across 3 files (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Shadow auto-approve: would not auto-approve. Auto-approval blocked by 1 unresolved issue from previous reviews.
View guided diff | Turn on auto-fix | Re-trigger cubic
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Shadow auto-approve: would not auto-approve. Auto-approval blocked by 1 unresolved issue from previous reviews.
View guided diff | Turn on auto-fix | Re-trigger cubic
2ynn
left a comment
There was a problem hiding this comment.
LGTM.
Could we also add a CI smoke test that verifies extraction/copying for the zSDKs/sdk-cli/scripts/install.ps1 ?
test-windows-installer:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
shell: [powershell, pwsh]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
- name: Test generated Windows installer
shell: ${{ matrix.shell }}
run: ./scripts/test-windows-installer.ps1
|
Added in 3771d0d: The script runs the generated |
There was a problem hiding this comment.
3 issues found across 2 files (changes from recent commits).
Confidence score: 3/5
scripts/test-windows-installer.ps1leaves each sandbox install directory in the persistent User PATH, so repeated runs keep adding stale entries. Restore the original User PATH after the tests.- The default
InstallerPathinscripts/test-windows-installer.ps1uses Windows-only separators, so the script may not find the installer under pwsh on Linux or macOS. Use forward slashes. - The sandbox roots in
scripts/test-windows-installer.ps1are left behind, and the second root can end up nested inside the first becauseGetTempPath()changes during the run.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/test-windows-installer.ps1">
<violation number="1" location="scripts/test-windows-installer.ps1:11">
P2: The default `InstallerPath` uses backslash separators, which only resolve on Windows. Use forward slashes so the path also resolves under pwsh on Linux/macOS, where this script is meant to run.</violation>
<violation number="2" location="scripts/test-windows-installer.ps1:29">
P3: Sandbox roots are never deleted, and the second sandbox is created inside the first one's temp directory because `GetTempPath()` returns the TEMP value that `Invoke-Installer` already changed. Build the root from the original temp path captured once at script start, and remove the root in the `finally` block after disposing the handle.</violation>
<violation number="3" location="scripts/test-windows-installer.ps1:57">
P2: Running the installer here writes the sandbox install directory into the persistent User PATH, and nothing restores it. Each run adds another temp `installer-test-<guid>` entry. Snapshot the User PATH before the tests and restore it in the `finally` block.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
View guided diff | Turn on auto-fix | Re-trigger cubic
| } | ||
| $global:InstallerTestArchive = $Sandbox.Archive | ||
| $global:InstallerTestDownloads = @() | ||
| & $InstallerPath *>&1 | ForEach-Object { "$_" } |
There was a problem hiding this comment.
P2: Running the installer here writes the sandbox install directory into the persistent User PATH, and nothing restores it. Each run adds another temp installer-test-<guid> entry. Snapshot the User PATH before the tests and restore it in the finally block.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At scripts/test-windows-installer.ps1, line 57:
<comment>Running the installer here writes the sandbox install directory into the persistent User PATH, and nothing restores it. Each run adds another temp `installer-test-<guid>` entry. Snapshot the User PATH before the tests and restore it in the `finally` block.</comment>
<file context>
@@ -0,0 +1,113 @@
+ }
+ $global:InstallerTestArchive = $Sandbox.Archive
+ $global:InstallerTestDownloads = @()
+ & $InstallerPath *>&1 | ForEach-Object { "$_" }
+}
+
</file context>
| #> | ||
| [CmdletBinding()] | ||
| param( | ||
| [string]$InstallerPath = (Join-Path $PSScriptRoot '..\zSDKs\sdk-cli\scripts\install.ps1') |
There was a problem hiding this comment.
P2: The default InstallerPath uses backslash separators, which only resolve on Windows. Use forward slashes so the path also resolves under pwsh on Linux/macOS, where this script is meant to run.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At scripts/test-windows-installer.ps1, line 11:
<comment>The default `InstallerPath` uses backslash separators, which only resolve on Windows. Use forward slashes so the path also resolves under pwsh on Linux/macOS, where this script is meant to run.</comment>
<file context>
@@ -0,0 +1,113 @@
+#>
+[CmdletBinding()]
+param(
+ [string]$InstallerPath = (Join-Path $PSScriptRoot '..\zSDKs\sdk-cli\scripts\install.ps1')
+)
+
</file context>
| [string]$InstallerPath = (Join-Path $PSScriptRoot '..\zSDKs\sdk-cli\scripts\install.ps1') | |
| [string]$InstallerPath = (Join-Path $PSScriptRoot '../zSDKs/sdk-cli/scripts/install.ps1') |
| } | ||
|
|
||
| function New-InstallerSandbox { | ||
| $root = Join-Path ([System.IO.Path]::GetTempPath()) "installer-test-$([guid]::NewGuid())" |
There was a problem hiding this comment.
P3: Sandbox roots are never deleted, and the second sandbox is created inside the first one's temp directory because GetTempPath() returns the TEMP value that Invoke-Installer already changed. Build the root from the original temp path captured once at script start, and remove the root in the finally block after disposing the handle.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At scripts/test-windows-installer.ps1, line 29:
<comment>Sandbox roots are never deleted, and the second sandbox is created inside the first one's temp directory because `GetTempPath()` returns the TEMP value that `Invoke-Installer` already changed. Build the root from the original temp path captured once at script start, and remove the root in the `finally` block after disposing the handle.</comment>
<file context>
@@ -0,0 +1,113 @@
+}
+
+function New-InstallerSandbox {
+ $root = Join-Path ([System.IO.Path]::GetTempPath()) "installer-test-$([guid]::NewGuid())"
+ foreach ($name in 'temp', 'localappdata', 'install', 'payload') {
+ New-Item -ItemType Directory -Path (Join-Path $root $name) -Force | Out-Null
</file context>
Summary
The generated
scripts/install.ps1deleted its download directory withRemove-Item -Recurseinside afinallyblock. On machines where$env:TEMPresolves to an 8.3 short path (a user profile such asC:\Users\USERNA~1.EXT), Windows PowerShell's filesystem provider fails that delete withAn object at the specified path ... does not exist(see PowerShell/PowerShell#21070 and #7760). The exception propagated to the top-level handler and was reported asInstallation failedeven though the binary and PATH update had already succeeded.Changes
[System.IO.Directory]::Delete($path, $true)instead ofRemove-Item -Recurse. The .NET call does not go through the PowerShell filesystem provider, so it tolerates short-name path components.Test-Path -LiteralPathto match the delete call.try/catchand emit a warning naming the leftover folder, so a cleanup failure can no longer mask a completed install.Testing
Regenerated the review CLI SDK; the only output change is
scripts/install.ps1and itsgen.lockchecksum. No PowerShell runtime is available locally, so the script was not executed.Summary by cubic
Fixes the Windows install script so a failed temporary directory cleanup no longer reports a completed installation as failed.
Remove-Item -Recurse, which fails when$env:TEMPresolves to an 8.3 short name likeC:\Users\USERNA~1.EXT.Test-Path -LiteralPathand deletes via[System.IO.Directory]::Delete, which tolerates short paths, and wraps cleanup in atry/catchthat prints a warning instead of throwing.scripts/test-windows-installer.ps1smoke test against the generated installer under both Windows PowerShell and PowerShell 7.Testing
Written for commit 3771d0d. Summary will update on new commits.