diff --git a/README.md b/README.md index 135bbb6e..a3766a51 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,9 @@ SQL Build Manager is a multi-faceted tool to allow you to manage the life-cycle - [The Basics](#the-basics) - [Build package meta-data](#build-package-meta-data) - [Creating a build package](#creating-a-build-package) + - [Targeting multiple databases](#targeting-multiple-databases) - [Running Locally](/docs/local_build.md) +- [Command Line reference](/docs/commandline.md) - [Leverage Azure Batch for massively parallel updates](/docs/azure_batch.md) - [Change notes](docs/change_notes.md) - For contributors: [Notes on Building and Unit Testing](/docs/setup_azure_environment.md) @@ -22,36 +24,36 @@ SQL Build Manager is a multi-faceted tool to allow you to manage the life-cycle ## Key Features -* Packaging of all of your update scripts and runtime meta-data into a single .sbm (zip file) or leverage data-tier application ([DACPAC](https://docs.microsoft.com/en-us/sql/relational-databases/data-tier-applications/deploy-a-data-tier-application)) deployment across your entire database fleet. -* Single transaction handling. If any one script fails, the entire package is rolled back, leaving the database unchanged. -* Handle multiple database updates in one package - seamlessly update all your databases with local threading or massively parallel Azure Batch processing. -* Full script run management. Control the script order, target database, and transaction handling -* Trial mode - runs scripts to test against database, then rolls back to leave in pristine state. -* Automatic logging and version tracking of scripts on a per-server/per-database level -* Full SHA-1 hashing of individual scripts and complete `.sbm` package files to ensure integrity of the scripts -* Execution of a build package (see below) is recorded in the database for full tracking of update history, script validation and potential rebuilding of packages -* Massively parallel execution across thousands of databases utilizing local threading or an Azure Batch execution +- Packaging of all of your update scripts and runtime meta-data into a single .sbm (zip file) or leverage data-tier application ([DACPAC](https://docs.microsoft.com/en-us/sql/relational-databases/data-tier-applications/deploy-a-data-tier-application)) deployment across your entire database fleet. +- Single transaction handling. If any one script fails, the entire package is rolled back, leaving the database unchanged. +- Handle multiple database updates in one package - seamlessly update all your databases with local threading or massively parallel Azure Batch processing. +- Full script run management. Control the script order, target database, and transaction handling +- Trial mode - runs scripts to test against database, then rolls back to leave in pristine state. +- Automatic logging and version tracking of scripts on a per-server/per-database level +- Full SHA-1 hashing of individual scripts and complete `.sbm` package files to ensure integrity of the scripts +- Execution of a build package (see below) is recorded in the database for full tracking of update history, script validation and potential rebuilding of packages +- Massively parallel execution across thousands of databases utilizing local threading or an Azure Batch execution # The Basics ## Build Package meta-data At the core of the process is the "SQL Build Manager Package" file (.sbm extension). Under the hood, this file is a Zip file that contains the scripts that constitute your "release" along with a configuration file (SqlSyncBuildProject.xml) that contains meta data on the scripts and execution parameters: -* `FileName`: Self explanatory, the name of the script file -* `BuildOrder`: The relative order that the scripts in the package will be run -* `Description`: Optional description about the script -* `RollBackOnError`: Option on whether or not to roll back the transaction if there is an error running this script (default: `true`) -* `CausesBuildFailure`: Option on whether or not to roll back the entire build if there is a failure with this script (default `true`) -* `DateAdded`: Date and time that the script was added to the package -* `ScriptId`: System generated GUID identifier for the script -* `Database`: Target database to run the scripts against. (This can be overridden in the case of multiple DB targets) -* `StripTransactionText`: Script handling to remove any inline transaction statements (default is `true` because you want SQL Build Manager to handle transactions) -* `AllowMultipleRuns`: Whether or not this script can be run on the same database multiple times (default is `true` and you should always write scripts so this is viable) -* `AddedBy`: User ID of the user that added the script to the package -* `ScriptTimeOut`: Timeout setting for the execution of this script -* `DateModified`: If the script has been modified after being added, this will be populated (otherwise `DateTime.Min`) -* `ModifiedBy`: If the script has been modified after being added, this will be populated with the user's ID -* `Tag`: Optional tag for the script +- `FileName`: Self explanatory, the name of the script file +- `BuildOrder`: The relative order that the scripts in the package will be run +- `Description`: Optional description about the script +- `RollBackOnError`: Option on whether or not to roll back the transaction if there is an error running this script (default: `true`) +- `CausesBuildFailure`: Option on whether or not to roll back the entire build if there is a failure with this script (default `true`) +- `DateAdded`: Date and time that the script was added to the package +- `ScriptId`: System generated GUID identifier for the script +- `Database`: Target database to run the scripts against. (This can be overridden in the case of multiple DB targets) +- `StripTransactionText`: Script handling to remove any inline transaction statements (default is `true` because you want SQL Build Manager to handle transactions) +- `AllowMultipleRuns`: Whether or not this script can be run on the same database multiple times (default is `true` and you should always write scripts so this is viable) +- `AddedBy`: User ID of the user that added the script to the package +- `ScriptTimeOut`: Timeout setting for the execution of this script +- `DateModified`: If the script has been modified after being added, this will be populated (otherwise `DateTime.Min`) +- `ModifiedBy`: If the script has been modified after being added, this will be populated with the user's ID +- `Tag`: Optional tag for the script If you are using a DACPAC deployment, this all gets generated for you based on your command line parameters and defaults @@ -79,9 +81,21 @@ While the focus of the app has changed to command line automation, the forms GUI ### Command line -The command line utility is geared more toward executing a build vs. creating the package itself. You can however extract a build package file from a DACPAC file using the `sbm scriptextract` command. This is useful if you are utilizing the recommended [data-tier application](https://docs.microsoft.com/en-us/sql/relational-databases/data-tier-applications/data-tier-applications?view=sql-server-2017) method. +The command line utility is geared more toward executing a build vs. creating the package itself. You can however create a build package file in a few ways: -A DACPAC can also be created directly from a target "Platinum Database" (why platinum? because it's even more precious than gold!). Using the `sbm threaded run` and `sbm batch run` commands along with the `--platinumdbsource=""` and `--platinumserversource=""` the app will generate a DACPAC from the source database then can then be used to run a build directly on your target(s). +1. From a DACPAC file using the `sbm scriptextract` command. This method leverages a DACPAC that was created against your "Platinum Database" (why platinum? because it's even more precious than gold!). The Platinum database should have the schema that you want all of your other databases to look like. (don't have a DACPAC created, don't worry, you can create one with the `sbm dacpac` command) Learn more about DACPACs and [data-tier applications](https://docs.microsoft.com/en-us/sql/relational-databases/data-tier-applications/data-tier-applications?view=sql-server-2017) method. + +2. From a set of script files using `sbm create`. This command allows you to specify an `--outputsbm` file to be created and a list of `--scripts` files to populate the SBM file with. + +3. From an SBX file. What is this? An SBX file is an XML file in the format of the `SqlSyncBuildProject.xml` file (see above) that has an `.sbx` extension. When you use the `sbm package` command, it will read the `.sbx` file and create the `.sbm` file with the referenced scripts. + +4. An SBM package file can be created indirectly as well, using the `sbm threaded run` and `sbm batch run` commands along with the `--platinumdbsource=""` and `--platinumserversource=""` the app will generate a DACPAC from the source database then will then be used to generate an SBM at run time to build directly on your target(s). + +---- + +## Targeting multiple databases + +You define your database update targets leveraging an `--override` file or leverage Azure Service Bus Topics when using Azure Batch. The details of database targeting can be found [here](docs/override_options.md#database-targeting-option) ---- @@ -99,7 +113,7 @@ Using the `sbm threaded run` command will allow for updating multiple databases ### **Batch** -Using the `sbm batch query` command leverages Azure Batch to permit massively parallel updates across thousands of databases. To leverage Azure Batch, you will first need to set up your Batch account. The instructions for this can be found [here](docs/azure_batch.md). +Using the `sbm batch query` command leverages Azure Batch to permit massively parallel updates across thousands of databases. To leverage Azure Batch, you will first need to set up your Batch account. The instructions for this can be found [here](docs/azure_batch.md). An excellent tool for viewing and monitoring your Azure batch accounts and jobs can be found here [https://azure.github.io/BatchExplorer/](https://azure.github.io/BatchExplorer/) ---- @@ -108,11 +122,10 @@ An excellent tool for viewing and monitoring your Azure batch accounts and jobs In addition to using Sql Build Manager to perform database updates, you can also run SELECT queries across all of your databases to collect data. In the case of both `threaded` and `batch` a consolidated results file is saved to the location of your choice -### **Threaded** +### Threaded Using the `sbm threaded query` command will allow for querying multiple databases in parallel, but still executed from the local machine. -### **Batch** +### Batch Using the `sbm batch query` command leverages Azure Batch to permit massively parallel queries across thousands of databases. (For information on how to get started with Azure Batch, go [here](docs/azure_batch.md)) - diff --git a/docs/change_notes.md b/docs/change_notes.md index fd53813e..1aea1e50 100644 --- a/docs/change_notes.md +++ b/docs/change_notes.md @@ -2,12 +2,20 @@ # SQL Build Manager Change Notes +### Version 13.0.3 + +- *FIXED:* Update to Dacpac change scripts to identify new header delimiter +- *FIXED:* Issue creating scripts between incompatable SQL Server versions. Will now output a warning and continue to create the scripts with the flag `AllowIncompatiblePlatform=true` +- *ADDED:* New command `sbm create` to create a new SBM file from a list of scripts +- *UPDATED:* Can now use Windows auth for DACPAC creation +- *UPDATED:* updated Nuget packages + ### Version 13.0.2 - *FIXED:* Update to ensure all Queue messages are retrieved efficiently - *ADDED:* New utility method `sbm batch dequeue` to remove all messages from the Service Bus Queue topic (without processing them) - *UPDATED:* Code clean up and refactoring to accommodate latest version of System.CommandLine -- *FIXED:* Issue with SQL text syntax higlighting formatting in .NET 5.0 +- *FIXED:* Issue with SQL text syntax highlighting formatting in .NET 5.0 - **NOTE:** Removed "Construct Command Line" menu options from Windows UI. Users should leverage the generated help docs for sbm.exe ### Version 13.0.1 @@ -23,7 +31,7 @@ ### Version 12.1.0 -- *UPDATED:* Removed log4net logging. Unified logging via ILogger created in SqlBuildManager.Loggging. Implements Serilog +- *UPDATED:* Removed log4net logging. Unified logging via ILogger created in SqlBuildManager.Logging. Implements Serilog ### Version 12.0.0 diff --git a/docs/local_build.md b/docs/local_build.md index d4a3caba..2119a353 100644 --- a/docs/local_build.md +++ b/docs/local_build.md @@ -1,6 +1,6 @@ # Local Builds -If you have a single databases to update, you can use a local build. +If you have a single databases to update, you can use a local build. Sample command: diff --git a/docs/override_options.md b/docs/override_options.md index 43c9c4a8..fcc9204f 100644 --- a/docs/override_options.md +++ b/docs/override_options.md @@ -25,7 +25,7 @@ Why `client`? Inside the `.sbm` file, there is a default database target set to This is why the flag name is `--override`! - ### Runtime +### Runtime If the `--override` setting is provided but there isn't a `--servicebustopicconnection` value, the runtime will use this file directly to update the database and/or distribute traffic for `threaded` and `batch`. It is important to also understand the impact of [concurrency options](concurrency_options.md). diff --git a/docs/threaded_build.md b/docs/threaded_build.md index e369f999..841ae044 100644 --- a/docs/threaded_build.md +++ b/docs/threaded_build.md @@ -12,5 +12,4 @@ sbm threaded run --username "dbusername" ^ --password "dbpassword" ^ --override "targetdatabases.cfg" ^ - -``` \ No newline at end of file +``` diff --git a/src/AssemblyVersioning.cs b/src/AssemblyVersioning.cs index 8e5ec9d7..d1118a78 100644 --- a/src/AssemblyVersioning.cs +++ b/src/AssemblyVersioning.cs @@ -25,7 +25,7 @@ // These can be found in SqlBuildManager.Setup -> Organize Your Setup -> General Information // ** Also, don't forget to update the change_notes.xml and .html files! -[assembly: AssemblyVersion("13.0.2")] -[assembly: AssemblyFileVersion("13.0.2")] +[assembly: AssemblyVersion("13.0.3")] +[assembly: AssemblyFileVersion("13.0.3")] diff --git a/src/SqlBuildManager.Console.Dependent.UnitTest/SqlBuildManager.Console.Dependent.UnitTest.csproj b/src/SqlBuildManager.Console.Dependent.UnitTest/SqlBuildManager.Console.Dependent.UnitTest.csproj index 10050833..6966c200 100644 --- a/src/SqlBuildManager.Console.Dependent.UnitTest/SqlBuildManager.Console.Dependent.UnitTest.csproj +++ b/src/SqlBuildManager.Console.Dependent.UnitTest/SqlBuildManager.Console.Dependent.UnitTest.csproj @@ -6,7 +6,7 @@ false - 1701;1702 + 1701;1702;NU1608 @@ -47,9 +47,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlBuildManager.Console.ExternalTest/CliTests.cs b/src/SqlBuildManager.Console.ExternalTest/CliTests.cs index 19be8cbf..a8c6ea8c 100644 --- a/src/SqlBuildManager.Console.ExternalTest/CliTests.cs +++ b/src/SqlBuildManager.Console.ExternalTest/CliTests.cs @@ -25,7 +25,6 @@ public class CliTests private string linuxSettingsFilePath; private string settingsFileKeyPath; - private string logFile; [TestInitialize] public void ConfigureProcessInfo() { diff --git a/src/SqlBuildManager.Console.ExternalTest/SqlBuildManager.Console.ExternalTest.csproj b/src/SqlBuildManager.Console.ExternalTest/SqlBuildManager.Console.ExternalTest.csproj index 4a418e1d..eb15dabf 100644 --- a/src/SqlBuildManager.Console.ExternalTest/SqlBuildManager.Console.ExternalTest.csproj +++ b/src/SqlBuildManager.Console.ExternalTest/SqlBuildManager.Console.ExternalTest.csproj @@ -3,11 +3,14 @@ netcoreapp3.1;net5.0 false + + 1701;1702;NU1608 + - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -29,9 +32,17 @@ + + + + + + + + diff --git a/src/SqlBuildManager.Console.UnitTest/SqlBuildManager.Console.UnitTest.csproj b/src/SqlBuildManager.Console.UnitTest/SqlBuildManager.Console.UnitTest.csproj index 86897c9f..5da4a7ab 100644 --- a/src/SqlBuildManager.Console.UnitTest/SqlBuildManager.Console.UnitTest.csproj +++ b/src/SqlBuildManager.Console.UnitTest/SqlBuildManager.Console.UnitTest.csproj @@ -5,6 +5,9 @@ false false + + 1701;1702;NU1608 + @@ -20,9 +23,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlBuildManager.Console/Batch/BatchCleaner.cs b/src/SqlBuildManager.Console/Batch/BatchCleaner.cs index 2dd7ce8c..6525ad07 100644 --- a/src/SqlBuildManager.Console/Batch/BatchCleaner.cs +++ b/src/SqlBuildManager.Console/Batch/BatchCleaner.cs @@ -21,7 +21,6 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -using System.Linq; using MoreLinq; namespace SqlBuildManager.Console.Batch { diff --git a/src/SqlBuildManager.Console/Batch/BatchExecution.cs b/src/SqlBuildManager.Console/Batch/BatchExecution.cs index 4aa9ae89..1e8c8bfd 100644 --- a/src/SqlBuildManager.Console/Batch/BatchExecution.cs +++ b/src/SqlBuildManager.Console/Batch/BatchExecution.cs @@ -94,7 +94,7 @@ public Execution(CommandLineArgs cmdLine, string queryFile, string outputFile) : log.LogInformation($"Extracting Platinum Dacpac from {cmdLine.DacPacArgs.PlatinumServerSource} : {cmdLine.DacPacArgs.PlatinumDbSource}"); string dacpacName = Path.Combine(cmdLine.RootLoggingPath, cmdLine.DacPacArgs.PlatinumDbSource + ".dacpac"); - if (!DacPacHelper.ExtractDacPac(cmdLine.DacPacArgs.PlatinumDbSource, cmdLine.DacPacArgs.PlatinumServerSource, cmdLine.AuthenticationArgs.UserName, cmdLine.AuthenticationArgs.Password, dacpacName)) + if (!DacPacHelper.ExtractDacPac(cmdLine.DacPacArgs.PlatinumDbSource, cmdLine.DacPacArgs.PlatinumServerSource, cmdLine.AuthenticationArgs.AuthenticationType, cmdLine.AuthenticationArgs.UserName, cmdLine.AuthenticationArgs.Password, dacpacName)) { log.LogError($"Error creating the Platinum dacpac from {cmdLine.DacPacArgs.PlatinumServerSource} : {cmdLine.DacPacArgs.PlatinumDbSource}"); } diff --git a/src/SqlBuildManager.Console/CommandLine/CommandLineArgs.cs b/src/SqlBuildManager.Console/CommandLine/CommandLineArgs.cs index db6a2461..4dc74192 100644 --- a/src/SqlBuildManager.Console/CommandLine/CommandLineArgs.cs +++ b/src/SqlBuildManager.Console/CommandLine/CommandLineArgs.cs @@ -110,6 +110,8 @@ public string Override { [JsonIgnore] public string OutputSbm { get; set; } [JsonIgnore] + public FileInfo[] Scripts { get; set; } + [JsonIgnore] public string DacpacName { get diff --git a/src/SqlBuildManager.Console/CommandLine/CommandLineBuilder.cs b/src/SqlBuildManager.Console/CommandLine/CommandLineBuilder.cs index fb0dcf00..d365480f 100644 --- a/src/SqlBuildManager.Console/CommandLine/CommandLineBuilder.cs +++ b/src/SqlBuildManager.Console/CommandLine/CommandLineBuilder.cs @@ -39,7 +39,7 @@ public static RootCommand SetUp() var platinumdbsourceOption = new Option(new string[] { "--platinumdbsource" }, "Instead of a formally built Platinum Dacpac, target this database as having the desired state schema"); var platinumserversourceOption = new Option(new string[] { "--platinumserversource" }, "Instead of a formally built Platinum Dacpac, target a database on this server as having the desired state schema"); var buildrevisionOption = new Option(new string[] { "--buildrevision" }, "If provided, the build will include an update to a \"Versions\" table and this will be the value used to add to a \"VersionNumber\" column (varchar(max))"); - var outputsbmOption = new Option(new string[] { "--outputsbm" }, "Name (and path) of the SBM package to create"); + var outputsbmOption = new Option(new string[] { "-o", "--outputsbm" }, "Name (and path) of the SBM package to create"); var deletebatchpoolOption = new Option(new string[] { "--deletebatchpool" }, () => false, "Whether or not to delete the batch pool servers after an execution"); var deletebatchjobOption = new Option(new string[] { "--deletebatchjob" }, () => false, "Whether or not to delete the batch job after an execution"); var batchnodecountOption = new Option(new string[] { "--nodecount", "--batchnodecount" }, "Number of nodes to provision to run the batch job"); @@ -67,6 +67,7 @@ public static RootCommand SetUp() var threadedConcurrencyOption = new Option(new string[] { "--concurrency" }, "Maximum concurrency for threaded executions"); var threadedConcurrencyTypeOption = new Option(new string[] { "--concurrencytype" }, "Type of concurrency, used in conjunction with --concurrency "); var logLevelOption = new Option(new string[] { "--loglevel" }, "Logging level for console and log file"); + var scriptListOption = new Option(new string[] {"-s", "--scripts"}, "List of script files to create SBM package from - separate names with spaces (will be added in order provided)") { IsRequired = true }.ExistingOnly(); //Create DACPAC from target database var dacpacCommand = new Command("dacpac", "Creates a DACPAC file from the target database") @@ -490,6 +491,15 @@ public static RootCommand SetUp() }; packageCommand.Handler = CommandHandler.Create(Program.PackageSbxFilesIntoSbmFiles); + //Create + var createCommand = new Command("create", "Creates an SBM package from a list of scripts") + { + outputsbmOption.Copy(true), + scriptListOption + + }; + createCommand.Handler = CommandHandler.Create(Program.CreatePackageFromScripts); + //Run a policy check var policyCheckCommand = new Command("policycheck", "Performs a script policy check on the specified SBM package") { @@ -523,6 +533,7 @@ public static RootCommand SetUp() rootCommand.Add(buildCommand); rootCommand.Add(threadedCommand); rootCommand.Add(batchCommand); + rootCommand.Add(createCommand); rootCommand.Add(packageCommand); rootCommand.Add(policyCheckCommand); rootCommand.Add(getHashCommand); diff --git a/src/SqlBuildManager.Console/Program.cs b/src/SqlBuildManager.Console/Program.cs index 8486c6a3..4752c33d 100644 --- a/src/SqlBuildManager.Console/Program.cs +++ b/src/SqlBuildManager.Console/Program.cs @@ -24,10 +24,13 @@ namespace SqlBuildManager.Console public class Program { + static Program() + { + log = SqlBuildManager.Logging.ApplicationLogging.CreateLogger(typeof(Program), applicationLogFileName); + } public const string applicationLogFileName = "SqlBuildManager.Console.log"; - private static Microsoft.Extensions.Logging.ILogger log = SqlBuildManager.Logging.ApplicationLogging.CreateLogger(typeof(Program), applicationLogFileName); - + private static Microsoft.Extensions.Logging.ILogger log; internal static string[] AppendLogFiles = new string[] { "commits.log", "errors.log", "successdatabases.cfg", "failuredatabases.cfg" }; static int Main(string[] args) @@ -621,7 +624,7 @@ internal static int CreateDacpac(CommandLineArgs cmdLine) Directory.CreateDirectory(path); } - if (!sb.DacPacHelper.ExtractDacPac(cmdLine.Database, cmdLine.Server, cmdLine.AuthenticationArgs.UserName, cmdLine.AuthenticationArgs.Password, fullName)) + if (!sb.DacPacHelper.ExtractDacPac(cmdLine.Database, cmdLine.Server, cmdLine.AuthenticationArgs.AuthenticationType, cmdLine.AuthenticationArgs.UserName, cmdLine.AuthenticationArgs.Password, fullName)) { log.LogError($"Error creating the dacpac from {cmdLine.Server} : {cmdLine.Database}"); return (int)ExecutionReturn.BuildFileExtractionError; @@ -694,6 +697,19 @@ internal static void CreateBackout(CommandLineArgs cmdLine) } } + internal static void CreatePackageFromScripts(CommandLineArgs cmdLine) + { + bool success = sb.SqlBuildFileHelper.SaveSqlFilesToNewBuildFile(cmdLine.OutputSbm, cmdLine.Scripts.Select(f => f.FullName).ToList(),"client", 500); + if(success) + { + log.LogInformation($"Successfully created build file {cmdLine.OutputSbm} with {cmdLine.Scripts.Count()} scripts"); + } + else + { + log.LogError("Unable to create the build file!"); + } + } + internal static void GetPackageHash(CommandLineArgs cmdLine) { SqlBuildManager.Logging.ApplicationLogging.SetLogLevel(cmdLine.LogLevel); @@ -906,6 +922,7 @@ internal static sb.DacpacDeltasStatus GetSbmFromDacPac(CommandLineArgs cmd, Mult cmd.DacPacArgs.TargetDacpac, string.Empty, string.Empty, + cmd.AuthenticationArgs.AuthenticationType, cmd.AuthenticationArgs.UserName, cmd.AuthenticationArgs.Password, cmd.BuildRevision, @@ -919,6 +936,7 @@ internal static sb.DacpacDeltasStatus GetSbmFromDacPac(CommandLineArgs cmd, Mult cmd.DacPacArgs.TargetDacpac, cmd.Database, cmd.Server, + cmd.AuthenticationArgs.AuthenticationType, cmd.AuthenticationArgs.UserName, cmd.AuthenticationArgs.Password, cmd.BuildRevision, diff --git a/src/SqlBuildManager.Console/Queue/QueueManager.cs b/src/SqlBuildManager.Console/Queue/QueueManager.cs index 991a8e27..316b7983 100644 --- a/src/SqlBuildManager.Console/Queue/QueueManager.cs +++ b/src/SqlBuildManager.Console/Queue/QueueManager.cs @@ -195,7 +195,7 @@ private async Task> GetSessionBasedTargetsFromQu _sessionReceiver = await this.Client.AcceptNextSessionAsync(this.topicName, this.topicSessionSubscriptionName, new ServiceBusSessionReceiverOptions() { ReceiveMode = ServiceBusReceiveMode.PeekLock }, token); log.LogInformation($"Obtained new subscription for batch job '{batchJobName}' and subscription Id '{_sessionReceiver.SessionId}' "); } - catch(TaskCanceledException tce) + catch(TaskCanceledException) { log.LogInformation("No session available by wait time expiration"); return lstMsg ; @@ -381,7 +381,7 @@ internal async Task ClearQueueMessages() _sessionReceiver = await this.Client.AcceptNextSessionAsync(this.topicName, this.topicSessionSubscriptionName, new ServiceBusSessionReceiverOptions() { ReceiveMode = ServiceBusReceiveMode.ReceiveAndDelete }, token); log.LogInformation($"Obtained new subscription for subscription Id '{_sessionReceiver.SessionId}' "); } - catch (TaskCanceledException tce) + catch (TaskCanceledException) { log.LogInformation("No more messages available - by wait time expiration"); break; @@ -411,7 +411,7 @@ internal async Task ClearQueueMessages() break; } } - catch (TaskCanceledException tce) + catch (TaskCanceledException) { log.LogInformation($"No more messages available in {this.topicSessionSubscriptionName} session {_sessionReceiver.SessionId} - by wait time expiration"); break; diff --git a/src/SqlBuildManager.Console/Threaded/ThreadedExecution.cs b/src/SqlBuildManager.Console/Threaded/ThreadedExecution.cs index cb1199fa..f11b065e 100644 --- a/src/SqlBuildManager.Console/Threaded/ThreadedExecution.cs +++ b/src/SqlBuildManager.Console/Threaded/ThreadedExecution.cs @@ -27,7 +27,6 @@ public class ThreadedExecution DateTime startTime; bool hasError = false; bool theadedLoggingInitiated = false; - private string[] args; private CommandLineArgs cmdLine = null; private QueueManager qManager = null; private int queueReturnValue = 0; @@ -340,7 +339,7 @@ private async Task ExecuteFromQueue(CommandLineArgs cmdLine, string buildRe log.LogInformation($"Extracting Platinum Dacpac from {cmdLine.DacPacArgs.PlatinumServerSource} : {cmdLine.DacPacArgs.PlatinumDbSource}"); string dacpacName = Path.Combine(ThreadedExecution.rootLoggingPath, cmdLine.DacPacArgs.PlatinumDbSource + ".dacpac"); - if (!DacPacHelper.ExtractDacPac(cmdLine.DacPacArgs.PlatinumDbSource, cmdLine.DacPacArgs.PlatinumServerSource, cmdLine.AuthenticationArgs.UserName, cmdLine.AuthenticationArgs.Password, dacpacName)) + if (!DacPacHelper.ExtractDacPac(cmdLine.DacPacArgs.PlatinumDbSource, cmdLine.DacPacArgs.PlatinumServerSource, cmdLine.AuthenticationArgs.AuthenticationType, cmdLine.AuthenticationArgs.UserName, cmdLine.AuthenticationArgs.Password, dacpacName)) { var m = new LogMsg() { diff --git a/src/SqlBuildManager.Console/Threaded/ThreadedRunner.cs b/src/SqlBuildManager.Console/Threaded/ThreadedRunner.cs index 5a38405f..9c98dca1 100644 --- a/src/SqlBuildManager.Console/Threaded/ThreadedRunner.cs +++ b/src/SqlBuildManager.Console/Threaded/ThreadedRunner.cs @@ -164,7 +164,7 @@ internal async Task RunDatabaseBuild() { runData.ForceCustomDacpac = true; //This will set the BuildData and BuildFileName and ProjectFileName properties on runData - var status = DacPacHelper.UpdateBuildRunDataForDacPacSync(ref runData, server, targetDatabase, this.username, this.password, loggingDirectory, cmdArgs.BuildRevision, cmdArgs.DefaultScriptTimeout); + var status = DacPacHelper.UpdateBuildRunDataForDacPacSync(ref runData, server, targetDatabase, this.authType, this.username, this.password, loggingDirectory, cmdArgs.BuildRevision, cmdArgs.DefaultScriptTimeout); switch(status) { case DacpacDeltasStatus.Success: diff --git a/src/SqlBuildManager.Console/sbm.csproj b/src/SqlBuildManager.Console/sbm.csproj index a3a7bb46..494c2fd8 100644 --- a/src/SqlBuildManager.Console/sbm.csproj +++ b/src/SqlBuildManager.Console/sbm.csproj @@ -26,36 +26,38 @@ - + - + - + - + - - - - + + + - + false false SqlBuildManager.Console + + 1701;1702;NU1608 + \ No newline at end of file diff --git a/src/SqlBuildManager.Enterprise.UnitTest/SqlBuildManager.Enterprise.UnitTest.csproj b/src/SqlBuildManager.Enterprise.UnitTest/SqlBuildManager.Enterprise.UnitTest.csproj index 2acdfa7a..17b7674e 100644 --- a/src/SqlBuildManager.Enterprise.UnitTest/SqlBuildManager.Enterprise.UnitTest.csproj +++ b/src/SqlBuildManager.Enterprise.UnitTest/SqlBuildManager.Enterprise.UnitTest.csproj @@ -15,9 +15,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlBuildManager.Enterprise/SqlBuildManager.Enterprise.csproj b/src/SqlBuildManager.Enterprise/SqlBuildManager.Enterprise.csproj index de2e1d57..00d64a06 100644 --- a/src/SqlBuildManager.Enterprise/SqlBuildManager.Enterprise.csproj +++ b/src/SqlBuildManager.Enterprise/SqlBuildManager.Enterprise.csproj @@ -37,6 +37,6 @@ - 1701;1702;CS0108 + 1701;1702;CS0108;CA1416 \ No newline at end of file diff --git a/src/SqlBuildManager.Logging/ApplicationLogger.cs b/src/SqlBuildManager.Logging/ApplicationLogger.cs index fd02973c..3f0aa212 100644 --- a/src/SqlBuildManager.Logging/ApplicationLogger.cs +++ b/src/SqlBuildManager.Logging/ApplicationLogger.cs @@ -28,7 +28,7 @@ public static void ConfigureStandardLogger(ILoggerFactory factory) .Enrich.WithThreadId() .Enrich.WithThreadName() .WriteTo.Console(outputTemplate: consoleOutput) - .WriteTo.Async(a => a.File(_logFileName, outputTemplate: logOutputTemplate, rollingInterval: RollingInterval.Day, rollOnFileSizeLimit: false, shared: true)) + .WriteTo.Async(a => a.File(LogFileName, outputTemplate: logOutputTemplate, rollingInterval: RollingInterval.Day, rollOnFileSizeLimit: false, shared: true)) .CreateLogger(); factory.AddSerilog(serilogLogger); diff --git a/src/SqlBuildManager.Logging/SqlBuildManager.Logging.csproj b/src/SqlBuildManager.Logging/SqlBuildManager.Logging.csproj index 3522664d..c0a9a537 100644 --- a/src/SqlBuildManager.Logging/SqlBuildManager.Logging.csproj +++ b/src/SqlBuildManager.Logging/SqlBuildManager.Logging.csproj @@ -14,10 +14,12 @@ + - - + + + @@ -28,8 +30,14 @@ - + + + + + ..\..\..\serilog-sinks-azureeventhub\src\Serilog.Sinks.AzureEventHub\bin\Debug\netstandard2.0\Serilog.Sinks.AzureEventHub.dll + + \ No newline at end of file diff --git a/src/SqlBuildManager.Logging/Threaded/EventHubLogging.cs b/src/SqlBuildManager.Logging/Threaded/EventHubLogging.cs index d8c069dc..4e02e5d6 100644 --- a/src/SqlBuildManager.Logging/Threaded/EventHubLogging.cs +++ b/src/SqlBuildManager.Logging/Threaded/EventHubLogging.cs @@ -1,4 +1,4 @@ -using Microsoft.Azure.EventHubs; +using Azure.Messaging.EventHubs.Producer; using Microsoft.Extensions.Logging; using Serilog; using Serilog.Formatting.Json; @@ -17,7 +17,7 @@ public class EventHubLogging public static void ConfigureEventHubLogger(ILoggerFactory factory) { - EventHubClient eventHubClient = EventHubClient.CreateFromConnectionString(_EventHubConnectionString); + EventHubProducerClient eventHubClient = new EventHubProducerClient(_EventHubConnectionString); serilogLogger = new LoggerConfiguration() diff --git a/src/SqlBuildManager.ScriptHandling.UnitTest/SqlBuildManager.ScriptHandling.UnitTest.csproj b/src/SqlBuildManager.ScriptHandling.UnitTest/SqlBuildManager.ScriptHandling.UnitTest.csproj index ee946ac5..a01fc1be 100644 --- a/src/SqlBuildManager.ScriptHandling.UnitTest/SqlBuildManager.ScriptHandling.UnitTest.csproj +++ b/src/SqlBuildManager.ScriptHandling.UnitTest/SqlBuildManager.ScriptHandling.UnitTest.csproj @@ -10,9 +10,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlSync.Connection.Dependent.UnitTest/SqlSync.Connection.Dependent.UnitTest.csproj b/src/SqlSync.Connection.Dependent.UnitTest/SqlSync.Connection.Dependent.UnitTest.csproj index 9204e824..7b47e1a5 100644 --- a/src/SqlSync.Connection.Dependent.UnitTest/SqlSync.Connection.Dependent.UnitTest.csproj +++ b/src/SqlSync.Connection.Dependent.UnitTest/SqlSync.Connection.Dependent.UnitTest.csproj @@ -13,9 +13,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlSync.Connection.UnitTest/SqlSync.Connection.UnitTest.csproj b/src/SqlSync.Connection.UnitTest/SqlSync.Connection.UnitTest.csproj index 9204e824..7b47e1a5 100644 --- a/src/SqlSync.Connection.UnitTest/SqlSync.Connection.UnitTest.csproj +++ b/src/SqlSync.Connection.UnitTest/SqlSync.Connection.UnitTest.csproj @@ -13,9 +13,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlSync.Connection/SqlSync.Connection.csproj b/src/SqlSync.Connection/SqlSync.Connection.csproj index 552be928..d8af60e1 100644 --- a/src/SqlSync.Connection/SqlSync.Connection.csproj +++ b/src/SqlSync.Connection/SqlSync.Connection.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/SqlSync.DbInformation.Dependent.UnitTest/SqlSync.DbInformation.Dependent.UnitTest.csproj b/src/SqlSync.DbInformation.Dependent.UnitTest/SqlSync.DbInformation.Dependent.UnitTest.csproj index a1c71ef0..c3597f65 100644 --- a/src/SqlSync.DbInformation.Dependent.UnitTest/SqlSync.DbInformation.Dependent.UnitTest.csproj +++ b/src/SqlSync.DbInformation.Dependent.UnitTest/SqlSync.DbInformation.Dependent.UnitTest.csproj @@ -7,9 +7,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlSync.ObjectScript.Dependent.UnitTest/SqlSync.ObjectScript.Dependent.UnitTest.csproj b/src/SqlSync.ObjectScript.Dependent.UnitTest/SqlSync.ObjectScript.Dependent.UnitTest.csproj index 9d372967..52ce41a3 100644 --- a/src/SqlSync.ObjectScript.Dependent.UnitTest/SqlSync.ObjectScript.Dependent.UnitTest.csproj +++ b/src/SqlSync.ObjectScript.Dependent.UnitTest/SqlSync.ObjectScript.Dependent.UnitTest.csproj @@ -7,9 +7,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlSync.ObjectScript.UnitTest/SqlSync.ObjectScript.UnitTest.csproj b/src/SqlSync.ObjectScript.UnitTest/SqlSync.ObjectScript.UnitTest.csproj index 4d8ae7ac..b064d022 100644 --- a/src/SqlSync.ObjectScript.UnitTest/SqlSync.ObjectScript.UnitTest.csproj +++ b/src/SqlSync.ObjectScript.UnitTest/SqlSync.ObjectScript.UnitTest.csproj @@ -7,9 +7,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlSync.ObjectScript/SqlSync.ObjectScript.csproj b/src/SqlSync.ObjectScript/SqlSync.ObjectScript.csproj index 3b9585c5..5ba0b740 100644 --- a/src/SqlSync.ObjectScript/SqlSync.ObjectScript.csproj +++ b/src/SqlSync.ObjectScript/SqlSync.ObjectScript.csproj @@ -24,4 +24,7 @@ false false + + 1701;1702;CA1416 + \ No newline at end of file diff --git a/src/SqlSync.SprocTest/SqlSync.SprocTest.csproj b/src/SqlSync.SprocTest/SqlSync.SprocTest.csproj index f9488468..8dfc8a3b 100644 --- a/src/SqlSync.SprocTest/SqlSync.SprocTest.csproj +++ b/src/SqlSync.SprocTest/SqlSync.SprocTest.csproj @@ -6,11 +6,11 @@ false - + - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlSync.SqlBuild.Dependent.UnitTest/DacPacHelperTest.cs b/src/SqlSync.SqlBuild.Dependent.UnitTest/DacPacHelperTest.cs index b45e1701..5ab75b92 100644 --- a/src/SqlSync.SqlBuild.Dependent.UnitTest/DacPacHelperTest.cs +++ b/src/SqlSync.SqlBuild.Dependent.UnitTest/DacPacHelperTest.cs @@ -10,12 +10,27 @@ public class DacPacHelperTest [TestMethod] public void ScriptDacPacDelta_Test() { - string workingDir = @"C:\temp"; // SqlBuildManager.Logging.Configure.AppDataPath; + string workingDir = @"C:\temp"; + string platinumPath = Path.Combine(workingDir, "PlatinumSchema_simple.dacpac"); + string tarnishedPath = Path.Combine(workingDir, "TarnishedSchema_simple.dacpac"); - File.WriteAllBytes(workingDir + @"\PlatinumSchema_simple.dacpac", Properties.Resources.PlatinumSchema_simple); - File.WriteAllBytes(workingDir + @"\TarnishedSchema_simple.dacpac", Properties.Resources.TarnishedSchema_simple); + File.WriteAllBytes(platinumPath, Properties.Resources.PlatinumSchema_simple); + File.WriteAllBytes(tarnishedPath, Properties.Resources.TarnishedSchema_simple); - string result = DacPacHelper.ScriptDacPacDeltas(workingDir + @"\PlatinumSchema_simple.dacpac", workingDir + @"\TarnishedSchema_simple.dacpac", workingDir); + string result = DacPacHelper.ScriptDacPacDeltas(platinumPath, tarnishedPath, workingDir); + Assert.IsNotNull(result); + Assert.IsFalse(string.IsNullOrEmpty(result)); + } + + [TestMethod] + public void ScriptDacPacDelta_InSync_Test() + { + string workingDir = @"C:\temp"; + string platinumPath = Path.Combine(workingDir, "PlatinumSchema_simple.dacpac"); + + File.WriteAllBytes(platinumPath, Properties.Resources.PlatinumSchema_simple); + + string result = DacPacHelper.ScriptDacPacDeltas(platinumPath, platinumPath, workingDir); Assert.IsNotNull(result); Assert.IsFalse(string.IsNullOrEmpty(result)); } @@ -24,31 +39,81 @@ public void ScriptDacPacDelta_Test() [Ignore] public void ScriptDacPacDelta_TestFull() { - string workingDir = @"C:\temp"; // SqlBuildManager.Logging.Configure.AppDataPath; + string workingDir = @"C:\temp"; + string platinumPath = Path.Combine(workingDir, "PlatinumSchema.dacpac"); + string tarnishedPath = Path.Combine(workingDir, "TarnishedSchema.dacpac"); - File.WriteAllBytes(workingDir + @"\PlatunumSchema.dacpac", Properties.Resources.PlatunumSchema); - File.WriteAllBytes(workingDir + @"\TarnishedSchema.dacpac", Properties.Resources.TarnishedSchema); + File.WriteAllBytes(platinumPath, Properties.Resources.PlatunumSchema); + File.WriteAllBytes(tarnishedPath, Properties.Resources.TarnishedSchema); - string result = DacPacHelper.ScriptDacPacDeltas(workingDir + @"\PlatunumSchema.dacpac", workingDir + @"\TarnishedSchema.dacpac", workingDir); + string result = DacPacHelper.ScriptDacPacDeltas(platinumPath, tarnishedPath, workingDir); Assert.IsNotNull(result); Assert.IsFalse(string.IsNullOrEmpty(result)); } [TestMethod] - public void CreateSbmFromDacPacDifferences_Test() + public void CreateSbmFromDacPacDifferences_Success_Test() + { + string workingDir = @"C:\temp"; + string platinumPath = Path.Combine(workingDir, "PlatinumSchema_simple.dacpac"); + string tarnishedPath = Path.Combine(workingDir, "TarnishedSchema_simple.dacpac"); + + File.WriteAllBytes(platinumPath, Properties.Resources.PlatinumSchema_simple); + File.WriteAllBytes(tarnishedPath, Properties.Resources.TarnishedSchema_simple); + string buildFileName = Path.GetTempFileName(); + + var result = DacPacHelper.CreateSbmFromDacPacDifferences(platinumPath, tarnishedPath, false, string.Empty,500, out buildFileName); + + Assert.IsTrue(result == DacpacDeltasStatus.Success); + Assert.IsTrue(File.ReadAllBytes(buildFileName).Length > 0); + } + [TestMethod] + public void CreateSbmFromDacPacDifferences1_Success_Test() { - string workingDir = @"C:\temp"; //SqlBuildManager.Logging.Configure.AppDataPath; + string workingDir = @"C:\temp"; + string platinumPath = Path.Combine(workingDir, "PlatinumSchema1.dacpac"); + string tarnishedPath = Path.Combine(workingDir, "TarnishedSchema1.dacpac"); - File.WriteAllBytes(workingDir + @"\PlatinumSchema_simple.dacpac", Properties.Resources.PlatinumSchema_simple); - File.WriteAllBytes(workingDir + @"\TarnishedSchema_simple.dacpac", Properties.Resources.TarnishedSchema_simple); + File.WriteAllBytes(platinumPath, Properties.Resources.Platinumschema1); + File.WriteAllBytes(tarnishedPath, Properties.Resources.TarnishedSchema1); string buildFileName = Path.GetTempFileName(); - var result = DacPacHelper.CreateSbmFromDacPacDifferences(workingDir + @"\PlatinumSchema_simple.dacpac", workingDir + @"\TarnishedSchema_simple.dacpac", false, string.Empty,500, out buildFileName); + var result = DacPacHelper.CreateSbmFromDacPacDifferences(platinumPath, tarnishedPath, false, string.Empty, 500, out buildFileName); Assert.IsTrue(result == DacpacDeltasStatus.Success); Assert.IsTrue(File.ReadAllBytes(buildFileName).Length > 0); } + [TestMethod] + public void CreateSbmFromDacPacDifferences_InSync_Test() + { + string workingDir = @"C:\temp"; + string platinumPath = Path.Combine(workingDir, "PlatinumSchema_simple.dacpac"); + + File.WriteAllBytes(platinumPath, Properties.Resources.PlatinumSchema_simple); + string buildFileName = Path.GetTempFileName(); + + var result = DacPacHelper.CreateSbmFromDacPacDifferences(platinumPath, platinumPath, false, string.Empty, 500, out buildFileName); + + Assert.IsTrue(result == DacpacDeltasStatus.InSync); + Assert.IsTrue(string.IsNullOrEmpty(buildFileName)); + } + + [TestMethod] + public void CreateSbmFromDacPacDifferences1_InSync_Test() + { + string workingDir = @"C:\temp"; + string platinumPath = Path.Combine(workingDir, "PlatinumSchema1.dacpac"); + + File.WriteAllBytes(platinumPath, Properties.Resources.Platinumschema1); + string buildFileName = Path.GetTempFileName(); + + var result = DacPacHelper.CreateSbmFromDacPacDifferences(platinumPath, platinumPath, false, string.Empty, 500, out buildFileName); + + Assert.IsTrue(result == DacpacDeltasStatus.InSync); + Assert.IsTrue(string.IsNullOrEmpty(buildFileName)); + } + [TestMethod] public void CleanDacPacScript_Test() { diff --git a/src/SqlSync.SqlBuild.Dependent.UnitTest/Properties/Resources.Designer.cs b/src/SqlSync.SqlBuild.Dependent.UnitTest/Properties/Resources.Designer.cs index 5c46cd3b..a89b557e 100644 --- a/src/SqlSync.SqlBuild.Dependent.UnitTest/Properties/Resources.Designer.cs +++ b/src/SqlSync.SqlBuild.Dependent.UnitTest/Properties/Resources.Designer.cs @@ -283,6 +283,16 @@ public static byte[] PlatinumSchema_simple { } } + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] Platinumschema1 { + get { + object obj = ResourceManager.GetObject("Platinumschema1", resourceCulture); + return ((byte[])(obj)); + } + } + /// /// Looks up a localized resource of type System.Byte[]. /// @@ -374,6 +384,16 @@ public static byte[] TarnishedSchema_simple { } } + /// + /// Looks up a localized resource of type System.Byte[]. + /// + public static byte[] TarnishedSchema1 { + get { + object obj = ResourceManager.GetObject("TarnishedSchema1", resourceCulture); + return ((byte[])(obj)); + } + } + /// /// Looks up a localized string similar to <?xml version="1.0" standalone="yes"?> ///<SqlSyncBuildData xmlns="http://INVALID.mckechney.com/SqlSyncBuildProject.xsd"> diff --git a/src/SqlSync.SqlBuild.Dependent.UnitTest/Properties/Resources.resx b/src/SqlSync.SqlBuild.Dependent.UnitTest/Properties/Resources.resx index 33835e8d..57a3f04a 100644 --- a/src/SqlSync.SqlBuild.Dependent.UnitTest/Properties/Resources.resx +++ b/src/SqlSync.SqlBuild.Dependent.UnitTest/Properties/Resources.resx @@ -154,6 +154,9 @@ ..\Resources\NoTrans_MultiDb.sbm;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\resources\platinumschema1.dacpac;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\PlatinumSchema-simple.dacpac;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -172,6 +175,9 @@ ..\Resources\TarnishedSchema.dacpac;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\resources\tarnishedschema1.dacpac;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\TarnishedSchema-simple.dacpac;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/src/SqlSync.SqlBuild.Dependent.UnitTest/Resources/Platinumschema1.dacpac b/src/SqlSync.SqlBuild.Dependent.UnitTest/Resources/Platinumschema1.dacpac new file mode 100644 index 00000000..43875645 Binary files /dev/null and b/src/SqlSync.SqlBuild.Dependent.UnitTest/Resources/Platinumschema1.dacpac differ diff --git a/src/SqlSync.SqlBuild.Dependent.UnitTest/Resources/TarnishedSchema1.dacpac b/src/SqlSync.SqlBuild.Dependent.UnitTest/Resources/TarnishedSchema1.dacpac new file mode 100644 index 00000000..a372e08d Binary files /dev/null and b/src/SqlSync.SqlBuild.Dependent.UnitTest/Resources/TarnishedSchema1.dacpac differ diff --git a/src/SqlSync.SqlBuild.Dependent.UnitTest/SqlSync.SqlBuild.Dependent.UnitTest.csproj b/src/SqlSync.SqlBuild.Dependent.UnitTest/SqlSync.SqlBuild.Dependent.UnitTest.csproj index 58d87b80..67ca93e5 100644 --- a/src/SqlSync.SqlBuild.Dependent.UnitTest/SqlSync.SqlBuild.Dependent.UnitTest.csproj +++ b/src/SqlSync.SqlBuild.Dependent.UnitTest/SqlSync.SqlBuild.Dependent.UnitTest.csproj @@ -31,11 +31,11 @@ - + - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlSync.SqlBuild.UnitTest/SqlSync.SqlBuild.UnitTest.csproj b/src/SqlSync.SqlBuild.UnitTest/SqlSync.SqlBuild.UnitTest.csproj index eaa74a75..93b60df6 100644 --- a/src/SqlSync.SqlBuild.UnitTest/SqlSync.SqlBuild.UnitTest.csproj +++ b/src/SqlSync.SqlBuild.UnitTest/SqlSync.SqlBuild.UnitTest.csproj @@ -12,11 +12,11 @@ - + - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/SqlSync.SqlBuild/Cryptography.cs b/src/SqlSync.SqlBuild/Cryptography.cs index 20334281..b59311c7 100644 --- a/src/SqlSync.SqlBuild/Cryptography.cs +++ b/src/SqlSync.SqlBuild/Cryptography.cs @@ -50,7 +50,7 @@ public static (bool, string) DecryptText(string input, string password, string d return (true, result); } - catch (Exception exe) + catch (Exception) { if (!suppressLog) { diff --git a/src/SqlSync.SqlBuild/CustomExtensionMethods.cs b/src/SqlSync.SqlBuild/CustomExtensionMethods.cs index 6a352167..701dc347 100644 --- a/src/SqlSync.SqlBuild/CustomExtensionMethods.cs +++ b/src/SqlSync.SqlBuild/CustomExtensionMethods.cs @@ -70,22 +70,22 @@ public static IEnumerable> SplitIntoChunks(this IEnumerable - public static T DeepClone(this object obj) where T : class - { - object cloned = new object(); - BinaryFormatter formatter = new BinaryFormatter(); - using (MemoryStream stream = new MemoryStream()) - { - formatter.Serialize(stream, obj); - stream.Flush(); - stream.Position = 0; - cloned = formatter.Deserialize(stream); - } + //public static T DeepClone(this object obj) where T : class + //{ + // object cloned = new object(); + // BinaryFormatter formatter = new BinaryFormatter(); + // using (MemoryStream stream = new MemoryStream()) + // { + // formatter.Serialize(stream, obj); + // stream.Flush(); + // stream.Position = 0; + // cloned = formatter.Deserialize(stream); + // } - return cloned as T; + // return cloned as T; - } + //} //This works, but splits one at a time vs. chunking.. I want chunking. //Keeping the code just in case I want it later for something else. diff --git a/src/SqlSync.SqlBuild/DacPacHelper.cs b/src/SqlSync.SqlBuild/DacPacHelper.cs index 8dc913ec..4fee7fca 100644 --- a/src/SqlSync.SqlBuild/DacPacHelper.cs +++ b/src/SqlSync.SqlBuild/DacPacHelper.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using Microsoft.SqlServer.Dac; +using SqlSync.Connection; using SqlSync.SqlBuild.MultiDb; using System; using System.Collections.Generic; @@ -14,7 +15,7 @@ public class DacPacHelper { private static ILogger log = SqlBuildManager.Logging.ApplicationLogging.CreateLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - public static bool ExtractDacPac(string sourceDatabase, string sourceServer, string userName, string password, string dacPacFileName) + public static bool ExtractDacPac(string sourceDatabase, string sourceServer, AuthenticationType authType, string userName, string password, string dacPacFileName) { try @@ -27,8 +28,9 @@ public static bool ExtractDacPac(string sourceDatabase, string sourceServer, str SqlConnectionStringBuilder connBuilder = new SqlConnectionStringBuilder(); - connBuilder.UserID = userName; - connBuilder.Password = password; + if (authType == AuthenticationType.Windows) connBuilder.IntegratedSecurity = true; + if (!string.IsNullOrWhiteSpace(userName)) connBuilder.UserID = userName; + if (!string.IsNullOrWhiteSpace(password)) connBuilder.Password = password; connBuilder.DataSource = sourceServer; connBuilder.InitialCatalog = sourceDatabase; @@ -47,7 +49,7 @@ public static bool ExtractDacPac(string sourceDatabase, string sourceServer, str } - internal static string ScriptDacPacDeltas(string platinumDacPacFileName, string targetDacPacFileName, string path) + internal static string ScriptDacPacDeltas(string platinumDacPacFileName, string targetDacPacFileName, string path, bool ignoreCompatError = false) { try { @@ -57,6 +59,10 @@ internal static string ScriptDacPacDeltas(string platinumDacPacFileName, string opts.IgnoreExtendedProperties = true; opts.BlockOnPossibleDataLoss = false; opts.IgnoreUserSettingsObjects = true; + if(ignoreCompatError) + { + opts.AllowIncompatiblePlatform = true; + } DacPackage platPackage = DacPackage.Load(platinumDacPacFileName); @@ -65,6 +71,19 @@ internal static string ScriptDacPacDeltas(string platinumDacPacFileName, string return script; } + catch(Microsoft.SqlServer.Dac.DacServicesException dexe) + { + if (dexe.ToString().Contains("DeploymentCompatibilityException")) + { + log.LogWarning("Encountered a Deployment Compatibility Exception! Generating scripts with \"AllowIncompatiblePlatform=true\" setting. This may result in script runtime errors."); + return ScriptDacPacDeltas(platinumDacPacFileName, targetDacPacFileName, path, true); + } + else + { + log.LogError($"Problem creating scripts between {platinumDacPacFileName} and {targetDacPacFileName}: {dexe.ToString()}"); + return string.Empty; + } + } catch (Exception exe) { log.LogError($"Problem creating scripts between {platinumDacPacFileName} and {targetDacPacFileName}: {exe.ToString()}"); @@ -160,7 +179,7 @@ internal static List BatchAndSaveScripts(string masterScript, string wor } return files; } - + /// /// Tries to eliminate the header information that the DACPAC tooling adds /// @@ -169,51 +188,38 @@ internal static List BatchAndSaveScripts(string masterScript, string wor /// internal static DacpacDeltasStatus CleanDacPacScript(string dacPacGeneratedScript, out string cleanedScript) { + int index = -1; + bool matchFound = false; cleanedScript = dacPacGeneratedScript; - //string matchString = Regex.Escape(@"USE [$(DatabaseName)];"); - //MatchCollection useMatches = Regex.Matches(dacPacGeneratedScript, matchString); - //var lastMatch = useMatches.Cast().Select(m => m.Index).LastOrDefault(); - - - //if(lastMatch == -1) //Odd, there should be something, but oh well... - //{ - // return DacpacDeltasStatus.InSync; - //} - - ////Get rid of the SQLCMD header scripts - //if (useMatches.Count < 3) - //{ - // int crAfter = dacPacGeneratedScript.IndexOf("GO", lastMatch); - // cleanedScript = dacPacGeneratedScript.Substring(crAfter + 2); - //}else - //{ - // int crAfter = dacPacGeneratedScript.IndexOf("GO", useMatches[1].Index); - // cleanedScript = dacPacGeneratedScript.Substring(crAfter + 2); - // cleanedScript = cleanedScript.Replace("USE [$(DatabaseName)];", "--USE [$(DatabaseName)];"); - //} - - //string loginString = @"(CREATE USER)|(CREATE LOGIN)|(REVOKE CONNECT)|(EXECUTE sp_addrolemember)"; - //while(Regex.Match(cleanedScript,loginString).Success) - //{ - // var mLogin = Regex.Matches(cleanedScript, loginString).Cast().Select(m => m.Index).FirstOrDefault(); - // int crAfter = cleanedScript.IndexOf("GO", mLogin); - // cleanedScript = cleanedScript.Substring(0, mLogin) + cleanedScript.Substring(crAfter + 2); - //} - - string endofHeader = Regex.Escape(@"Please run the below section of statements against the database"); + //look for basic header + string endofHeader = Regex.Escape(@"Please run the below section of statements against the database"); MatchCollection endMatchs = Regex.Matches(dacPacGeneratedScript, endofHeader); var endMatch = endMatchs.Cast().LastOrDefault(); - if(endMatch == null || endMatch.Index == -1 || string.IsNullOrWhiteSpace(endMatch.Value)) //Odd, there should be something, but oh well... + index = (endMatch == null) ? -1 : endMatch.Index; + if (endMatch != null && endMatch.Index != -1) { - return DacpacDeltasStatus.InSync; + matchFound = true; + var endOfLineIndex = dacPacGeneratedScript.IndexOf(Environment.NewLine, index); + cleanedScript = dacPacGeneratedScript.Substring(endOfLineIndex + 1); } - else + + //look for the database settings header + endMatchs = Regex.Matches(cleanedScript, Regex.Escape("$(DatabaseName)")); + endMatch = endMatchs.Cast().LastOrDefault(); + if (endMatch != null && endMatch.Index != -1) { - var endOfLineIndex = dacPacGeneratedScript.IndexOf(Environment.NewLine, endMatch.Index); - cleanedScript = dacPacGeneratedScript.Substring(endOfLineIndex + 1); - // var lineNumber = dacPacGeneratedScript.Take(endMatch).Count(c => c == '\n') + 1; + matchFound = true; + //get the "GO" delimiter after this match + index = 2 + Regex.Matches(cleanedScript, "GO").Where(m => m.Index > endMatch.Index).FirstOrDefault().Index; + cleanedScript = cleanedScript.Substring(index); + } + if (!matchFound) + { + log.LogInformation("Unable to find script headers, nothing to update?"); + log.LogDebug($"Script contents:{Environment.NewLine}{dacPacGeneratedScript}"); + return DacpacDeltasStatus.InSync; } //Look for the "Post-Deployment Script Template" @@ -224,6 +230,7 @@ internal static DacpacDeltasStatus CleanDacPacScript(string dacPacGeneratedScrip var lineNumber = cleanedScript.Take(postDeploy.Index).Count(c => c == '\n') + 1; if(lineNumber < 25) { + log.LogDebug($"Cleand script contents:{Environment.NewLine}{cleanedScript}"); return DacpacDeltasStatus.OnlyPostDeployment; } } @@ -234,18 +241,20 @@ internal static DacpacDeltasStatus CleanDacPacScript(string dacPacGeneratedScrip .Where(x => !x.StartsWith("GO", StringComparison.InvariantCultureIgnoreCase)); if(!realLines.Any()) { + log.LogDebug($"Cleand script contents:{Environment.NewLine}{cleanedScript}"); return DacpacDeltasStatus.InSync; } + log.LogDebug($"Cleand script contents:{Environment.NewLine}{cleanedScript}"); return DacpacDeltasStatus.Success; } - public static DacpacDeltasStatus UpdateBuildRunDataForDacPacSync(ref SqlBuildRunData runData, string targetServerName, string targetDatabase, string userName, string password, string workingDirectory, string buildRevision, int defaultScriptTimeout) + public static DacpacDeltasStatus UpdateBuildRunDataForDacPacSync(ref SqlBuildRunData runData, string targetServerName, string targetDatabase, AuthenticationType authType, string userName, string password, string workingDirectory, string buildRevision, int defaultScriptTimeout) { string tmpDacPacName = Path.Combine(workingDirectory,targetDatabase + ".dacpac"); - if(!ExtractDacPac(targetDatabase, targetServerName, userName, password, tmpDacPacName)) + if(!ExtractDacPac(targetDatabase, targetServerName, authType, userName, password, tmpDacPacName)) { return DacpacDeltasStatus.ExtractionFailure; } @@ -283,7 +292,7 @@ public static DacpacDeltasStatus UpdateBuildRunDataForDacPacSync(ref SqlBuildRun return DacpacDeltasStatus.Success; } - public static DacpacDeltasStatus GetSbmFromDacPac(string rootLoggingPath, string platinumDacPac, string targetDacpac, string database, string server, string username, string password, string buildRevision, int defaultScriptTimeout, MultiDbData multiDb, out string sbmName) + public static DacpacDeltasStatus GetSbmFromDacPac(string rootLoggingPath, string platinumDacPac, string targetDacpac, string database, string server, AuthenticationType authType, string username, string password, string buildRevision, int defaultScriptTimeout, MultiDbData multiDb, out string sbmName) { string workingFolder = (!string.IsNullOrEmpty(rootLoggingPath) ? rootLoggingPath : Path.GetTempPath()); @@ -304,7 +313,7 @@ public static DacpacDeltasStatus GetSbmFromDacPac(string rootLoggingPath, string else if (!string.IsNullOrEmpty(database) && !string.IsNullOrEmpty(server)) { string targetDacPac = Path.Combine(workingFolder, database + ".dacpac"); - if (!DacPacHelper.ExtractDacPac(database, server, username, password, targetDacPac)) + if (!DacPacHelper.ExtractDacPac(database, server, authType, username, password, targetDacPac)) { log.LogError($"Error extracting dacpac from {database} : {server}"); return DacpacDeltasStatus.ExtractionFailure; @@ -322,7 +331,7 @@ public static DacpacDeltasStatus GetSbmFromDacPac(string rootLoggingPath, string database = serv.OverrideSequence.ElementAt(i).Value[0].OverrideDbTarget; string targetDacPac = Path.Combine(workingFolder, database + ".dacpac"); - if (!DacPacHelper.ExtractDacPac(database, server, username, password, targetDacPac)) + if (!DacPacHelper.ExtractDacPac(database, server, authType, username, password, targetDacPac)) { log.LogError($"Error extracting dacpac from {server} : {database}"); return DacpacDeltasStatus.ExtractionFailure; @@ -370,9 +379,9 @@ public static DacpacDeltasStatus GetSbmFromDacPac(string rootLoggingPath, string } return stat; } - public static DacpacDeltasStatus GetSbmFromDacPac(string rootLoggingPath, string platinumDacPac, string database, string server, string username, string password, string buildRevision, int defaultScriptTimeout, MultiDbData multiDb, out string sbmName) + public static DacpacDeltasStatus GetSbmFromDacPac(string rootLoggingPath, string platinumDacPac, string database, AuthenticationType authType, string server, string username, string password, string buildRevision, int defaultScriptTimeout, MultiDbData multiDb, out string sbmName) { - return GetSbmFromDacPac(rootLoggingPath, platinumDacPac, string.Empty, database, server, username, password, buildRevision, defaultScriptTimeout, multiDb, out sbmName); + return GetSbmFromDacPac(rootLoggingPath, platinumDacPac, string.Empty, database, server, authType, username, password, buildRevision, defaultScriptTimeout, multiDb, out sbmName); } diff --git a/src/SqlSync.SqlBuild/Properties/Resources.Designer.cs b/src/SqlSync.SqlBuild/Properties/Resources.Designer.cs index 5e581ff2..1ed820ea 100644 --- a/src/SqlSync.SqlBuild/Properties/Resources.Designer.cs +++ b/src/SqlSync.SqlBuild/Properties/Resources.Designer.cs @@ -84,7 +84,15 @@ internal static string LoggingTable { return ResourceManager.GetString("LoggingTable", resourceCulture); } } - + + internal static string DacpacExclusion + { + get + { + return ResourceManager.GetString("DacpacExclusion", resourceCulture); + } + } + /// /// Looks up a localized string similar to --Add extra index to improve hash check performance ///IF NOT EXISTS (SELECT 1 FROM sysindexes WHERE name = 'IX_SqlBuild_Logging_CommitCheck' AND OBJECT_NAME(id) = N'SqlBuild_Logging') diff --git a/src/SqlSync.SqlBuild/SQLSync.SqlBuild.csproj b/src/SqlSync.SqlBuild/SQLSync.SqlBuild.csproj index 321d52b1..faa83fd8 100644 --- a/src/SqlSync.SqlBuild/SQLSync.SqlBuild.csproj +++ b/src/SqlSync.SqlBuild/SQLSync.SqlBuild.csproj @@ -16,9 +16,9 @@ - + - + @@ -30,6 +30,9 @@ + + + false false diff --git a/src/SqlSync.SqlBuild/SqlBuildFileHelper.cs b/src/SqlSync.SqlBuild/SqlBuildFileHelper.cs index a8acbd29..829b5dcd 100644 --- a/src/SqlSync.SqlBuild/SqlBuildFileHelper.cs +++ b/src/SqlSync.SqlBuild/SqlBuildFileHelper.cs @@ -357,6 +357,10 @@ public static bool SaveSqlFilesToNewBuildFile(string buildFileName, List return false; } string directory = Path.GetDirectoryName(buildFileName); + if(string.IsNullOrWhiteSpace(directory)) + { + directory = System.IO.Directory.GetCurrentDirectory(); + } try { SqlSyncBuildData buildData = SqlBuildFileHelper.CreateShellSqlSyncBuildDataObject(); diff --git a/src/SqlSync.SqlBuild/SqlBuildHelper.cs b/src/SqlSync.SqlBuild/SqlBuildHelper.cs index ccb12a04..79c6792f 100644 --- a/src/SqlSync.SqlBuild/SqlBuildHelper.cs +++ b/src/SqlSync.SqlBuild/SqlBuildHelper.cs @@ -286,7 +286,7 @@ internal SqlSyncBuildData.BuildRow ProcessBuild(SqlBuildRunData runData, Backgro var database = ((SqlSyncBuildData.ScriptRow)filteredScripts[0].Row).Database; string targetDatabase = GetTargetDatabase(database); log.LogWarning($"Custom dacpac required for {serverName} : {targetDatabase}. Generating file."); - var stat = DacPacHelper.UpdateBuildRunDataForDacPacSync(ref runData, serverName, targetDatabase, this.connData.UserId, this.connData.Password, projectFilePath, runData.BuildRevision, runData.DefaultScriptTimeout); + var stat = DacPacHelper.UpdateBuildRunDataForDacPacSync(ref runData, serverName, targetDatabase, this.connData.AuthenticationType, this.connData.UserId, this.connData.Password, projectFilePath, runData.BuildRevision, runData.DefaultScriptTimeout); if(stat == DacpacDeltasStatus.Success) { diff --git a/src/SqlSync.SqlBuild/SqlSync.SqlBuild.csproj b/src/SqlSync.SqlBuild/SqlSync.SqlBuild.csproj index 321d52b1..faa83fd8 100644 --- a/src/SqlSync.SqlBuild/SqlSync.SqlBuild.csproj +++ b/src/SqlSync.SqlBuild/SqlSync.SqlBuild.csproj @@ -16,9 +16,9 @@ - + - + @@ -30,6 +30,9 @@ + + + false false diff --git a/src/SqlSync.TableScript/SqlSync.TableScript.csproj b/src/SqlSync.TableScript/SqlSync.TableScript.csproj index 320ac5ba..c3dddae1 100644 --- a/src/SqlSync.TableScript/SqlSync.TableScript.csproj +++ b/src/SqlSync.TableScript/SqlSync.TableScript.csproj @@ -49,7 +49,7 @@ - + diff --git a/src/SqlSync/Analysis/LinkedRichTextBoxes.cs b/src/SqlSync/Analysis/LinkedRichTextBoxes.cs index cb716247..887fee4d 100644 --- a/src/SqlSync/Analysis/LinkedRichTextBoxes.cs +++ b/src/SqlSync/Analysis/LinkedRichTextBoxes.cs @@ -28,7 +28,7 @@ public LinkedRichTextBoxes() { InitializeComponent(); - if (Properties.Settings.Default.DiffBackgroundColor != null) + if (Properties.Settings.Default.DiffBackgroundColor != this.diffColor) { this.diffColor = Properties.Settings.Default.DiffBackgroundColor; } @@ -40,9 +40,9 @@ public LinkedRichTextBoxes() } - if (Properties.Settings.Default.DiffForegroundColor != null) + if (Properties.Settings.Default.DiffForegroundColor != this.diffForeColor) { - this.diffColor = Properties.Settings.Default.DiffForegroundColor; + this.diffForeColor = Properties.Settings.Default.DiffForegroundColor; } else { diff --git a/src/SqlSync/AutoScript/AutoScripting.cs b/src/SqlSync/AutoScript/AutoScripting.cs index 1deb88a3..69044b95 100644 --- a/src/SqlSync/AutoScript/AutoScripting.cs +++ b/src/SqlSync/AutoScript/AutoScripting.cs @@ -6,6 +6,7 @@ using SqlSync.AutoScript; using SqlSync.Connection; using SqlSync.ObjectScript; +using Microsoft.Extensions.Logging; namespace SqlSync { /// @@ -41,7 +42,8 @@ public class AutoScripting : System.Windows.Forms.Form private SplitContainer splitContainer1; private Panel panel1; private bool zipScripts = true; - public AutoScripting(string configFile) + private static ILogger log = SqlBuildManager.Logging.ApplicationLogging.CreateLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + public AutoScripting(string configFile) { InitializeComponent(); this.configFileName = configFile; diff --git a/src/SqlSync/ProcessHelper.cs b/src/SqlSync/ProcessHelper.cs index fce17b7c..0f21d704 100644 --- a/src/SqlSync/ProcessHelper.cs +++ b/src/SqlSync/ProcessHelper.cs @@ -71,8 +71,8 @@ public int ExecuteProcess(string processName, string arguments) this.prc.WaitForExit(); - if (!THRoutput.Join(new TimeSpan(0, 3, 0))) THRoutput.Abort(); - if (!THRerror.Join(new TimeSpan(0, 3, 0))) THRerror.Abort(); + THRoutput.Join(new TimeSpan(0, 3, 0)); + THRerror.Join(new TimeSpan(0, 3, 0)); this.endTime = DateTime.Now; diff --git a/src/SqlSync/SQLSync.csproj b/src/SqlSync/SQLSync.csproj index 4c2dd0b7..ec2015ce 100644 --- a/src/SqlSync/SQLSync.csproj +++ b/src/SqlSync/SQLSync.csproj @@ -13,6 +13,10 @@ SqlBuildManager.ico SqlBuildManager + + + 1701;1702;CA1416 + @@ -340,20 +344,20 @@ - + - + - + - + - + diff --git a/src/SqlSync/SqlBuild/SqlBuildForm.cs b/src/SqlSync/SqlBuild/SqlBuildForm.cs index 86f484ae..66a79449 100644 --- a/src/SqlSync/SqlBuild/SqlBuildForm.cs +++ b/src/SqlSync/SqlBuild/SqlBuildForm.cs @@ -6834,7 +6834,7 @@ private void autoScriptListItem_Click(object sender, EventArgs e) if (File.Exists(this.autoScriptListRegistration.Items[i].File)) { System.Diagnostics.Process prc = new System.Diagnostics.Process(); - prc.StartInfo.FileName = System.Reflection.Assembly.GetExecutingAssembly().CodeBase; + prc.StartInfo.FileName = System.Reflection.Assembly.GetExecutingAssembly().Location; prc.StartInfo.Arguments = " \"" + this.autoScriptListRegistration.Items[i].File + "\""; prc.Start(); } diff --git a/src/SqlSync/change_notes.html b/src/SqlSync/change_notes.html index ddf9378b..275b5df5 100644 --- a/src/SqlSync/change_notes.html +++ b/src/SqlSync/change_notes.html @@ -39,6 +39,18 @@

SQL Build Manager Change Notes

+
Version 13.0.3
+
+ FIXED: Update to Dacpac change scripts to identify new header delimiter
+
+ FIXED: Issue creating scripts between incompatable SQL Server versions. Will now output a warning and continue to create the scripts with the flag `AllowIncompatiblePlatform=true`
+
+ ADDED: New command `sbm create` to create a new SBM file from a list of scripts
+
+ UPDATED: Can now use Windows auth for DACPAC creation
+
+ UPDATED: updated Nuget packages
+
Version 13.0.2
FIXED: Update to ensure all Queue messages are retrieved efficiently
@@ -47,7 +59,7 @@

SQL Build Manager Change Notes

UPDATED: Code clean up and refactoring to accommodate latest version of System.CommandLine
- FIXED: Issue with SQL text syntax higlighting formatting in .NET 5.0
+ FIXED: Issue with SQL text syntax highlighting formatting in .NET 5.0
NOTE: Removed "Construct Command Line" menu options from Windows UI. Users should leverage the generated help docs for sbm.exe

@@ -67,7 +79,7 @@

SQL Build Manager Change Notes


Version 12.1.0
- UPDATED: Removed log4net logging. Unified logging via ILogger created in SqlBuildManager.Loggging. Implements Serilog
+ UPDATED: Removed log4net logging. Unified logging via ILogger created in SqlBuildManager.Logging. Implements Serilog
Version 12.0.0
diff --git a/src/SqlSync/change_notes.xml b/src/SqlSync/change_notes.xml index 4e8bf43c..199e7246 100644 --- a/src/SqlSync/change_notes.xml +++ b/src/SqlSync/change_notes.xml @@ -1,10 +1,17 @@ + + Update to Dacpac change scripts to identify new header delimiter + Issue creating scripts between incompatable SQL Server versions. Will now output a warning and continue to create the scripts with the flag `AllowIncompatiblePlatform=true` + New command `sbm create` to create a new SBM file from a list of scripts + Can now use Windows auth for DACPAC creation + updated Nuget packages + Update to ensure all Queue messages are retrieved efficiently New utility method `sbm batch dequeue` to remove all messages from the Service Bus Queue topic (without processing them) Code clean up and refactoring to accommodate latest version of System.CommandLine - Issue with SQL text syntax higlighting formatting in .NET 5.0 + Issue with SQL text syntax highlighting formatting in .NET 5.0 Removed "Construct Command Line" menu options from Windows UI. Users should leverage the generated help docs for sbm.exe @@ -17,7 +24,7 @@ Modified unit tests to Close and Flush loggers to avoid file locking issues - Removed log4net logging. Unified logging via ILogger created in SqlBuildManager.Loggging. Implements Serilog + Removed log4net logging. Unified logging via ILogger created in SqlBuildManager.Logging. Implements Serilog **Removed old style command line (leveraging the `/Action=verb` flag etc.). Run `sbm --help` for instructions**