diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommandRunner.cs b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommandRunner.cs index 4ec1c00300a..62cc1533ca3 100644 --- a/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommandRunner.cs +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommandRunner.cs @@ -107,6 +107,22 @@ public async Task ExecuteCommand(PackageReferenceArgs packageReferenceArgs, // Setup the Credential Service before making any potential http calls. DefaultCredentialServiceUtility.SetupDefaultCredentialService(packageReferenceArgs.Logger, !packageReferenceArgs.Interactive); + if (packageReferenceArgs.Sources?.Any() == true) + { + // Convert relative path to absolute path if there is any + List sources = new List(); + + foreach (string source in packageReferenceArgs.Sources) + { + sources.Add(UriUtility.GetAbsolutePath(Environment.CurrentDirectory, source)); + } + + originalPackageSpec.RestoreMetadata.Sources = + sources.Where(ns => !string.IsNullOrEmpty(ns)) + .Select(ns => new PackageSource(ns)) + .ToList(); + } + PackageDependency packageDependency = default; if (packageReferenceArgs.NoVersion) { @@ -338,8 +354,8 @@ private static async Task PreviewAddPackageReferenceAsync(Pac Log = packageReferenceArgs.Logger, MachineWideSettings = new XPlatMachineWideSetting(), GlobalPackagesFolder = packageReferenceArgs.PackageDirectory, - PreLoadedRequestProviders = providers, - Sources = packageReferenceArgs.Sources?.ToList() + PreLoadedRequestProviders = providers + // Sources : No need to pass it, because SourceRepositories contains the already built SourceRepository objects }; // Generate Restore Requests. There will always be 1 request here since we are restoring for 1 project. diff --git a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetAddPackageTests.cs b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetAddPackageTests.cs new file mode 100644 index 00000000000..ce29c557c23 --- /dev/null +++ b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetAddPackageTests.cs @@ -0,0 +1,228 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using FluentAssertions; +using NuGet.Packaging; +using NuGet.Packaging.Core; +using NuGet.ProjectModel; +using NuGet.Test.Utility; +using NuGet.Versioning; +using NuGet.XPlat.FuncTest; +using Xunit; + +namespace Dotnet.Integration.Test +{ + [Collection("Dotnet Integration Tests")] + public class DotnetAddPackageTests + { + private readonly MsbuildIntegrationTestFixture _fixture; + + public DotnetAddPackageTests(MsbuildIntegrationTestFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public async Task AddPkg_V3LocalSourceFeed_WithRelativePath_NoVersionSpecified_Success() + { + using (var pathContext = new SimpleTestPathContext()) + { + var projectName = "projectA"; + var targetFrameworks = "net5.0"; + SimpleTestProjectContext projectA = XPlatTestUtils.CreateProject(projectName, pathContext, targetFrameworks); + var packageX = "packageX"; + var packageX_V1 = new PackageIdentity(packageX, new NuGetVersion("1.0.0")); + var packageX_V2 = new PackageIdentity(packageX, new NuGetVersion("2.0.0")); + var packageFrameworks = "net472; netcoreapp2.0"; + var packageX_V1_Context = XPlatTestUtils.CreatePackage(packageX_V1.Id, packageX_V1.Version.Version.ToString(), frameworkString: packageFrameworks); + var packageX_V2_Context = XPlatTestUtils.CreatePackage(packageX_V2.Id, packageX_V2.Version.Version.ToString(), frameworkString: packageFrameworks); + var customSourcePath = Path.Combine(pathContext.WorkingDirectory, "Custompackages"); + var sourceRelativePath = Path.Combine("..", "..", "Custompackages"); + + // Generate Package + await SimpleTestPackageUtility.CreateFolderFeedV3Async( + customSourcePath, + PackageSaveMode.Defaultv3, + new SimpleTestPackageContext[] { packageX_V1_Context, packageX_V2_Context }); + + var projectDirectory = Path.Combine(pathContext.SolutionRoot, projectName); + var projectFilePath = Path.Combine(projectDirectory, $"{projectName}.csproj"); + + // Act + CommandRunnerResult result = _fixture.RunDotnet(projectDirectory, $"add {projectFilePath} package {packageX} -s {sourceRelativePath}", ignoreExitCode: true); + + // Assert + result.Success.Should().BeTrue(because: result.AllOutput); + + // Make sure source is replaced in generated dgSpec file. + PackageSpec packageSpec = projectA.AssetsFile.PackageSpec; + string[] sources = packageSpec.RestoreMetadata.Sources.Select(s => s.Name).ToArray(); + Assert.Equal(sources.Count(), 1); + Assert.Equal(sources[0], customSourcePath); + + var ridlessTarget = projectA.AssetsFile.Targets.Where(e => string.IsNullOrEmpty(e.RuntimeIdentifier)).Single(); + ridlessTarget.Libraries.Should().Contain(e => e.Type == "package" && e.Name == packageX); + // Should resolve to specified package. + ridlessTarget.Libraries.Should().Contain(e => e.Version.Equals(packageX_V2.Version)); + } + } + + [Fact] + public async Task AddPkg_V3LocalSourceFeed_WithRelativePath_NoVersionSpecified_Fail() + { + using (var pathContext = new SimpleTestPathContext()) + { + var projectName = "projectA"; + var targetFrameworks = "net5.0"; + XPlatTestUtils.CreateProject(projectName, pathContext, targetFrameworks); + var packageX = "packageX"; + var packageY = "packageY"; + var packageY_V1 = new PackageIdentity(packageY, new NuGetVersion("1.0.0")); + var packageFrameworks = "net472; netcoreapp2.0"; + var packageY_V1_Context = XPlatTestUtils.CreatePackage(packageY_V1.Id, packageY_V1.Version.Version.ToString(), frameworkString: packageFrameworks); + var customSourcePath = Path.Combine(pathContext.WorkingDirectory, "Custompackages"); + var sourceRelativePath = Path.Combine("..", "..", "Custompackages"); + + // Generate Package + await SimpleTestPackageUtility.CreateFolderFeedV3Async( + customSourcePath, + PackageSaveMode.Defaultv3, + new SimpleTestPackageContext[] { packageY_V1_Context }); + + var projectDirectory = Path.Combine(pathContext.SolutionRoot, projectName); + var projectFilePath = Path.Combine(projectDirectory, $"{projectName}.csproj"); + + // Act + CommandRunnerResult result = _fixture.RunDotnet(projectDirectory, $"add {projectFilePath} package {packageX} -s {sourceRelativePath}", ignoreExitCode: true); + + // Assert + result.Success.Should().BeFalse(because: result.AllOutput); + } + } + + [Fact] + public async Task AddPkg_V3LocalSourceFeed_WithRelativePath_VersionSpecified_Success() + { + using (var pathContext = new SimpleTestPathContext()) + { + var projectName = "projectA"; + var targetFrameworks = "net5.0"; + SimpleTestProjectContext projectA = XPlatTestUtils.CreateProject(projectName, pathContext, targetFrameworks); + var packageX = "packageX"; + var packageX_V1 = new PackageIdentity(packageX, new NuGetVersion("1.0.0")); + var packageX_V2 = new PackageIdentity(packageX, new NuGetVersion("2.0.0")); + var packageFrameworks = "net472; netcoreapp2.0"; + var packageX_V1_Context = XPlatTestUtils.CreatePackage(packageX_V1.Id, packageX_V1.Version.Version.ToString(), frameworkString: packageFrameworks); + var packageX_V2_Context = XPlatTestUtils.CreatePackage(packageX_V2.Id, packageX_V2.Version.Version.ToString(), frameworkString: packageFrameworks); + var customSourcePath = Path.Combine(pathContext.WorkingDirectory, "Custompackages"); + var sourceRelativePath = Path.Combine("..", "..", "Custompackages"); + + // Generate Package + await SimpleTestPackageUtility.CreateFolderFeedV3Async( + customSourcePath, + PackageSaveMode.Defaultv3, + new SimpleTestPackageContext[] { packageX_V1_Context, packageX_V2_Context }); + + var projectDirectory = Path.Combine(pathContext.SolutionRoot, projectName); + var projectFilePath = Path.Combine(projectDirectory, $"{projectName}.csproj"); + + // Act + CommandRunnerResult result = _fixture.RunDotnet(projectDirectory, $"add {projectFilePath} package {packageX} -s {sourceRelativePath} -v {packageX_V1.Version}", ignoreExitCode: true); + + // Assert + result.Success.Should().BeTrue(because: result.AllOutput); + + // Make sure source is replaced in generated dgSpec file. + PackageSpec packageSpec = projectA.AssetsFile.PackageSpec; + string[] sources = packageSpec.RestoreMetadata.Sources.Select(s => s.Name).ToArray(); + Assert.Equal(sources.Count(), 1); + Assert.Equal(sources[0], customSourcePath); + + var ridlessTarget = projectA.AssetsFile.Targets.Where(e => string.IsNullOrEmpty(e.RuntimeIdentifier)).Single(); + ridlessTarget.Libraries.Should().Contain(e => e.Type == "package" && e.Name == packageX); + // Should resolve to specified package. + ridlessTarget.Libraries.Should().Contain(e => e.Version.Equals(packageX_V1.Version)); + } + } + + [Fact] + public async Task AddPkg_V3LocalSourceFeed_WithRelativePath_VersionSpecified_Fail() + { + using (var pathContext = new SimpleTestPathContext()) + { + var projectName = "projectA"; + var targetFrameworks = "net5.0"; + SimpleTestProjectContext projectA = XPlatTestUtils.CreateProject(projectName, pathContext, targetFrameworks); + var packageX = "packageX"; + var packageX_V1 = new PackageIdentity(packageX, new NuGetVersion("1.0.0")); + var packageX_V2 = new PackageIdentity(packageX, new NuGetVersion("2.0.0")); + var packageFrameworks = "net472; netcoreapp2.0"; + var packageX_V1_Context = XPlatTestUtils.CreatePackage(packageX_V1.Id, packageX_V1.Version.Version.ToString(), frameworkString: packageFrameworks); + var customSourcePath = Path.Combine(pathContext.WorkingDirectory, "Custompackages"); + var sourceRelativePath = Path.Combine("..", "..", "Custompackages"); + + // Generate Package + await SimpleTestPackageUtility.CreateFolderFeedV3Async( + customSourcePath, + PackageSaveMode.Defaultv3, + new SimpleTestPackageContext[] { packageX_V1_Context }); + + var projectDirectory = Path.Combine(pathContext.SolutionRoot, projectName); + var projectFilePath = Path.Combine(projectDirectory, $"{projectName}.csproj"); + + // Act + CommandRunnerResult result = _fixture.RunDotnet(projectDirectory, $"add {projectFilePath} package {packageX} -s {sourceRelativePath} -v {packageX_V2.Version}", ignoreExitCode: true); + + // Assert + result.Success.Should().BeFalse(because: result.AllOutput); + } + } + + [Fact] + public async Task AddPkg_V3LocalSourceFeed_WithDefaultSolutiuonSource_NoVersionSpecified_Success() + { + using (var pathContext = new SimpleTestPathContext()) + { + var projectName = "projectA"; + var targetFrameworks = "net5.0"; + SimpleTestProjectContext projectA = XPlatTestUtils.CreateProject(projectName, pathContext, targetFrameworks); + var packageY = "packageY"; + var packageY_V1 = new PackageIdentity(packageY, new NuGetVersion("1.0.0")); + var packageY_V2 = new PackageIdentity(packageY, new NuGetVersion("2.0.0")); + var packageFrameworks = "net472; netcoreapp2.0"; + var packageY_V1_Context = XPlatTestUtils.CreatePackage(packageY_V1.Id, packageY_V1.Version.Version.ToString(), frameworkString: packageFrameworks); + var packageY_V2_Context = XPlatTestUtils.CreatePackage(packageY_V2.Id, packageY_V2.Version.Version.ToString(), frameworkString: packageFrameworks); + + // Generate V3 Package + await SimpleTestPackageUtility.CreateFolderFeedV3Async( + pathContext.PackageSource, // using default solution source folder, not passing source as parameter. + PackageSaveMode.Defaultv3, + new SimpleTestPackageContext[] { packageY_V1_Context, packageY_V2_Context }); + + var projectDirectory = Path.Combine(pathContext.SolutionRoot, projectName); + var projectFilePath = Path.Combine(projectDirectory, $"{projectName}.csproj"); + + // Act + CommandRunnerResult result = _fixture.RunDotnet(projectDirectory, $"add {projectFilePath} package {packageY}", ignoreExitCode: true); + + // Assert + result.Success.Should().BeTrue(because: result.AllOutput); + + // Make sure source is replaced in generated dgSpec file. + PackageSpec packageSpec = projectA.AssetsFile.PackageSpec; + string[] sources = packageSpec.RestoreMetadata.Sources.Select(s => s.Name).ToArray(); + Assert.Equal(sources.Count(), 1); + Assert.Equal(sources[0], pathContext.PackageSource); + + var ridlessTarget = projectA.AssetsFile.Targets.Where(e => string.IsNullOrEmpty(e.RuntimeIdentifier)).Single(); + // Should resolve to specified package. + ridlessTarget.Libraries.Should().Contain(e => e.Type == "package" && e.Name == packageY); + // Should resolve to highest available version. + ridlessTarget.Libraries.Should().Contain(e => e.Version.Equals(packageY_V2.Version)); + } + } + } +} diff --git a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatAddPkgTests.cs b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatAddPkgTests.cs index acf4cd7595d..95a563a2345 100644 --- a/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatAddPkgTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.XPlat.FuncTest/XPlatAddPkgTests.cs @@ -7,16 +7,18 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using FluentAssertions; using Microsoft.Extensions.CommandLineUtils; using Moq; using NuGet.CommandLine.XPlat; -using NuGet.CommandLine.XPlat.Utility; using NuGet.Commands; using NuGet.Common; using NuGet.Configuration; using NuGet.Packaging; using NuGet.Packaging.Core; +using NuGet.ProjectModel; using NuGet.Test.Utility; +using NuGet.Versioning; using Xunit; namespace NuGet.XPlat.FuncTest @@ -745,6 +747,170 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( } } + [Fact] + public async Task AddPkg_V3LocalSourceFeed_WithAbsolutePath_NoVersionSpecified_Success() + { + using (var pathContext = new SimpleTestPathContext()) + { + var projectFrameworks = "net472"; + var packageFrameworks = "net472; netcoreapp2.0"; + var projectA = XPlatTestUtils.CreateProject(ProjectName, pathContext, projectFrameworks); + var packageX = "packageX"; + var packageX_V1 = new PackageIdentity(packageX, new NuGetVersion("1.0.0")); + var packageX_V2 = new PackageIdentity(packageX, new NuGetVersion("2.0.0")); + var packageX_V1_Context = XPlatTestUtils.CreatePackage(packageX_V1.Id, packageX_V1.Version.Version.ToString(), frameworkString: packageFrameworks); + var packageX_V2_Context = XPlatTestUtils.CreatePackage(packageX_V2.Id, packageX_V2.Version.Version.ToString(), frameworkString: packageFrameworks); + var customSourcePath = Path.Combine(pathContext.WorkingDirectory, "Custompackages"); + + // Generate Package + await SimpleTestPackageUtility.CreateFolderFeedV3Async( + customSourcePath, + PackageSaveMode.Defaultv3, + new SimpleTestPackageContext[] { packageX_V1_Context, packageX_V2_Context }); + + // Since user is not inputing a version, it is converted to a " * " in the command + var packageArgs = XPlatTestUtils.GetPackageReferenceArgs(packageX_V1.Id, "*", + projectA, + sources: customSourcePath); + + var commandRunner = new AddPackageReferenceCommandRunner(); + + // Act + var result = await commandRunner.ExecuteCommand(packageArgs, MsBuild); + + // Assert + Assert.Equal(0, result); + + // Make sure source is replaced in generated dgSpec file. + PackageSpec packageSpec = projectA.AssetsFile.PackageSpec; + string[] sources = packageSpec.RestoreMetadata.Sources.Select(s => s.Name).ToArray(); + Assert.Equal(sources.Count(), 1); + Assert.Equal(sources[0], customSourcePath); + + var ridlessTarget = projectA.AssetsFile.Targets.Where(e => string.IsNullOrEmpty(e.RuntimeIdentifier)).Single(); + ridlessTarget.Libraries.Should().Contain(e => e.Type == "package" && e.Name == packageX); + // Should resolve to highest available version. + ridlessTarget.Libraries.Should().Contain(e => e.Version.Equals(packageX_V2.Version)); + } + } + + [Fact] + public async Task AddPkg_V3LocalSourceFeed_WithAbsolutePath_NoVersionSpecified_Fail() + { + using (var pathContext = new SimpleTestPathContext()) + { + var projectFrameworks = "net472"; + var packageFrameworks = "net472; netcoreapp2.0"; + var projectA = XPlatTestUtils.CreateProject(ProjectName, pathContext, projectFrameworks); + var packageX = "packageX"; + var packageY = "packageY"; + var packageX_V1_Context = XPlatTestUtils.CreatePackage(packageX, frameworkString: packageFrameworks); + var packageY_V1_Context = XPlatTestUtils.CreatePackage(packageY, frameworkString: packageFrameworks); + var customSourcePath = Path.Combine(pathContext.WorkingDirectory, "Custompackages"); + + // Generate Package + await SimpleTestPackageUtility.CreateFolderFeedV3Async( + customSourcePath, + PackageSaveMode.Defaultv3, + new SimpleTestPackageContext[] { packageY_V1_Context }); + + // Since user is not inputing a version, it is converted to a " * " in the command + var packageArgs = XPlatTestUtils.GetPackageReferenceArgs(packageX, "*", + projectA, + sources: customSourcePath); + + var commandRunner = new AddPackageReferenceCommandRunner(); + + // Act + var result = await commandRunner.ExecuteCommand(packageArgs, MsBuild); + + // Assert + Assert.Equal(1, result); + } + } + + [Fact] + public async Task AddPkg_V3LocalSourceFeed_WithAbsolutePath_VersionSpecified_Success() + { + using (var pathContext = new SimpleTestPathContext()) + { + var projectFrameworks = "net472"; + var packageFrameworks = "net472; netcoreapp2.0"; + var projectA = XPlatTestUtils.CreateProject(ProjectName, pathContext, projectFrameworks); + var packageX = "packageX"; + var packageX_V1 = new PackageIdentity(packageX, new NuGetVersion("1.0.0")); + var packageX_V2 = new PackageIdentity(packageX, new NuGetVersion("2.0.0")); + var packageX_V1_Context = XPlatTestUtils.CreatePackage(packageX_V1.Id, packageX_V1.Version.Version.ToString(), frameworkString: packageFrameworks); + var packageX_V2_Context = XPlatTestUtils.CreatePackage(packageX_V2.Id, packageX_V2.Version.Version.ToString(), frameworkString: packageFrameworks); + var customSourcePath = Path.Combine(pathContext.WorkingDirectory, "Custompackages"); + + // Generate Package + await SimpleTestPackageUtility.CreateFolderFeedV3Async( + customSourcePath, + PackageSaveMode.Defaultv3, + new SimpleTestPackageContext[] { packageX_V1_Context, packageX_V2_Context }); + + var packageArgs = XPlatTestUtils.GetPackageReferenceArgs(packageX_V1.Id, packageX_V1.Version.ToString(), + projectA, + sources: customSourcePath); + + var commandRunner = new AddPackageReferenceCommandRunner(); + + // Act + var result = await commandRunner.ExecuteCommand(packageArgs, MsBuild); + + // Assert + Assert.Equal(0, result); + + // Make sure source is replaced in generated dgSpec file. + PackageSpec packageSpec = projectA.AssetsFile.PackageSpec; + string[] sources = packageSpec.RestoreMetadata.Sources.Select(s => s.Name).ToArray(); + Assert.Equal(sources.Count(), 1); + Assert.Equal(sources[0], customSourcePath); + + var ridlessTarget = projectA.AssetsFile.Targets.Where(e => string.IsNullOrEmpty(e.RuntimeIdentifier)).Single(); + ridlessTarget.Libraries.Should().Contain(e => e.Type == "package" && e.Name == packageX); + // Should resolve to specified version. + ridlessTarget.Libraries.Should().Contain(e => e.Version.Equals(packageX_V1.Version)); + } + } + + [Fact] + public async Task AddPkg_V3LocalSourceFeed_WithAbsolutePath_VersionSpecified_Fail() + { + using (var pathContext = new SimpleTestPathContext()) + { + var projectFrameworks = "net472"; + var packageFrameworks = "net472; netcoreapp2.0"; + var projectA = XPlatTestUtils.CreateProject(ProjectName, pathContext, projectFrameworks); + var packageX = "packageX"; + var packageX_V1 = new PackageIdentity(packageX, new NuGetVersion("1.0.0")); + var packageX_V2 = new PackageIdentity(packageX, new NuGetVersion("2.0.0")); + var packageX_V3 = new PackageIdentity(packageX, new NuGetVersion("3.0.0")); + var packageX_V1_Context = XPlatTestUtils.CreatePackage(packageX, packageX_V1.Version.Version.ToString(), frameworkString: packageFrameworks); + var packageX_V2_Context = XPlatTestUtils.CreatePackage(packageX, packageX_V2.Version.Version.ToString(), frameworkString: packageFrameworks); + var customSourcePath = Path.Combine(pathContext.WorkingDirectory, "Custompackages"); + + // Generate Package + await SimpleTestPackageUtility.CreateFolderFeedV3Async( + customSourcePath, + PackageSaveMode.Defaultv3, + new SimpleTestPackageContext[] { packageX_V1_Context, packageX_V2_Context }); + + var packageArgs = XPlatTestUtils.GetPackageReferenceArgs(packageX_V3.Id, packageX_V3.Version.ToString(), + projectA, + sources: customSourcePath); + + var commandRunner = new AddPackageReferenceCommandRunner(); + + // Act + var result = await commandRunner.ExecuteCommand(packageArgs, MsBuild); + + // Assert + Assert.Equal(1, result); + } + } + [Theory] [InlineData("net46", "net46; netcoreapp1.0", "net46")] [InlineData("net46; netcoreapp1.0", "net46; netcoreapp1.0", "net46")]