diff --git a/Packages.props b/Packages.props index 3017a447..2399365b 100644 --- a/Packages.props +++ b/Packages.props @@ -23,7 +23,7 @@ - + diff --git a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.162.0.28-alpha.nupkg b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.162.0.28-alpha.nupkg deleted file mode 100644 index 32b039cc..00000000 Binary files a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.162.0.28-alpha.nupkg and /dev/null differ diff --git a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.162.0.32-alpha.nupkg b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.162.0.32-alpha.nupkg new file mode 100644 index 00000000..bea4926a Binary files /dev/null and b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.162.0.32-alpha.nupkg differ diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Folders/ExcludeFolder.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Folders/ExcludeFolder.cs new file mode 100644 index 00000000..cc4fdd4b --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Folders/ExcludeFolder.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.SqlTools.ServiceLayer.Utility; + +namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts +{ + /// + /// Exclude a folder and its contents from a project + /// + public class ExcludeFolderRequest + { + public static readonly RequestType Type = RequestType.Create("sqlProjects/excludeFolder"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Folders/MoveFolder.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Folders/MoveFolder.cs new file mode 100644 index 00000000..c6fc45d3 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Folders/MoveFolder.cs @@ -0,0 +1,31 @@ +// +// 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 moving a folder + /// + public class MoveFolderParams : FolderParams + { + /// + /// Path of the folder, typically relative to the .sqlproj file + /// + public string DestinationPath { get; set; } + } + + /// + /// Move a folder and its contents within a project + /// + public class MoveFolderRequest + { + public static readonly RequestType Type = RequestType.Create("sqlProjects/moveFolder"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs index bae3ede5..f9112560 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs @@ -81,6 +81,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects serviceHost.SetRequestHandler(GetFoldersRequest.Type, HandleGetFoldersRequest, isParallelProcessingSupported: true); serviceHost.SetRequestHandler(AddFolderRequest.Type, HandleAddFolderRequest, isParallelProcessingSupported: false); serviceHost.SetRequestHandler(DeleteFolderRequest.Type, HandleDeleteFolderRequest, isParallelProcessingSupported: false); + serviceHost.SetRequestHandler(ExcludeFolderRequest.Type, HandleExcludeFolderRequest, isParallelProcessingSupported: false); + serviceHost.SetRequestHandler(MoveFolderRequest.Type, HandleMoveFolderRequest, isParallelProcessingSupported: false); // SQLCMD variable functions serviceHost.SetRequestHandler(GetSqlCmdVariablesRequest.Type, HandleGetSqlCmdVariablesRequest, isParallelProcessingSupported: true); @@ -343,6 +345,16 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).Folders.Delete(requestParams.Path), requestContext); } + internal async Task HandleExcludeFolderRequest(FolderParams requestParams, RequestContext requestContext) + { + await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).Folders.Exclude(requestParams.Path), requestContext); + } + + internal async Task HandleMoveFolderRequest(MoveFolderParams requestParams, RequestContext requestContext) + { + await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).Folders.Move(requestParams.Path, requestParams.DestinationPath), requestContext); + } + #endregion #endregion diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs index 78ebce82..ec87835d 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs @@ -372,7 +372,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects } [Test] - public async Task TestPostDeploymentScriptAddDeleteExcludeMove() + public async Task TestPostDeploymentScriptOperations() { // Setup SqlProjectsService service = new(); @@ -816,9 +816,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects requestMock.AssertSuccess(nameof(service.HandleAddFolderRequest)); Assert.AreEqual(1, service.Projects[projectUri].Folders.Count, "Folder count after add"); Assert.IsTrue(Directory.Exists(Path.Join(Path.GetDirectoryName(projectUri), folderParams.Path)), $"Subfolder '{folderParams.Path}' expected to exist on disk"); - Assert.IsTrue(service.Projects[projectUri].Folders.Contains(folderParams.Path), $"SqlObjectScripts expected to contain {folderParams.Path}"); + Assert.IsTrue(service.Projects[projectUri].Folders.Contains(folderParams.Path), $"Folders expected to contain {folderParams.Path}"); - // Validate getting a list of the post-deployment scripts + // Validate getting a list of the folders MockRequest getMock = new(); await service.HandleGetFoldersRequest(new SqlProjectParams() { @@ -829,12 +829,48 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects Assert.AreEqual(1, getMock.Result.Folders.Length); Assert.AreEqual(folderParams.Path, getMock.Result.Folders[0]); + // Validate moving a folder + requestMock = new(); + const string parentFolder = "NewParentFolder"; + MoveFolderParams moveFolderParams = new MoveFolderParams() + { + ProjectUri = projectUri, + Path = folderParams.Path, + DestinationPath = $@"{parentFolder}\{folderParams.Path}" + }; + + await service.HandleMoveFolderRequest(moveFolderParams, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleMoveFolderRequest)); + Assert.AreEqual(2, service.Projects[projectUri].Folders.Count, "Folder count after move"); + Assert.IsTrue(service.Projects[projectUri].Folders.Contains(parentFolder), $"Folders expected to contain '{parentFolder}' after move"); + Assert.IsTrue(service.Projects[projectUri].Folders.Contains(moveFolderParams.DestinationPath), $"Folders expected to contain '{moveFolderParams.DestinationPath}' after move"); + + // Validate excluding a folder + requestMock = new(); + await service.HandleExcludeFolderRequest(new FolderParams() + { + ProjectUri = projectUri, + Path = moveFolderParams.DestinationPath + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleExcludeFolderRequest)); + Assert.AreEqual(1, service.Projects[projectUri].Folders.Count, "Folder count after exclude"); + Assert.IsTrue(service.Projects[projectUri].Folders.Contains(parentFolder), $"Folders expected to still contain '{parentFolder}' after exclude"); + Assert.IsFalse(service.Projects[projectUri].Folders.Contains(moveFolderParams.DestinationPath), $"Folders expected to no longer contain '{moveFolderParams.DestinationPath}' after exclude"); + Assert.IsTrue(Directory.Exists(Path.Join(service.Projects[projectUri].DirectoryPath, parentFolder, folderParams.Path)), "Folder should still exist on disk after exclude"); + // Validate deleting a folder requestMock = new(); - await service.HandleDeleteFolderRequest(folderParams, requestMock.Object); + await service.HandleDeleteFolderRequest(new FolderParams() + { + ProjectUri = projectUri, + Path = parentFolder + }, requestMock.Object); requestMock.AssertSuccess(nameof(service.HandleDeleteFolderRequest)); Assert.AreEqual(0, service.Projects[projectUri].Folders.Count, "Folder count after delete"); + Assert.IsFalse(Directory.Exists(Path.Join(service.Projects[projectUri].DirectoryPath, parentFolder)), "Folder should have been deleted from disk"); } [Test]