Repository navigation
feat(install): prettier progress output + completion banner - #207
juhovainio wants to merge 2 commits into
Conversation
Summary
Remaining ConcernsBlocking
Non-blocking
Tradeoffs
Missing elements
Positive signals
Deployment Notes
|
f10e515 to
8f642bc
Compare
|
Rebased onto main (116 commits stale, clean rebase). Addressed both blocking findings from volen-silo's review, in 8f642bc:
Neither change touches any message text, so all the e2e-cucumber substring assertions this PR's own test plan verified ( Left the non-blocking items as-is: the UTF-8 banner encoding gap when output is redirected (real but low-impact — no assertion inspects the banner text), the incomplete helper-migration spots, and the PATH-hint discrepancy between the two scripts. On that last one specifically: install.sh always suggests "open a new terminal", but I don't think blindly copying that to install.ps1 is correct — the documented primary install method ( Could not run PowerShell lint or exercise install.ps1 locally (no pwsh in this environment) — same limitation the original PR's own test plan noted. |
|
Fixed the PowerShell lint failure: added the missing UTF-8 BOM (the banner uses non-ASCII box-drawing characters) and replaced the empty catch block around the best-effort console-encoding switch with a |
be36d55 to
f8c3c7d
Compare
tomastola
left a comment
There was a problem hiding this comment.
Nice polish, and the stderr and console-gating fixes from the earlier round look right. The install.sh helpers behave correctly under a pty, piped and split-stream, with NO_COLOR set, empty and unset. My main point is that nothing tests the new behaviour; the rest are non-blocking.
| esac | ||
|
|
||
| echo "next:" | ||
| if [ "${UPDATE_SHELL_PATH}" = "1" ]; then |
There was a problem hiding this comment.
The colour gating, the !! prefix, the banner and the final hint have no test. The current e2e substring checks all pass with this PR reverted, and the piped e2e runs never take the colour branch. AGENTS.md asks for a scenario for user-observable CLI output. Please add lifecycle steps asserting that Get started: and the final hint appear, and that no \x1b[ appears when piped or with NO_COLOR set. A pty scenario in the style of download_progress_pty.feature can cover the TTY path.
| @@ -1,4 +1,4 @@ | |||
| param( | |||
| param( | |||
There was a problem hiding this comment.
Non-blocking: this file now starts with a UTF-8 BOM, which the description doesn't mention, and it would be the only .ps1 in the repo with one. The README's Windows install is irm … | iex, and I believe Windows PowerShell 5.1 can leave the BOM in the returned string, which would make iex fail on param(. I couldn't run 5.1, so please check it. Alternatively build the banner from [char] codes and keep the file ASCII.
| function Write-CompletionBanner { | ||
| param([string] $NextHint) | ||
| try { | ||
| [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 |
There was a problem hiding this comment.
Non-blocking: [Console]::OutputEncoding is set for the caller's session and never restored, and under irm | iex that is the user's own session. Please restore it in a finally, or skip the assignment when output is redirected.
|
|
||
| $ErrorActionPreference = "Stop" | ||
|
|
||
| # [Console]::IsOutputRedirected is checked alongside NO_COLOR because |
There was a problem hiding this comment.
Non-blocking: the comment states that Write-Host -ForegroundColor throws HostException under WinRM or scheduled tasks as fact. Please soften it unless you've reproduced it. Also, IsOutputRedirected is not the same as "no console attached".
| Write-Host $NextHint | ||
| } | ||
|
|
||
| function Fail { |
There was a problem hiding this comment.
Non-blocking: Fail has no !! prefix, while install.sh's fail does. This is part of the parity gap the earlier review already raised.
| } | ||
|
|
||
| use_color=0 | ||
| # Both stdout and stderr must be TTYs: color() only ever colors stdout |
There was a problem hiding this comment.
Non-blocking: the comment says "color() only ever colors …", but there is no color(). The helpers read the C_* variables directly.
nowycondro
left a comment
There was a problem hiding this comment.
🔴 Automated review · pr-review-watcher · f8c3c7d
Review
Read install.sh and install.ps1 in full as changed between merge-base 2844d797 and head f8c3c7dc, plus the e2e-cucumber install-lifecycle scenario/step files, AGENTS.md's testing conventions, and the docs that describe how these scripts are invoked. The polish itself (TTY/NO_COLOR gating, the new helper functions, the completion banner) is implemented carefully and CI is fully green, but two things should be resolved before merge: a byte-level change to install.ps1 that risks breaking the documented one-line Windows install command, and a gap versus this repo's own test-coverage rule for new CLI output.
Blocking
-
A UTF-8 BOM was added to the start of
install.ps1, which risks breaking the documentedirm | iexone-liner —install.ps1:1.
Commitf8c3c7dc("satisfy PSScriptAnalyzer") prepends a 3-byte UTF-8 BOM (EF BB BF) beforeparam(, to satisfy a PSScriptAnalyzer rule about the new non-ASCII box-drawing art. Confirmed by inspecting the raw bytes before/after the commit. This repo's documented install command isirm https://raw.githubusercontent.com/.../install.ps1 | iex(README, andskills/rocm-doctor/SKILL.md). That specific pattern — a BOM-prefixed script fetched withInvoke-RestMethodand piped intoInvoke-Expression— is a well-known, frequently-reported Windows PowerShell failure mode:Invoke-RestMethoddoes not strip the BOM from the returned string the way file reads do, soInvoke-Expressionsees a strayU+FEFFglued to the first token, which has produced parser errors ("unexpected token", "missing closing ')'", etc.) for a number of other projects using the same one-line install pattern. The CI "Lint (PowerShell)" job executes the file directly (file-based execution tolerates a BOM), so it would not catch this; the PR's own test plan notes Windows smoke-testing wasn't possible in that environment. I don't have a PowerShell interpreter available to reproduce this directly, so this is argued from the documented failure pattern plus the confirmed BOM and confirmedirm | iexusage, not from a live repro.
Confidence 85 · architectural · Fix: verifyirm <raw-url>/install.ps1 | iexactually runs on Windows PowerShell 5.1 (not justpwsh -File) before merging; if it fails, either keep the file BOM-free (there are other ways to satisfy the lint rule, or the rule can be suppressed for this specific case) or strip the BOM in the README's one-liner itself (e.g.($script).TrimStart([char]0xFEFF) | iex). -
No Gherkin scenario covers the new output behavior this PR introduces, per this repo's own written testing rule —
tests/e2e-cucumber/features/install_lifecycle.feature,tests/e2e-cucumber/tests/e2e/lifecycle_steps.rs.
AGENTS.mdstates: "User-observable behavior needs a scenario, not only a unit test... If the change alters what a user of the CLI can observe — command output... — then that behavior must be covered by a Gherkin scenario..., adding or updating the scenario... when no existing scenario already covers it." The TTY/NO_COLORgating and the completion banner are new, user-observable installer output, and no scenario or step definition anywhere intests/e2e-cucumbermentions color,NO_COLOR, the banner, or piped output — the existing scenarios that still pass are asserting pre-existing status-line substrings that happen to survive regardless of whether color codes are present; they don't exercise the new gating logic itself. The PR's test plan covers this behavior only with a manual smoke test. This independently confirms the point already raised in the existing human review on this PR.
Confidence 85 · test-coverage · Fix: add (or extend) a cucumber scenario that asserts piped/redirected output contains no raw ANSI escapes and thatNO_COLOR=1suppresses color under a pty, per the convention above.
Non-blocking
-
The two scripts' completion banners don't quite mirror each other —
install.sh(print_completion_banner),install.ps1(Write-CompletionBanner).
install.shemits an extra blank line (via theprintf '%s\n' "${C_RESET}"after thecatheredoc) between the ASCII art and "Get started:";install.ps1'sWrite-Host $artis followed immediately byWrite-Host "Get started:"with no equivalent blank line. Minor visual difference between platforms, and the PR description states the PowerShell version mirrors the shell version exactly.
Confidence 75 · mechanical · Fix: add a blankWrite-Host ""after the art ininstall.ps1for parity. -
The new output helpers weren't applied everywhere —
install.ps1(Write-MinimalConfigIfMissing, and the "not on PATH" note near the end of the install flow).
install.sh's equivalent config messages were converted to the newinfo()helper, butinstall.ps1's"config: existing $configPath"/"config: created $configPath"and the "note: $InstallDir is not on PATH" block are still rawWrite-Hostcalls, unconverted toWrite-Detail/the other new helpers. Cosmetic only, but leaves the two scripts (andinstall.ps1internally) slightly inconsistent after a PR whose purpose is exactly this kind of output consistency.
Confidence 70 · mechanical · Fix: route the remaining call sites through the new helpers for consistency, or note why they're deliberately left plain.
Decisions for the author
NO_COLORset-but-empty is treated the same as unset ininstall.sh— tradeoff.
[ -z "${NO_COLOR:-}" ]can't distinguish "NO_COLORunset" from "NO_COLORexported as an empty string"; both leave color enabled on a TTY. The informal NO_COLOR convention says color should be suppressed whenever the variable is merely present, regardless of value. The existing human review on this PR explicitly tested "NO_COLORset, empty and unset" and found the behavior correct, so this looks like a deliberate, already-reviewed choice rather than an oversight — flagging only so it's confirmed as intentional.
Positive signals
- The comment explaining why
install.sh's color gate checks both stdout and stderr TTYs (to avoid leaking raw ANSI into a redirected stderr stream while stdout stays a terminal) is a genuinely non-obvious edge case, and it's called out clearly in the code rather than left implicit. - The
[Console]::OutputEncodingtry/catch ininstall.ps1logs the swallowed exception viaWrite-Verboseinstead of silently discarding it (per the PSScriptAnalyzer fix commit), with a clear comment on why that console-access failure is expected in WinRM/service contexts.
Deployment notes
- CI is fully green: build-and-test, windows-build-and-test, clippy, PowerShell lint, E2E tests and the E2E consolidated report, coverage, third-party notices, license headers, CodeQL/static analysis, markdown links, commit sign-off/signatures, and the Read the Docs preview build all report pass. The GPU-hardware-specific E2E lanes report "skipping", which is expected without attached runners in this check context.
- This is an installer-output-only change with no schema or data migration, but the BOM point above is specifically a "safe to merge" concern: the affected file is fetched raw by every Windows user following the README's documented one-liner, so it's worth settling before the next release rather than after.
What this covered
Read install.sh and install.ps1 in full as changed between merge-base 2844d797 and head f8c3c7dc, plus tests/e2e-cucumber/features/install_lifecycle.feature, tests/e2e-cucumber/tests/e2e/lifecycle_steps.rs, the relevant section of AGENTS.md, and the docs referencing install.ps1's invocation (README, skills/rocm-doctor/SKILL.md). Verified the BOM addition directly via raw byte inspection of the file before/after the relevant commit, and checked CI status via gh pr checks.
Did not run shellcheck, PSScriptAnalyzer, cargo, or any PowerShell interpreter — none are available in this environment (no network for toolchain fetch, no pwsh binary) — so the BOM/irm | iex concern above is argued from a well-documented class of failure plus the confirmed facts in this diff, not from a direct reproduction here; everything else relies on the green CI results plus direct reading. This review was done as a single pass rather than split across parallel reviewers. Not reconciled against the existing human review beyond reading it for context; the test-coverage finding above independently arrives at the same point it raised.
siloteemu
left a comment
There was a problem hiding this comment.
🔴 Automated review · pr-review-watcher · f8c3c7d
This automation never files a GitHub approval, so no approving review will
appear here whatever the outcome — the merge decision stays with a human
reviewer.
Review — needs work
Full review of the whole change (prw-base...HEAD, merge-base 2844d79, 3 commits, install.sh and install.ps1 only).
The description says the change adds colored step markers, gated on TTY/NO_COLOR, and a completion banner with a getting-started list. It also says piped and redirected output is "unaffected". The description is read in Step 9; no ticket is named.
Blocking
-
No test or scenario exercises any of the new installer output —
install.sh(whole diff),install.ps1(whole diff); existing assertions attests/e2e-cucumber/tests/e2e/lifecycle_steps.rs:958-990,:1096-1114and:1130.- What the diff changes for users:
- the
==>,::,!!markers; - the TTY/
NO_COLORcolor gating; - the banner and "Get started" block;
- the replacement of the
next:andrun:blocks with a hint line, whose wording differs between platforms; - the PowerShell encoding guard.
- the
- The diff adds or edits no
.featurefile, step definition or test. The existing lifecycle steps only callout.contains(...)onsignature verified,user PATH updated,installer PATH updated,shell profile updated, the failure messages at:1096-1114andremoving previous rocm-cli install. All of those substrings are kept by the change. - Verdict 1 (would it still pass with the production change reverted): yes, so no existing test covers the change.
- Verdict 2 (what stays green if one branch inside the change is broken alone): everything. The color branch, the
NO_COLORbranch, the banner text, the hint text, the!!prefix and the PowerShellcatchcan each break with every existing check staying green. - The harness captures the installer through pipes (
lifecycle_steps.rs:226-244), so only the no-color branch ever runs. A PTY harness already exists (features/download_progress_pty.feature,tests/e2e/tui_driver.rs), so a TTY-gated scenario is feasible. AGENTS.md§3 requires a Gherkin scenario intests/e2e-cucumber/features/for changed command output. The PR text does not name an@id:, a gated lane, or a reason the change is purely internal.- Confidence 85 · logic · Fix: add or extend a
@lifecyclescenario that:- asserts a piped run has no ESC bytes and
NO_COLORsuppresses them; - asserts the "Get started:" block and the hint appear;
- asserts the failure prefix;
- adds a PTY case for the colored path, plus the Windows equivalent on the Windows lane.
- asserts a piped run has no ESC bytes and
- Otherwise state in the PR text exactly which
@id:covers each behavior and which lane runs it. The lifecycle scenarios are opt-in (E2E_INCLUDE_LIFECYCLE).
- What the diff changes for users:
-
A UTF-8 byte-order mark was added to
install.ps1, and it may break the documented Windows one-liner —install.ps1:1; consumersREADME.md:99,README.md:107,skills/rocm-doctor/SKILL.md:92at HEAD (README.md:103and:111atprw-base).- Evidence: the first bytes are
ef bb bf 70 61 72at HEAD and70 61 72 61 6d 28atprw-base. The base file had no non-ASCII bytes; the new banner and em dash are the first. It is now the only tracked.ps1file with a BOM. - Documented install is
irm https://raw.githubusercontent.com/.../install.ps1 | iex. Windows PowerShell 5.1 (documented as supported indocs/release-trust.md) returns the response as a decoded string, and my recollection is that it does not strip the BOM. In that caseiexreceivesU+FEFFbeforeparam(, and the script fails to parse or to run. - Nothing in CI exercises that path, so the breakage would be invisible:
ci.ymlusesGet-Content -Raw, which strips the BOM.nightly.ymlandrelease.ymldownload with-OutFileand run-File, which tolerates a BOM.- The e2e harness also runs
-File.
- I could not run PowerShell here (none installed). This is argued from documented behavior, not reproduced, so confidence is 70.
- Confidence 70 · architectural · Fix:
- Keep
install.ps1ASCII and build the banner from code points (for example[char]0x2588). - Exclude
PSUseBOMForUnicodeEncodedFileinPSScriptAnalyzerSettings.psd1instead of adding the BOM. - Or, if the BOM stays, show the one-liner working under 5.1 and PowerShell 7 and cover it in CI.
- Keep
- The author can discharge this finding by running the one-liner on Windows PowerShell 5.1 against the BOM'd file and reporting the result.
- Evidence: the first bytes are
-
The description misstates the change in both directions — PR description (Summary and Test plan); code at
install.sh:342-361,install.sh:588-593,install.ps1:58-90,install.ps1:790-796,install.ps1:1,install.ps1:61-68.- It claims too much:
- Piped and redirected output is "unaffected". The banner, "Get started" block, new hint wording and
!!error prefix are all printed unconditionally; only the ANSI escapes are gated.install.shoutput was pure ASCII before; it no longer is when piped. - The
install.ps1changes "mirror the verifiedinstall.shpattern exactly". They do not:install.ps1:480,:506and:785-787still use bareWrite-Host, andFail(install.ps1:92-96) has no marker, whileinstall.shconverted all of these.
- Piped and redirected output is "unaffected". The banner, "Get started" block, new hint wording and
- It omits changes that are in the diff and a reader would check:
- the BOM added at
install.ps1:1; [Console]::OutputEncodingset to UTF-8 and never restored (install.ps1:61-68).
- the BOM added at
- Confidence 85 · logic · Fix: narrow the description to what the diff does, or finish the work. State the BOM and encoding change, drop or qualify "unaffected", and say which
@id:covers which behavior (the first finding).
- It claims too much:
Non-blocking
-
A new comment names a function that does not exist —
install.sh:41.- The comment says "color() only ever colors stdout (step/ok) or stderr (fail)". There is no
colorfunction ininstall.sh; the helpers arestep,ok,info,failand theC_*variables. - The code governs: gating on both stdout and stderr matches the rest of the comment and
install.sh:48. The comment is the side that is wrong. - Confidence 85 · mechanical · Fix: name
step()/ok()/fail().
- The comment says "color() only ever colors stdout (step/ok) or stderr (fail)". There is no
-
PowerShell session encoding is changed and not restored —
install.ps1:61-68.- Under the documented
irm | iex, the script runs inside the user's own session.[Console]::OutputEncoding = UTF8then persists after the installer finishes. Legacy OEM-encoded output from native tools in that session is decoded as UTF-8 for the rest of it. - It also runs when output is redirected, where it serves no purpose. This is from documented .NET behavior, not run.
- Confidence 70 · logic · Fix: save the previous value, set UTF-8 only when writing the banner to a real console, restore it in the existing
finally.
- Under the documented
-
install.ps1andinstall.shdisagree on the output contract at three sites —install.ps1:480,install.ps1:506,install.ps1:785-787,install.ps1:92-96againstinstall.sh:191,:215,:14.install.shnow routesconfig: existing/createdthroughinfo, which indents.install.ps1still prints those lines, and thenote: ... not on PATHlines, as bare unindentedWrite-Host.install.shfail()prefixes!!;install.ps1Failhas no equivalent.- The PowerShell choice for
Failis defensible becauseWrite-Erroralready renders as an error record, but nothing says so. - Confidence 85 · mechanical · Fix: use
Write-Detailat those sites, and say whetherFailshould carry a marker.
-
The "Get started" examples do not match the hint printed directly below them —
install.sh:356-361withinstall.sh:595-598;install.ps1:787-796.- The block shows bare
rocm ...commands. WithROCM_CLI_UPDATE_SHELL_PATH=0the hint isRun: <install_dir>/rocm examine. On Windows, when the process PATH is not updated, it is& "<path>\rocm.exe" examine. In both cases barerocmdoes not work in the shell that just ran the installer. rocm examineis the only command the hint points to, yet it is not in the "Get started" list.- I ran this on
install.shand confirmed it there; the Windows case is from reading. - Confidence 70 · mechanical · Fix: build the examples from the same prefix as the hint, or put the hint first and make the first step consistent.
- The block shows bare
-
The commit history carries two review-fix commits on top of the feature —
f5de08f("gate color on both TTYs, guard PowerShell console access") andf8c3c7d("satisfy PSScriptAnalyzer on install.ps1").- The messages are descriptive, not noise. Squashing them into
17122dbwould make the history easier to read. - Suggestion only.
- The messages are descriptive, not noise. Squashing them into
Decisions for the author
-
The banner and getting-started block print on every successful install, including piped and CI runs — tradeoff
- Pro: a consistent, friendly finish, and the e2e harness's substring assertions still pass.
- Con: it cannot be suppressed (
NO_COLORdrops only color). On a non-UTF-8 locale, a Linux console or a legacy Windows codepage, the box-drawing characters and the em dash render as garbage. - I confirmed in
install.shwithLANG=Cand piped output that the raw UTF-8 bytes are written regardless; the Windows rendering is from reading. - Confirm this is intended, or gate the banner on a TTY and a UTF-8 locale.
-
install.shrequires both stdout and stderr to be TTYs for color;install.ps1checks onlyIsOutputRedirectedandNO_COLOR— tradeoffinstall.shwritesfailto stderr, so gating on both stops escape codes leaking into2>error.log. I confirmed under a pseudo-terminal that2>filedrops all color on both streams.- The cost is that any stderr redirect also removes color from stdout.
install.ps1fails throughWrite-Error, so stdout-only gating is reasonable. Confirm both are intended.
-
The comment's claim that
Write-Host -ForegroundColorthrows under WinRM or scheduled tasks is unverified — non-blocking-improvement- Neither I nor any worker could run PowerShell, and the commit message for
f5de08fsays as much.[Console]::IsOutputRedirectedis a conservative proxy and harmless if the claim overstates. - The
try/catcharound the encoding assignment is correct independently. Consider softening the comment or confirming the claim on a real host.
- Neither I nor any worker could run PowerShell, and the commit message for
Positive signals
- The
[ -t 1 ] && [ -t 2 ]gate ininstall.shkeeps ANSI bytes out of a redirected error log; I confirmed it under a pseudo-terminal with2>file. - The
downloaded:line thatapps/rocm/src/remote/provision.rsparses is deliberately left as a plainecho, and the download-only path exits before the banner, so remote provisioning keeps working. - Commands named in the banner (
rocm install sdk,rocm serve <model>,rocm) all exist at this head, and the banner art matchesREADME.mdbyte for byte. install.shstill runs cleanly underdash, and output with and without color has the same structure.- The
catchthat now writesWrite-Verbosefixes the empty-catch lint without letting$ErrorActionPreference = "Stop"abort the install.
Deployment notes
- Windows users on the documented
irm | iexpath are the ones exposed to the BOM (second blocking finding). The console code page change is user-visible for the rest of that session. - Failed installs now surface
!! rocm-cli installer: ...on stderr.provision.rsputs stderr into itsbail!messages, sorocm remoteerror text gains the!!prefix. No test asserts the old text. - The branch is 125 commits behind
prw-base.git merge-treeshows no textual conflict, but base changed hunks next to the edited ones in both installers, so re-run the lifecycle and uninstall scenarios after rebasing. AGENTS.mdatprw-baseis stricter than the checkout's copy, with rules on showing a new test fails when its target is broken and on naming the lane that runs new behavior. Those apply after the rebase.
What this covered
- Read:
install.shandinstall.ps1in full at HEAD, and their diff againstprw-base, three-dot, merge-base 2844d79. - Surrounding code and consumers:
apps/rocm/src/remote/provision.rsandbootstrap.rs;tests/e2e-cucumber(install_lifecycle.feature,lifecycle_steps.rs,installer_fixture.rs);.github/workflows/ci.yml,nightly.ymlandrelease.yml;.pre-commit-config.yaml,PSScriptAnalyzerSettings.psd1and the xtask PowerShell lint;README.mdandskills/rocm-doctor/SKILL.md.
- Ran:
install.shend to end in a scratch directory (no TTY, pseudo-terminal, pseudo-terminal with2>file,dash,LANG=C);- byte inspection of line 1 of
install.ps1at HEAD andprw-base; - the sign-off check over
prw-base..HEAD: 3 commits checked, none missing a trailer (AGENTS.mdrequires DCO sign-off).
- Passes: code passes by coupling (
install.sh;install.ps1), agent-instruction adherence, history, prior changes (earlier merged PRs' review comments read throughgh, never this PR's discussion), code comments, impact analysis and design review. Findings were merged by root cause. - Did not run or could not make:
- No PowerShell was available, so every
install.ps1claim, including both BOM-related findings and the encoding finding, is argued from documented behavior and not reproduced. shellcheckwas not installed, so the repository'sshellcheck --enable=allhook was not re-run.- No cargo, build or e2e suite was run.
- The CI rollup was taken from the caller's statement: the listed checks passed, and the hardware E2E, docs and skillscope checks were skipped. The passing checks do not exercise the new output, the color paths or
irm | iex. - Commit signature status was not checked; the DCO check above covers sign-off only.
- No PowerShell was available, so every
- Not reconciled against any discussion here. The fixes are the author's own; the workers were Sonnet-tier fan-out passes.
|
Addressed review 5709740888 in 66ed3bb. Blocking
Non-blocking, done
Left as is, for the author/maintainers
|
tomastola
left a comment
There was a problem hiding this comment.
Thanks for the follow-up. On the Linux side every point from my last review is fixed. The new lifecycle scenarios 23–25 cover the get-started block, the hint that names the binary by its path, the !! marker and output with no escape codes, and the color() comment is corrected. In install.ps1 the BOM is gone, the console encoding is now restored in a finally, and the HostException comment is softened. Your reason for leaving the !! prefix off Fail (Write-Error already renders as an error) is fine with me.
However, this commit adds two bugs to the Windows banner, and the new Windows scenario can't detect them. I ran the function on its own under PowerShell 7.4.6 (pwsh), calling it the way the script does, Write-CompletionBanner "Run: rocm examine", with NoColor set. It printed:
╚oca╚ AI on AMD GPUs — one binary, zero se╗up
Get started:
Run: rocm examine install sdk # set up a managed ROCm runtime
Run: rocm examine serve qwen # serve a small built-in assistant model
Run: rocm examine # open the launcher
Blocking
-
install.ps1:816: the call site still passes one argument.Write-CompletionBannernow takes($Cmd, $NextHint), but it is still called asWrite-CompletionBanner $nextHint. So the whole hint is bound to$Cmd, and$NextHintis empty. Every Windows install would print "Run: rocm examine install sdk" and so on, and the real next-step line would be blank. The call site needs to work out the command (rocmwhen the install folder is on PATH, otherwise& "<dir>\rocm.exe") and pass both values. This is the same split the Linux code already does atinstall.sh:596-602. -
install.ps1glyph table: the swaps also hit letters in the tagline, because@{}keys ignore case. A PowerShell hashtable literal matches keys case-insensitively. Lowercaselandttherefore match theLandTplaceholders, so "Local … setup" comes out as "╚oca╚ … se╗up". Lowercasefandjare in the table too, so the same thing would happen to them. Possible fixes:- build the table with
[System.Collections.Generic.Dictionary[char,char]]::new(), which is case-sensitive; or - use placeholder characters that have no other case and can't be mistaken for text, for example digits; or
- swap characters only in the six art lines and leave the tagline alone.
- build the table with
-
Scenario
lifecycle-windows-install-output-bannerpasses even with both bugs.then_get_started_blockonly checks thatGet started:,install sdk,serve qwenandexamineappear somewhere. With bug 1 all four still appear, because the hint is printed in front of every example. Please give Windows its own version ofthen_hint_names_binary: the last line should be exactlyRun: & "<dir>\rocm.exe" examine(orRun: rocm examine), and each example should start with that same command. If you add a check that the tagline readsLocal AI on AMD GPUs, it catches bug 2 on both platforms. -
No CI has run on
66ed3bbd, and the PR has a merge conflict. The only check reported is Read the Docs, and there are no workflow runs for this commit. GitHub reports the PR asCONFLICTINGwith main (DIRTY), and the branch is 127 commits behind. Your reply says the Windows scenario "runs on the Windows lifecycle lane only", but that lane has never run it. Please rebase so CI runs, and confirm the Windows lifecycle job passes once the fixes above are in.
Non-blocking
- The PR description wasn't updated. Your comment says the "unaffected" and "mirrors exactly" claims were too broad, but the PR body still says both. It also still lists "9/9 lifecycle scenarios" and an unticked PowerShell lint item. Please change the body itself to the corrected scope from your comment, because the body is what ends up in the squash commit.
lifecycle-linux-install-output-no-color-envadds no coverage. The test harness always pipes the installer's output, and piped output already turns color off beforeNO_COLORis looked at. So this scenario still passes if theNO_COLORcheck is deleted, and it proves nothing beyond scenario 23. Either drop it, or make it meaningful: a test hook that forces the TTY branch on, run withNO_COLORset. Failing that, a comment in the feature file saying it only guards against regressions would do.- One
note:line ininstall.ps1still bypassesWrite-Detail. The comment says the remainingconfig:andnote:lines now go throughWrite-Detail. The twoconfig:lines do, butnote: $InstallDir is not on PATHatinstall.ps1:805(with its two follow-up lines) still callsWrite-Hostdirectly. docs/testing.md:1173: the new sentence is added as one very long line in a paragraph that is otherwise hard-wrapped. Please re-wrap it to match.
Colored ==> / :: step markers and a !! failure prefix, gated on TTY and NO_COLOR (only the ANSI escapes are gated; markers and the get-started block print unconditionally). A completion get-started block names the binary the same way as the next-step hint; the box-drawing banner is shown only on an interactive UTF-8 terminal. install.ps1 stays ASCII-only (no BOM, so irm | iex works on Windows PowerShell 5.1) and switches the console encoding only on a real console, restoring it afterwards. Add lifecycle scenarios 23-26 covering the get-started block, hint, failure marker, and absence of ANSI escapes and banner art when piped or NO_COLOR is set. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
nowycondro
left a comment
There was a problem hiding this comment.
🔴 Automated review · pr-review-watcher · 66ed3bb
This automation never files a GitHub approval, so no approving review will appear here whatever the outcome — the merge decision stays with a human reviewer.
Review — needs work
Full review of the whole change (5 files, 2844d797...66ed3bb).
No ticket named; the PR's own description is the only stated intent. The description's final test-plan line justifies skipping manual Windows testing by claiming "the install.ps1 changes mirror the verified install.sh pattern exactly" — this is contradicted by Blocking finding 1 below: at the one call site that matters, they do not mirror each other, and that is exactly how both blocking bugs below shipped untested.
Blocking
-
install.ps1:816callsWrite-CompletionBannerwith one positional argument against a two-parameter function, silently dropping the real next-step instruction —install.ps1:56-57(param([string] $Cmd, [string] $NextHint)),install.ps1:816(Write-CompletionBanner $nextHint).
Only one argument is passed, so PowerShell binds it positionally to$Cmd;$NextHintis never bound. Confirmed via git history: the function took a single$NextHintparameter in this PR's first commit (17122db) with a matching one-argument call site; a later commit in this same PR added the$Cmdparameter in front of it for the "Get started" examples but never updated the call site. Effect, on every single Windows install: the three "Get started" lines are built as"$Cmd install sdk"/"$Cmd serve qwen"/"$Cmd", with$Cmdnow holding the full hint sentence (e.g."Run: rocm examine install sdk # set up a managed ROCm runtime"), and the actual next-step instruction — the one piece of actionable guidance the banner exists to deliver — is replaced by a blank line.install.sh's equivalent call (install.sh:603,print_completion_banner "${cmd}" "${next_hint}") correctly passes two arguments, so the two scripts do not in fact mirror each other here. No existing test catches it: the Windows scenario'sthen_get_started_block(tests/e2e-cucumber/tests/e2e/lifecycle_steps.rs) only checks loose substrings ("Get started:", "install sdk", "serve qwen", "examine") that remain present even in the garbled text, and the stricterthen_hint_names_binarycheck that pins the literal hint line is@requires-os:linuxonly.
Confidence 100 · logic · Fix: build a$cmdvalue in thetryblock the same wayinstall.sh:596-602does (rocmwhen the install dir is already on PATH, otherwise the fullrocm.exepath) and pass bothWrite-CompletionBanner $cmd $nextHint. -
install.ps1's glyph-substitution loop corrupts the plain-English caption, not just the box-drawing art —install.ps1:61-69(the$arthere-string, caption on line 69),install.ps1:71-75(glyph map),install.ps1:76-78(substitution loop).
The loop (-join ($art.ToCharArray() | ForEach-Object { if ($glyphs.ContainsKey(...)) {...} else {$_} })) runs over the entire here-string, including the caption"Local AI on AMD GPUs ~ one binary, zero setup"on line 69, not just the six art rows above it. I reproduced the substitution against the literal here-string content (Python simulation of the exact algorithm): the leadingLof "Local" maps to the glyph table's'L' → [char]0x255A(╚). Separately, PowerShell hashtable literals (@{}) use case-insensitive key lookup by default (OrdinalIgnoreCase— confirmed via Microsoft's ownabout_Case-Sensitivitydocumentation, not reproduced in a livepwshsession since none is available here), so the trailing lowercaselin "Local" and thetin "setup" also match the'L'/'T'keys. The caption therefore renders as"╚oca╚ AI on AMD GPUs — one binary, zero se╗up"on every single Windows install, color on or off (the substitution runs unconditionally before the$script:NoColorbranch). The PR's own test-plan claim of having "diffed the embedded ASCII art... byte-for-byte against README.md" would not have caught this: that diff is necessarily against the pre-substitution placeholder source, not the runtime-rendered output.
Confidence 100 · logic · Fix: scope the substitution to only the art rows (e.g. apply it before appending the caption, or keep the caption as a separate literal string outside the here-string), or use a case-sensitive key comparer ([System.Collections.Generic.Dictionary[char,char]]) plus placeholder characters that can't collide with ordinary English letters.
Non-blocking
-
NO_COLORset-but-empty is treated the same as unset, in both scripts —install.sh:46([ -z "${NO_COLOR:-}" ]),install.ps1:29([string]::IsNullOrEmpty($env:NO_COLOR)).
The NO_COLOR convention calls for suppressing color whenever the variable is merely present, regardless of value;NO_COLOR=(exported empty) leaves color enabled on a TTY in both scripts here. Narrow edge case, and consistent between the two scripts, so plausibly a deliberate simplification rather than an oversight — worth confirming.
Confidence 80 · mechanical · Fix: check[ "${NO_COLOR+set}" = set ]/-not [string]::IsNullOrEmpty($env:NO_COLOR) -or (Test-Path env:NO_COLOR)-style presence checks instead of emptiness checks. -
One converted call site was missed in
install.ps1—install.ps1:805-807(Write-Host "note: $InstallDir is not on PATH"and its two follow-up lines).
Every structurally parallel status block elsewhere in this change (e.g.Add-InstallDirToUserPath's PATH-already-configured/updated messages) was routed through the newWrite-Detail/Write-Okhelpers; this one was left on rawWrite-Host. Cosmetic only.
Confidence 85 · mechanical · Fix: route throughWrite-Detail, or note why it's deliberately left plain.
Decisions for the author
- The colored-TTY output path is entirely untested — tradeoff.
install_lifecycle.feature's own comment anddocs/testing.md's updated line both honestly state that the harness only drives the piped/no-color contract, becauserun_installer_commandusesCommand::output()(OS pipes, no PTY). A PTY-capable driver already exists elsewhere in this harness for other purposes (chat sessions,when_installed_chat_pty), but isn't wired to the installer scripts. Building that out is real extra work, and shipping with a clearly documented gap is defensible — but both blocking bugs above demonstrate concretely what that gap costs: the only assertions actually exercised (loose substring checks) did not and structurally could not have caught either one. Worth confirming this is still the intended tradeoff, and consider at minimum giving the Windows scenario its own exact-match hint assertion (mirroringthen_hint_names_binary, which exists only for Linux) — that alone would have caught finding 1, and a check for the literal substring"Local AI on AMD GPUs"would have caught finding 2 on both platforms without needing a PTY.
Positive signals
install.sh's dual-TTY gate for color ([ -t 1 ] && [ -t 2 ],install.sh:46) with its explanatory comment correctly prevents ANSI leaking into a redirected stderr stream while stdout stays a terminal — a genuinely non-obvious edge case, called out clearly rather than left implicit.- Every new
printf-based helper ininstall.sh(step,info,ok,fail,print_completion_banner) consistently keeps dynamic content in the%sargument position rather than the format-string slot — no format-string injection risk even for adversarial input, verified directly. - The embedded ASCII-art banner in both scripts matches
README.md's banner byte-for-byte at the source level (confirmed by direct comparison), and the commands it advertises (rocm install sdk,rocm serve qwen,rocm) all exist at this head. - The BOM risk flagged by an earlier review round (a UTF-8 BOM breaking the documented
irm | iexone-liner) is resolved at this head: direct byte inspection confirms no BOM anywhere ininstall.ps1, achieved by reverting to an ASCII-only placeholder/glyph encoding — the approach that, unfortunately, is also the source of blocking finding 2 above, but the underlying BOM/irm | iexrisk itself is gone.
Deployment notes
- No CI has run against this exact pinned head commit:
get_check_runsreports 0 runs, andget_statusshows only a Read the Docs preview build success. The PR also currently reportsmergeable_state: dirty(conflicts withmain). Whatever the PR's test-plan checklist describes (shellcheck clean, "9/9 lifecycle scenarios pass") was produced against an earlier commit in this PR's history, not this one, and has not been re-verified at this head. - This change alters the literal text printed on installer failure (prefixing
!!on stderr); anything that parses or re-surfaces that stderr text downstream should be checked against the new prefix.
What this covered
Read all 5 changed files in full (install.sh, install.ps1, docs/testing.md, tests/e2e-cucumber/features/install_lifecycle.feature, tests/e2e-cucumber/tests/e2e/lifecycle_steps.rs) against both their pre- and post-change versions, 2844d797...66ed3bb, plus AGENTS.md at the base commit and the full git log -p across this PR's 4 commits for history context. Fan-out: three independent workers (install.sh + docs/testing.md; install.ps1; the two e2e test files), each given full file contents and told to read completely or report inability to; all three returned complete passes. Passes run: code review by coupling (above), agent-instruction adherence (AGENTS.md), history (this PR's own commit sequence, which shows the BOM fix and the Write-CompletionBanner signature change happening in different commits), code comments (cross-checked the feature file's and docs/testing.md's self-described PTY/coverage gap against the actual harness code — accurate), impact analysis (checked README.md and other docs for stale references to the old installer output format — none found), and design review (Step 7, above). Prior-changes pass found no earlier PR touching these two scripts with directly applicable review feedback.
No PowerShell interpreter or shellcheck is available in this environment; the two blocking install.ps1 findings rest on direct reading, a reproduction of the described substitution algorithm against the literal source text, and Microsoft's own documentation for the hashtable case-insensitivity claim — not on running pwsh. The mandated pre-publish check confirmed the PR is open and non-draft, and that no review from GitHub login "nowycondro" exists at this exact pinned head commit (their prior review was against an earlier commit, f8c3c7d). A different human reviewer did independently submit a CHANGES_REQUESTED review at this exact head shortly before this one was prepared, reaching substantially the same two blocking conclusions; this review's findings were derived independently beforehand and are reported here as required by this task rather than copied from that review. Not otherwise reconciled against any PR discussion.
66ed3bb to
a76d4f2
Compare
|
Follow-up to the previous comment: the three items I had left open are now done, in
Local checks: Linux lifecycle lane 16/16, clippy |
…tion intact Write-CompletionBanner took ($Cmd, $NextHint) but was called with one argument, so the hint became the command prefix of every example. The glyph substitution also rewrote letters in the caption (hashtable keys are case-insensitive); the caption now sits outside it. The Windows lifecycle scenario now pins the exact hint line and the example prefixes, shared with the Linux step. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
|
Addressed review 5710773423 in 438ba2c. Blocking
Non-blocking
Verification: Linux lifecycle lane 16/16, clippy |
nowycondro
left a comment
There was a problem hiding this comment.
🤖 Automated review (Claude Code) · 438ba2c
This automation never files a GitHub approval, so no approving review will appear here whatever the outcome — the merge decision stays with a human reviewer.
Review — no blocking findings
Full review of the whole change (2 commits, df1548a2...438ba2c6: install.sh, install.ps1, docs/testing.md, tests/e2e-cucumber/features/install_lifecycle.feature, tests/e2e-cucumber/tests/e2e/lifecycle_steps.rs).
No ticket named; the PR description is the only stated intent (colored installer output + a completion banner). The description accurately describes the diff: it states what the new scenarios cover, states the one deliberate coverage gap (the colored-TTY branch, since the harness pipes output), and is appropriately conservative about what the author personally verified on Windows ("not run on real Windows PowerShell... reviewed by reading and a standalone run of the banner function by a reviewer").
Ran this as a single-context pass by deliberate instruction (no sub-agent fan-out), reading every changed file in full rather than splitting by group.
Blocking
None.
The second commit (438ba2c6, "pass the command to the Windows banner and keep its caption intact") fixes both defects a class of bug like this would be expected to carry:
- Dropped argument:
Write-CompletionBannertakes($Cmd, $NextHint)(install.ps1:56-57); the call site now passes both (install.ps1:829:Write-CompletionBanner $cmd "Run: $cmd examine"), matchinginstall.sh's two-argumentprint_completion_banner "${cmd}" "${next_hint}"(install.sh:649). - Case-insensitive glyph substitution corrupting the caption: the here-string that undergoes the placeholder→box-drawing substitution (
install.ps1:61-76) now contains only the art rows; the caption ("Local AI on AMD GPUs ... zero setup") is appended afterward as a separate string (install.ps1:79), structurally outside the substitution loop rather than patched with a case-sensitive comparer. No lowercase glyph-table letters (l/t/f/j) appear anywhere in the art rows, so there is nothing left for a case-insensitive@{}lookup to collide with.
Verified both fixes two ways beyond reading: (1) the Windows lifecycle scenario (lifecycle-31) was extended in this same commit to pin the exact last line of output (Run: <cmd> examine) and the literal prefix of every "Get started" example, on both platforms via the shared then_hint_names_binary step (tests/e2e-cucumber/tests/e2e/lifecycle_steps.rs:1207-1237) — this is exactly the assertion whose absence let the two bugs ship previously; (2) gh-equivalent CI data for this exact head commit shows the windows-build-and-test job's "Acceptance install lifecycle" step (which runs @lifecycle scenarios including lifecycle-31 via pwsh on windows-latest) completed successfully, so the fix was exercised on real Windows PowerShell in CI, not only read.
Non-blocking
None.
Decisions for the author
NO_COLORset-but-empty is treated the same as unset, in both scripts — tradeoff.
install.sh:46([ -z "${NO_COLOR:-}" ]) andinstall.ps1:29([string]::IsNullOrEmpty($env:NO_COLOR)) both leave color on forNO_COLOR=(exported empty), whereas the informal NO_COLOR convention suppresses color whenever the variable is merely present. Narrow edge case, consistent across both platforms, plausibly deliberate.install.ps1'sFailcarries no!!marker, unlikeinstall.sh'sfail()— tradeoff, already explained in the PR description ("Write-Erroralready renders as an error record"). Reasonable; stderr text for installer failures differs slightly in form between platforms as a result.
Positive signals
- The caption is now kept structurally outside the substitution loop rather than patched with a narrower case-sensitive comparer — a fix that removes the hazard rather than just the symptom that was reported.
install.sh's dual-TTY gate ([ -t 1 ] && [ -t 2 ],install.sh:46) with its explanatory comment correctly keeps ANSI bytes out of a redirected stderr stream while stdout stays a terminal, a genuinely non-obvious edge case called out clearly rather than left implicit.- The
DOWNLOAD_ONLYpath still exits before the banner and thedownloaded:lineapps/rocm/src/remote/provision.rsparses is left as a plain, unchangedecho— remote provisioning is unaffected by this output change. - The previously long, oddly-wrapped sentence added to
docs/testing.mdhas been re-wrapped in this same commit to match the paragraph's existing hard-wrap style. - New installer output (banner, hint,
!!marker, color gating) is covered by four new Gherkin scenarios (lifecycle-28..31) per this repo's ownAGENTS.md§3 rule, and the one real coverage gap (colored TTY branch, since the harness only pipes output) is explicitly documented in both the feature file anddocs/testing.mdrather than silently left out.
Deployment notes
- Installer failures on
install.shnow print with a!!prefix on stderr (unchanged by this specific commit, but worth restating): anything parsing or re-surfacing that stderr text downstream (e.g.rocm remote's error messages viaprovision.rs) sees the new prefix. - CI for this exact head commit is fully green across all 23 reported checks (
build-and-test,windows-build-and-testincluding its PowerShell "Acceptance install lifecycle" step,clippy,Lint (PowerShell)/ PSScriptAnalyzer on both PowerShell 7 and Windows PowerShell 5.1, E2E tests + consolidated report, coverage, third-party notices, license headers, CodeQL/static analysis, markdown links, commit signatures + sign-off); the only skips are the docs/skillscope jobs, which are no-ops here.
What this covered
Read install.sh, install.ps1, docs/testing.md, tests/e2e-cucumber/features/install_lifecycle.feature, and tests/e2e-cucumber/tests/e2e/lifecycle_steps.rs in full, as they stand at 438ba2c6 and diffed against df1548a2 (both commits in the range individually, not only the squashed result), plus AGENTS.md's §3 testing rule and README.md for stale-reference checking. Cross-checked .github/workflows/ci.yml to confirm the @lifecycle scenarios (including the Windows one) run as a required, non-optional step on every PR rather than only locally, and pulled this exact head commit's check-run and job-step data to confirm the relevant steps actually executed and passed.
Did not run shellcheck, cargo, or a PowerShell interpreter myself in this environment; CI's own execution of PSScriptAnalyzer and the lifecycle scenarios on real Windows runners substitutes for that. This was a single-context review per explicit instruction, not a multi-worker fan-out. Per the claim-check step, the one necessary read of this PR's existing get_reviews output (to confirm no review already exists at this exact head commit) incidentally exposed prior review text; every finding above was independently re-derived and re-verified directly against the code and CI data at this head rather than taken on that text's say-so, and the discussion/threads on this PR were otherwise not consulted.
Summary
==>/::/!!step markers toinstall.shandinstall.ps1. Only the ANSI colors are gated: they are off unless stdout and stderr are terminals (install.sh) or output is not redirected (install.ps1), andNO_COLORturns them off. The markers themselves, theGet started:block, the new next-step hint wording and the!!failure prefix print unconditionally, including in piped output.install.ps1'sFailhas no!!marker;Write-Erroralready renders as an error record.Get started:block (rocm install sdk,rocm serve qwen,rocm) and a next-step hint, replacing the previous barenext:/run:hint. When the install folder is not on PATH, the hint and every example name the binary by path.install.sh, not redirected forinstall.ps1).install.ps1stays ASCII-only (no BOM, soirm | iexis unaffected): the art is drawn with placeholder letters and expanded to box-drawing characters at run time, and the caption is kept outside that substitution.Tests
lifecycle-28..31ininstall_lifecycle.featureassert theGet started:block, no banner art and no ANSI escapes in piped output, the!!failure prefix, and a hint that names the installed binary. The hint step pins the exact last line (Run: <cmd> examine) and the example prefixes on both Linux and Windows.lifecycle-29(NO_COLOR) is a regression guard only, since piped output already disables color.lifecycle-31) runs on the Windows lifecycle lane only.cargo clippy -p e2e-cucumber --all-targets -- -D warningsand PSScriptAnalyzer are clean.install.ps1itself has not been run on real Windows PowerShell (none available to the author). Reviewed by reading and a standalone run of the banner function by a reviewer on pwsh 7.4.6, which found the two bugs fixed here.