dotnetup: classify PATH dotnet by managed hive; fix env config doc#55349
Conversation
Specify whether the active path is the dotnetup managed hive rather than whether it is a system-installed path
|
Azure Pipelines: Successfully started running 2 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Pull request overview
This PR refines dotnetup’s notion of the dotnet that wins on PATH to distinguish dotnetup-managed hives from arbitrary user-writable installs, preventing dotnetup dotnet/uninstall from acting on installs it does not own. It also aligns documentation with actual DotnetAccessMode JSON parsing behavior and updates a user-facing env message (with localization updates).
Changes:
- Replaces
InstallType (User/System)classification fromGetCurrentPathConfigurationwithIsDotnetupHiveand realignsDotnetCommand,UninstallWorkflow, andInitWorkflowsaccordingly. - Updates telemetry for “existing install type” to use
InstallPathClassifier.ClassifyInstallPathbuckets. - Updates tests and documentation; adjusts one env-related user-facing string and propagates it to XLFs.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| test/dotnetup.Tests/UninstallWorkflowTests.cs | Updates uninstall path-resolution tests to reflect “dotnetup hive vs not” semantics and adds a regression test for unmanaged user installs. |
| test/dotnetup.Tests/DotnetCommandTests.cs | Updates dotnetup dotnet tests to gate use of the PATH-resolved root on IsDotnetupHive. |
| src/Installer/dotnetup.Library/xlf/Strings.zh-Hant.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.zh-Hans.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.tr.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.ru.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.pt-BR.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.pl.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.ko.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.ja.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.it.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.fr.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.es.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.de.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/xlf/Strings.cs.xlf | Updates localized resource unit for the changed env message. |
| src/Installer/dotnetup.Library/Strings.resx | Updates the source string shown after env changes so it’s clearer that restarts are required for other terminals/apps. |
| src/Installer/dotnetup.Library/IDotnetEnvironmentManager.cs | Updates the contract to return DotnetInstallRootConfiguration with IsDotnetupHive and adds clarifying XML docs. |
| src/Installer/dotnetup.Library/DotnetEnvironmentManager.cs | Implements hive classification by comparing the PATH-resolved root to the default dotnetup install path. |
| src/Installer/dotnetup.Library/Commands/Shared/UninstallWorkflow.cs | Ensures uninstall only targets the PATH-resolved root when it’s a dotnetup-managed hive. |
| src/Installer/dotnetup.Library/Commands/Shared/InstallWorkflow.cs | Records “existing install type” telemetry using path classification buckets rather than InstallType. |
| src/Installer/dotnetup.Library/Commands/Init/InitWorkflows.cs | Restores explicit “is system/admin install” checks where that’s the real requirement (migration display). |
| src/Installer/dotnetup.Library/Commands/Dotnet/DotnetCommand.cs | Ensures dotnetup dotnet only uses the PATH-resolved root when it’s the managed hive. |
| documentation/general/dotnetup/designs/dotnetup-env.md | Corrects the design doc to match actual JSON converter behavior (legacy spellings are not accepted). |
| // a dotnetup hive is irrelevant here; we want its location only when it is a system install. | ||
| var currentInstall = dotnetEnvironment.GetCurrentPathConfiguration(); | ||
| string systemPath = currentInstall?.InstallType == InstallType.System | ||
| string systemPath = currentInstall is not null && InstallPathClassifier.IsAdminInstallPath(currentInstall.Path) |
There was a problem hiding this comment.
I think this should be using a method to check GetPathWinningDotnet rather than IsAdminInstallPath since we'd want to convert from whatever toolset was winning in the past but I acknowledge this might be worth doing in a separate issue.
There was a problem hiding this comment.
After the init, you can use --migrate-from-system to go back and do the migration. I think it's simpler to keep parity with that. If we wanted to support more broader migration then we'd want to think about how it would work as a follow-up command too. I think it's not a mainline scenario so probably not worth worrying about, but feel free to file a follow-up issue if you prefer.
| { | ||
| // Allow override for testing — lets tests point the managed hive at a temp directory | ||
| // without touching the real user profile. | ||
| var overridePath = Environment.GetEnvironmentVariable("DOTNET_TESTHOOK_DEFAULT_DOTNET_PATH"); |
There was a problem hiding this comment.
Rather than make DOTNET_TESTHOOK_DEFAULT_DOTNET_PATH why don't we make this an explicit setting here such as DOTNETUP_HOME?
There was a problem hiding this comment.
I think what we'd want for the mainline user scenario is to set this via the configuration, not via an environment variable. That's covered by #55346.
| </data> | ||
| <data name="EnvOpenNewTerminalForOtherSurfaces" xml:space="preserve"> | ||
| <value>Open a new terminal for the change to take effect in other terminals and applications.</value> | ||
| <value>Other open terminals and applications will pick up this change after they're restarted.</value> |
There was a problem hiding this comment.
I think it's better to start with an action verb. Why was this changed? I'm on board with trying to make it clear this applies to apps & terminals earlier in the message.
There was a problem hiding this comment.
Open a new terminal for the change to take effect in other terminals and applications.
This seems incorrect to me. To me it's telling you that opening a new terminal will cause existing terminals and applications to get the update.
There was a problem hiding this comment.
Great point, I hadn't considered that. I lean slightly towards starting with a verb but good to move forward with this!
| // a dotnetup hive is irrelevant here; we want its location only when it is a system install. | ||
| var currentInstall = dotnetEnvironment.GetCurrentPathConfiguration(); | ||
| string systemPath = currentInstall?.InstallType == InstallType.System | ||
| string systemPath = currentInstall is not null && InstallPathClassifier.IsAdminInstallPath(currentInstall.Path) |
There was a problem hiding this comment.
nit: It'd be nice to have a regression test - e.g. mock the registry reading behavior to point to a non expected system install besides dotnetup and see if it uses the correct dotnet executable or not (one could be an exe that fails, the other returns 0)
There was a problem hiding this comment.
I'm not following. This code just controls what is printed when its asking whether you want to migrate existing installs. Can you clarify?
There was a problem hiding this comment.
I meant for this comment to be in the dotnetup dotnet section, so this was focused on adding a test for the executable selected there. While this would be nice to have, I think we should move forward on this fix.
There was a problem hiding this comment.
OK, in that case I think we probably have the coverage you were looking for (copilot thought we did at least).
nagilson
left a comment
There was a problem hiding this comment.
Thanks for taking my feedback into account here, I appreciate the follow up as well from the prior PR! ![]()
| </data> | ||
| <data name="EnvOpenNewTerminalForOtherSurfaces" xml:space="preserve"> | ||
| <value>Open a new terminal for the change to take effect in other terminals and applications.</value> | ||
| <value>Other open terminals and applications will pick up this change after they're restarted.</value> |
There was a problem hiding this comment.
Great point, I hadn't considered that. I lean slightly towards starting with a verb but good to move forward with this!
| // a dotnetup hive is irrelevant here; we want its location only when it is a system install. | ||
| var currentInstall = dotnetEnvironment.GetCurrentPathConfiguration(); | ||
| string systemPath = currentInstall?.InstallType == InstallType.System | ||
| string systemPath = currentInstall is not null && InstallPathClassifier.IsAdminInstallPath(currentInstall.Path) |
| // a dotnetup hive is irrelevant here; we want its location only when it is a system install. | ||
| var currentInstall = dotnetEnvironment.GetCurrentPathConfiguration(); | ||
| string systemPath = currentInstall?.InstallType == InstallType.System | ||
| string systemPath = currentInstall is not null && InstallPathClassifier.IsAdminInstallPath(currentInstall.Path) |
There was a problem hiding this comment.
I meant for this comment to be in the dotnetup dotnet section, so this was focused on adding a test for the executable selected there. While this would be nice to have, I think we should move forward on this fix.
Follow-up to #54545 addressing review feedback (especially #54545 (comment)). Also includes improvement to some wording I noticed when testing.
Copilot description:
Changes
1. Classify the PATH dotnet by "is it a dotnetup-managed hive?" (not system vs user)
GetCurrentPathConfigurationpreviously returned anInstallType(User/System) derived fromIsAdminInstallPath. But the consumers actually need to know whether thedotnetwinning onPATHis a hive dotnetup owns — something it may run or uninstall from. Under the old axis, adotnetthat merely lives in a user-writable location (e.g. a hand-extractedC:\dotnetonPATH) was labeledUser, sodotnetup dotnetanddotnetup uninstall(without--install-path) would run or target an install dotnetup does not own.DotnetInstallRootConfiguration.InstallType→bool IsDotnetupHive.IsDotnetupHiveistrueonly when the resolved root is dotnetup's managed hive (today, the default install path; configurable hives tracked in dotnetup: Support custom dotnet roots #55346).DotnetCommand/UninstallWorkflowact on the configured path only when it's the hive;InitWorkflowsusesInstallPathClassifier.IsAdminInstallPathdirectly where it genuinely needs "is this a system install?"; install telemetry records the existing install's location bucket viaClassifyInstallPath.Behavior change:
dotnetup dotnet/uninstallno longer act on a non-manageddotnetthat happens to win onPATH; they fall back to the managed hive.2. Doc fix:
DotnetAccessModelegacy spellings are not acceptedThe
dotnetup envdesign doc claimed the JSON converter accepts legacy spellings (full/fullpathreplacement). It does not —DotnetAccessModeJsonConverteris a plain camel-case string-enum converter (integer values rejected), and unrecognized values are treated as a corrupt config that re-defaults on next write. Corrected the doc to match the code and the rest of the doc.Testing
Built
dotnetup.Tests(Release); the affectedUninstallWorkflowTestsandDotnetCommandTestspass (23/23).