diff --git a/Packages.props b/Packages.props index 1bd05d5e..28815de0 100644 --- a/Packages.props +++ b/Packages.props @@ -23,7 +23,7 @@ - + diff --git a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8439.0-alpha.nupkg b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8439.0-alpha.nupkg deleted file mode 100644 index 35e14c33..00000000 Binary files a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8439.0-alpha.nupkg and /dev/null differ diff --git a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8442.0-alpha.nupkg b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8442.0-alpha.nupkg deleted file mode 100644 index ab110b5f..00000000 Binary files a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8442.0-alpha.nupkg and /dev/null differ diff --git a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.162.0.25-alpha.nupkg b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.162.0.25-alpha.nupkg new file mode 100644 index 00000000..83b33816 Binary files /dev/null and b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.162.0.25-alpha.nupkg differ diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddNugetPackageReferenceParams.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddNugetPackageReferenceParams.cs new file mode 100644 index 00000000..7f76abaf --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddNugetPackageReferenceParams.cs @@ -0,0 +1,36 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#nullable disable + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.SqlTools.ServiceLayer.Utility; + +namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts +{ + /// + /// Parameters for adding a NuGet package reference to a SQL project + /// + public class AddNugetPackageReferenceParams : AddUserDatabaseReferenceParams + { + /// + /// NuGet package name + /// + public string PackageName { get; set; } + + /// + /// NuGet package version + /// + public string PackageVersion { get; set; } + } + + /// + /// Add a NuGet package reference to a project + /// + public class AddNugetPackageReferenceRequest + { + public static readonly RequestType Type = RequestType.Create("sqlprojects/addNugetPackageReference"); + } +} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/GetDatabaseReferences.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/GetDatabaseReferences.cs index 1bf393b3..ab8f56f5 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/GetDatabaseReferences.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/GetDatabaseReferences.cs @@ -38,5 +38,10 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts /// Array of SQL project references contained in the project /// public SqlProjectReference[] SqlProjectReferences { get; set; } + + /// + /// Array of NuGet package references contained in the project + /// + public NugetPackageReference[] NugetPackageReferences { get; set; } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs index 0dd44953..7ce9d01b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs @@ -93,6 +93,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects serviceHost.SetRequestHandler(AddSystemDatabaseReferenceRequest.Type, HandleAddSystemDatabaseReferenceRequest, isParallelProcessingSupported: false); serviceHost.SetRequestHandler(AddDacpacReferenceRequest.Type, HandleAddDacpacReferenceRequest, isParallelProcessingSupported: false); serviceHost.SetRequestHandler(AddSqlProjectReferenceRequest.Type, HandleAddSqlProjectReferenceRequest, isParallelProcessingSupported: false); + serviceHost.SetRequestHandler(AddNugetPackageReferenceRequest.Type, HandleAddNugetPackageReferenceRequest, isParallelProcessingSupported: false); serviceHost.SetRequestHandler(DeleteDatabaseReferenceRequest.Type, HandleDeleteDatabaseReferenceRequest, isParallelProcessingSupported: false); } @@ -358,7 +359,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects ErrorMessage = null, SystemDatabaseReferences = GetProject(requestParams.ProjectUri).DatabaseReferences.OfType().ToArray(), DacpacReferences = GetProject(requestParams.ProjectUri).DatabaseReferences.OfType().ToArray(), - SqlProjectReferences = GetProject(requestParams.ProjectUri).DatabaseReferences.OfType().ToArray() + SqlProjectReferences = GetProject(requestParams.ProjectUri).DatabaseReferences.OfType().ToArray(), + NugetPackageReferences = GetProject(requestParams.ProjectUri).DatabaseReferences.OfType().ToArray() }; }, requestContext); } @@ -443,6 +445,42 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects }, requestContext); } + internal async Task HandleAddNugetPackageReferenceRequest(AddNugetPackageReferenceParams requestParams, RequestContext requestContext) + { + await RunWithErrorHandling(() => + { + requestParams.Validate(); + + SqlProject project = GetProject(requestParams.ProjectUri!); + NugetPackageReference reference; + + if (!string.IsNullOrWhiteSpace(requestParams.DatabaseLiteral)) // same server, different database via database name literal + { + reference = new NugetPackageReference( + requestParams.PackageName, + requestParams.PackageVersion, + requestParams.SuppressMissingDependencies, + requestParams.DatabaseLiteral); + } + else if (!string.IsNullOrWhiteSpace(requestParams.DatabaseVariable)) // different database, possibly different server via sqlcmdvar + { + reference = new NugetPackageReference( + requestParams.PackageName, + requestParams.PackageVersion, + requestParams.SuppressMissingDependencies, + project.SqlCmdVariables.Get(requestParams.DatabaseVariable!), + requestParams.ServerVariable != null ? project.SqlCmdVariables.Get(requestParams.ServerVariable) : null); + } + else // same database + { + reference = new NugetPackageReference(requestParams.PackageName, requestParams.PackageVersion, requestParams.SuppressMissingDependencies); + } + + project.DatabaseReferences.Add(reference); + }, requestContext); + } + + internal async Task HandleDeleteDatabaseReferenceRequest(DeleteDatabaseReferenceParams requestParams, RequestContext requestContext) { await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri!).DatabaseReferences.Delete(requestParams.Name!), requestContext); diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs index 32fed4c7..c4629fae 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs @@ -472,10 +472,12 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects SystemDatabaseReference systemDatabaseReference = new SystemDatabaseReference(SystemDatabase.MSDB, suppressMissingDependencies: true); DacpacReference dacpacReference = new DacpacReference("OtherDatabaseDacpac.dacpac", suppressMissingDependencies: true); SqlProjectReference sqlProjectReference = new SqlProjectReference("OtherDatabaseProject.sqlproj", projectGuid: TEST_GUID, suppressMissingDependencies: true); + NugetPackageReference nugetPackageReference = new NugetPackageReference("Project1", "2.0.0", suppressMissingDependencies: true); service.Projects[projectUri].DatabaseReferences.Add(systemDatabaseReference); service.Projects[projectUri].DatabaseReferences.Add(dacpacReference); service.Projects[projectUri].DatabaseReferences.Add(sqlProjectReference); + service.Projects[projectUri].DatabaseReferences.Add(nugetPackageReference); // Validate getting a list of the post-deployment scripts MockRequest getMock = new(); @@ -494,6 +496,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects Assert.AreEqual(1, getMock.Result.SqlProjectReferences.Length); Assert.AreEqual(sqlProjectReference, getMock.Result.SqlProjectReferences[0]); + + Assert.AreEqual(1, getMock.Result.NugetPackageReferences.Length); + Assert.AreEqual(nugetPackageReference, getMock.Result.NugetPackageReferences[0]); } [Test] @@ -694,6 +699,100 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects Assert.IsFalse(projectRef.SuppressMissingDependencies, nameof(projectRef.SuppressMissingDependencies)); } + [Test] + public async Task TestNugetPackageReferenceAdd() + { + var (service, projectUri, databaseVar, serverVar) = await SetUpDatabaseReferenceTest(); + + // Validate adding a nupkg reference on the same server + string mockPackageName = "OtherDatabaseSameServer"; + string mockPackageVersion = "2.0.0"; + + MockRequest requestMock = new(); + await service.HandleAddNugetPackageReferenceRequest(new AddNugetPackageReferenceParams() + { + ProjectUri = projectUri, + PackageName = mockPackageName, + PackageVersion = mockPackageVersion, + SuppressMissingDependencies = false + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleAddNugetPackageReferenceRequest), "same server"); + Assert.AreEqual(1, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding nupkg reference (same server)"); + NugetPackageReference nupkgRef = (NugetPackageReference)service.Projects[projectUri].DatabaseReferences.Get(mockPackageName); + Assert.AreEqual(mockPackageName, nupkgRef.PackageName, "Referenced nupkg"); + Assert.AreEqual(mockPackageVersion, nupkgRef.Version, "Referenced nupkg version"); + Assert.IsFalse(nupkgRef.SuppressMissingDependencies, nameof(nupkgRef.SuppressMissingDependencies)); + Assert.IsNull(nupkgRef.DatabaseVariableLiteralName, nameof(nupkgRef.DatabaseVariableLiteralName)); + Assert.IsNull(nupkgRef.DatabaseVariable, nameof(nupkgRef.DatabaseVariable)); + + // Validate adding a nupkg reference via SQLCMD variable + mockPackageName = "OtherDatabaseSqlCmd"; + + requestMock = new(); + await service.HandleAddNugetPackageReferenceRequest(new AddNugetPackageReferenceParams() + { + ProjectUri = projectUri, + PackageName = mockPackageName, + PackageVersion = mockPackageVersion, + SuppressMissingDependencies = false, + DatabaseVariable = databaseVar.Name, + ServerVariable = serverVar.Name + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleAddNugetPackageReferenceRequest), "sqlcmdvar"); + Assert.AreEqual(2, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding nupkg reference (sqlcmdvar)"); + nupkgRef = (NugetPackageReference)service.Projects[projectUri].DatabaseReferences.Get(mockPackageName); + Assert.AreEqual(mockPackageName, nupkgRef.PackageName, "Referenced nupkg"); + Assert.AreEqual(mockPackageVersion, nupkgRef.Version, "Referenced nupkg version"); + Assert.AreEqual(databaseVar.Name, nupkgRef.DatabaseVariable!.VarName); + Assert.AreEqual(serverVar.Name, nupkgRef.ServerVariable!.VarName); + Assert.IsFalse(nupkgRef.SuppressMissingDependencies, nameof(nupkgRef.SuppressMissingDependencies)); + + // Validate adding a nupkg reference via database literal + mockPackageName = "OtherDatabaseLiteral"; + + requestMock = new(); + await service.HandleAddNugetPackageReferenceRequest(new AddNugetPackageReferenceParams() + { + ProjectUri = projectUri, + PackageName = mockPackageName, + PackageVersion = mockPackageVersion, + SuppressMissingDependencies = false, + DatabaseLiteral = "NupkgLiteral" + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleAddNugetPackageReferenceRequest), "db literal"); + Assert.AreEqual(3, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding nupkg reference (db literal)"); + nupkgRef = (NugetPackageReference)service.Projects[projectUri].DatabaseReferences.Get(mockPackageName); + Assert.AreEqual(mockPackageName, nupkgRef.PackageName, "Referenced nupkg"); + Assert.AreEqual(mockPackageVersion, nupkgRef.Version, "Referenced nupkg version"); + Assert.AreEqual("NupkgLiteral", nupkgRef.DatabaseVariableLiteralName, nameof(nupkgRef.DatabaseVariableLiteralName)); + Assert.IsFalse(nupkgRef.SuppressMissingDependencies, nameof(nupkgRef.SuppressMissingDependencies)); + + // Validate adding a nupkg reference via database literal when an empty string is passed in for DatabaseVariable + mockPackageName = "AnotherDatabaseLiteral"; + + requestMock = new(); + await service.HandleAddNugetPackageReferenceRequest(new AddNugetPackageReferenceParams() + { + ProjectUri = projectUri, + PackageName = mockPackageName, + PackageVersion = mockPackageVersion, + SuppressMissingDependencies = false, + DatabaseLiteral = "NupkgLiteral2", + DatabaseVariable = "" + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleAddNugetPackageReferenceRequest), "db literal"); + Assert.AreEqual(4, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding nupkg reference with an empty string passed in for database variable(db literal)"); + nupkgRef = (NugetPackageReference)service.Projects[projectUri].DatabaseReferences.Get(mockPackageName); + Assert.AreEqual(mockPackageName, nupkgRef.PackageName, "Referenced nupkg"); + Assert.AreEqual("NupkgLiteral2", nupkgRef.DatabaseVariableLiteralName, nameof(nupkgRef.DatabaseVariableLiteralName)); + Assert.IsFalse(nupkgRef.SuppressMissingDependencies, nameof(nupkgRef.SuppressMissingDependencies)); + Assert.AreEqual(null, nupkgRef.DatabaseVariable, nameof(nupkgRef.DatabaseVariable)); + } + #endregion [Test]