Skip to content

chore(installer): honest step labels + per-tool progress in the Windows installer (#422) - #477

Merged
shujaatTracebloc merged 8 commits into
developfrom
fix/422-honest-step-progress
Jul 30, 2026
Merged

chore(installer): honest step labels + per-tool progress in the Windows installer (#422)#477
shujaatTracebloc merged 8 commits into
developfrom
fix/422-honest-step-progress

Conversation

@shujaatTracebloc

@shujaatTracebloc shujaatTracebloc commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What & why

Step 1/5 "Checking system requirements" in the PowerShell installer actually installed ~700 MB of tooling (Docker Desktop, kubectl, k3d, helm) — nearly all console-silent (the download progress overlay is off for speed since #471, and the winget / Add-AppxPackage / installer invocations print nothing). Users read the dead air as a hang. The k3d cluster start re-run path also streamed raw INFO[0000] … lines past the style system.

Changes (scripts/install-k8s.ps1)

  • Honest step split: Step 1 "Checking system requirements" (preflight / GPU / virtualisation) and a dedicated Step 2 "Installing system tools"; renumbered to /6.
  • Invoke-WithHeartbeat: runs a blocking op in a background job with a live spinner (built on the existing Wait-JobWithProgress), so nothing in Steps 1–2 sits silent >10s. Wired into every tool download (kubectl / k3d / helm / winget / Docker Desktop), the winget installs, Add-AppxPackage, and the Docker Desktop installer.
  • Get-ToolSummaryLine: one honest line per tool as it becomes ready — name, version, size, elapsed (e.g. kubectl v1.31.0 (~60 MB, 12s)).
  • k3d start output: routed through Invoke-WithHeartbeat — captured to the log with a styled heartbeat instead of raw INFO[…], and now fails loudly if start fails (was always reporting "started").

Acceptance (from #422)

  • Split Step 1 into check vs install
  • Per-tool line: name, version, size, elapsed
  • Spinner + label during each winget invocation
  • Route k3d start/create output through the tone engine
  • No console-silent window >10s in Steps 1–2

Copy catalog

The copy catalog is bash-driven (reads step_header from install-k8s.sh), and the bash installer already splits check (a) from install (b) with real progress (spin_cmd / download_with_progress). This change is PowerShell-only, so the catalog golden is unaffected — copy-catalog.bats stays green.

Tests

  • Pester: Get-ToolSummaryLine (formatting), Invoke-WithHeartbeat (returns output / throws on failure / passes ArgumentList), and source guards for the 6-step split + no-raw-k3d-output.

Local verification

Pester 241/0/8 · bats 559 ok (only the 3 known macOS-local flakes) · copy-catalog green · check-style pass · drift clean · manifest regenerated · PS parse OK.

Closes #422


Note

Low Risk
Installer UX and progress/error-handling only on Windows PowerShell; no auth, cluster logic, or bash installer changes beyond the manifest hash.

Overview
The Windows install-k8s.ps1 flow is renumbered to six steps: preflight/GPU/virtualization stay in step 1, and ~700 MB of tooling (winget, Docker Desktop, kubectl, k3d, helm) moves to a dedicated “Installing system tools” step so labels match what actually runs.

Invoke-WithHeartbeat wraps long silent work (HTTPS downloads, Add-AppxPackage) with the existing spinner via background jobs; Get-ToolSummaryLine prints one green line per tool (version, size, elapsed) after Assert-ToolRuns. Job init now re-applies TLS 1.2 in job runspaces so corporate proxies don’t break in-job downloads.

winget, the Docker Desktop installer, and k3d cluster start use Start-Process + Wait-ProcessWithDeadline (kill on timeout) instead of jobs that could orphan children. Docker install adds winget→direct-download fallback and explicit failure if the exe never appears. Pester covers the new helpers and source guards; manifest.sha256 is updated for install-k8s.ps1.

Reviewed by Cursor Bugbot for commit ef4b7c5. Bugbot is set up for automated code reviews on this repo. Configure here.

…PS installer

Step 1/5 "Checking system requirements" actually installed ~700 MB of tools,
nearly all console-silent (downloads with the progress overlay off since #471,
plus silent winget/Add-AppxPackage/installer invocations), which reads as a hang.
The k3d start path also streamed raw INFO[...] lines past the style system.

- Split Step 1 into "Checking system requirements" (preflight/GPU/virtualisation)
  and a dedicated "Installing system tools" step; renumber to /6.
- Invoke-WithHeartbeat: run a blocking op in a background job with a live spinner
  (built on the existing Wait-JobWithProgress) so no op sits silent >10s. Wired
  into every tool download (kubectl/k3d/helm/winget/Docker Desktop), the winget
  installs, Add-AppxPackage, and the Docker Desktop installer.
- Get-ToolSummaryLine: one honest line per tool (name, version, size, elapsed),
  printed as each tool becomes ready.
- Route `k3d cluster start` through Invoke-WithHeartbeat: capture its raw output
  to the log + show a styled heartbeat instead of streaming INFO[...] lines
  (and fail loudly if start fails, instead of always reporting "started").
- Tests: Pester for Get-ToolSummaryLine, Invoke-WithHeartbeat, and source guards
  for the 6-step split + no-raw-k3d-output.

The copy catalog is bash-driven and the bash installer already splits check
(step a) from install (step b) with real progress, so its golden is unaffected.

Closes #422

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shujaatTracebloc shujaatTracebloc self-assigned this Jul 29, 2026
@LukasWodka

Copy link
Copy Markdown
Contributor

👋 Heads-up — Code review queue is at 34 / 30

Above the WIP limit. The team convention is to review existing PRs before opening new work.

Open PRs currently in Code review (oldest first):

Pull from review before opening new work. (This is a nudge from the kanban WIP check, not a block.)

@shujaatTracebloc
shujaatTracebloc marked this pull request as ready for review July 29, 2026 14:52
Comment thread scripts/install-k8s.ps1
Comment thread scripts/install-k8s.ps1
Comment thread scripts/install-k8s.ps1
shujaatTracebloc and others added 2 commits July 29, 2026 16:58
…p-progress

# Conflicts:
#	scripts/manifest.sha256
#	scripts/tests/install-k8s.Tests.ps1
…gbot)

Two High-severity findings from moving work into Start-Job via Invoke-WithHeartbeat:

- TLS 1.2 doesn't carry into job runspaces (PS 5.1 defaults to TLS 1.0/1.1), so
  in-job HTTPS downloads (kubectl/k3d/helm/winget/Docker Desktop) could fail
  SSL/TLS on hosts that need the explicit floor. Re-apply Tls12 in $script:JobInit
  (OR-in, don't clobber), which every job runs before its scriptblock.
- A native `k3d cluster start` non-zero exit leaves the job state 'Completed', so
  Invoke-WithHeartbeat never threw and the installer reported "Compute environment
  started." on a stopped cluster. The start scriptblock now checks $LASTEXITCODE
  and throws its captured output, so the existing catch surfaces a real Err.

Adds a functional in-job-TLS test and a source guard for the exit-code throw.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread scripts/install-k8s.ps1 Outdated
Comment thread scripts/install-k8s.ps1 Outdated
…nstall (Bugbot)

Two follow-on findings from the Start-Job/heartbeat design:
- Invoke-WithHeartbeat threw a generic 'Failed while: ...' and swallowed the
  job's real error (Receive-Job -ErrorAction SilentlyContinue), so the k3d-start
  detail never reached the log/Err. Now capture output+error (2>&1) and the job's
  terminating reason, and include it in the throw; the k3d-start catch passes it
  as Err detail too.
- The Docker Desktop installer Start-Process had no -ErrorAction Stop and no exit
  check, so a spawn/install failure completed the job as success and Step 2
  continued. Now -ErrorAction Stop + PassThru + exit-code throw, wrapped so it
  Errs cleanly with the real detail.

Adds a heartbeat failure-detail test + a Docker-installer source guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread scripts/install-k8s.ps1 Outdated
k3d and helm printed their green Get-ToolSummaryLine 'ready' line inside the
download branch, before Assert-ToolRuns — so a corrupt/wrong-arch binary showed
as ready and then failed the gate (kubectl already gates first). Compute the
summary at download time (correct elapsed) but defer the Ok until after the
execute-gate passes. Adds a source guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread scripts/install-k8s.ps1 Outdated
The winget Docker path soft-logged failures, never checked $LASTEXITCODE, and
had no direct-download fallback when winget was present — so a failed winget
install let Step 2 continue and only surfaced as the 10-minute Docker-wait
timeout later. Now: the winget scriptblock throws on a non-zero exit; if winget
is absent OR didn't land the exe, fall through to the direct download (parity
with k3d/helm); and a final Test-Path guard Errs immediately if neither path
installed Docker. Adds a source guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread scripts/install-k8s.ps1 Outdated
…s (Bugbot)

Start-Process -Wait / winget install inside Invoke-WithHeartbeat (a background
job) leaks the child process on timeout: Stop-Job ends the job runspace but the
installer keeps running, and the winget path could time out then fall through to
a second concurrent install. Switch the Docker Desktop installer + all winget
installs (Docker, k3d, helm) to Start-Process -PassThru + Wait-ProcessWithDeadline,
which shows the spinner AND kills the actual process on timeout, then checks the
exit code. Downloads (Invoke-WebRequest) stay on Invoke-WithHeartbeat — no child
process to orphan. Updates the Docker source guards accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e6be743. Configure here.

Comment thread scripts/install-k8s.ps1
Same orphan hazard as the installers: k3d cluster start ran inside
Invoke-WithHeartbeat (a job), so Stop-Job on timeout left the native k3d child
running. Switch it to Start-Process -PassThru + Wait-ProcessWithDeadline (kills
on timeout), redirecting its raw INFO[...] to temp files for the log; check both
the deadline and the exit code so a failed/stuck start Errs with the real reason
instead of a false 'started'. Now every process-spawning op is killable; only
in-runspace downloads + Add-AppxPackage remain on the job-based heartbeat.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shujaatTracebloc
shujaatTracebloc merged commit 0f744ab into develop Jul 30, 2026
35 checks passed
@shujaatTracebloc
shujaatTracebloc deleted the fix/422-honest-step-progress branch July 30, 2026 06:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants