Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

using Microsoft.DotNet.Cli.ToolManifest;
using Microsoft.DotNet.Cli.ToolPackage;
using Microsoft.DotNet.Cli.Utils;
Expand All @@ -12,10 +10,11 @@ namespace Microsoft.DotNet.Cli.Commands.Tool;

internal static class ToolManifestFinderExtensions
{
public static (FilePath? filePath, string warningMessage) ExplicitManifestOrFindManifestContainPackageId(
public static (FilePath? filePath, string? warningMessage) ExplicitManifestOrFindManifestContainPackageId(
this IToolManifestFinder toolManifestFinder,
string explicitManifestFile,
PackageId packageId)
string? explicitManifestFile,
PackageId packageId,
bool throwIfNoManifestFound = true)
{
if (!string.IsNullOrWhiteSpace(explicitManifestFile))
{
Expand All @@ -29,12 +28,16 @@ public static (FilePath? filePath, string warningMessage) ExplicitManifestOrFind
}
catch (ToolManifestCannotBeFoundException e)
{
throw new GracefulException([e.Message, CliCommandStrings.ToolCommonNoManifestGuide], verboseMessages: [e.VerboseMessage], isUserError: false);
if (throwIfNoManifestFound)
{
throw new GracefulException([e.Message, CliCommandStrings.ToolCommonNoManifestGuide], verboseMessages: [e.VerboseMessage], isUserError: false);
}
return (null, null);
}

if (manifestFilesContainPackageId.Any())
{
string warning = null;
string? warning = null;
if (manifestFilesContainPackageId.Count > 1)
{
warning =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,15 @@ public override int Execute()

private int ExecuteInstallCommand(PackageId packageId, VersionRange? versionRange)
{
FilePath manifestFile = GetManifestFilePath();

(FilePath? manifestFileOptional, string warningMessage) =
_toolManifestFinder.ExplicitManifestOrFindManifestContainPackageId(_explicitManifestFile, packageId);
(FilePath? manifestFileOptional, string? warningMessage) =
_toolManifestFinder.ExplicitManifestOrFindManifestContainPackageId(_explicitManifestFile, packageId, throwIfNoManifestFound: false);

if (warningMessage != null)
{
_reporter.WriteLine(warningMessage.Yellow());
}

manifestFile = manifestFileOptional ?? GetManifestFilePath();
FilePath manifestFile = manifestFileOptional ?? GetManifestFilePath();
var existingPackageWithPackageId = _toolManifestFinder.Find(manifestFile).Where(p => p.PackageId.Equals(packageId));

if (!existingPackageWithPackageId.Any())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,36 @@ public void GivenNoManifestFileAndCreateManifestIfNeededFlagItShouldCreateManife
_fileSystem.File.Exists(Path.Combine(_temporaryDirectory, "dotnet-tools.json")).Should().BeTrue();
}

[Fact]
public void GivenExistingEmptyManifestItShouldInstallToolSuccessfully()
{
// Regression test for https://github.com/dotnet/sdk/issues/[issue-number]
// This test verifies that installing a tool into an existing empty manifest
// (like one created by 'dotnet new tool-manifest') works correctly.
// The bug was that ExplicitManifestOrFindManifestContainPackageId would throw
// when no manifest contained the package, even though a manifest existed.

// The test setup already creates an empty manifest in _jsonContent,
// so we just need to verify installation works
ParseResult parseResult = Parser.Parse($"dotnet tool install {_packageIdA.ToString()}");

var installLocalCommand = new ToolInstallLocalCommand(
parseResult,
_toolPackageDownloaderMock,
_toolManifestFinder,
_toolManifestEditor,
_localToolsResolverCache,
_reporter);

// This should succeed without throwing NullReferenceException
installLocalCommand.Execute().Should().Be(0);

// Verify the tool was actually installed to the manifest
var manifestPackages = _toolManifestFinder.Find();
manifestPackages.Should().HaveCount(1);
manifestPackages.Single().PackageId.Should().Be(_packageIdA);
}

private IToolPackageDownloader GetToolToolPackageInstallerWithPreviewInFeed()
{
List<MockFeed> feeds = new()
Expand Down