Applying Changes to SQL Database Projects and Using Projects in Comparison (#1282)

* passing initial testing

* update local project from database

* update local project

* update project from database

* update project from database

* update project from database

* update project from database

* update project from database

* update project from database

* update project from database

* update project from database

* update project from database

* update project from database

* Bump .net version

* PR feedback

Co-authored-by: Noureldine Yehia <t-nyehia@microsoft.com>
This commit is contained in:
Benjin Dubishar
2021-11-04 21:36:59 -04:00
committed by GitHub
parent eda47bc0a4
commit 6acda6e1e6
12 changed files with 1036 additions and 103 deletions

View File

@@ -13,7 +13,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
/// <summary>
/// Parameters for a schema compare generate script request.
/// </summary>
public class SchemaCompareGenerateScriptParams : SchemaComparePublishChangesParams
public class SchemaCompareGenerateScriptParams : SchemaComparePublishDatabaseChangesParams
{
}

View File

@@ -2,6 +2,7 @@
// 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;
@@ -9,9 +10,9 @@ using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
{
/// <summary>
/// Parameters for a schema compare publish changes request.
/// Parameters for a schema compare publish database changes request.
/// </summary>
public class SchemaComparePublishChangesParams
public class SchemaComparePublishDatabaseChangesParams
{
/// <summary>
/// Operation id of the schema compare operation
@@ -35,11 +36,11 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
}
/// <summary>
/// Defines the Schema Compare publish changes request type
/// Defines the Schema Compare publish database changes request type
/// </summary>
class SchemaComparePublishChangesRequest
class SchemaComparePublishDatabaseChangesRequest
{
public static readonly RequestType<SchemaComparePublishChangesParams, ResultStatus> Type =
RequestType<SchemaComparePublishChangesParams, ResultStatus>.Create("schemaCompare/publish");
public static readonly RequestType<SchemaComparePublishDatabaseChangesParams, ResultStatus> Type =
RequestType<SchemaComparePublishDatabaseChangesParams, ResultStatus>.Create("schemaCompare/publishDatabase");
}
}

View File

@@ -0,0 +1,47 @@
//
// 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.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
{
/// <summary>
/// Parameters for a schema compare publish project changes request.
/// </summary>
public class SchemaComparePublishProjectChangesParams
{
/// <summary>
/// Operation id of the schema compare operation
/// </summary>
public string OperationId { get; set; }
/// <summary>
/// Path of project folder
/// </summary>
public string TargetProjectPath { get; set; }
/// <summary>
/// folder structure of target folder
/// </summary>
public DacExtractTarget TargetFolderStructure { get; set; }
/// <summary>
/// Execution mode for the operation. Default is execution
/// </summary>
public TaskExecutionMode TaskExecutionMode { get; set; }
}
/// <summary>
/// Defines the Schema Compare publish project changes request type
/// </summary>
class SchemaComparePublishProjectChangesRequest
{
public static readonly RequestType<SchemaComparePublishProjectChangesParams, SchemaComparePublishProjectResult> Type =
RequestType<SchemaComparePublishProjectChangesParams, SchemaComparePublishProjectResult>.Create("schemaCompare/publishProject");
}
}

View File

@@ -12,12 +12,19 @@ using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
{
/// <summary>
/// Types of schema compare endpoints
/// </summary>
public enum SchemaCompareEndpointType
{
Database,
Project,
Dacpac
}
/// <summary>
/// Info needed from endpoints for schema comparison
/// </summary>
public class SchemaCompareEndpointInfo
{
/// <summary>
@@ -25,6 +32,21 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
/// </summary>
public SchemaCompareEndpointType EndpointType { get; set; }
/// <summary>
/// Gets or sets the project file path
/// </summary>
public string ProjectFilePath { get; set; }
/// <summary>
/// Gets or sets the scripts included in project
/// </summary>
public string[] TargetScripts { get; set; }
/// <summary>
/// Gets or sets the project data schema provider
/// </summary>
public string DataSchemaProvider { get; set; }
/// <summary>
/// Gets or sets package filepath
/// </summary>

View File

@@ -100,13 +100,17 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
{
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)
// if the endpoint is a dacpac or a project we don't need to parse the xml
if (endpoint is SchemaCompareDacpacEndpoint dacpacEndpoint)
{
endpointInfo.EndpointType = SchemaCompareEndpointType.Dacpac;
endpointInfo.PackageFilePath = dacpacEndpoint.FilePath;
}
else if (endpoint is SchemaCompareProjectEndpoint projectEndpoint)
{
endpointInfo.EndpointType = SchemaCompareEndpointType.Project;
endpointInfo.ProjectFilePath = projectEndpoint.ProjectFilePath;
}
else
{
// need to parse xml to get connection string of database
@@ -131,7 +135,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
}
catch (Exception e)
{
ErrorMessage = string.Format(SR.OpenScmpConnectionBasedModelParsingError, ((SchemaCompareDatabaseEndpoint)endpoint).DatabaseName,e.Message);
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;
}

View File

@@ -2,79 +2,38 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Threading;
using Microsoft.SqlServer.Dac.Compare;
using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
using Microsoft.SqlTools.Utility;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
{
/// <summary>
/// Class to represent an in-progress schema compare publish changes operation
/// </summary>
class SchemaComparePublishChangesOperation : ITaskOperation
abstract class SchemaComparePublishChangesOperation : ITaskOperation
{
private CancellationTokenSource cancellation = new CancellationTokenSource();
/// <summary>
/// Gets the unique id associated with this instance.
/// </summary>
public string OperationId { get; private set; }
public SchemaComparePublishChangesParams Parameters { get; }
protected CancellationToken CancellationToken { get { return this.cancellation.Token; } }
public string ErrorMessage { get; set; }
public SqlTask SqlTask { get; set; }
public SchemaComparisonResult ComparisonResult { get; set; }
public SchemaComparePublishResult PublishResult { get; set; }
public string ErrorMessage { get; set; }
public SchemaComparePublishChangesOperation(SchemaComparePublishChangesParams parameters, SchemaComparisonResult comparisonResult)
protected CancellationToken CancellationToken { get { return cancellation.Token; } }
protected readonly CancellationTokenSource cancellation = new();
public SchemaComparePublishChangesOperation(SchemaComparisonResult comparisonResult)
{
Validate.IsNotNull("parameters", parameters);
this.Parameters = parameters;
Validate.IsNotNull("comparisonResult", comparisonResult);
this.ComparisonResult = comparisonResult;
Validate.IsNotNull(nameof(comparisonResult), comparisonResult);
ComparisonResult = comparisonResult;
}
public abstract void Execute(TaskExecutionMode mode);
public void Execute(TaskExecutionMode mode)
{
if (this.CancellationToken.IsCancellationRequested)
{
throw new OperationCanceledException(this.CancellationToken);
}
try
{
this.PublishResult = this.ComparisonResult.PublishChangesToTarget(this.CancellationToken);
if (!this.PublishResult.Success)
{
// Sending only errors and warnings - because overall message might be too big for task view
ErrorMessage = string.Join(Environment.NewLine, this.PublishResult.Errors.Where(x => x.MessageType == SqlServer.Dac.DacMessageType.Error || x.MessageType == SqlServer.Dac.DacMessageType.Warning));
throw new Exception(ErrorMessage);
}
}
catch (Exception e)
{
ErrorMessage = e.Message;
Logger.Write(TraceEventType.Error, string.Format("Schema compare publish changes operation {0} failed with exception {1}", this.OperationId, e.Message));
throw;
}
}
// The schema compare public api doesn't currently take a cancellation token so the operation can't be cancelled
public void Cancel()
{
this.cancellation.Cancel();
cancellation.Cancel();
}
}
}

View File

@@ -0,0 +1,56 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.SqlServer.Dac.Compare;
using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
using Microsoft.SqlTools.Utility;
using Microsoft.SqlServer.Dac;
namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
{
/// <summary>
/// Class to represent an in-progress schema compare publish database changes operation
/// </summary>
class SchemaComparePublishDatabaseChangesOperation : SchemaComparePublishChangesOperation
{
public SchemaComparePublishDatabaseChangesParams Parameters { get; }
public SchemaComparePublishResult PublishResult { get; set; }
public SchemaComparePublishDatabaseChangesOperation(SchemaComparePublishDatabaseChangesParams parameters, SchemaComparisonResult comparisonResult) : base(comparisonResult)
{
Validate.IsNotNull(nameof(parameters), parameters);
Parameters = parameters;
}
public override void Execute(TaskExecutionMode mode)
{
CancellationToken.ThrowIfCancellationRequested();
try
{
PublishResult = ComparisonResult.PublishChangesToDatabase(CancellationToken);
if (!PublishResult.Success)
{
// Sending only errors and warnings - because overall message might be too big for task view
ErrorMessage = String.Join(Environment.NewLine, this.PublishResult.Errors.Where(x => x.MessageType == SqlServer.Dac.DacMessageType.Error || x.MessageType == SqlServer.Dac.DacMessageType.Warning));
throw new DacServicesException(ErrorMessage);
}
}
catch (Exception e)
{
ErrorMessage = e.Message;
Logger.Write(TraceEventType.Error, string.Format("Schema compare publish database changes operation {0} failed with exception {1}", this.OperationId, e.Message));
throw;
}
}
}
}

View File

@@ -0,0 +1,57 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Diagnostics;
using System.Threading;
using Microsoft.SqlServer.Dac;
using Microsoft.SqlServer.Dac.Compare;
using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
{
/// <summary>
/// Class to represent an in-progress schema compare publish project changes operation
/// </summary>
class SchemaComparePublishProjectChangesOperation: SchemaComparePublishChangesOperation
{
public SchemaComparePublishProjectChangesParams Parameters { get; }
public SchemaComparePublishProjectResult PublishResult { get; set; }
public SchemaComparePublishProjectChangesOperation(SchemaComparePublishProjectChangesParams parameters, SchemaComparisonResult comparisonResult) : base(comparisonResult)
{
Validate.IsNotNull(nameof(parameters), parameters);
Parameters = parameters;
}
public override void Execute(TaskExecutionMode mode)
{
if (CancellationToken.IsCancellationRequested)
{
throw new OperationCanceledException(CancellationToken);
}
try
{
PublishResult = ComparisonResult.PublishChangesToProject(Parameters.TargetProjectPath, Parameters.TargetFolderStructure);
if (!PublishResult.Success)
{
ErrorMessage = PublishResult.ErrorMessage;
throw new DacServicesException(ErrorMessage);
}
}
catch (Exception e)
{
ErrorMessage = e.Message;
Logger.Write(TraceEventType.Error, string.Format("Schema compare publish project changes operation {0} failed with exception {1}", OperationId, e.Message));
throw;
}
}
}
}

View File

@@ -51,7 +51,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
serviceHost.SetRequestHandler(SchemaCompareRequest.Type, this.HandleSchemaCompareRequest);
serviceHost.SetRequestHandler(SchemaCompareCancellationRequest.Type, this.HandleSchemaCompareCancelRequest);
serviceHost.SetRequestHandler(SchemaCompareGenerateScriptRequest.Type, this.HandleSchemaCompareGenerateScriptRequest);
serviceHost.SetRequestHandler(SchemaComparePublishChangesRequest.Type, this.HandleSchemaComparePublishChangesRequest);
serviceHost.SetRequestHandler(SchemaComparePublishDatabaseChangesRequest.Type, this.HandleSchemaComparePublishDatabaseChangesRequest);
serviceHost.SetRequestHandler(SchemaComparePublishProjectChangesRequest.Type, this.HandleSchemaComparePublishProjectChangesRequest);
serviceHost.SetRequestHandler(SchemaCompareIncludeExcludeNodeRequest.Type, this.HandleSchemaCompareIncludeExcludeNodeRequest);
serviceHost.SetRequestHandler(SchemaCompareGetDefaultOptionsRequest.Type, this.HandleSchemaCompareGetDefaultOptionsRequest);
serviceHost.SetRequestHandler(SchemaCompareOpenScmpRequest.Type, this.HandleSchemaCompareOpenScmpRequest);
@@ -195,16 +196,16 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
}
/// <summary>
/// Handles request for schema compare publish changes script
/// Handles request for schema compare publish database changes script
/// </summary>
/// <returns></returns>
public async Task HandleSchemaComparePublishChangesRequest(SchemaComparePublishChangesParams parameters, RequestContext<ResultStatus> requestContext)
public async Task HandleSchemaComparePublishDatabaseChangesRequest(SchemaComparePublishDatabaseChangesParams parameters, RequestContext<ResultStatus> requestContext)
{
SchemaComparePublishChangesOperation operation = null;
SchemaComparePublishDatabaseChangesOperation operation = null;
try
{
SchemaComparisonResult compareResult = schemaCompareResults.Value[parameters.OperationId];
operation = new SchemaComparePublishChangesOperation(parameters, compareResult);
operation = new SchemaComparePublishDatabaseChangesOperation(parameters, compareResult);
SqlTask sqlTask = null;
TaskMetadata metadata = new TaskMetadata();
metadata.TaskOperation = operation;
@@ -222,7 +223,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
}
catch (Exception e)
{
Logger.Write(TraceEventType.Error, "Failed to publish schema compare changes. Error: " + e);
Logger.Write(TraceEventType.Error, "Failed to publish schema compare database changes. Error: " + e);
await requestContext.SendResult(new ResultStatus()
{
Success = false,
@@ -231,6 +232,51 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
}
}
/// <summary>
/// Handles request for schema compare publish database changes script
/// </summary>
/// <returns></returns>
public async Task HandleSchemaComparePublishProjectChangesRequest(SchemaComparePublishProjectChangesParams parameters, RequestContext<SchemaComparePublishProjectResult> requestContext)
{
SchemaComparePublishProjectChangesOperation operation = null;
try
{
SchemaComparisonResult compareResult = schemaCompareResults.Value[parameters.OperationId];
operation = new SchemaComparePublishProjectChangesOperation(parameters, compareResult);
TaskMetadata metadata = new()
{
TaskOperation = operation,
TargetLocation = parameters.TargetProjectPath,
Name = SR.PublishChangesTaskName
};
SqlTask sqlTask = SqlTaskManagerInstance.CreateTask<SqlTask>(metadata);
await sqlTask.RunAsync();
await requestContext.SendResult(new SchemaComparePublishProjectResult()
{
ChangedFiles = operation.PublishResult.ChangedFiles,
AddedFiles = operation.PublishResult.AddedFiles,
DeletedFiles = operation.PublishResult.DeletedFiles,
Success = true,
ErrorMessage = operation.ErrorMessage
});
}
catch (Exception e)
{
Logger.Write(TraceEventType.Error, "Failed to publish schema compare database changes. Error: " + e);
await requestContext.SendResult(new SchemaComparePublishProjectResult()
{
ChangedFiles = Array.Empty<string>(),
AddedFiles = Array.Empty<string>(),
DeletedFiles = Array.Empty<string>(),
Success = false,
ErrorMessage = operation?.ErrorMessage ?? e.Message
});
}
}
/// <summary>
/// Handles request for exclude incude node in Schema compare result
/// </summary>

View File

@@ -114,6 +114,10 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
{
switch (endpointInfo.EndpointType)
{
case SchemaCompareEndpointType.Project:
{
return new SchemaCompareProjectEndpoint(endpointInfo.ProjectFilePath, endpointInfo.TargetScripts, endpointInfo.DataSchemaProvider);
}
case SchemaCompareEndpointType.Dacpac:
{
return new SchemaCompareDacpacEndpoint(endpointInfo.PackageFilePath);