Skip to content

fix(dotnet): validate SDK installs with list-sdks - #10691

Merged
jdx merged 1 commit into
mainfrom
codex/dotnet-list-sdks
Jul 1, 2026
Merged

jdx merged 1 commit into
mainfrom
codex/dotnet-list-sdks

Conversation

@jdx

@jdx jdx commented Jul 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • validate .NET SDK installs with dotnet --list-sdks instead of dotnet --version
  • check the installed SDK inventory for the requested version and report a clearer error if it is missing
  • add an e2e regression where global.json selects an unavailable SDK while installing an older SDK

Context

dotnet --version is affected by global.json and SDK roll-forward rules, so it can fail even after dotnet-install successfully installs the requested SDK. dotnet --list-sdks checks the installed SDK inventory directly, which matches the shared DOTNET_ROOT model introduced for side-by-side SDK installs.

Addresses discussion #10688.

Tests

  • cargo fmt --check
  • cargo test plugins::core::dotnet::tests
  • CMAKE="$(mise x cmake@latest -- command -v cmake)" mise run test:e2e test_dotnet

Note: the e2e run also matched backend/test_dotnet, which skipped because system dotnet is not installed; core/test_dotnet passed. The run emitted the existing slow-test warning for core/test_dotnet taking over 20s.

This PR was generated by an AI coding assistant.


Note

Medium Risk
Touches shared command execution (CmdLineRunner::read) and .NET install verification; behavior change is targeted but affects all SDK post-install checks.

Overview
Fixes false failures when a repo’s global.json pins an SDK that isn’t installed: post-install verification no longer uses dotnet --version (selection/roll-forward) and instead checks dotnet --list-sdks for an exact match on the requested SDK version, with clearer errors that include the captured list output.

CmdLineRunner gains async read() so callers can capture stdout while still piping (including when MISE_RAW / raw mode would otherwise inherit stdio); failures replay captured stderr via replay_captured_stderr, and RunningPidGuard tracks PIDs for cleanup during read().

E2E core/test_dotnet now installs SDK 8.0.408 under a global.json that demands 10.0.301 with roll-forward disabled, asserting --list-sdks still shows the installed SDK.

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

Summary by CodeRabbit

  • Bug Fixes

    • Improved .NET SDK detection by checking for an exact installed SDK version in the full SDK list output, reducing false matches.
    • Enhanced failure diagnostics by including the captured --list-sdks output when the requested SDK isn’t found.
    • Made command output reading more consistent by returning the expected stdout even when raw mode is enabled.
  • Tests

    • Updated SDK detection coverage with exact-match and non-exact variant cases.
    • Adjusted .NET SDK e2e checks to better validate SDK selection behavior around global.json.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Dotnet command handling now includes a reusable async stdout reader, dotnet SDK checks use exact --list-sdks matching, and the e2e dotnet script updates its global.json-based verification.

Changes

Dotnet SDK verification via --list-sdks

Layer / File(s) Summary
Command read helper
src/cmd.rs
Adds CmdLineRunner::read, shared captured-output formatting, and a test showing raw mode does not affect returned stdout.
Exact-match SDK verification helper and plugin logic
src/plugins/core/dotnet.rs
Switches SDK verification to dotnet --list-sdks, matches the requested version against the first token of each line, formats errors with the captured SDK list, and adds helper tests.
E2E global.json test updates
e2e/core/test_dotnet
Adds a pinned global.json, checks dotnet --list-sdks for 8.0.408, and adjusts the idiomatic file support sequence.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Poem

