diff --git a/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/DeploymentOptions.cs b/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/DeploymentOptions.cs index 13027f3e..923d9ad6 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/DeploymentOptions.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/DeploymentOptions.cs @@ -2,192 +2,223 @@ // 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.ComponentModel; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.SqlServer.Dac; +using System.Reflection; +using System.Collections.Generic; namespace Microsoft.SqlTools.ServiceLayer.DacFx.Contracts { /// - /// Class to define deployment options. + /// Class to define deployment option default value and the description + /// + public class DeploymentOptionProperty + { + public DeploymentOptionProperty(T value, string description = "", string displayName = "") + { + this.Value = value; + this.Description = description; + this.DisplayName = displayName; + } + + // Default and selected value of the deployment options + public T Value { get; set; } + + // Description of the deployment options + public string Description { get; set; } = string.Empty; + + // To display the options in ADS extensions UI in SchemaCompare/SQL-DB-Project/Dacpac extensions + public string DisplayName { get; set; } + } + + /// + /// Class to define deployment options. /// Keeping the order and defaults same as DacFx /// The default values here should also match the default values in ADS UX + /// NOTE: When new deployment options are added in DacFx, they need to be added here too /// public class DeploymentOptions { #region Properties - public bool IgnoreTableOptions { get; set; } + public DeploymentOptionProperty IgnoreTableOptions { get; set; } - public bool IgnoreSemicolonBetweenStatements { get; set; } + public DeploymentOptionProperty IgnoreSemicolonBetweenStatements { get; set; } - public bool IgnoreRouteLifetime { get; set; } + public DeploymentOptionProperty IgnoreRouteLifetime { get; set; } - public bool IgnoreRoleMembership { get; set; } + public DeploymentOptionProperty IgnoreRoleMembership { get; set; } - public bool IgnoreQuotedIdentifiers { get; set; } + public DeploymentOptionProperty IgnoreQuotedIdentifiers { get; set; } - public bool IgnorePermissions { get; set; } + public DeploymentOptionProperty IgnorePermissions { get; set; } - public bool IgnorePartitionSchemes { get; set; } + public DeploymentOptionProperty IgnorePartitionSchemes { get; set; } - public bool IgnoreObjectPlacementOnPartitionScheme { get; set; } + public DeploymentOptionProperty IgnoreObjectPlacementOnPartitionScheme { get; set; } - public bool IgnoreNotForReplication { get; set; } + public DeploymentOptionProperty IgnoreNotForReplication { get; set; } - public bool IgnoreLoginSids { get; set; } + public DeploymentOptionProperty IgnoreLoginSids { get; set; } - public bool IgnoreLockHintsOnIndexes { get; set; } + public DeploymentOptionProperty IgnoreLockHintsOnIndexes { get; set; } - public bool IgnoreKeywordCasing { get; set; } + public DeploymentOptionProperty IgnoreKeywordCasing { get; set; } - public bool IgnoreIndexPadding { get; set; } + public DeploymentOptionProperty IgnoreIndexPadding { get; set; } - public bool IgnoreIndexOptions { get; set; } + public DeploymentOptionProperty IgnoreIndexOptions { get; set; } - public bool IgnoreIncrement { get; set; } + public DeploymentOptionProperty IgnoreIncrement { get; set; } - public bool IgnoreIdentitySeed { get; set; } + public DeploymentOptionProperty IgnoreIdentitySeed { get; set; } - public bool IgnoreUserSettingsObjects { get; set; } + public DeploymentOptionProperty IgnoreUserSettingsObjects { get; set; } - public bool IgnoreFullTextCatalogFilePath { get; set; } + public DeploymentOptionProperty IgnoreFullTextCatalogFilePath { get; set; } - public bool IgnoreWhitespace { get; set; } + public DeploymentOptionProperty IgnoreWhitespace { get; set; } - public bool IgnoreWithNocheckOnForeignKeys { get; set; } + public DeploymentOptionProperty IgnoreWithNocheckOnForeignKeys { get; set; } - public bool VerifyCollationCompatibility { get; set; } + public DeploymentOptionProperty VerifyCollationCompatibility { get; set; } - public bool UnmodifiableObjectWarnings { get; set; } + public DeploymentOptionProperty UnmodifiableObjectWarnings { get; set; } - public bool TreatVerificationErrorsAsWarnings { get; set; } + public DeploymentOptionProperty TreatVerificationErrorsAsWarnings { get; set; } - public bool ScriptRefreshModule { get; set; } + public DeploymentOptionProperty ScriptRefreshModule { get; set; } - public bool ScriptNewConstraintValidation { get; set; } + public DeploymentOptionProperty ScriptNewConstraintValidation { get; set; } - public bool ScriptFileSize { get; set; } + public DeploymentOptionProperty ScriptFileSize { get; set; } - public bool ScriptDeployStateChecks { get; set; } + public DeploymentOptionProperty ScriptDeployStateChecks { get; set; } - public bool ScriptDatabaseOptions { get; set; } + public DeploymentOptionProperty ScriptDatabaseOptions { get; set; } - public bool ScriptDatabaseCompatibility { get; set; } + public DeploymentOptionProperty ScriptDatabaseCompatibility { get; set; } - public bool ScriptDatabaseCollation { get; set; } + public DeploymentOptionProperty ScriptDatabaseCollation { get; set; } - public bool RunDeploymentPlanExecutors { get; set; } + public DeploymentOptionProperty RunDeploymentPlanExecutors { get; set; } - public bool RegisterDataTierApplication { get; set; } + public DeploymentOptionProperty RegisterDataTierApplication { get; set; } - public bool PopulateFilesOnFileGroups { get; set; } + public DeploymentOptionProperty PopulateFilesOnFileGroups { get; set; } - public bool NoAlterStatementsToChangeClrTypes { get; set; } + public DeploymentOptionProperty NoAlterStatementsToChangeClrTypes { get; set; } - public bool IncludeTransactionalScripts { get; set; } + public DeploymentOptionProperty IncludeTransactionalScripts { get; set; } - public bool IncludeCompositeObjects { get; set; } + public DeploymentOptionProperty IncludeCompositeObjects { get; set; } - public bool AllowUnsafeRowLevelSecurityDataMovement { get; set; } + public DeploymentOptionProperty AllowUnsafeRowLevelSecurityDataMovement { get; set; } - public bool IgnoreWithNocheckOnCheckConstraints { get; set; } + public DeploymentOptionProperty IgnoreWithNocheckOnCheckConstraints { get; set; } - public bool IgnoreFillFactor { get; set; } + public DeploymentOptionProperty IgnoreFillFactor { get; set; } - public bool IgnoreFileSize { get; set; } + public DeploymentOptionProperty IgnoreFileSize { get; set; } - public bool IgnoreFilegroupPlacement { get; set; } + public DeploymentOptionProperty IgnoreFilegroupPlacement { get; set; } - public bool DoNotAlterReplicatedObjects { get; set; } + public DeploymentOptionProperty DoNotAlterReplicatedObjects { get; set; } - public bool DoNotAlterChangeDataCaptureObjects { get; set; } + public DeploymentOptionProperty DoNotAlterChangeDataCaptureObjects { get; set; } - public bool DisableAndReenableDdlTriggers { get; set; } + public DeploymentOptionProperty DisableAndReenableDdlTriggers { get; set; } - public bool DeployDatabaseInSingleUserMode { get; set; } + public DeploymentOptionProperty DeployDatabaseInSingleUserMode { get; set; } - public bool CreateNewDatabase { get; set; } + public DeploymentOptionProperty CreateNewDatabase { get; set; } - public bool CompareUsingTargetCollation { get; set; } + public DeploymentOptionProperty CompareUsingTargetCollation { get; set; } - public bool CommentOutSetVarDeclarations { get; set; } + public DeploymentOptionProperty CommentOutSetVarDeclarations { get; set; } - public int CommandTimeout { get; set; } = 120; + // Command timeout to 120 seconds when executing queries against SQL Server. + public DeploymentOptionProperty CommandTimeout { get; set; } = new DeploymentOptionProperty(120); - public int LongRunningCommandTimeout { get; set; } = 0; + // LongRunningCommandTimeout 0 seconds to wait indefinitely. + public DeploymentOptionProperty LongRunningCommandTimeout { get; set; } = new DeploymentOptionProperty(0); - public int DatabaseLockTimeout { get; set; } = 60; + // Wait 60 seconds to lock database when executing queries against SQL Server. + public DeploymentOptionProperty DatabaseLockTimeout { get; set; } = new DeploymentOptionProperty(60); - public bool BlockWhenDriftDetected { get; set; } + public DeploymentOptionProperty BlockWhenDriftDetected { get; set; } - public bool BlockOnPossibleDataLoss { get; set; } + public DeploymentOptionProperty BlockOnPossibleDataLoss { get; set; } - public bool BackupDatabaseBeforeChanges { get; set; } + public DeploymentOptionProperty BackupDatabaseBeforeChanges { get; set; } - public bool AllowIncompatiblePlatform { get; set; } + public DeploymentOptionProperty AllowIncompatiblePlatform { get; set; } - public bool AllowDropBlockingAssemblies { get; set; } + public DeploymentOptionProperty AllowDropBlockingAssemblies { get; set; } - public string AdditionalDeploymentContributorArguments { get; set; } + public DeploymentOptionProperty AdditionalDeploymentContributorArguments { get; set; } - public string AdditionalDeploymentContributors { get; set; } + public DeploymentOptionProperty AdditionalDeploymentContributors { get; set; } - public bool DropConstraintsNotInSource { get; set; } + public DeploymentOptionProperty DropConstraintsNotInSource { get; set; } - public bool DropDmlTriggersNotInSource { get; set; } + public DeploymentOptionProperty DropDmlTriggersNotInSource { get; set; } - public bool DropExtendedPropertiesNotInSource { get; set; } + public DeploymentOptionProperty DropExtendedPropertiesNotInSource { get; set; } - public bool DropIndexesNotInSource { get; set; } + public DeploymentOptionProperty DropIndexesNotInSource { get; set; } - public bool IgnoreFileAndLogFilePath { get; set; } + public DeploymentOptionProperty IgnoreFileAndLogFilePath { get; set; } - public bool IgnoreExtendedProperties { get; set; } + public DeploymentOptionProperty IgnoreExtendedProperties { get; set; } - public bool IgnoreDmlTriggerState { get; set; } + public DeploymentOptionProperty IgnoreDmlTriggerState { get; set; } - public bool IgnoreDmlTriggerOrder { get; set; } + public DeploymentOptionProperty IgnoreDmlTriggerOrder { get; set; } - public bool IgnoreDefaultSchema { get; set; } + public DeploymentOptionProperty IgnoreDefaultSchema { get; set; } - public bool IgnoreDdlTriggerState { get; set; } + public DeploymentOptionProperty IgnoreDdlTriggerState { get; set; } - public bool IgnoreDdlTriggerOrder { get; set; } + public DeploymentOptionProperty IgnoreDdlTriggerOrder { get; set; } - public bool IgnoreCryptographicProviderFilePath { get; set; } + public DeploymentOptionProperty IgnoreCryptographicProviderFilePath { get; set; } - public bool VerifyDeployment { get; set; } + public DeploymentOptionProperty VerifyDeployment { get; set; } - public bool IgnoreComments { get; set; } + public DeploymentOptionProperty IgnoreComments { get; set; } - public bool IgnoreColumnCollation { get; set; } + public DeploymentOptionProperty IgnoreColumnCollation { get; set; } - public bool IgnoreAuthorizer { get; set; } + public DeploymentOptionProperty IgnoreAuthorizer { get; set; } - public bool IgnoreAnsiNulls { get; set; } + public DeploymentOptionProperty IgnoreAnsiNulls { get; set; } - public bool GenerateSmartDefaults { get; set; } + public DeploymentOptionProperty GenerateSmartDefaults { get; set; } - public bool DropStatisticsNotInSource { get; set; } + public DeploymentOptionProperty DropStatisticsNotInSource { get; set; } - public bool DropRoleMembersNotInSource { get; set; } + public DeploymentOptionProperty DropRoleMembersNotInSource { get; set; } - public bool DropPermissionsNotInSource { get; set; } + public DeploymentOptionProperty DropPermissionsNotInSource { get; set; } - public bool DropObjectsNotInSource { get; set; } + public DeploymentOptionProperty DropObjectsNotInSource { get; set; } - public bool IgnoreColumnOrder { get; set; } + public DeploymentOptionProperty IgnoreColumnOrder { get; set; } - public bool IgnoreTablePartitionOptions { get; set; } // DW Specific + public DeploymentOptionProperty IgnoreTablePartitionOptions { get; set; } // DW Specific - public string AdditionalDeploymentContributorPaths { get; set; } = string.Empty; + public DeploymentOptionProperty AdditionalDeploymentContributorPaths { get; set; } - public ObjectType[] DoNotDropObjectTypes { get; set; } = null; + public DeploymentOptionProperty DoNotDropObjectTypes { get; set; } - public ObjectType[] ExcludeObjectTypes { get; set; } = - { + public DeploymentOptionProperty ExcludeObjectTypes { get; set; } = new DeploymentOptionProperty + ( + new ObjectType[] { ObjectType.ServerTriggers, ObjectType.Routes, ObjectType.LinkedServerLogins, @@ -209,15 +240,172 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx.Contracts ObjectType.DatabaseOptions, ObjectType.EventNotifications, ObjectType.ServerRoleMembership, - ObjectType.AssemblyFiles, - }; + ObjectType.AssemblyFiles + } + ); + + public DeploymentOptionProperty AllowExternalLibraryPaths { get; set; } + + public DeploymentOptionProperty AllowExternalLanguagePaths { get; set; } + + public DeploymentOptionProperty DoNotEvaluateSqlCmdVariables { get; set; } + + public DeploymentOptionProperty DisableParallelismForEnablingIndexes { get; set; } + + public DeploymentOptionProperty DoNotDropWorkloadClassifiers { get; set; } + + public DeploymentOptionProperty DisableIndexesForDataPhase { get; set; } + + public DeploymentOptionProperty DoNotDropDatabaseWorkloadGroups { get; set; } + + public DeploymentOptionProperty HashObjectNamesInLogs { get; set; } + + public DeploymentOptionProperty IgnoreWorkloadClassifiers { get; set; } + + public DeploymentOptionProperty IgnoreDatabaseWorkloadGroups { get; set; } + + public DeploymentOptionProperty IsAlwaysEncryptedParameterizationEnabled { get; set; } + + public DeploymentOptionProperty PreserveIdentityLastValues { get; set; } + + public DeploymentOptionProperty RestoreSequenceCurrentValue { get; set; } + + public DeploymentOptionProperty RebuildIndexesOfflineForDataPhase { get; set; } + + private Dictionary _displayNameMapDict; #endregion + /// + /// Mapping the DisplayName to the dac deploy option + /// Adding new properties here would give easy handling of new option to all extensions + /// + private void SetDisplayNameForOption() + { + #region Display Name and Dac Options Mapping + DacDeployOptions d = new DacDeployOptions(); + _displayNameMapDict = new Dictionary(); + + // Ex: displayNameMapDict["DacFx Option Name"] = "ADS UI Display Name" + _displayNameMapDict[nameof(d.AdditionalDeploymentContributorArguments)] = "Additional Deployment Contributor Arguments"; + _displayNameMapDict[nameof(d.AdditionalDeploymentContributorPaths)] = "Additional Deployment Contributor Paths"; + _displayNameMapDict[nameof(d.AdditionalDeploymentContributors)] = "Additional Deployment Contributors"; + _displayNameMapDict[nameof(d.AllowDropBlockingAssemblies)] = "Allow Drop Blocking Assemblies"; + _displayNameMapDict[nameof(d.AllowExternalLanguagePaths)] = "Allow External Language Paths"; + _displayNameMapDict[nameof(d.AllowExternalLibraryPaths)] = "Allow External Library Paths"; + _displayNameMapDict[nameof(d.AllowIncompatiblePlatform)] = "Allow Incompatible Platform"; + _displayNameMapDict[nameof(d.AllowUnsafeRowLevelSecurityDataMovement)] = "Allow Unsafe RowLevel Security Data Movement"; + _displayNameMapDict[nameof(d.AzureSharedAccessSignatureToken)] = "Azure Shared Access Signature Token"; + _displayNameMapDict[nameof(d.AzureStorageBlobEndpoint)] = "Azure Storage Blob Endpoint"; + _displayNameMapDict[nameof(d.AzureStorageContainer)] = "Azure Storage Container"; + _displayNameMapDict[nameof(d.AzureStorageKey)] = "Azure Storage Key"; + _displayNameMapDict[nameof(d.AzureStorageRootPath)] = "Azure Storage Root Path"; + _displayNameMapDict[nameof(d.BackupDatabaseBeforeChanges)] = "Backup Database Before Changes"; + _displayNameMapDict[nameof(d.BlockOnPossibleDataLoss)] = "Block On Possible Data Loss"; + _displayNameMapDict[nameof(d.BlockWhenDriftDetected)] = "Block When Drift Detected"; + _displayNameMapDict[nameof(d.CommandTimeout)] = "Command Timeout"; + _displayNameMapDict[nameof(d.CommentOutSetVarDeclarations)] = "Comment Out SetVar Declarations"; + _displayNameMapDict[nameof(d.CompareUsingTargetCollation)] = "Compare Using Target Collation"; + _displayNameMapDict[nameof(d.CreateNewDatabase)] = "Create New Database"; + _displayNameMapDict[nameof(d.DatabaseLockTimeout)] = "Database Lock Timeout"; + _displayNameMapDict[nameof(d.DatabaseSpecification)] = "Database Specification"; + _displayNameMapDict[nameof(d.DataOperationStateProvider)] = "Data Operation State Provider"; + _displayNameMapDict[nameof(d.DeployDatabaseInSingleUserMode)] = "Deploy Database In Single User Mode"; + _displayNameMapDict[nameof(d.DisableAndReenableDdlTriggers)] = "Disable And Reenable Ddl Triggers"; + _displayNameMapDict[nameof(d.DisableIndexesForDataPhase)] = "Disable Indexes For Data Phase"; + _displayNameMapDict[nameof(d.DisableParallelismForEnablingIndexes)] = "Disable Parallelism For Enabling Indexes"; + _displayNameMapDict[nameof(d.DoNotAlterChangeDataCaptureObjects)] = "Do Not Alter Change Data Capture Objects"; + _displayNameMapDict[nameof(d.DoNotAlterReplicatedObjects)] = "Do Not Alter Replicated Objects"; + _displayNameMapDict[nameof(d.DoNotDropDatabaseWorkloadGroups)] = "Do Not Drop Database Workload Groups"; + _displayNameMapDict[nameof(d.DoNotDropObjectTypes)] = "Do Not Drop Object Types"; + _displayNameMapDict[nameof(d.DoNotDropWorkloadClassifiers)] = "Do Not Drop Workload Classifiers"; + _displayNameMapDict[nameof(d.DoNotEvaluateSqlCmdVariables)] = "Do Not Evaluate Sql Cmd Variables"; + _displayNameMapDict[nameof(d.DropConstraintsNotInSource)] = "Drop Constraints Not In Source"; + _displayNameMapDict[nameof(d.DropDmlTriggersNotInSource)] = "Drop Dml Triggers Not In Source"; + _displayNameMapDict[nameof(d.DropExtendedPropertiesNotInSource)] = "Drop Extended Properties Not In Source"; + _displayNameMapDict[nameof(d.DropIndexesNotInSource)] = "Drop Indexes Not In Source"; + _displayNameMapDict[nameof(d.DropObjectsNotInSource)] = "Drop Objects Not In Source"; + _displayNameMapDict[nameof(d.DropPermissionsNotInSource)] = "Drop Permissions Not In Source"; + _displayNameMapDict[nameof(d.DropRoleMembersNotInSource)] = "Drop Role Members Not In Source"; + _displayNameMapDict[nameof(d.DropStatisticsNotInSource)] = "Drop Statistics Not In Source"; + _displayNameMapDict[nameof(d.EnclaveAttestationProtocol)] = "Enclave Attestation Protocol"; + _displayNameMapDict[nameof(d.EnclaveAttestationUrl)] = "Enclave Attestation Url"; + _displayNameMapDict[nameof(d.ExcludeObjectTypes)] = "Exclude Object Types"; + _displayNameMapDict[nameof(d.GenerateSmartDefaults)] = "Generate Smart Defaults"; + _displayNameMapDict[nameof(d.HashObjectNamesInLogs)] = "Hash Object Names In Logs"; + _displayNameMapDict[nameof(d.IgnoreAnsiNulls)] = "Ignore Ansi Nulls"; + _displayNameMapDict[nameof(d.IgnoreAuthorizer)] = "Ignore Authorizer"; + _displayNameMapDict[nameof(d.IgnoreColumnCollation)] = "Ignore Column Collation"; + _displayNameMapDict[nameof(d.IgnoreColumnOrder)] = "Ignore Column Order"; + _displayNameMapDict[nameof(d.IgnoreComments)] = "Ignore Comments"; + _displayNameMapDict[nameof(d.IgnoreCryptographicProviderFilePath)] = "Ignore Cryptographic Provider File Path"; + _displayNameMapDict[nameof(d.IgnoreDatabaseWorkloadGroups)] = "Ignore Database Workload Groups"; + _displayNameMapDict[nameof(d.IgnoreDdlTriggerOrder)] = "Ignore Ddl Trigger Order"; + _displayNameMapDict[nameof(d.IgnoreDdlTriggerState)] = "Ignore Ddl Trigger State"; + _displayNameMapDict[nameof(d.IgnoreDefaultSchema)] = "Ignore Default Schema"; + _displayNameMapDict[nameof(d.IgnoreDmlTriggerOrder)] = "Ignore Dml Trigger Order"; + _displayNameMapDict[nameof(d.IgnoreDmlTriggerState)] = "Ignore Dml Trigger State"; + _displayNameMapDict[nameof(d.IgnoreExtendedProperties)] = "Ignore Extended Properties"; + _displayNameMapDict[nameof(d.IgnoreFileAndLogFilePath)] = "Ignore File And Log File Path"; + _displayNameMapDict[nameof(d.IgnoreFileSize)] = "Ignore File Size"; + _displayNameMapDict[nameof(d.IgnoreFilegroupPlacement)] = "Ignore File Group Placement"; + _displayNameMapDict[nameof(d.IgnoreFillFactor)] = "Ignore Fill Factor"; + _displayNameMapDict[nameof(d.IgnoreFullTextCatalogFilePath)] = "Ignore Full Text Catalog File Path"; + _displayNameMapDict[nameof(d.IgnoreIdentitySeed)] = "Ignore Identity Seed"; + _displayNameMapDict[nameof(d.IgnoreIncrement)] = "Ignore Increment"; + _displayNameMapDict[nameof(d.IgnoreIndexOptions)] = "Ignore Index Options"; + _displayNameMapDict[nameof(d.IgnoreIndexPadding)] = "Ignore Index Padding"; + _displayNameMapDict[nameof(d.IgnoreKeywordCasing)] = "Ignore Keyword Casing"; + _displayNameMapDict[nameof(d.IgnoreLockHintsOnIndexes)] = "IgnoreLock Hints On Indexes"; + _displayNameMapDict[nameof(d.IgnoreLoginSids)] = "IgnoreLogin Sids"; + _displayNameMapDict[nameof(d.IgnoreNotForReplication)] = "IgnoreNotForReplication"; + _displayNameMapDict[nameof(d.IgnoreObjectPlacementOnPartitionScheme)] = "Ignore Object Placement On Partition Scheme"; + _displayNameMapDict[nameof(d.IgnorePartitionSchemes)] = "Ignore Partition Schemes"; + _displayNameMapDict[nameof(d.IgnorePermissions)] = "Ignore Permissions"; + _displayNameMapDict[nameof(d.IgnoreQuotedIdentifiers)] = "Ignore Quoted Identifiers"; + _displayNameMapDict[nameof(d.IgnoreRoleMembership)] = "Ignore Role Membership"; + _displayNameMapDict[nameof(d.IgnoreRouteLifetime)] = "Ignore Route Lifetime"; + _displayNameMapDict[nameof(d.IgnoreSemicolonBetweenStatements)] = "Ignore Semicolon Between Statements"; + _displayNameMapDict[nameof(d.IgnoreTableOptions)] = "Ignore Table Options"; + _displayNameMapDict[nameof(d.IgnoreTablePartitionOptions)] = "Ignore Table Partition Options"; + _displayNameMapDict[nameof(d.IgnoreUserSettingsObjects)] = "Ignore User Settings Objects"; + _displayNameMapDict[nameof(d.IgnoreWhitespace)] = "Ignore Whitespace"; + _displayNameMapDict[nameof(d.IgnoreWithNocheckOnCheckConstraints)] = "Ignore With Nocheck On Check Constraints"; + _displayNameMapDict[nameof(d.IgnoreWithNocheckOnForeignKeys)] = "Ignore With Nocheck On Foreign Keys"; + _displayNameMapDict[nameof(d.IgnoreWorkloadClassifiers)] = "Ignore Workload Classifiers"; + _displayNameMapDict[nameof(d.IncludeCompositeObjects)] = "Include Composite Objects"; + _displayNameMapDict[nameof(d.IncludeTransactionalScripts)] = "Include Transactional Scripts"; + _displayNameMapDict[nameof(d.IsAlwaysEncryptedParameterizationEnabled)] = "Is Always Encrypted Parameterization Enabled"; + _displayNameMapDict[nameof(d.LongRunningCommandTimeout)] = "Long Running Command Timeout"; + _displayNameMapDict[nameof(d.NoAlterStatementsToChangeClrTypes)] = "No Alter Statements To Change Clr Types"; + _displayNameMapDict[nameof(d.PopulateFilesOnFileGroups)] = "Populate Files On File Groups"; + _displayNameMapDict[nameof(d.PreserveIdentityLastValues)] = "Preserve Identity Last Values"; + _displayNameMapDict[nameof(d.RebuildIndexesOfflineForDataPhase)] = "Rebuild Indexes Offline For Data Phase"; + _displayNameMapDict[nameof(d.RegisterDataTierApplication)] = "Register Data Tier Application"; + _displayNameMapDict[nameof(d.RestoreSequenceCurrentValue)] = "Restore Sequence Current Value"; + _displayNameMapDict[nameof(d.RunDeploymentPlanExecutors)] = "Run Deployment Plan Executors"; + _displayNameMapDict[nameof(d.ScriptDatabaseCollation)] = "Script Database Collation"; + _displayNameMapDict[nameof(d.ScriptDatabaseCompatibility)] = "Script Database Compatibility"; + _displayNameMapDict[nameof(d.ScriptDatabaseOptions)] = "Script Database Options"; + _displayNameMapDict[nameof(d.ScriptDeployStateChecks)] = "Script Deploy State Checks"; + _displayNameMapDict[nameof(d.ScriptFileSize)] = "Script File Size"; + _displayNameMapDict[nameof(d.ScriptNewConstraintValidation)] = "Script New Constraint Validation"; + _displayNameMapDict[nameof(d.ScriptRefreshModule)] = "Script Refresh Module"; + _displayNameMapDict[nameof(d.SqlCommandVariableValues)] = "Sql Command Variable Values"; + _displayNameMapDict[nameof(d.TreatVerificationErrorsAsWarnings)] = "Treat Verification Errors As Warnings"; + _displayNameMapDict[nameof(d.UnmodifiableObjectWarnings)] = "Unmodifiable Object Warnings"; + _displayNameMapDict[nameof(d.VerifyCollationCompatibility)] = "Verify Collation Compatibility"; + _displayNameMapDict[nameof(d.VerifyDeployment)] = "Verify Deployment"; + #endregion + } + public DeploymentOptions() { DacDeployOptions options = new DacDeployOptions(); + // Setting Display names for all dacDeploy options + SetDisplayNameForOption(); + // Adding these defaults to ensure behavior similarity with other tools. Dacfx and SSMS import/export wizards use these defaults. // Tracking the full fix : https://github.com/microsoft/azuredatastudio/issues/5599 options.AllowDropBlockingAssemblies = true; @@ -228,7 +416,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx.Contracts options.IgnoreKeywordCasing = false; options.IgnoreSemicolonBetweenStatements = false; - System.Reflection.PropertyInfo[] deploymentOptionsProperties = this.GetType().GetProperties(); + PropertyInfo[] deploymentOptionsProperties = this.GetType().GetProperties(); foreach (var deployOptionsProp in deploymentOptionsProperties) { @@ -237,13 +425,17 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx.Contracts // Note that we set excluded object types here since dacfx has this value as null; if (prop != null && deployOptionsProp.Name != "ExcludeObjectTypes") { - deployOptionsProp.SetValue(this, prop.GetValue(options)); + // Setting DacFx default values to the generic deployment options properties. + SetGenericDeployOptionProps(prop, options, deployOptionsProp); } } } public DeploymentOptions(DacDeployOptions options) { + // Setting Display names for all dacDeploy options + SetDisplayNameForOption(); + SetOptions(options); } @@ -295,14 +487,30 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx.Contracts foreach (var deployOptionsProp in deploymentOptionsProperties) { var prop = options.GetType().GetProperty(deployOptionsProp.Name); - + // Note that we set excluded object types here since dacfx has this value as null; if (prop != null) { - deployOptionsProp.SetValue(this, prop.GetValue(options)); + SetGenericDeployOptionProps(prop, options, deployOptionsProp); } } } + /// + /// Sets the Value and Description to all properties + /// + /// + /// + /// + public void SetGenericDeployOptionProps(PropertyInfo prop, DacDeployOptions options, PropertyInfo deployOptionsProp) + { + var val = prop.GetValue(options); + var attribute = prop.GetCustomAttributes(true).FirstOrDefault(); + Type type = val != null ? typeof(DeploymentOptionProperty<>).MakeGenericType(val.GetType()) + : typeof(DeploymentOptionProperty<>).MakeGenericType(prop.PropertyType); + object setProp = Activator.CreateInstance(type, val, attribute.Description,_displayNameMapDict[deployOptionsProp.Name]); + deployOptionsProp.SetValue(this, setProp); + } + public static DeploymentOptions GetDefaultSchemaCompareOptions() { return new DeploymentOptions(); @@ -312,7 +520,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx.Contracts { DeploymentOptions result = new DeploymentOptions(); - result.ExcludeObjectTypes = result.ExcludeObjectTypes.Where(x => x != ObjectType.DatabaseScopedCredentials).ToArray(); // re-include database-scoped credentials + result.ExcludeObjectTypes.Value = result.ExcludeObjectTypes.Value.Where(x => x != ObjectType.DatabaseScopedCredentials).ToArray(); // re-include database-scoped credentials return result; } diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs index 6a33f178..5c16aa31 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text.RegularExpressions; using Microsoft.SqlServer.Dac; using Microsoft.SqlServer.Dac.Compare; @@ -24,7 +25,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare { internal static DacDeployOptions CreateSchemaCompareOptions(DeploymentOptions deploymentOptions) { - System.Reflection.PropertyInfo[] deploymentOptionsProperties = deploymentOptions.GetType().GetProperties(); + PropertyInfo[] deploymentOptionsProperties = deploymentOptions.GetType().GetProperties(); DacDeployOptions dacOptions = new DacDeployOptions(); foreach (var deployOptionsProp in deploymentOptionsProperties) @@ -32,7 +33,18 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare var prop = dacOptions.GetType().GetProperty(deployOptionsProp.Name); if (prop != null) { - prop.SetValue(dacOptions, deployOptionsProp.GetValue(deploymentOptions)); + var val = deployOptionsProp.GetValue(deploymentOptions); + var selectedVal = val.GetType().GetProperty("Value").GetValue(val); + + // JSON.NET by default reads Number type as Int64, deserializing an object type to dacOptions of Int32 type required to convert into Int32 from Int64. + // If not converted setting value(Int64) to dacOption(Int32) will throw {"Object of type 'System.Int64' cannot be converted to type 'System.Int32'."}. + // As these integer type options are non-editable and are not availbale in ADS to update, integer overflow exception will not be happening here. + if (selectedVal != null && selectedVal.GetType() == typeof(System.Int64)) + { + selectedVal = Convert.ToInt32(selectedVal); + } + + prop.SetValue(dacOptions, selectedVal); } } return dacOptions; diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs index 09fa0a70..762c172e 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs @@ -586,8 +586,8 @@ FROM MissingEdgeHubInputStream'"; UpgradeExisting = true, DeploymentOptions = new DeploymentOptions() { - DropObjectsNotInSource = false, - ExcludeObjectTypes = new[] { ObjectType.Views } + DropObjectsNotInSource = new DeploymentOptionProperty(false), + ExcludeObjectTypes = new DeploymentOptionProperty(new[] { ObjectType.Views }) } }; @@ -664,8 +664,8 @@ FROM MissingEdgeHubInputStream'"; DatabaseName = targetDb.DatabaseName, DeploymentOptions = new DeploymentOptions() { - DropObjectsNotInSource = false, - ExcludeObjectTypes = new[] { ObjectType.Views } + DropObjectsNotInSource = new DeploymentOptionProperty(false), + ExcludeObjectTypes = new DeploymentOptionProperty(new[] { ObjectType.Views }) } }; @@ -682,8 +682,8 @@ FROM MissingEdgeHubInputStream'"; DatabaseName = targetDb.DatabaseName, DeploymentOptions = new DeploymentOptions() { - DropObjectsNotInSource = true, - ExcludeObjectTypes = new[] { ObjectType.Views } + DropObjectsNotInSource = new DeploymentOptionProperty(true), + ExcludeObjectTypes = new DeploymentOptionProperty( new[] { ObjectType.Views }) } }; @@ -727,9 +727,10 @@ FROM MissingEdgeHubInputStream'"; DeploymentOptions expectedResults = DeploymentOptions.GetDefaultPublishOptions(); expectedResults.ExcludeObjectTypes = null; - expectedResults.IncludeCompositeObjects = true; - expectedResults.BlockOnPossibleDataLoss = true; - expectedResults.AllowIncompatiblePlatform = true; + expectedResults.IncludeCompositeObjects = new DeploymentOptionProperty(true); + expectedResults.BlockOnPossibleDataLoss = new DeploymentOptionProperty(true); + expectedResults.AllowIncompatiblePlatform = new DeploymentOptionProperty(true); + expectedResults.DisableIndexesForDataPhase = new DeploymentOptionProperty(false); var dacfxRequestContext = new Mock>(); dacfxRequestContext.Setup((RequestContext x) => x.SendResult(It.Is((result) => ValidateOptions(expectedResults, result.DeploymentOptions) == true))).Returns(Task.FromResult(new object())); @@ -754,6 +755,7 @@ FROM MissingEdgeHubInputStream'"; { DeploymentOptions expectedResults = DeploymentOptions.GetDefaultPublishOptions(); expectedResults.ExcludeObjectTypes = null; + expectedResults.DisableIndexesForDataPhase = new DeploymentOptionProperty(false); var dacfxRequestContext = new Mock>(); dacfxRequestContext.Setup((RequestContext x) => x.SendResult(It.Is((result) => ValidateOptions(expectedResults, result.DeploymentOptions) == true))).Returns(Task.FromResult(new object())); @@ -843,7 +845,9 @@ Streaming query statement contains a reference to missing output stream 'Missing foreach (var v in deploymentOptionsProperties) { var defaultP = v.GetValue(expected); + var defaultPValue = defaultP != null ? defaultP.GetType().GetProperty("Value").GetValue(defaultP): defaultP; var actualP = v.GetValue(actual); + var actualPValue = actualP.GetType().GetProperty("Value").GetValue(actualP); if (v.Name == "ExcludeObjectTypes") { @@ -851,7 +855,17 @@ Streaming query statement contains a reference to missing output stream 'Missing } else { - Assert.True((defaultP == null && actualP == null) || (defaultP == null && (actualP as string) == string.Empty) || defaultP.Equals(actualP), $"Actual Property from Service is not equal to default property for {v.Name}, Actual value: {actualP} and Default value: {defaultP}"); + // Verifying expected and actual deployment options properties are equal + Assert.True((defaultP == null && actualP == null) + || (defaultP == null && String.IsNullOrEmpty(actualP as string)) + || defaultP.Equals(actualP) + , $"Actual Property from Service is not equal to default property for {v.Name}, Actual property: {actualP} and Default property: {defaultP}"); + + // Verifying expected and actual deployment options property values are equal + Assert.True((defaultPValue == null && actualPValue == null) + || (defaultPValue == null && String.IsNullOrEmpty(actualPValue as string)) + || (defaultPValue).Equals(actualPValue) + , $"Actual Property from Service is not equal to default property for {v.Name}, Actual value: {actualPValue} and Default value: {defaultPValue}"); } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs index 8ae403d4..ba362a93 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs @@ -72,39 +72,42 @@ END private DeploymentOptions GetIgnoreColumnOptions() { var options = new DeploymentOptions(); - options.IgnoreColumnOrder = true; + options.IgnoreColumnOrder = new DeploymentOptionProperty(true); return options; } private DeploymentOptions GetExcludeTableValuedFunctionOptions() { var options = new DeploymentOptions(); - options.ExcludeObjectTypes = new ObjectType[]{ - ObjectType.ServerTriggers, - ObjectType.Routes, - ObjectType.LinkedServerLogins, - ObjectType.Endpoints, - ObjectType.ErrorMessages, - ObjectType.Filegroups, - ObjectType.Files, - ObjectType.Logins, - ObjectType.LinkedServers, - ObjectType.Credentials, - ObjectType.DatabaseScopedCredentials, - ObjectType.DatabaseEncryptionKeys, - ObjectType.MasterKeys, - ObjectType.DatabaseAuditSpecifications, - ObjectType.Audits, - ObjectType.ServerAuditSpecifications, - ObjectType.CryptographicProviders, - ObjectType.ServerRoles, - ObjectType.EventSessions, - ObjectType.DatabaseOptions, - ObjectType.EventNotifications, - ObjectType.ServerRoleMembership, - ObjectType.AssemblyFiles, - ObjectType.TableValuedFunctions, //added Functions to excluded types - }; + options.ExcludeObjectTypes = new DeploymentOptionProperty + ( + new ObjectType[]{ + ObjectType.ServerTriggers, + ObjectType.Routes, + ObjectType.LinkedServerLogins, + ObjectType.Endpoints, + ObjectType.ErrorMessages, + ObjectType.Filegroups, + ObjectType.Files, + ObjectType.Logins, + ObjectType.LinkedServers, + ObjectType.Credentials, + ObjectType.DatabaseScopedCredentials, + ObjectType.DatabaseEncryptionKeys, + ObjectType.MasterKeys, + ObjectType.DatabaseAuditSpecifications, + ObjectType.Audits, + ObjectType.ServerAuditSpecifications, + ObjectType.CryptographicProviders, + ObjectType.ServerRoles, + ObjectType.EventSessions, + ObjectType.DatabaseOptions, + ObjectType.EventNotifications, + ObjectType.ServerRoleMembership, + ObjectType.AssemblyFiles, + ObjectType.TableValuedFunctions, //added Functions to excluded types + } + ); return options; } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs index 5a006e91..d7365a6a 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs @@ -1355,8 +1355,8 @@ WITH VALUES DeploymentOptions options = new DeploymentOptions(); // ensure that files are excluded seperate from filegroups - Assert.True(options.ExcludeObjectTypes.Contains(SqlServer.Dac.ObjectType.Files)); - Assert.False(options.ExcludeObjectTypes.Contains(SqlServer.Dac.ObjectType.Filegroups)); + Assert.True(options.ExcludeObjectTypes.Value.Contains(SqlServer.Dac.ObjectType.Files)); + Assert.False(options.ExcludeObjectTypes.Value.Contains(SqlServer.Dac.ObjectType.Filegroups)); var schemaCompareParams = new SchemaCompareParams { @@ -1826,12 +1826,13 @@ WITH VALUES DeploymentOptions = new DeploymentOptions() { // change some random ones explicitly - AllowDropBlockingAssemblies = true, - DropConstraintsNotInSource = true, - IgnoreAnsiNulls = true, - NoAlterStatementsToChangeClrTypes = false, - PopulateFilesOnFileGroups = false, - VerifyDeployment = false, + AllowDropBlockingAssemblies = new DeploymentOptionProperty(true), + DropConstraintsNotInSource = new DeploymentOptionProperty(true), + IgnoreAnsiNulls = new DeploymentOptionProperty(true), + NoAlterStatementsToChangeClrTypes = new DeploymentOptionProperty(false), + PopulateFilesOnFileGroups = new DeploymentOptionProperty(false), + VerifyDeployment = new DeploymentOptionProperty(false), + DisableIndexesForDataPhase = new DeploymentOptionProperty(false) }, ScmpFilePath = filePath, ExcludedSourceObjects = schemaCompareObjectIds, diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs index 002ab8ea..32689afa 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs @@ -135,11 +135,17 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare Assert.True(dacProp != null, $"DacDeploy property not present for {deployOptionsProp.Name}"); var deployOptionsValue = deployOptionsProp.GetValue(deploymentOptions); - var dacValue = dacProp.GetValue(dacDeployOptions); + var changedDacValue = deployOptionsValue != null ? deployOptionsValue.GetType().GetProperty("Value").GetValue(deployOptionsValue) : deployOptionsValue; + var dafaultDacValue = dacProp.GetValue(dacDeployOptions); if (deployOptionsProp.Name != "ExcludeObjectTypes") // do not compare for ExcludeObjectTypes because it will be different { - Assert.True((deployOptionsValue == null && dacValue == null) || deployOptionsValue.Equals(dacValue), $"DacFx DacDeploy property not equal to Tools Service DeploymentOptions for { deployOptionsProp.Name}, SchemaCompareOptions value: {deployOptionsValue} and DacDeployOptions value: {dacValue} "); + Assert.True((deployOptionsValue == null && dafaultDacValue == null) + || deployOptionsValue.Equals(dafaultDacValue) + || changedDacValue == null && (dafaultDacValue as string) == string.Empty + || changedDacValue == null && dafaultDacValue == null + || (changedDacValue).Equals(dafaultDacValue) + , $"DacFx DacDeploy property not equal to Tools Service DeploymentOptions for { deployOptionsProp.Name}, SchemaCompareOptions value: {changedDacValue} and DacDeployOptions value: {dafaultDacValue} "); } } } @@ -153,14 +159,27 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare foreach (var v in deploymentOptionsProperties) { var defaultP = v.GetValue(defaultOpt); + var defaultPValue = defaultP != null ? defaultP.GetType().GetProperty("Value").GetValue(defaultP) : defaultP; var actualP = v.GetValue(actualOpt); + var actualPValue = actualP.GetType().GetProperty("Value").GetValue(actualP); + if (v.Name == "ExcludeObjectTypes") { - Assert.True((defaultP as ObjectType[]).Length == (actualP as ObjectType[]).Length, $"Number of excluded objects is different; expected: {(defaultP as ObjectType[]).Length} actual: {(actualP as ObjectType[]).Length}"); + Assert.True((defaultPValue as ObjectType[]).Length == (actualPValue as ObjectType[]).Length, $"Number of excluded objects is different; expected: {(defaultPValue as ObjectType[]).Length} actual: {(actualPValue as ObjectType[]).Length}"); } else { - Assert.True((defaultP == null && actualP == null) || defaultP.Equals(actualP), $"Actual Property from Service is not equal to default property for { v.Name}, Actual value: {actualP} and Default value: {defaultP}"); + // Verifying expected and actual deployment options properties are equal + Assert.True((defaultP == null && actualP == null) + || (defaultP == null && String.IsNullOrEmpty(actualP as string)) + || defaultP.Equals(actualP) + , $"Actual Property from Service is not equal to default property for {v.Name}, Actual property: {actualP} and Default property: {defaultP}"); + + // Verifying expected and actual deployment options property values are equal + Assert.True((defaultPValue == null && actualPValue == null) + || (defaultPValue == null && String.IsNullOrEmpty(actualPValue as string)) + || (defaultPValue).Equals(actualPValue) + , $"Actual Property from Service is not equal to default property for {v.Name}, Actual value: {actualPValue} and Default value: {defaultPValue}"); } } return true;