diff --git a/Packages.props b/Packages.props
index 9b8c20d4..da22294c 100644
--- a/Packages.props
+++ b/Packages.props
@@ -20,8 +20,8 @@
-
-
+
+
diff --git a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8056.0-alpha.nupkg b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8056.0-alpha.nupkg
deleted file mode 100644
index 467c2e00..00000000
Binary files a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8056.0-alpha.nupkg and /dev/null differ
diff --git a/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8086.0-alpha.nupkg b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8086.0-alpha.nupkg
new file mode 100644
index 00000000..d9a24430
Binary files /dev/null and b/bin/nuget/Microsoft.SqlServer.DacFx.Projects.161.8086.0-alpha.nupkg differ
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/GetCrossPlatformCompatibility.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/GetCrossPlatformCompatibility.cs
new file mode 100644
index 00000000..cd6bbdd4
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/GetCrossPlatformCompatibility.cs
@@ -0,0 +1,28 @@
+//
+// 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
+{
+ public class GetCrossPlatformCompatiblityRequest
+ {
+ public static readonly RequestType Type = RequestType.Create("sqlProjects/getCrossPlatformCompatibility");
+ }
+
+ ///
+ /// Result containing whether the project is cross-platform compatible
+ ///
+ public class GetCrossPlatformCompatiblityResult : ResultStatus
+ {
+ ///
+ /// Whether the project is cross-platform compatible
+ ///
+ public bool IsCrossPlatformCompatible { get; set; }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/UpdateProjectForCrossPlatform.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/UpdateProjectForCrossPlatform.cs
new file mode 100644
index 00000000..2d43c692
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/Contracts/Projects/UpdateProjectForCrossPlatform.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 UpdateProjectForCrossPlatformRequest
+ {
+ public static readonly RequestType Type = RequestType.Create("sqlProjects/updateProjectForCrossPlatform");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
index 0d8b212f..091fb90b 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SqlProjects/SqlProjectsService.cs
@@ -44,6 +44,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
serviceHost.SetRequestHandler(OpenSqlProjectRequest.Type, HandleOpenSqlProjectRequest, isParallelProcessingSupported: true);
serviceHost.SetRequestHandler(CloseSqlProjectRequest.Type, HandleCloseSqlProjectRequest, isParallelProcessingSupported: true);
serviceHost.SetRequestHandler(NewSqlProjectRequest.Type, HandleNewSqlProjectRequest, isParallelProcessingSupported: true);
+ serviceHost.SetRequestHandler(GetCrossPlatformCompatiblityRequest.Type, HandleGetCrossPlatformCompatibilityRequest, isParallelProcessingSupported: true);
+ serviceHost.SetRequestHandler(UpdateProjectForCrossPlatformRequest.Type, HandleUpdateProjectForCrossPlatformRequest, isParallelProcessingSupported: false);
// SQL object script functions
serviceHost.SetRequestHandler(AddSqlObjectScriptRequest.Type, HandleAddSqlObjectScriptRequest, isParallelProcessingSupported: false);
@@ -78,12 +80,29 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
{
await RunWithErrorHandling(async () =>
{
- await SqlProject.CreateProjectAsync(requestParams.ProjectUri, requestParams.SqlProjectType, requestParams.DatabaseSchemaProvider);
+ await SqlProject.CreateProjectAsync(requestParams.ProjectUri, new CreateSqlProjectParams() { ProjectType = requestParams.SqlProjectType, DspVersion = requestParams.DatabaseSchemaProvider });
GetProject(requestParams.ProjectUri); // load into the cache
-
}, requestContext);
}
+ internal async Task HandleGetCrossPlatformCompatibilityRequest(SqlProjectParams requestParams, RequestContext requestContext)
+ {
+ await RunWithErrorHandling(() =>
+ {
+ return new GetCrossPlatformCompatiblityResult()
+ {
+ Success = true,
+ ErrorMessage = null,
+ IsCrossPlatformCompatible = GetProject(requestParams.ProjectUri).CrossPlatformCompatible
+ };
+ }, requestContext);
+ }
+
+ internal async Task HandleUpdateProjectForCrossPlatformRequest(SqlProjectParams requestParams, RequestContext requestContext)
+ {
+ await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).UpdateForCrossPlatform(), requestContext);
+ }
+
#endregion
#region SQL object script functions
@@ -119,25 +138,33 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
internal async Task HandleAddDacpacReferenceRequest(AddDacpacReferenceParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).DatabaseReferences.Add(
- new DacpacReference(
- requestParams.DacpacPath,
- requestParams.SuppressMissingDependencies,
- requestParams.DatabaseVariable,
- requestParams.ServerVariable)),
- requestContext);
+ await RunWithErrorHandling(() =>
+ {
+ SqlProject project = GetProject(requestParams.ProjectUri);
+
+ project.DatabaseReferences.Add(
+ new DacpacReference(
+ requestParams.DacpacPath,
+ requestParams.SuppressMissingDependencies,
+ project.SqlCmdVariables.Get(requestParams.DatabaseVariable),
+ project.SqlCmdVariables.Get(requestParams.ServerVariable)));
+ }, requestContext);
}
internal async Task HandleAddSqlProjectReferenceRequest(AddSqlProjectReferenceParams requestParams, RequestContext requestContext)
{
- await RunWithErrorHandling(() => GetProject(requestParams.ProjectUri).DatabaseReferences.Add(
- new SqlProjectReference(
- requestParams.ProjectPath,
- requestParams.ProjectGuid,
- requestParams.SuppressMissingDependencies,
- requestParams.DatabaseVariable,
- requestParams.ServerVariable)),
- requestContext);
+ await RunWithErrorHandling(() =>
+ {
+ SqlProject project = GetProject(requestParams.ProjectUri);
+
+ project.DatabaseReferences.Add(
+ new SqlProjectReference(
+ requestParams.ProjectPath,
+ requestParams.ProjectGuid,
+ requestParams.SuppressMissingDependencies,
+ project.SqlCmdVariables.Get(requestParams.DatabaseVariable),
+ project.SqlCmdVariables.Get(requestParams.ServerVariable)));
+ }, requestContext);
}
internal async Task HandleDeleteDatabaseReferenceRequest(DeleteDatabaseReferenceParams requestParams, RequestContext requestContext)
@@ -189,26 +216,67 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
#region Helper methods
+ ///
+ /// Synchronous action with standard ResultStatus
+ ///
+ ///
+ ///
+ ///
private async Task RunWithErrorHandling(Action action, RequestContext requestContext)
{
await RunWithErrorHandling(async () => await Task.Run(action), requestContext);
}
+ ///
+ /// Asynchronous action with standard ResultStatus
+ ///
+ ///
+ ///
+ ///
private async Task RunWithErrorHandling(Func action, RequestContext requestContext)
{
- try
+ await RunWithErrorHandling(async () =>
{
await action();
- await requestContext.SendResult(new ResultStatus()
+ return new ResultStatus()
{
Success = true,
ErrorMessage = null
- });
+ };
+ }, requestContext);
+ }
+
+
+ ///
+ /// Synchronous action with custom result
+ ///
+ ///
+ ///
+ ///
+ ///
+ private async Task RunWithErrorHandling(Func action, RequestContext requestContext) where T : ResultStatus, new()
+ {
+ await RunWithErrorHandling(async () => await Task.Run(action), requestContext);
+ }
+
+ ///
+ /// Asynchronous action with custom result
+ ///
+ ///
+ ///
+ ///
+ ///
+ private async Task RunWithErrorHandling(Func> action, RequestContext requestContext) where T : ResultStatus, new()
+ {
+ try
+ {
+ T result = await action();
+ await requestContext.SendResult(result);
}
catch (Exception ex)
{
- await requestContext.SendResult(new ResultStatus()
+ await requestContext.SendResult(new T()
{
Success = false,
ErrorMessage = ex.Message
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj
index 7eb7a671..edb2fd7d 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj
@@ -57,5 +57,8 @@
+
+ PreserveNewest
+
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/Inputs/SSDTProject.sqlproj b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/Inputs/SSDTProject.sqlproj
new file mode 100644
index 00000000..818fb5d1
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/Inputs/SSDTProject.sqlproj
@@ -0,0 +1,67 @@
+
+
+
+ Debug
+ AnyCPU
+ TestProjectLegacyNetFramework
+ 2.0
+ 4.1
+ {BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575}
+ Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider
+ Database
+
+
+ TestProjectLegacyNetFramework
+ TestProjectLegacyNetFramework
+ 1033, CI
+ BySchemaAndSchemaType
+ True
+ v4.7.2
+ CS
+ Properties
+ False
+ True
+ True
+
+
+ bin\Release\
+ $(MSBuildProjectName).sql
+ False
+ pdbonly
+ true
+ false
+ true
+ prompt
+ 4
+
+
+ bin\Debug\
+ $(MSBuildProjectName).sql
+ false
+ true
+ full
+ false
+ true
+ true
+ prompt
+ 4
+
+
+ 11.0
+
+ True
+ 11.0
+
+
+
+
+
+
+
+
+ $(DacPacRootPath)\Extensions\Microsoft\SQLDB\Extensions\SqlServer\150\SqlSchemas\master.dacpac
+ False
+ master
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
index 18e1e89d..5a90c422 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SqlProjects/SqlProjectsServiceTests.cs
@@ -3,8 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-#nullable disable
-
using System;
using System.IO;
using System.Linq;
@@ -192,7 +190,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects
Assert.AreEqual(1, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding system db reference");
SystemDatabaseReference systemDbRef = (SystemDatabaseReference)service.Projects[projectUri].DatabaseReferences.First(x => x is SystemDatabaseReference);
Assert.AreEqual(SystemDatabase.MSDB, systemDbRef.SystemDb, "Referenced system DB");
- Assert.AreEqual("$(EmEssDeeBee)", systemDbRef.DatabaseVariable);
+ Assert.AreEqual("$(EmEssDeeBee)", systemDbRef.DatabaseVariableLiteralName);
Assert.IsFalse(systemDbRef.SuppressMissingDependencies, nameof(systemDbRef.SuppressMissingDependencies));
// Validate adding a dacpac reference
@@ -212,8 +210,8 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects
Assert.AreEqual(2, service.Projects[projectUri].DatabaseReferences.Count, "Database references after adding dacpac reference");
DacpacReference dacpacRef = (DacpacReference)service.Projects[projectUri].DatabaseReferences.First(x => x is DacpacReference);
Assert.AreEqual(FileUtils.NormalizePath(mockReferencePath, PlatformID.Win32NT), dacpacRef.DacpacPath, "Referenced dacpac");
- Assert.AreEqual(databaseVar.Name, dacpacRef.DatabaseVariable);
- Assert.AreEqual(serverVar.Name, dacpacRef.ServerVariable);
+ Assert.AreEqual(databaseVar.Name, dacpacRef.DatabaseVariable.VarName);
+ Assert.AreEqual(serverVar.Name, dacpacRef.ServerVariable.VarName);
Assert.IsFalse(dacpacRef.SuppressMissingDependencies, nameof(dacpacRef.SuppressMissingDependencies));
// Validate adding a project reference
@@ -235,8 +233,8 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects
SqlProjectReference projectRef = (SqlProjectReference)service.Projects[projectUri].DatabaseReferences.First(x => x is SqlProjectReference);
Assert.AreEqual(mockReferencePath, projectRef.ProjectPath, "Referenced project");
Assert.AreEqual(TEST_GUID, projectRef.ProjectGuid, "Referenced project GUID");
- Assert.AreEqual(databaseVar.Name, projectRef.DatabaseVariable);
- Assert.AreEqual(serverVar.Name, projectRef.ServerVariable);
+ Assert.AreEqual(databaseVar.Name, projectRef.DatabaseVariable.VarName);
+ Assert.AreEqual(serverVar.Name, projectRef.ServerVariable.VarName);
Assert.IsFalse(projectRef.SuppressMissingDependencies, nameof(projectRef.SuppressMissingDependencies));
// Validate deleting a reference
@@ -337,6 +335,46 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SqlProjects
requestMock.AssertSuccess(nameof(service.HandleDeleteSqlCmdVariableRequest));
Assert.AreEqual(0, service.Projects[projectUri].SqlCmdVariables.Count, "Number of SQLCMD variables after deletion not as expected");
}
+
+ [Test]
+ public async Task TestCrossPlatformUpdates()
+ {
+ string inputProjectPath = Path.Join(Path.GetDirectoryName(typeof(SqlProjectsServiceTests).Assembly.Location), "SqlProjects", "Inputs", "SSDTProject.sqlproj");
+ string projectPath = Path.Join(TestContext.CurrentContext.GetTestWorkingFolder(), "SSDTProject.sqlproj");
+
+ Directory.CreateDirectory(Path.GetDirectoryName(projectPath)!);
+ File.Copy(inputProjectPath, projectPath);
+ SqlProjectsService service = new();
+
+ /// Validate that the cross-platform status can be fetched
+ MockRequest getRequestMock = new();
+ await service.HandleGetCrossPlatformCompatibilityRequest(new SqlProjectParams()
+ {
+ ProjectUri = projectPath
+ }, getRequestMock.Object);
+
+ getRequestMock.AssertSuccess(nameof(service.HandleGetCrossPlatformCompatibilityRequest));
+ Assert.IsFalse(getRequestMock.Result.IsCrossPlatformCompatible, "Input file should not be cross-platform compatible before conversion");
+
+ // Validate that the project can be updated
+ MockRequest updateRequestMock = new();
+ await service.HandleUpdateProjectForCrossPlatformRequest(new SqlProjectParams()
+ {
+ ProjectUri = projectPath,
+ }, updateRequestMock.Object);
+
+ updateRequestMock.AssertSuccess(nameof(service.HandleUpdateProjectForCrossPlatformRequest));
+
+ // Validate that the cross-platform status has changed
+ getRequestMock = new();
+ await service.HandleGetCrossPlatformCompatibilityRequest(new SqlProjectParams()
+ {
+ ProjectUri = projectPath
+ }, getRequestMock.Object);
+
+ getRequestMock.AssertSuccess(nameof(service.HandleGetCrossPlatformCompatibilityRequest));
+ Assert.IsTrue(((GetCrossPlatformCompatiblityResult)getRequestMock.Result).IsCrossPlatformCompatible, "Input file should be cross-platform compatible after conversion");
+ }
}
internal static class SqlProjectsExtensions