mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 18:47:57 -05:00
Add support to save publish profile (#1844)
* Add support to save publish profile * Address comments * Update dacfx nuget package version * Fix test * Address comments * Resolve package.props conflict * Add content verification in test and use handler methods instead of try-catch * Address comments
This commit is contained in:
@@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.DacFx.Contracts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Parameters for a DacFx save publish profile request.
|
||||||
|
/// </summary>
|
||||||
|
public class SavePublishProfileParams
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the profile path
|
||||||
|
/// </summary>
|
||||||
|
public string ProfilePath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets name for database
|
||||||
|
/// </summary>
|
||||||
|
public string? DatabaseName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets target connection string
|
||||||
|
/// </summary>
|
||||||
|
public string? ConnectionString { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets SQLCMD variables for deployment
|
||||||
|
/// </summary>
|
||||||
|
public IDictionary<string, string>? SqlCommandVariableValues { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the options for deployment
|
||||||
|
/// </summary>
|
||||||
|
public DeploymentOptions? DeploymentOptions { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the DacFx save publish profile request type
|
||||||
|
/// </summary>
|
||||||
|
class SavePublishProfileRequest
|
||||||
|
{
|
||||||
|
public static readonly RequestType<SavePublishProfileParams, ResultStatus> Type =
|
||||||
|
RequestType<SavePublishProfileParams, ResultStatus>.Create("dacfx/savePublishProfile");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -15,6 +15,7 @@ using Microsoft.SqlTools.ServiceLayer.Hosting;
|
|||||||
using Microsoft.SqlTools.ServiceLayer.TaskServices;
|
using Microsoft.SqlTools.ServiceLayer.TaskServices;
|
||||||
using Microsoft.SqlServer.Dac.Model;
|
using Microsoft.SqlServer.Dac.Model;
|
||||||
using DacTableDesigner = Microsoft.Data.Tools.Sql.DesignServices.TableDesigner.TableDesigner;
|
using DacTableDesigner = Microsoft.Data.Tools.Sql.DesignServices.TableDesigner.TableDesigner;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.DacFx
|
namespace Microsoft.SqlTools.ServiceLayer.DacFx
|
||||||
{
|
{
|
||||||
@@ -60,6 +61,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx
|
|||||||
serviceHost.SetRequestHandler(ParseTSqlScriptRequest.Type, this.HandleParseTSqlScriptRequest, true);
|
serviceHost.SetRequestHandler(ParseTSqlScriptRequest.Type, this.HandleParseTSqlScriptRequest, true);
|
||||||
serviceHost.SetRequestHandler(GenerateTSqlModelRequest.Type, this.HandleGenerateTSqlModelRequest, true);
|
serviceHost.SetRequestHandler(GenerateTSqlModelRequest.Type, this.HandleGenerateTSqlModelRequest, true);
|
||||||
serviceHost.SetRequestHandler(GetObjectsFromTSqlModelRequest.Type, this.HandleGetObjectsFromTSqlModelRequest, true);
|
serviceHost.SetRequestHandler(GetObjectsFromTSqlModelRequest.Type, this.HandleGetObjectsFromTSqlModelRequest, true);
|
||||||
|
serviceHost.SetRequestHandler(SavePublishProfileRequest.Type, this.HandleSavePublishProfileRequest, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -311,6 +313,36 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles request to save a publish profile
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task HandleSavePublishProfileRequest(SavePublishProfileParams parameters, RequestContext<ResultStatus> requestContext)
|
||||||
|
{
|
||||||
|
await BaseService.RunWithErrorHandling(() =>
|
||||||
|
{
|
||||||
|
if (parameters.ProfilePath != null)
|
||||||
|
{
|
||||||
|
DacProfile profile = new DacProfile();
|
||||||
|
profile.TargetDatabaseName = parameters.DatabaseName;
|
||||||
|
profile.TargetConnectionString = parameters.ConnectionString;
|
||||||
|
//TODO: Set deploy options to pass on to DacFx
|
||||||
|
|
||||||
|
if (parameters.SqlCommandVariableValues != null)
|
||||||
|
{
|
||||||
|
foreach (string key in parameters.SqlCommandVariableValues.Keys)
|
||||||
|
{
|
||||||
|
profile.DeployOptions.SqlCommandVariableValues[key] = parameters.SqlCommandVariableValues[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO: Add return from Save with success/fail status
|
||||||
|
profile.Save(parameters.ProfilePath);
|
||||||
|
}
|
||||||
|
}, requestContext);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
private void ExecuteOperation(DacFxOperation operation, DacFxParams parameters, string taskName, RequestContext<DacFxResult> requestContext)
|
private void ExecuteOperation(DacFxOperation operation, DacFxParams parameters, string taskName, RequestContext<DacFxResult> requestContext)
|
||||||
{
|
{
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ using Microsoft.SqlServer.Dac.Model;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Test.Common.RequestContextMocking;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DacFx
|
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DacFx
|
||||||
{
|
{
|
||||||
@@ -868,6 +870,37 @@ Streaming query statement contains a reference to missing output stream 'Missing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// <summary>
|
||||||
|
/// Verify that publish profile gets created and saved
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public async Task ValidateSavePublishProfile()
|
||||||
|
{
|
||||||
|
DacFxService service = new DacFxService();
|
||||||
|
string fileName = "validateSavePublishProfile.publish.xml";
|
||||||
|
string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "DacFxTest");
|
||||||
|
string profileFilePath = Path.Combine(folderPath, fileName);
|
||||||
|
string expectedFile = Path.Combine(publishProfileFolder, fileName);
|
||||||
|
|
||||||
|
var savePublishProfileParams = new SavePublishProfileParams
|
||||||
|
{
|
||||||
|
ProfilePath = profileFilePath,
|
||||||
|
DatabaseName = "testDb",
|
||||||
|
ConnectionString = "testConnString",
|
||||||
|
SqlCommandVariableValues = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ "testvar", "testval" }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MockRequest<ResultStatus> requestMock = new();
|
||||||
|
|
||||||
|
await service.HandleSavePublishProfileRequest(savePublishProfileParams, requestMock.Object);
|
||||||
|
requestMock.AssertSuccess(nameof(service.HandleSavePublishProfileRequest));
|
||||||
|
|
||||||
|
await VerifyContentAndCleanupAsync(expectedFile, profileFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
private bool ValidateStreamingJobErrors(ValidateStreamingJobResult expected, ValidateStreamingJobResult actual)
|
private bool ValidateStreamingJobErrors(ValidateStreamingJobResult expected, ValidateStreamingJobResult actual)
|
||||||
{
|
{
|
||||||
return expected.Success == actual.Success
|
return expected.Success == actual.Success
|
||||||
@@ -942,6 +975,24 @@ Streaming query statement contains a reference to missing output stream 'Missing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task VerifyContentAndCleanupAsync(string baselineFilePath, string outputFilePath)
|
||||||
|
{
|
||||||
|
// Verify it was created
|
||||||
|
Assert.True(File.Exists(outputFilePath), "The output file did not get generated.");
|
||||||
|
|
||||||
|
//Verify the contents are same
|
||||||
|
string baseline = await File.ReadAllTextAsync(baselineFilePath);
|
||||||
|
string output = await File.ReadAllTextAsync(outputFilePath);
|
||||||
|
|
||||||
|
Assert.That(output, Is.EqualTo(baseline), $"The output doesn't match the baseline. Expected {Environment.NewLine} {baseline} {Environment.NewLine} Actual {Environment.NewLine} {output}");
|
||||||
|
|
||||||
|
// Remove the file
|
||||||
|
if (File.Exists(outputFilePath))
|
||||||
|
{
|
||||||
|
File.Delete(outputFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verify expected and actual DeploymentOptions BooleanOptionsDictionary values
|
/// Verify expected and actual DeploymentOptions BooleanOptionsDictionary values
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetDatabaseName>testDb</TargetDatabaseName>
|
||||||
|
<TargetConnectionString>testConnString</TargetConnectionString>
|
||||||
|
<ProfileVersionNumber>1</ProfileVersionNumber>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<SqlCmdVariable Include="testvar">
|
||||||
|
<Value>testval</Value>
|
||||||
|
</SqlCmdVariable>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user