mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-13 17:23:02 -05:00
Adds support for checking and updating cross-compatibility for SQL Projects (#1847)
* Adding cross-platform check and update * Checkpoint * checkpoint * Updating for latest nuget package * Correctly typing the result object
This commit is contained in:
@@ -20,8 +20,8 @@
|
||||
|
||||
<PackageReference Update="Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider" Version="1.1.1" />
|
||||
<PackageReference Update="Microsoft.SqlServer.Management.SmoMetadataProvider" Version="170.12.0" />
|
||||
<PackageReference Update="Microsoft.SqlServer.DacFx" Version="161.8055.0-preview" />
|
||||
<PackageReference Update="Microsoft.SqlServer.DacFx.Projects" Version="161.8056.0-alpha" />
|
||||
<PackageReference Update="Microsoft.SqlServer.DacFx" Version="161.8085.0-preview" />
|
||||
<PackageReference Update="Microsoft.SqlServer.DacFx.Projects" Version="161.8086.0-alpha" />
|
||||
<PackageReference Update="Microsoft.Azure.Kusto.Data" Version="9.0.4" />
|
||||
<PackageReference Update="Microsoft.Azure.Kusto.Language" Version="9.0.4" />
|
||||
<PackageReference Update="Microsoft.SqlServer.Assessment" Version="[1.1.17]" />
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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<SqlProjectParams, GetCrossPlatformCompatiblityResult> Type = RequestType<SqlProjectParams, GetCrossPlatformCompatiblityResult>.Create("sqlProjects/getCrossPlatformCompatibility");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result containing whether the project is cross-platform compatible
|
||||
/// </summary>
|
||||
public class GetCrossPlatformCompatiblityResult : ResultStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the project is cross-platform compatible
|
||||
/// </summary>
|
||||
public bool IsCrossPlatformCompatible { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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<SqlProjectParams, ResultStatus> Type = RequestType<SqlProjectParams, ResultStatus>.Create("sqlProjects/updateProjectForCrossPlatform");
|
||||
}
|
||||
}
|
||||
@@ -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<GetCrossPlatformCompatiblityResult> requestContext)
|
||||
{
|
||||
await RunWithErrorHandling(() =>
|
||||
{
|
||||
return new GetCrossPlatformCompatiblityResult()
|
||||
{
|
||||
Success = true,
|
||||
ErrorMessage = null,
|
||||
IsCrossPlatformCompatible = GetProject(requestParams.ProjectUri).CrossPlatformCompatible
|
||||
};
|
||||
}, requestContext);
|
||||
}
|
||||
|
||||
internal async Task HandleUpdateProjectForCrossPlatformRequest(SqlProjectParams requestParams, RequestContext<ResultStatus> 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<ResultStatus> 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<ResultStatus> 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<ResultStatus> requestContext)
|
||||
@@ -189,26 +216,67 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlProjects
|
||||
|
||||
#region Helper methods
|
||||
|
||||
/// <summary>
|
||||
/// Synchronous action with standard ResultStatus
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <param name="requestContext"></param>
|
||||
/// <returns></returns>
|
||||
private async Task RunWithErrorHandling(Action action, RequestContext<ResultStatus> requestContext)
|
||||
{
|
||||
await RunWithErrorHandling(async () => await Task.Run(action), requestContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronous action with standard ResultStatus
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <param name="requestContext"></param>
|
||||
/// <returns></returns>
|
||||
private async Task RunWithErrorHandling(Func<Task> action, RequestContext<ResultStatus> requestContext)
|
||||
{
|
||||
try
|
||||
await RunWithErrorHandling<ResultStatus>(async () =>
|
||||
{
|
||||
await action();
|
||||
|
||||
await requestContext.SendResult(new ResultStatus()
|
||||
return new ResultStatus()
|
||||
{
|
||||
Success = true,
|
||||
ErrorMessage = null
|
||||
});
|
||||
};
|
||||
}, requestContext);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Synchronous action with custom result
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="action"></param>
|
||||
/// <param name="requestContext"></param>
|
||||
/// <returns></returns>
|
||||
private async Task RunWithErrorHandling<T>(Func<T> action, RequestContext<T> requestContext) where T : ResultStatus, new()
|
||||
{
|
||||
await RunWithErrorHandling<T>(async () => await Task.Run(action), requestContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronous action with custom result
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="action"></param>
|
||||
/// <param name="requestContext"></param>
|
||||
/// <returns></returns>
|
||||
private async Task RunWithErrorHandling<T>(Func<Task<T>> action, RequestContext<T> 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
|
||||
|
||||
@@ -57,5 +57,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="SchemaCompare\SqlProjects\emptyTemplate.sqlproj" />
|
||||
<None Include="SqlProjects\Inputs\SSDTProject.sqlproj">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<Name>TestProjectLegacyNetFramework</Name>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectVersion>4.1</ProjectVersion>
|
||||
<ProjectGuid>{BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575}</ProjectGuid>
|
||||
<DSP>Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider</DSP>
|
||||
<OutputType>Database</OutputType>
|
||||
<RootPath>
|
||||
</RootPath>
|
||||
<RootNamespace>TestProjectLegacyNetFramework</RootNamespace>
|
||||
<AssemblyName>TestProjectLegacyNetFramework</AssemblyName>
|
||||
<ModelCollation>1033, CI</ModelCollation>
|
||||
<DefaultFileStructure>BySchemaAndSchemaType</DefaultFileStructure>
|
||||
<DeployToDatabase>True</DeployToDatabase>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<TargetLanguage>CS</TargetLanguage>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<SqlServerVerification>False</SqlServerVerification>
|
||||
<IncludeCompositeObjects>True</IncludeCompositeObjects>
|
||||
<TargetDatabaseSet>True</TargetDatabaseSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>
|
||||
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<DefineDebug>false</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
|
||||
<!-- Default to the v11.0 targets path if the targets file for the current VS version is not found -->
|
||||
<SSDTExists Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets')">True</SSDTExists>
|
||||
<VisualStudioVersion Condition="'$(SSDTExists)' == ''">11.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Condition="'$(SQLDBExtensionsRefPath)' != ''" Project="$(SQLDBExtensionsRefPath)\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
|
||||
<Import Condition="'$(SQLDBExtensionsRefPath)' == ''" Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ArtifactReference Include="$(DacPacRootPath)\Extensions\Microsoft\SQLDB\Extensions\SqlServer\150\SqlSchemas\master.dacpac">
|
||||
<HintPath>$(DacPacRootPath)\Extensions\Microsoft\SQLDB\Extensions\SqlServer\150\SqlSchemas\master.dacpac</HintPath>
|
||||
<SuppressMissingDependenciesErrors>False</SuppressMissingDependenciesErrors>
|
||||
<DatabaseVariableLiteralValue>master</DatabaseVariableLiteralValue>
|
||||
</ArtifactReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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<GetCrossPlatformCompatiblityResult> 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<ResultStatus> 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
|
||||
|
||||
Reference in New Issue
Block a user