Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Cli/dotnet/CliStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,12 @@ setx PATH "%PATH%;{0}"
<data name="MissingToolSettingsFile" xml:space="preserve">
<value>Settings file 'DotnetToolSettings.xml' was not found in the package.</value>
</data>
<data name="ToolRequiresHigherDotNetVersion" xml:space="preserve">
<value>Tool '{0}' requires a higher version of .NET than is currently installed. The tool targets {1}, but the current runtime is {2}.</value>
</data>
<data name="ToolRequiresHigherDotNetVersionSuggestion" xml:space="preserve">
<value>To use this tool, upgrade to .NET {0} or later, or use a version of the tool that is compatible with .NET {1}.</value>
</data>
<data name="ToolPackageConflictPackageId" xml:space="preserve">
<value>Tool '{0}' (version '{1}') is already installed.</value>
</data>
Expand Down
47 changes: 44 additions & 3 deletions src/Cli/dotnet/ToolPackage/ToolPackageInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public ToolPackageInstance(PackageId id,
ResolvedPackageVersion = Version;
}

var toolConfiguration = DeserializeToolConfiguration(library, packageDirectory, _fileSystem);
var toolConfiguration = DeserializeToolConfiguration(library, packageDirectory, ResolvedPackageId, _fileSystem);
Warnings = toolConfiguration.Warnings;

var installPath = new VersionFolderPathResolver(PackageDirectory.Value).GetInstallPath(ResolvedPackageId.ToString(), ResolvedPackageVersion);
Expand Down Expand Up @@ -165,17 +165,58 @@ public static ToolConfiguration GetToolConfiguration(PackageId id,
{
var lockFile = new LockFileFormat().Read(assetsJsonParentDirectory.WithFile(AssetsFileName).Value);
var lockFileTargetLibrary = FindLibraryInLockFile(lockFile);
return DeserializeToolConfiguration(lockFileTargetLibrary, packageDirectory, fileSystem);
return DeserializeToolConfiguration(lockFileTargetLibrary, packageDirectory, id, fileSystem);

}

private static ToolConfiguration DeserializeToolConfiguration(LockFileTargetLibrary library, DirectoryPath packageDirectory, IFileSystem fileSystem)
private static ToolConfiguration DeserializeToolConfiguration(LockFileTargetLibrary library, DirectoryPath packageDirectory, PackageId packageId, IFileSystem fileSystem)
{
try
{
var dotnetToolSettings = FindItemInTargetLibrary(library, ToolSettingsFileName);
if (dotnetToolSettings == null)
{
// Check if this is because of framework incompatibility
// Load available frameworks from the package to provide better error messages
var installPath = new VersionFolderPathResolver(packageDirectory.Value).GetInstallPath(library.Name, library.Version);
var toolsPackagePath = Path.Combine(installPath, "tools");

if (fileSystem.Directory.Exists(toolsPackagePath))
{
var availableFrameworks = fileSystem.Directory.EnumerateDirectories(toolsPackagePath)
.Select(path => NuGetFramework.ParseFolder(Path.GetFileName(path)))
.Where(f => f.Framework == FrameworkConstants.FrameworkIdentifiers.NetCoreApp)
.ToList();

if (availableFrameworks.Count > 0)
{
var currentFramework = new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.NetCoreApp, new Version(Environment.Version.Major, Environment.Version.Minor));

// Find the minimum framework version required by the tool
var minRequiredFramework = availableFrameworks.MinBy(f => f.Version);

// If all available frameworks require a higher version than current runtime
if (minRequiredFramework != null && minRequiredFramework.Version > currentFramework.Version)
{
var requiredVersionString = $".NET {minRequiredFramework.Version.Major}.{minRequiredFramework.Version.Minor}";
var currentVersionString = $".NET {currentFramework.Version.Major}.{currentFramework.Version.Minor}";

var errorMessage = string.Format(
CliStrings.ToolRequiresHigherDotNetVersion,
packageId,
requiredVersionString,
currentVersionString);

var suggestion = string.Format(
CliStrings.ToolRequiresHigherDotNetVersionSuggestion,
minRequiredFramework.Version.Major,
currentFramework.Version.Major);
Comment on lines +201 to +213
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

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

The error message format parameters may be misleading. In line 201-202, the code constructs version strings like ".NET 99.0" by using {Version.Major}.{Version.Minor}, but in line 212-213, the suggestion only uses the major version like ".NET {minRequiredFramework.Version.Major}". This creates an inconsistency where the error message shows ".NET 99.0" but the suggestion says ".NET 99".

Consider using consistent formatting in both places. Either use Major.Minor in both (e.g., ".NET 99.0" throughout), or use just Major in both (e.g., ".NET 99" throughout). The latter is more common in .NET version naming (e.g., ".NET 8" instead of ".NET 8.0").

Copilot uses AI. Check for mistakes.

throw new GracefulException($"{errorMessage} {suggestion}", isUserError: false);
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

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

The isUserError parameter should be true instead of false. When a user tries to install or run a tool that requires a higher .NET version than is currently installed, this is a user error - the user needs to either upgrade their .NET runtime or choose a compatible version of the tool. Setting isUserError: false incorrectly categorizes this as a system error rather than a user action that needs to be corrected.

Suggested change
throw new GracefulException($"{errorMessage} {suggestion}", isUserError: false);
throw new GracefulException($"{errorMessage} {suggestion}", isUserError: true);

Copilot uses AI. Check for mistakes.
}
}
}

throw new ToolConfigurationException(
CliStrings.MissingToolSettingsFile);
}
Expand Down
10 changes: 10 additions & 0 deletions src/Cli/dotnet/xlf/CliStrings.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Cli/dotnet/xlf/CliStrings.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Cli/dotnet/xlf/CliStrings.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Cli/dotnet/xlf/CliStrings.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Cli/dotnet/xlf/CliStrings.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Cli/dotnet/xlf/CliStrings.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Cli/dotnet/xlf/CliStrings.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Cli/dotnet/xlf/CliStrings.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Cli/dotnet/xlf/CliStrings.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Cli/dotnet/xlf/CliStrings.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Cli/dotnet/xlf/CliStrings.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading