diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSystemDatabaseReference.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSystemDatabaseReference.cs index 6bdcc57b..83b1fc7e 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSystemDatabaseReference.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/DatabaseReferences/AddSystemDatabaseReference.cs @@ -24,6 +24,6 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts public class AddSystemDatabaseReferenceRequest { - public static readonly RequestType Type = RequestType.Create("sqlprojects/addSystemDatabaseReference"); + public static readonly RequestType Type = RequestType.Create("sqlprojects/addSystemDatabaseReference"); } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/AddPostDeploymentScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/AddPostDeploymentScript.cs new file mode 100644 index 00000000..8a9cd25b --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/AddPostDeploymentScript.cs @@ -0,0 +1,15 @@ +// +// 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 +{ + public class AddPostDeploymentScriptRequest + { + public static readonly RequestType Type = RequestType.Create("sqlProjects/addPostDeploymentScript"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/AddPreDeploymentScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/AddPreDeploymentScript.cs new file mode 100644 index 00000000..e19fe04e --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/AddPreDeploymentScript.cs @@ -0,0 +1,15 @@ +// +// 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 +{ + public class AddPreDeploymentScriptRequest + { + public static readonly RequestType Type = RequestType.Create("sqlProjects/addPreDeploymentScript"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/DeletePostDeploymentScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/DeletePostDeploymentScript.cs new file mode 100644 index 00000000..0f416197 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/DeletePostDeploymentScript.cs @@ -0,0 +1,15 @@ +// +// 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 +{ + public class DeletePostDeploymentScriptRequest + { + public static readonly RequestType Type = RequestType.Create("sqlProjects/deletePostDeploymentScript"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/DeletePreDeploymentScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/DeletePreDeploymentScript.cs new file mode 100644 index 00000000..c9aeb06a --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/DeletePreDeploymentScript.cs @@ -0,0 +1,15 @@ +// +// 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 +{ + public class DeletePreDeploymentScriptRequest + { + public static readonly RequestType Type = RequestType.Create("sqlProjects/deletePreDeploymentScript"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/ExcludePostDeploymentScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/ExcludePostDeploymentScript.cs new file mode 100644 index 00000000..93720e01 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/ExcludePostDeploymentScript.cs @@ -0,0 +1,15 @@ +// +// 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 +{ + public class ExcludePostDeploymentScriptRequest + { + public static readonly RequestType Type = RequestType.Create("sqlProjects/excludePostDeploymentScript"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/ExcludePreDeploymentScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/ExcludePreDeploymentScript.cs new file mode 100644 index 00000000..ea6443cb --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/PrePostDeploymentScripts/ExcludePreDeploymentScript.cs @@ -0,0 +1,15 @@ +// +// 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 +{ + public class ExcludePreDeploymentScriptRequest + { + public static readonly RequestType Type = RequestType.Create("sqlProjects/excludePreDeploymentScript"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjects/AddSqlObjectScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/AddSqlObjectScript.cs similarity index 100% rename from src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjects/AddSqlObjectScript.cs rename to src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/AddSqlObjectScript.cs diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjects/DeleteSqlObjectScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/DeleteSqlObjectScript.cs similarity index 100% rename from src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjects/DeleteSqlObjectScript.cs rename to src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/DeleteSqlObjectScript.cs diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjects/ExcludeSqlObjectScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/ExcludeSqlObjectScript.cs similarity index 100% rename from src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjects/ExcludeSqlObjectScript.cs rename to src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/SqlObjectScripts/ExcludeSqlObjectScript.cs diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs index eafec25e..666984de 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs @@ -3,7 +3,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -#nullable disable using System; using System.Collections.Concurrent; using System.Threading.Tasks; @@ -52,6 +51,15 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects serviceHost.SetRequestHandler(DeleteSqlObjectScriptRequest.Type, HandleDeleteSqlObjectScriptRequest, isParallelProcessingSupported: false); serviceHost.SetRequestHandler(ExcludeSqlObjectScriptRequest.Type, HandleExcludeSqlObjectScriptRequest, isParallelProcessingSupported: false); + // Pre/Post-deployment script functions + serviceHost.SetRequestHandler(AddPreDeploymentScriptRequest.Type, HandleAddPreDeploymentScriptRequest, isParallelProcessingSupported: false); + serviceHost.SetRequestHandler(DeletePreDeploymentScriptRequest.Type, HandleDeletePreDeploymentScriptRequest, isParallelProcessingSupported: false); + serviceHost.SetRequestHandler(ExcludePreDeploymentScriptRequest.Type, HandleExcludePreDeploymentScriptRequest, isParallelProcessingSupported: false); + + serviceHost.SetRequestHandler(AddPostDeploymentScriptRequest.Type, HandleAddPostDeploymentScriptRequest, isParallelProcessingSupported: false); + serviceHost.SetRequestHandler(DeletePostDeploymentScriptRequest.Type, HandleDeletePostDeploymentScriptRequest, isParallelProcessingSupported: false); + serviceHost.SetRequestHandler(ExcludePostDeploymentScriptRequest.Type, HandleExcludePostDeploymentScriptRequest, isParallelProcessingSupported: false); + // Folder functions serviceHost.SetRequestHandler(AddFolderRequest.Type, HandleAddFolderRequest, isParallelProcessingSupported: false); serviceHost.SetRequestHandler(DeleteFolderRequest.Type, HandleDeleteFolderRequest, isParallelProcessingSupported: false); @@ -60,6 +68,11 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects serviceHost.SetRequestHandler(AddSqlCmdVariableRequest.Type, HandleAddSqlCmdVariableRequest, isParallelProcessingSupported: false); serviceHost.SetRequestHandler(DeleteSqlCmdVariableRequest.Type, HandleDeleteSqlCmdVariableRequest, isParallelProcessingSupported: false); serviceHost.SetRequestHandler(UpdateSqlCmdVariableRequest.Type, HandleUpdateSqlCmdVariableRequest, isParallelProcessingSupported: false); + + // Database reference functions + serviceHost.SetRequestHandler(AddSystemDatabaseReferenceRequest.Type, HandleAddSystemDatabaseReferenceRequest, isParallelProcessingSupported: false); + serviceHost.SetRequestHandler(AddDacpacReferenceRequest.Type, HandleAddDacpacReferenceRequest, isParallelProcessingSupported: false); + serviceHost.SetRequestHandler(AddSqlProjectReferenceRequest.Type, HandleAddSqlProjectReferenceRequest, isParallelProcessingSupported: false); } #region Handlers @@ -105,6 +118,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects #endregion + #region Script/folder functions + #region SQL object script functions internal async Task HandleAddSqlObjectScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext) @@ -124,7 +139,57 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects #endregion - #region Database Reference calls + #region Pre/Post-deployment script functions + + internal async Task HandleAddPreDeploymentScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext) + { + await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).PreDeployScripts.Add(new PreDeployScript(requestParams.Path)), requestContext); + } + + internal async Task HandleDeletePreDeploymentScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext) + { + await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).PreDeployScripts.Delete(requestParams.Path), requestContext); + } + + internal async Task HandleExcludePreDeploymentScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext) + { + await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).PreDeployScripts.Exclude(requestParams.Path), requestContext); + } + + internal async Task HandleAddPostDeploymentScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext) + { + await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).PostDeployScripts.Add(new PostDeployScript(requestParams.Path)), requestContext); + } + + internal async Task HandleDeletePostDeploymentScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext) + { + await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).PostDeployScripts.Delete(requestParams.Path), requestContext); + } + + internal async Task HandleExcludePostDeploymentScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext) + { + await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).PostDeployScripts.Exclude(requestParams.Path), requestContext); + } + + #endregion + + #region Folder functions + + internal async Task HandleAddFolderRequest(FolderParams requestParams, RequestContext requestContext) + { + await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).Folders.Add(new Folder(requestParams.Path)), requestContext); + } + + internal async Task HandleDeleteFolderRequest(FolderParams requestParams, RequestContext requestContext) + { + await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).Folders.Delete(requestParams.Path), requestContext); + } + + #endregion + + #endregion + + #region Database Reference functions internal async Task HandleAddSystemDatabaseReferenceRequest(AddSystemDatabaseReferenceParams requestParams, RequestContext requestContext) { @@ -174,20 +239,6 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects #endregion - #region Folder functions - - internal async Task HandleAddFolderRequest(FolderParams requestParams, RequestContext requestContext) - { - await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).Folders.Add(new Folder(requestParams.Path)), requestContext); - } - - internal async Task HandleDeleteFolderRequest(FolderParams requestParams, RequestContext requestContext) - { - await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).Folders.Delete(requestParams.Path), requestContext); - } - - #endregion - #region SQLCMD variable functions internal async Task HandleAddSqlCmdVariableRequest(AddSqlCmdVariableParams requestParams, RequestContext requestContext) diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs index 5a90c422..baf32e57 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs @@ -161,6 +161,128 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects Assert.IsFalse(File.Exists(scriptFullPath), $"{scriptFullPath} expected to have been deleted from disk"); } + [Test] + public async Task TestPreDeploymentScriptAddDeleteExclude() + { + // Setup + SqlProjectsService service = new(); + string projectUri = await service.CreateSqlProject(); + Assert.AreEqual(0, service.Projects[projectUri].PreDeployScripts.Count, "Baseline number of Pre-deployment scripts"); + + // Validate adding a pre-deployment script + MockRequest requestMock = new(); + string scriptRelativePath = "PreDeploymentScript.sql"; + string scriptFullPath = Path.Join(Path.GetDirectoryName(projectUri), scriptRelativePath); + await File.WriteAllTextAsync(scriptFullPath, "SELECT 'Deployment starting...'"); + Assert.IsTrue(File.Exists(scriptFullPath), $"{scriptFullPath} expected to be on disk"); + + await service.HandleAddPreDeploymentScriptRequest(new SqlProjectScriptParams() + { + ProjectUri = projectUri, + Path = scriptRelativePath + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleAddPreDeploymentScriptRequest)); + Assert.AreEqual(1, service.Projects[projectUri].PreDeployScripts.Count, "PreDeployScript count after add"); + Assert.IsTrue(service.Projects[projectUri].PreDeployScripts.Contains(scriptRelativePath), $"PreDeployScripts expected to contain {scriptRelativePath}"); + + // Validate excluding a pre-deployment script + requestMock = new(); + await service.HandleExcludePreDeploymentScriptRequest(new SqlProjectScriptParams() + { + ProjectUri = projectUri, + Path = scriptRelativePath + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleExcludePreDeploymentScriptRequest)); + Assert.AreEqual(0, service.Projects[projectUri].PreDeployScripts.Count, "PreDeployScripts count after exclude"); + Assert.IsTrue(File.Exists(scriptFullPath), $"{scriptFullPath} expected to still exist on disk"); + + // Re-add to set up for Delete + requestMock = new(); + await service.HandleAddPreDeploymentScriptRequest(new SqlProjectScriptParams() + { + ProjectUri = projectUri, + Path = scriptRelativePath + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleAddPreDeploymentScriptRequest)); + Assert.AreEqual(1, service.Projects[projectUri].PreDeployScripts .Count, "PreDeployScripts count after re-add"); + + // Validate deleting a pre-deployment script + requestMock = new(); + await service.HandleDeletePreDeploymentScriptRequest(new SqlProjectScriptParams() + { + ProjectUri = projectUri, + Path = scriptRelativePath + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleDeletePreDeploymentScriptRequest)); + Assert.AreEqual(0, service.Projects[projectUri].PreDeployScripts.Count, "PreDeployScripts count after delete"); + Assert.IsFalse(File.Exists(scriptFullPath), $"{scriptFullPath} expected to have been deleted from disk"); + } + + [Test] + public async Task TestPostDeploymentScriptAddDeleteExclude() + { + // Setup + SqlProjectsService service = new(); + string projectUri = await service.CreateSqlProject(); + Assert.AreEqual(0, service.Projects[projectUri].PostDeployScripts.Count, "Baseline number of Post-deployment scripts"); + + // Validate adding a Post-deployment script + MockRequest requestMock = new(); + string scriptRelativePath = "PostDeploymentScript.sql"; + string scriptFullPath = Path.Join(Path.GetDirectoryName(projectUri), scriptRelativePath); + await File.WriteAllTextAsync(scriptFullPath, "SELECT 'Deployment finished!'"); + Assert.IsTrue(File.Exists(scriptFullPath), $"{scriptFullPath} expected to be on disk"); + + await service.HandleAddPostDeploymentScriptRequest(new SqlProjectScriptParams() + { + ProjectUri = projectUri, + Path = scriptRelativePath + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleAddPostDeploymentScriptRequest)); + Assert.AreEqual(1, service.Projects[projectUri].PostDeployScripts.Count, "PostDeployScript count after add"); + Assert.IsTrue(service.Projects[projectUri].PostDeployScripts.Contains(scriptRelativePath), $"PostDeployScripts expected to contain {scriptRelativePath}"); + + // Validate excluding a Post-deployment script + requestMock = new(); + await service.HandleExcludePostDeploymentScriptRequest(new SqlProjectScriptParams() + { + ProjectUri = projectUri, + Path = scriptRelativePath + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleExcludePostDeploymentScriptRequest)); + Assert.AreEqual(0, service.Projects[projectUri].PostDeployScripts.Count, "PostDeployScripts count after exclude"); + Assert.IsTrue(File.Exists(scriptFullPath), $"{scriptFullPath} expected to still exist on disk"); + + // Re-add to set up for Delete + requestMock = new(); + await service.HandleAddPostDeploymentScriptRequest(new SqlProjectScriptParams() + { + ProjectUri = projectUri, + Path = scriptRelativePath + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleAddPostDeploymentScriptRequest)); + Assert.AreEqual(1, service.Projects[projectUri].PostDeployScripts.Count, "PostDeployScripts count after re-add"); + + // Validate deleting a Post-deployment script + requestMock = new(); + await service.HandleDeletePostDeploymentScriptRequest(new SqlProjectScriptParams() + { + ProjectUri = projectUri, + Path = scriptRelativePath + }, requestMock.Object); + + requestMock.AssertSuccess(nameof(service.HandleDeletePostDeploymentScriptRequest)); + Assert.AreEqual(0, service.Projects[projectUri].PostDeployScripts.Count, "PostDeployScripts count after delete"); + Assert.IsFalse(File.Exists(scriptFullPath), $"{scriptFullPath} expected to have been deleted from disk"); + } + [Test] public async Task TestDatabaseReferenceAddDelete() {