mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-17 02:51:45 -05:00
Schema Compare open SCMP file (#825)
* initial open scmp changes * more open scmp changes and adding tests * moving some common test code * simplify endpoint info parsing * addressing comments and moving more common test code * addressing comments
This commit is contained in:
@@ -21,7 +21,7 @@ using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
|||||||
using Microsoft.SqlTools.ServiceLayer.Metadata;
|
using Microsoft.SqlTools.ServiceLayer.Metadata;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Profiler;
|
using Microsoft.SqlTools.ServiceLayer.Profiler;
|
||||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||||
using Microsoft.SqlTools.ServiceLayer.SchemaCopmare;
|
using Microsoft.SqlTools.ServiceLayer.SchemaCompare;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Scripting;
|
using Microsoft.SqlTools.ServiceLayer.Scripting;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Security;
|
using Microsoft.SqlTools.ServiceLayer.Security;
|
||||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||||
@@ -119,7 +119,7 @@ namespace Microsoft.SqlTools.ServiceLayer
|
|||||||
CmsService.Instance.InitializeService(serviceHost);
|
CmsService.Instance.InitializeService(serviceHost);
|
||||||
serviceProvider.RegisterSingleService(CmsService.Instance);
|
serviceProvider.RegisterSingleService(CmsService.Instance);
|
||||||
|
|
||||||
SchemaCopmare.SchemaCompareService.Instance.InitializeService(serviceHost);
|
SchemaCompare.SchemaCompareService.Instance.InitializeService(serviceHost);
|
||||||
serviceProvider.RegisterSingleService(SchemaCompareService.Instance);
|
serviceProvider.RegisterSingleService(SchemaCompareService.Instance);
|
||||||
|
|
||||||
InitializeHostedServices(serviceProvider, serviceHost);
|
InitializeHostedServices(serviceProvider, serviceHost);
|
||||||
|
|||||||
@@ -2933,6 +2933,14 @@ namespace Microsoft.SqlTools.ServiceLayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string OpenScmpConnectionBasedModelParsingError
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Keys.GetString(Keys.OpenScmpConnectionBasedModelParsingError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string ConnectionServiceListDbErrorNotConnected(string uri)
|
public static string ConnectionServiceListDbErrorNotConnected(string uri)
|
||||||
{
|
{
|
||||||
return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri);
|
return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri);
|
||||||
@@ -4270,6 +4278,9 @@ namespace Microsoft.SqlTools.ServiceLayer
|
|||||||
public const string SchemaCompareExcludeIncludeNodeNotFound = "SchemaCompareExcludeIncludeNodeNotFound";
|
public const string SchemaCompareExcludeIncludeNodeNotFound = "SchemaCompareExcludeIncludeNodeNotFound";
|
||||||
|
|
||||||
|
|
||||||
|
public const string OpenScmpConnectionBasedModelParsingError = "OpenScmpConnectionBasedModelParsingError";
|
||||||
|
|
||||||
|
|
||||||
private Keys()
|
private Keys()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|||||||
@@ -1719,4 +1719,8 @@
|
|||||||
<value>Failed to find the specified change in the model</value>
|
<value>Failed to find the specified change in the model</value>
|
||||||
<comment></comment>
|
<comment></comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="OpenScmpConnectionBasedModelParsingError" xml:space="preserve">
|
||||||
|
<value>Error encountered while trying to parse connection information for endpoint '{0}' with error message '{1}'</value>
|
||||||
|
<comment></comment>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -796,4 +796,5 @@ ExtractInvalidVersion = Invalid version '{0}' passed. Version must be in the for
|
|||||||
############################################################################
|
############################################################################
|
||||||
# Schema Compare
|
# Schema Compare
|
||||||
PublishChangesTaskName = Apply schema compare changes
|
PublishChangesTaskName = Apply schema compare changes
|
||||||
SchemaCompareExcludeIncludeNodeNotFound = Failed to find the specified change in the model
|
SchemaCompareExcludeIncludeNodeNotFound = Failed to find the specified change in the model
|
||||||
|
OpenScmpConnectionBasedModelParsingError = Error encountered while trying to parse connection information for endpoint '{0}' with error message '{1}'
|
||||||
@@ -1996,6 +1996,11 @@
|
|||||||
<target state="new">Failed to find the specified change in the model</target>
|
<target state="new">Failed to find the specified change in the model</target>
|
||||||
<note></note>
|
<note></note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="OpenScmpConnectionBasedModelParsingError">
|
||||||
|
<source>Error encountered while trying to parse connection information for endpoint '{0}' with error message '{1}'</source>
|
||||||
|
<target state="new">Error encountered while trying to parse connection information for endpoint '{0}' with error message '{1}'</target>
|
||||||
|
<note></note>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
@@ -232,5 +232,20 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DeploymentOptions(DacDeployOptions options)
|
||||||
|
{
|
||||||
|
System.Reflection.PropertyInfo[] deploymentOptionsProperties = this.GetType().GetProperties();
|
||||||
|
|
||||||
|
foreach (var deployOptionsProp in deploymentOptionsProperties)
|
||||||
|
{
|
||||||
|
var prop = options.GetType().GetProperty(deployOptionsProp.Name);
|
||||||
|
|
||||||
|
if (prop != null)
|
||||||
|
{
|
||||||
|
deployOptionsProp.SetValue(this, prop.GetValue(options));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
//
|
||||||
|
// 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.TaskServices;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
|
||||||
|
{
|
||||||
|
public class SchemaCompareObjectId
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Name to create object identifier
|
||||||
|
/// </summary>
|
||||||
|
public string[] NameParts;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// sql object type
|
||||||
|
/// </summary>
|
||||||
|
public string SqlObjectType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameters for a schema compare open scmp file request.
|
||||||
|
/// </summary>
|
||||||
|
public class SchemaCompareOpenScmpParams
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// filepath of scmp
|
||||||
|
/// </summary>
|
||||||
|
public string filePath { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameters returned from a schema compare open scmp request.
|
||||||
|
/// </summary>
|
||||||
|
public class SchemaCompareOpenScmpResult : ResultStatus
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the current source endpoint info
|
||||||
|
/// </summary>
|
||||||
|
public SchemaCompareEndpointInfo SourceEndpointInfo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the current target endpoint info
|
||||||
|
/// </summary>
|
||||||
|
public SchemaCompareEndpointInfo TargetEndpointInfo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the original target name. This is the initial target name, not necessarily the same as TargetEndpointInfo if they were swapped
|
||||||
|
/// The original target name is used to determine whether to use ExcludedSourceElements or ExcludedTargetElements if source and target were swapped
|
||||||
|
/// </summary>
|
||||||
|
public string OriginalTargetName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the original target connection string. This is the initial target connection string, not necessarily the same as TargetEndpointInfo if they were swapped
|
||||||
|
/// The target connection string is necessary if the source and target are a dacpac and db with the same name
|
||||||
|
/// </summary>
|
||||||
|
public string OriginalTargetConnectionString { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the deployment options
|
||||||
|
/// </summary>
|
||||||
|
public DeploymentOptions DeploymentOptions { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the excluded source elements. This is based on the initial source, not necessarily the same as SourceEndpointInfo if they were swapped
|
||||||
|
/// </summary>
|
||||||
|
public List<SchemaCompareObjectId> ExcludedSourceElements { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the excluded target elements. This is based on the initial target, not necessarily the same as TargetEndpointInfo if they were swapped
|
||||||
|
/// </summary>
|
||||||
|
public List<SchemaCompareObjectId> ExcludedTargetElements { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the Schema Compare open scmp request type
|
||||||
|
/// </summary>
|
||||||
|
class SchemaCompareOpenScmpRequest
|
||||||
|
{
|
||||||
|
public static readonly RequestType<SchemaCompareOpenScmpParams, SchemaCompareOpenScmpResult> Type =
|
||||||
|
RequestType<SchemaCompareOpenScmpParams, SchemaCompareOpenScmpResult>.Create("schemaCompare/openScmp");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
//
|
//
|
||||||
using Microsoft.SqlServer.Dac.Compare;
|
using Microsoft.SqlServer.Dac.Compare;
|
||||||
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
|
||||||
using Microsoft.SqlTools.ServiceLayer.TaskServices;
|
using Microsoft.SqlTools.ServiceLayer.TaskServices;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -37,6 +38,11 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
|
|||||||
/// Connection uri
|
/// Connection uri
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string OwnerUri { get; set; }
|
public string OwnerUri { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Connection details
|
||||||
|
/// </summary>
|
||||||
|
public ConnectionDetails ConnectionDetails { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
using Microsoft.SqlServer.Dac;
|
||||||
|
using Microsoft.SqlServer.Dac.Compare;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.TaskServices;
|
||||||
|
using Microsoft.SqlTools.Utility;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Schema compare load scmp operation
|
||||||
|
/// </summary>
|
||||||
|
class SchemaCompareOpenScmpOperation : ITaskOperation
|
||||||
|
{
|
||||||
|
private CancellationTokenSource cancellation = new CancellationTokenSource();
|
||||||
|
private bool disposed = false;
|
||||||
|
|
||||||
|
public SqlTask SqlTask { get; set; }
|
||||||
|
|
||||||
|
public SchemaCompareOpenScmpParams Parameters { get; set; }
|
||||||
|
|
||||||
|
public SchemaCompareOpenScmpResult Result { get; private set; }
|
||||||
|
|
||||||
|
private XDocument scmpInfo { get; set; }
|
||||||
|
|
||||||
|
public SchemaCompareOpenScmpOperation(SchemaCompareOpenScmpParams parameters)
|
||||||
|
{
|
||||||
|
Validate.IsNotNull("parameters", parameters);
|
||||||
|
this.Parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CancellationToken CancellationToken { get { return this.cancellation.Token; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The error occurred during operation
|
||||||
|
/// </summary>
|
||||||
|
public string ErrorMessage { get; set; }
|
||||||
|
|
||||||
|
// The schema compare public api doesn't currently take a cancellation token so the operation can't be cancelled
|
||||||
|
public void Cancel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disposes the operation.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (!disposed)
|
||||||
|
{
|
||||||
|
this.Cancel();
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(TaskExecutionMode mode)
|
||||||
|
{
|
||||||
|
if (this.CancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
throw new OperationCanceledException(this.CancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SchemaComparison compare = new SchemaComparison(this.Parameters.filePath);
|
||||||
|
|
||||||
|
// load xml file because some parsing still needs to be done
|
||||||
|
this.scmpInfo = XDocument.Load(this.Parameters.filePath);
|
||||||
|
|
||||||
|
this.Result = new SchemaCompareOpenScmpResult()
|
||||||
|
{
|
||||||
|
DeploymentOptions = new DeploymentOptions(compare.Options),
|
||||||
|
Success = true,
|
||||||
|
SourceEndpointInfo = this.GetEndpointInfo(true, compare.Source),
|
||||||
|
TargetEndpointInfo = this.GetEndpointInfo(false, compare.Target),
|
||||||
|
OriginalTargetName = this.GetOriginalTargetName(),
|
||||||
|
OriginalTargetConnectionString = this.GetOriginalTargetConnectionString(),
|
||||||
|
ExcludedSourceElements = this.GetExcludedElements(compare.ExcludedSourceObjects),
|
||||||
|
ExcludedTargetElements = this.GetExcludedElements(compare.ExcludedTargetObjects)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
ErrorMessage = e.Message;
|
||||||
|
Logger.Write(TraceEventType.Error, string.Format("Schema compare open scmp operation failed with exception {0}", e));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SchemaCompareEndpointInfo GetEndpointInfo(bool source, SchemaCompareEndpoint endpoint)
|
||||||
|
{
|
||||||
|
SchemaCompareEndpointInfo endpointInfo = new SchemaCompareEndpointInfo();
|
||||||
|
|
||||||
|
// if the endpoint is a dacpac we don't need to parse the xml
|
||||||
|
SchemaCompareDacpacEndpoint dacpacEndpoint = endpoint as SchemaCompareDacpacEndpoint;
|
||||||
|
if (dacpacEndpoint != null)
|
||||||
|
{
|
||||||
|
endpointInfo.EndpointType = SchemaCompareEndpointType.Dacpac;
|
||||||
|
endpointInfo.PackageFilePath = dacpacEndpoint.FilePath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// need to parse xml to get connection string of database
|
||||||
|
var result = this.scmpInfo.Descendants("ConnectionBasedModelProvider");
|
||||||
|
string searchingFor = source ? "Source" : "Target";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
foreach (XElement node in result)
|
||||||
|
{
|
||||||
|
if (node.Parent.Name.ToString().Contains(searchingFor))
|
||||||
|
{
|
||||||
|
endpointInfo.ConnectionDetails = SchemaCompareService.ConnectionServiceInstance.ParseConnectionString(node.Value);
|
||||||
|
endpointInfo.ConnectionDetails.ConnectionString = node.Value;
|
||||||
|
endpointInfo.DatabaseName = endpointInfo.ConnectionDetails.DatabaseName;
|
||||||
|
endpointInfo.EndpointType = SchemaCompareEndpointType.Database;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
ErrorMessage = string.Format(SR.OpenScmpConnectionBasedModelParsingError, ((SchemaCompareDatabaseEndpoint)endpoint).DatabaseName,e.Message);
|
||||||
|
Logger.Write(TraceEventType.Error, string.Format("Schema compare open scmp operation failed during xml parsing with exception {0}", e.Message));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpointInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SchemaCompareObjectId> GetExcludedElements(IList<SchemaComparisonExcludedObjectId> excludedObjects)
|
||||||
|
{
|
||||||
|
List<SchemaCompareObjectId> excludedElements = new List<SchemaCompareObjectId>();
|
||||||
|
|
||||||
|
foreach (SchemaComparisonExcludedObjectId entry in excludedObjects)
|
||||||
|
{
|
||||||
|
excludedElements.Add(new SchemaCompareObjectId()
|
||||||
|
{
|
||||||
|
NameParts = entry.Identifier.Parts.Cast<string>().ToArray(),
|
||||||
|
SqlObjectType = entry.TypeName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return excludedElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The original target name is used to determine whether to use ExcludedSourceElements or ExcludedTargetElements if source and target were swapped
|
||||||
|
private string GetOriginalTargetName()
|
||||||
|
{
|
||||||
|
var result = this.scmpInfo.Descendants("PropertyElementName")
|
||||||
|
.Where(x => x.Element("Name").Value == "TargetDatabaseName")
|
||||||
|
.Select(x => x.Element("Value")).FirstOrDefault();
|
||||||
|
|
||||||
|
return result != null ? result.Value : string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The original target connection string is used if comparing a dacpac and db with the same name
|
||||||
|
private string GetOriginalTargetConnectionString()
|
||||||
|
{
|
||||||
|
var result = this.scmpInfo.Descendants("PropertyElementName")
|
||||||
|
.Where(x => x.Element("Name").Value == "TargetConnectionString")
|
||||||
|
.Select(x => x.Element("Value")).FirstOrDefault();
|
||||||
|
|
||||||
|
return result != null ? result.Value : string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,11 +10,10 @@ using Microsoft.SqlTools.ServiceLayer.TaskServices;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.SqlTools.ServiceLayer.SchemaCompare;
|
|
||||||
using Microsoft.SqlServer.Dac.Compare;
|
using Microsoft.SqlServer.Dac.Compare;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare
|
namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Main class for SchemaCompare service
|
/// Main class for SchemaCompare service
|
||||||
@@ -27,6 +26,9 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare
|
|||||||
private Lazy<ConcurrentDictionary<string, SchemaComparisonResult>> schemaCompareResults =
|
private Lazy<ConcurrentDictionary<string, SchemaComparisonResult>> schemaCompareResults =
|
||||||
new Lazy<ConcurrentDictionary<string, SchemaComparisonResult>>(() => new ConcurrentDictionary<string, SchemaComparisonResult>());
|
new Lazy<ConcurrentDictionary<string, SchemaComparisonResult>>(() => new ConcurrentDictionary<string, SchemaComparisonResult>());
|
||||||
|
|
||||||
|
// For testability
|
||||||
|
internal Task CurrentSchemaCompareTask;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the singleton instance object
|
/// Gets the singleton instance object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -46,8 +48,11 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare
|
|||||||
serviceHost.SetRequestHandler(SchemaComparePublishChangesRequest.Type, this.HandleSchemaComparePublishChangesRequest);
|
serviceHost.SetRequestHandler(SchemaComparePublishChangesRequest.Type, this.HandleSchemaComparePublishChangesRequest);
|
||||||
serviceHost.SetRequestHandler(SchemaCompareIncludeExcludeNodeRequest.Type, this.HandleSchemaCompareIncludeExcludeNodeRequest);
|
serviceHost.SetRequestHandler(SchemaCompareIncludeExcludeNodeRequest.Type, this.HandleSchemaCompareIncludeExcludeNodeRequest);
|
||||||
serviceHost.SetRequestHandler(SchemaCompareGetDefaultOptionsRequest.Type, this.HandleSchemaCompareGetDefaultOptionsRequest);
|
serviceHost.SetRequestHandler(SchemaCompareGetDefaultOptionsRequest.Type, this.HandleSchemaCompareGetDefaultOptionsRequest);
|
||||||
|
serviceHost.SetRequestHandler(SchemaCompareOpenScmpRequest.Type, this.HandleSchemaCompareOpenScmpRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles schema compare request
|
/// Handles schema compare request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -86,7 +91,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare
|
|||||||
Differences = operation.Differences
|
Differences = operation.Differences
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await requestContext.SendResult(new SchemaCompareResult()
|
await requestContext.SendResult(new SchemaCompareResult()
|
||||||
{
|
{
|
||||||
@@ -185,7 +190,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare
|
|||||||
operation = new SchemaCompareIncludeExcludeNodeOperation(parameters, compareResult);
|
operation = new SchemaCompareIncludeExcludeNodeOperation(parameters, compareResult);
|
||||||
|
|
||||||
operation.Execute(parameters.TaskExecutionMode);
|
operation.Execute(parameters.TaskExecutionMode);
|
||||||
|
|
||||||
await requestContext.SendResult(new ResultStatus()
|
await requestContext.SendResult(new ResultStatus()
|
||||||
{
|
{
|
||||||
Success = true,
|
Success = true,
|
||||||
@@ -227,6 +232,41 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles schema compare open SCMP request
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task HandleSchemaCompareOpenScmpRequest(SchemaCompareOpenScmpParams parameters, RequestContext<SchemaCompareOpenScmpResult> requestContext)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CurrentSchemaCompareTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
SchemaCompareOpenScmpOperation operation = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
operation = new SchemaCompareOpenScmpOperation(parameters);
|
||||||
|
operation.Execute(TaskExecutionMode.Execute);
|
||||||
|
|
||||||
|
await requestContext.SendResult(operation.Result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
await requestContext.SendResult(new SchemaCompareOpenScmpResult()
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
ErrorMessage = operation == null ? e.Message : operation.ErrorMessage,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
await requestContext.SendError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private SqlTaskManager SqlTaskManagerInstance
|
private SqlTaskManager SqlTaskManagerInstance
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Microsoft.SqlTools.ServiceLayer.SchemaCopmare;
|
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare
|
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// Copyright (c) Microsoft. All rights reserved.
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
//
|
//
|
||||||
|
using Microsoft.SqlServer.Dac.Compare;
|
||||||
using Microsoft.SqlTools.Hosting.Protocol;
|
using Microsoft.SqlTools.Hosting.Protocol;
|
||||||
using Microsoft.SqlTools.ServiceLayer.SchemaCompare;
|
using Microsoft.SqlTools.ServiceLayer.SchemaCompare;
|
||||||
using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts;
|
using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts;
|
||||||
@@ -495,5 +496,117 @@ CREATE TABLE [dbo].[table3]
|
|||||||
string afterIncludeScript = generateScriptOperation.ScriptGenerationResult.Script;
|
string afterIncludeScript = generateScriptOperation.ScriptGenerationResult.Script;
|
||||||
Assert.True(initialScript.Length == afterIncludeScript.Length, $"Changes should be same as inital since we included what we excluded, before {initialScript}, now {afterIncludeScript}");
|
Assert.True(initialScript.Length == afterIncludeScript.Length, $"Changes should be same as inital since we included what we excluded, before {initialScript}, now {afterIncludeScript}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verify opening an scmp comparing two databases
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public async void SchemaCompareOpenScmpDatabaseToDatabaseRequest()
|
||||||
|
{
|
||||||
|
await CreateAndOpenScmp(SchemaCompareEndpointType.Database, SchemaCompareEndpointType.Database);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verify opening an scmp comparing a dacpac and database
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public async void SchemaCompareOpenScmpDacpacToDatabaseRequest()
|
||||||
|
{
|
||||||
|
await CreateAndOpenScmp(SchemaCompareEndpointType.Dacpac, SchemaCompareEndpointType.Database);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verify opening an scmp comparing two dacpacs
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public async void SchemaCompareOpenScmpDacpacToDacpacRequest()
|
||||||
|
{
|
||||||
|
await CreateAndOpenScmp(SchemaCompareEndpointType.Dacpac, SchemaCompareEndpointType.Dacpac);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CreateAndOpenScmp(SchemaCompareEndpointType sourceEndpointType, SchemaCompareEndpointType targetEndpointType)
|
||||||
|
{
|
||||||
|
SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareOpenScmpSource");
|
||||||
|
SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareOpenScmpTarget");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SchemaCompareEndpoint sourceEndpoint = CreateSchemaCompareEndpoint(sourceDb, sourceEndpointType);
|
||||||
|
SchemaCompareEndpoint targetEndpoint = CreateSchemaCompareEndpoint(targetDb, targetEndpointType);
|
||||||
|
|
||||||
|
// create a comparison and exclude the first difference
|
||||||
|
SchemaComparison compare = new SchemaComparison(sourceEndpoint, targetEndpoint);
|
||||||
|
SchemaComparisonResult result = compare.Compare();
|
||||||
|
Assert.NotEmpty(result.Differences);
|
||||||
|
SchemaDifference difference = result.Differences.First();
|
||||||
|
if (difference.SourceObject != null)
|
||||||
|
{
|
||||||
|
compare.ExcludedSourceObjects.Add(new SchemaComparisonExcludedObjectId(difference.SourceObject.ObjectType, difference.SourceObject.Name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
compare.ExcludedSourceObjects.Add(new SchemaComparisonExcludedObjectId(difference.TargetObject.ObjectType, difference.TargetObject.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// save to scmp
|
||||||
|
string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest");
|
||||||
|
Directory.CreateDirectory(folderPath);
|
||||||
|
string filePath = Path.Combine(folderPath, string.Format("SchemaCompareOpenScmpTest{0}.scmp", DateTime.Now.ToFileTime()));
|
||||||
|
compare.SaveToFile(filePath);
|
||||||
|
Assert.True(File.Exists(filePath));
|
||||||
|
|
||||||
|
var schemaCompareOpenScmpParams = new SchemaCompareOpenScmpParams
|
||||||
|
{
|
||||||
|
filePath = filePath
|
||||||
|
};
|
||||||
|
|
||||||
|
SchemaCompareOpenScmpOperation schemaCompareOpenScmpOperation = new SchemaCompareOpenScmpOperation(schemaCompareOpenScmpParams);
|
||||||
|
schemaCompareOpenScmpOperation.Execute(TaskExecutionMode.Execute);
|
||||||
|
|
||||||
|
Assert.NotNull(schemaCompareOpenScmpOperation.Result);
|
||||||
|
Assert.True(schemaCompareOpenScmpOperation.Result.Success);
|
||||||
|
Assert.NotEmpty(schemaCompareOpenScmpOperation.Result.ExcludedSourceElements);
|
||||||
|
Assert.Equal(1, schemaCompareOpenScmpOperation.Result.ExcludedSourceElements.Count());
|
||||||
|
Assert.Empty(schemaCompareOpenScmpOperation.Result.ExcludedTargetElements);
|
||||||
|
Assert.Equal(targetDb.DatabaseName, schemaCompareOpenScmpOperation.Result.OriginalTargetName);
|
||||||
|
ValidateResultEndpointInfo(sourceEndpoint, schemaCompareOpenScmpOperation.Result.SourceEndpointInfo, sourceDb.ConnectionString);
|
||||||
|
ValidateResultEndpointInfo(targetEndpoint, schemaCompareOpenScmpOperation.Result.TargetEndpointInfo, targetDb.ConnectionString);
|
||||||
|
|
||||||
|
SchemaCompareTestUtils.VerifyAndCleanup(filePath);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
sourceDb.Cleanup();
|
||||||
|
targetDb.Cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SchemaCompareEndpoint CreateSchemaCompareEndpoint(SqlTestDb db, SchemaCompareEndpointType endpointType)
|
||||||
|
{
|
||||||
|
if (endpointType == SchemaCompareEndpointType.Dacpac)
|
||||||
|
{
|
||||||
|
string dacpacFilePath = SchemaCompareTestUtils.CreateDacpac(db);
|
||||||
|
return new SchemaCompareDacpacEndpoint(dacpacFilePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new SchemaCompareDatabaseEndpoint(db.ConnectionString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateResultEndpointInfo(SchemaCompareEndpoint originalEndpoint, SchemaCompareEndpointInfo resultEndpoint, string connectionString)
|
||||||
|
{
|
||||||
|
if (resultEndpoint.EndpointType == SchemaCompareEndpointType.Dacpac)
|
||||||
|
{
|
||||||
|
SchemaCompareDacpacEndpoint dacpacEndpoint = originalEndpoint as SchemaCompareDacpacEndpoint;
|
||||||
|
Assert.Equal(dacpacEndpoint.FilePath, resultEndpoint.PackageFilePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SchemaCompareDatabaseEndpoint databaseEndpoint = originalEndpoint as SchemaCompareDatabaseEndpoint;
|
||||||
|
Assert.Equal(databaseEndpoint.DatabaseName, resultEndpoint.DatabaseName);
|
||||||
|
Assert.Contains(resultEndpoint.ConnectionDetails.ConnectionString, connectionString); // connectionString has password but resultEndpoint doesn't
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user