diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/AddNoneScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/AddNoneScript.cs
new file mode 100644
index 00000000..99bc39b1
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/AddNoneScript.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
+{
+ ///
+ /// Add a SQL object script to a project
+ ///
+ public class AddNoneScriptRequest
+ {
+ public static readonly RequestType Type = RequestType.Create("sqlProjects/addNoneScript");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/DeleteNoneScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/DeleteNoneScript.cs
new file mode 100644
index 00000000..6940569b
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/DeleteNoneScript.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
+{
+ ///
+ /// Delete a SQL object script from a project
+ ///
+ public class DeleteNoneScriptRequest
+ {
+ public static readonly RequestType Type = RequestType.Create("sqlProjects/deleteNoneScript");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/ExcludeNoneScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/ExcludeNoneScript.cs
new file mode 100644
index 00000000..c96d1bda
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/ExcludeNoneScript.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 SQL object script from a project
+ ///
+ public class ExcludeNoneScriptRequest
+ {
+ public static readonly RequestType Type = RequestType.Create("sqlProjects/excludeNoneScript");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/GetNoneScripts.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/GetNoneScripts.cs
new file mode 100644
index 00000000..b2eeef89
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/GetNoneScripts.cs
@@ -0,0 +1,16 @@
+//
+// 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;
+
+namespace Microsoft.SqlTools.ServiceLayer.SqlProjects.Contracts
+{
+ public class GetNoneScriptsRequest
+ {
+ public static readonly RequestType Type = RequestType.Create("sqlProjects/getNoneScripts");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/MoveNoneScript.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/MoveNoneScript.cs
new file mode 100644
index 00000000..72835c91
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/NoneScripts/MoveNoneScript.cs
@@ -0,0 +1,20 @@
+//
+// 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
+{
+ ///
+ /// Move a SQL object script in a project
+ ///
+ public class MoveNoneScriptRequest
+ {
+ public static readonly RequestType Type = RequestType.Create("sqlProjects/moveNoneScript");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
index b73d66f7..66a4a1a4 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
@@ -67,6 +67,13 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
serviceHost.SetRequestHandler(ExcludePostDeploymentScriptRequest.Type, HandleExcludePostDeploymentScriptRequest, isParallelProcessingSupported: false);
serviceHost.SetRequestHandler(MovePostDeploymentScriptRequest.Type, HandleMovePostDeploymentScriptRequest, isParallelProcessingSupported: false);
+ // None script functions
+ serviceHost.SetRequestHandler(GetNoneScriptsRequest.Type, HandleGetNoneScriptsRequest, isParallelProcessingSupported: true);
+ serviceHost.SetRequestHandler(AddNoneScriptRequest.Type, HandleAddNoneScriptRequest, isParallelProcessingSupported: false);
+ serviceHost.SetRequestHandler(DeleteNoneScriptRequest.Type, HandleDeleteNoneScriptRequest, isParallelProcessingSupported: false);
+ serviceHost.SetRequestHandler(ExcludeNoneScriptRequest.Type, HandleExcludeNoneScriptRequest, isParallelProcessingSupported: false);
+ serviceHost.SetRequestHandler(MoveNoneScriptRequest.Type, HandleMoveNoneScriptRequest, isParallelProcessingSupported: false);
+
// Folder functions
serviceHost.SetRequestHandler(GetFoldersRequest.Type, HandleGetFoldersRequest, isParallelProcessingSupported: true);
serviceHost.SetRequestHandler(AddFolderRequest.Type, HandleAddFolderRequest, isParallelProcessingSupported: false);
@@ -237,6 +244,43 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
#endregion
+ #region None script functions
+
+ internal async Task HandleGetNoneScriptsRequest(SqlProjectParams requestParams, RequestContext requestContext)
+ {
+ await RunWithErrorHandling(() =>
+ {
+ return new GetScriptsResult()
+ {
+ Success = true,
+ ErrorMessage = null,
+ Scripts = GetProject(requestParams.ProjectUri).NoneScripts.Select(x => x.Path).ToArray()
+ };
+ }, requestContext);
+ }
+
+ internal async Task HandleAddNoneScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext)
+ {
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).NoneScripts.Add(new NoneScript(requestParams.Path!)), requestContext);
+ }
+
+ internal async Task HandleDeleteNoneScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext)
+ {
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).NoneScripts.Delete(requestParams.Path!), requestContext);
+ }
+
+ internal async Task HandleExcludeNoneScriptRequest(SqlProjectScriptParams requestParams, RequestContext requestContext)
+ {
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).NoneScripts.Exclude(requestParams.Path!), requestContext);
+ }
+
+ internal async Task HandleMoveNoneScriptRequest(MoveItemParams requestParams, RequestContext requestContext)
+ {
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).NoneScripts.Move(requestParams.Path, requestParams.DestinationPath), requestContext);
+ }
+
+ #endregion
+
#region Folder functions
internal async Task HandleGetFoldersRequest(SqlProjectParams requestParams, RequestContext requestContext)
@@ -370,7 +414,6 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
#endregion
-
#region SQLCMD variable functions
internal async Task HandleGetSqlCmdVariablesRequest(SqlProjectParams requestParams, RequestContext requestContext)
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
index 86f04e99..48b04201 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
@@ -189,6 +189,99 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects
Assert.IsFalse(File.Exists(movedScriptAbsolutePath), $"{movedScriptAbsolutePath} expected to have been deleted from disk");
}
+ [Test]
+ public async Task TestNoneScriptOperations()
+ {
+ // Setup
+ SqlProjectsService service = new();
+ string projectUri = await service.CreateSqlProject();
+ Assert.AreEqual(0, service.Projects[projectUri].NoneScripts.Count, "Baseline number of NoneScripts");
+
+ // Validate adding a None script
+ MockRequest requestMock = new();
+ string relativePath = "NoneIncludeFile.json";
+ string absolutePath = Path.Join(Path.GetDirectoryName(projectUri), relativePath);
+
+ #pragma warning disable JSON002 // Probable JSON string detected
+ await File.WriteAllTextAsync(absolutePath, @"{""included"" : false }");
+ #pragma warning restore JSON002 // Probable JSON string detected
+
+ Assert.IsTrue(File.Exists(absolutePath), $"{absolutePath} expected to be on disk");
+
+ await service.HandleAddNoneScriptRequest(new SqlProjectScriptParams()
+ {
+ ProjectUri = projectUri,
+ Path = relativePath
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleAddNoneScriptRequest));
+ Assert.AreEqual(1, service.Projects[projectUri].NoneScripts.Count, "NoneScripts count after add");
+ Assert.IsTrue(service.Projects[projectUri].NoneScripts.Contains(relativePath), $"NoneScripts expected to contain {relativePath}");
+
+ // Validate getting a list of the None scripts
+ MockRequest getMock = new();
+ await service.HandleGetNoneScriptsRequest(new SqlProjectParams()
+ {
+ ProjectUri = projectUri
+ }, getMock.Object);
+
+ getMock.AssertSuccess(nameof(service.HandleGetNoneScriptsRequest));
+ Assert.AreEqual(1, getMock.Result.Scripts.Length);
+ Assert.AreEqual(relativePath, getMock.Result.Scripts[0]);
+
+ // Validate excluding a None script
+ requestMock = new();
+ await service.HandleExcludeNoneScriptRequest(new SqlProjectScriptParams()
+ {
+ ProjectUri = projectUri,
+ Path = relativePath
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleExcludeNoneScriptRequest));
+ Assert.AreEqual(0, service.Projects[projectUri].NoneScripts.Count, "NoneScripts count after exclude");
+ Assert.IsTrue(File.Exists(absolutePath), $"{absolutePath} expected to still exist on disk");
+
+ // Re-add to set up for Delete
+ requestMock = new();
+ await service.HandleAddNoneScriptRequest(new SqlProjectScriptParams()
+ {
+ ProjectUri = projectUri,
+ Path = relativePath
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleAddNoneScriptRequest));
+ Assert.AreEqual(1, service.Projects[projectUri].NoneScripts.Count, "NoneScripts count after re-add");
+
+ // Validate moving a None script
+ string movedScriptRelativePath = @"SubPath\RenamedNoneIncludeFile.json";
+ string movedScriptAbsolutePath = Path.Join(Path.GetDirectoryName(projectUri), movedScriptRelativePath);
+ Directory.CreateDirectory(Path.GetDirectoryName(movedScriptAbsolutePath)!);
+
+ requestMock = new();
+ await service.HandleMoveNoneScriptRequest(new MoveItemParams()
+ {
+ ProjectUri = projectUri,
+ Path = relativePath,
+ DestinationPath = movedScriptRelativePath
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleMoveNoneScriptRequest));
+ Assert.IsTrue(File.Exists(movedScriptAbsolutePath), "Script should exist at new location");
+ Assert.AreEqual(1, service.Projects[projectUri].NoneScripts.Count, "NoneScripts count after move");
+
+ // Validate deleting a None script
+ requestMock = new();
+ await service.HandleDeleteNoneScriptRequest(new SqlProjectScriptParams()
+ {
+ ProjectUri = projectUri,
+ Path = movedScriptRelativePath
+ }, requestMock.Object);
+
+ requestMock.AssertSuccess(nameof(service.HandleDeleteNoneScriptRequest));
+ Assert.AreEqual(0, service.Projects[projectUri].NoneScripts.Count, "NoneScripts count after delete");
+ Assert.IsFalse(File.Exists(movedScriptAbsolutePath), $"{movedScriptAbsolutePath} expected to have been deleted from disk");
+ }
+
[Test]
public async Task TestPreDeploymentScriptOperations()
{