A rabbit hopped through SDK trails,
With exact-match ears and careful nails. 🐇
--list-sdks sang, line by line,
And global.json kept the path aligned.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: switching .NET SDK validation to dotnet --list-sdks.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 1, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes flaky post-install validation for .NET SDKs by replacing dotnet --version (which honors global.json and roll-forward rules) with dotnet --list-sdks and an exact first-token version match, so validation reflects what is actually on disk rather than what the active SDK selection resolves to.

  • CmdLineRunner::read() is added to capture stdout even when raw mode (MISE_RAW=1) is globally enabled; uses RunningPidGuard for RAII PID cleanup and replay_captured_stderr() / captured_output_lines() for correct failure diagnostics.
  • sdk_list_contains_version performs an exact first-whitespace-token match so 8.0.128 cannot be confused with 8.0.1280 or a path containing the version string; sdk_list_display shows a human-readable (no SDKs listed) placeholder when the list is empty.
  • E2E regression adds a global.json that disables roll-forward to an unavailable SDK version, then asserts dotnet --list-sdks still surfaces the installed 8.0.408 under MISE_RAW=1.

Confidence Score: 5/5

Safe to merge — all changed paths are scoped to .NET post-install validation and the new read() helper; the fix is narrowly targeted and fully covered by unit tests and an e2e regression.

The core fix (switching from --version to --list-sdks) is straightforward and addresses a real root cause. The new read() method correctly preserves Stdio::piped() from CmdLineRunner::new() and never overrides it, so raw-mode callers still get captured output as intended. RunningPidGuard cleanly handles PID removal on all exit paths including timeouts. Unit tests cover exact-match, prefix-guard, empty-list, and raw-mode scenarios; the e2e test reproduces the original failure condition. No pre-existing code paths are altered.

No files require special attention.

Important Files Changed

Filename Overview
src/cmd.rs Adds RunningPidGuard for RAII PID tracking, a new async read() method that always pipes stdout regardless of raw mode, captured_output_lines() helper, and replay_captured_stderr() for correct failure diagnostics; all new paths are tested.
src/plugins/core/dotnet.rs Replaces dotnet --version post-install check with dotnet --list-sdks using the new read() helper; adds exact first-token version matching with sdk_list_contains_version and formatted error output; well-covered by new unit tests.
e2e/core/test_dotnet Adds a global.json regression that pins an unavailable SDK (10.0.301, rollForward: disable) before the install assertion, confirming --list-sdks still reports the installed 8.0.408 even under MISE_RAW=1; existing --version and idiomatic-file tests preserved.

Reviews (5): Last reviewed commit: "fix(dotnet): validate SDK installs with ..." | Re-trigger Greptile

Comment thread src/plugins/core/dotnet.rs Resolved
@jdx
jdx force-pushed the codex/dotnet-list-sdks branch from 6bd6dae to f73ef0e Compare July 1, 2026 20:04
Comment thread src/plugins/core/dotnet.rs Resolved

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/plugins/core/dotnet.rs (2)

316-322: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a test for sdk_list_display with non-empty input.

Only the empty-input placeholder case is tested; the join-with-newline branch for non-empty lines is not directly covered.

✅ Suggested additional test
+    #[test]
+    fn sdk_list_display_joins_lines() {
+        let lines = vec!["8.0.128 [/path]".to_string(), "10.0.301 [/path2]".to_string()];
+        assert_eq!(sdk_list_display(&lines), "8.0.128 [/path]\n10.0.301 [/path2]");
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/core/dotnet.rs` around lines 316 - 322, Add a test that exercises
sdk_list_display with a non-empty slice so the join-with-newline branch is
covered. Locate the helper sdk_list_display in dotnet.rs and add a unit test
that passes multiple SDK strings and asserts the returned value is the same
items joined by newline, complementing the existing empty-input test.

72-72: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Stale comment references the old --version check.

The comment still explains the skip rationale in terms of dotnet --version, but the function below no longer calls --version — it now uses --list-sdks. Worth updating for clarity since a future reader may be confused about which command the skip applies to.

✏️ Suggested comment update
-            // Skip version check for runtime-only installs — `dotnet --version` exits non-zero without an SDK
+            // Skip SDK check for runtime-only installs — no SDK is expected to be present
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/core/dotnet.rs` at line 72, Update the stale inline comment in
the runtime-only install check near the dotnet version probing logic so it
matches the current `--list-sdks` behavior instead of `dotnet --version`. Keep
the comment in the same area of the `dotnet.rs` code that handles the skip path,
and revise the wording to explain that runtime-only installs are skipped because
the SDK list check can fail when no SDK is present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/plugins/core/dotnet.rs`:
- Around line 316-322: Add a test that exercises sdk_list_display with a
non-empty slice so the join-with-newline branch is covered. Locate the helper
sdk_list_display in dotnet.rs and add a unit test that passes multiple SDK
strings and asserts the returned value is the same items joined by newline,
complementing the existing empty-input test.
- Line 72: Update the stale inline comment in the runtime-only install check
near the dotnet version probing logic so it matches the current `--list-sdks`
behavior instead of `dotnet --version`. Keep the comment in the same area of the
`dotnet.rs` code that handles the skip path, and revise the wording to explain
that runtime-only installs are skipped because the SDK list check can fail when
no SDK is present.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c070eba-a18c-43f4-a735-7197797cd858

📥 Commits

Reviewing files that changed from the base of the PR and between 6bd6dae and f73ef0e.

📒 Files selected for processing (2)
  • e2e/core/test_dotnet
  • src/plugins/core/dotnet.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • e2e/core/test_dotnet

@jdx
jdx force-pushed the codex/dotnet-list-sdks branch 2 times, most recently from d005dca to ec6f721 Compare July 1, 2026 20:21

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cmd.rs`:
- Around line 927-961: The read() path in cmd::Cmd currently spawns a child
process but never registers its PID in RUNNING_PIDS, so cleanup paths like
kill_all() cannot see or terminate it. Update Cmd::read (and its
spawn_async_with_etxtbsy_retry / wait_with_output flow if needed) to add the
spawned child PID to RUNNING_PIDS right after spawn and ensure it is removed
when the process exits or on error/timeout, matching the tracking used by other
execution paths.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 6d099bbf-a3f4-4a0c-b38d-7624e9c49a5c

📥 Commits

Reviewing files that changed from the base of the PR and between f73ef0e and d005dca.

📒 Files selected for processing (3)
  • e2e/core/test_dotnet
  • src/cmd.rs
  • src/plugins/core/dotnet.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • e2e/core/test_dotnet

Comment thread src/cmd.rs Resolved
@jdx
jdx force-pushed the codex/dotnet-list-sdks branch from ec6f721 to d3cdcf2 Compare July 1, 2026 20:33

@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 d3cdcf2. Configure here.

Comment thread src/cmd.rs Resolved
@jdx
jdx force-pushed the codex/dotnet-list-sdks branch from d3cdcf2 to db64320 Compare July 1, 2026 20:38
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.14 x -- echo 32.8 ± 3.1 25.4 45.2 1.00
mise x -- echo 33.4 ± 3.3 25.0 46.8 1.02 ± 0.14

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.14 env 29.2 ± 2.6 22.9 36.7 1.00
mise env 31.9 ± 2.9 24.9 45.6 1.09 ± 0.14

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.14 hook-env 30.9 ± 2.8 22.9 39.9 1.00
mise hook-env 33.1 ± 3.4 25.7 44.1 1.07 ± 0.15

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.6.14 ls 24.8 ± 2.1 19.4 31.7 1.00
mise ls 26.8 ± 2.4 21.2 35.0 1.08 ± 0.13

xtasks/test/perf

Command mise-2026.6.14 mise Variance
install (cached) 184ms 182ms +1%
ls (cached) 92ms 98ms -6%
bin-paths (cached) 99ms 99ms +0%
task-ls (cached) 183ms 188ms -2%

@jdx
jdx enabled auto-merge (squash) July 1, 2026 20:53
@jdx
jdx merged commit f9ef294 into main Jul 1, 2026
33 of 34 checks passed
@jdx
jdx deleted the codex/dotnet-list-sdks branch July 1, 2026 20:59
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.

1 participant