private async Task ModifyInternalAsync(ScriptModificationModel model) { var(errorsWhileLoading, oldDefaultConstraints, currentDefaultConstraints) = await GetDefaultConstraints(model.Paths); if (errorsWhileLoading) { return; } var defaultConstraintsToRemove = oldDefaultConstraints.Where(m => m.ConstraintName == null) .Except(currentDefaultConstraints) .ToDictionary(constraint => constraint, constraint => false); var(resultText, regexMatchTimeouts, failedReplacements) = ReplaceUnnamedDefaultConstraintStatements(model.CurrentScript, defaultConstraintsToRemove); if (regexMatchTimeouts > 0) { await _logger.LogWarningAsync($"{nameof(ReplaceUnnamedDefaultConstraintDropsModifier)}: Regular expression matching timed out {regexMatchTimeouts} time(s)."); } if (failedReplacements > 0) { await _logger.LogWarningAsync($"{nameof(ReplaceUnnamedDefaultConstraintDropsModifier)}: Script defines {failedReplacements} unnamed default constraint(s) more to drop than the DACPAC models provide."); } model.CurrentScript = resultText; }
public async Task Modify_ReplaceSpecialKeyword_PreviousVersion_Async() { // Arrange IScriptModifier s = new AddCustomHeaderModifier(); const string input = "foobar"; var project = new SqlProject("a", "b", "c"); project.ProjectProperties.DacVersion = new Version(1, 3, 0); var configuration = new ConfigurationModel { CustomHeader = "Script base version: {PREVIOUS_VERSION}" }; var directories = new DirectoryPaths("projectDirectory", "latestArtifactsDirectory", "newArtifactsDirectory"); var sourcePaths = new DeploySourcePaths("newDacpacPath", "publishProfilePath", "previousDacpacPath"); var targetPaths = new DeployTargetPaths("deployScriptPath", "deployReportPath"); var paths = new PathCollection(directories, sourcePaths, targetPaths); var model = new ScriptModificationModel(input, project, configuration, paths, new Version(1, 2, 0), false); // Act await s.ModifyAsync(model); // Assert Assert.IsNotNull(model.CurrentScript); Assert.AreEqual("Script base version: 1.2.0\r\nfoobar", model.CurrentScript); }
Task IScriptModifier.ModifyAsync(ScriptModificationModel model) { if (model == null) { throw new ArgumentNullException(nameof(model)); } return(RemoveSqlCmdStatementsInternal(model)); }
public async Task ModifyAsync_ErrorsGettingDacpacConstraints_Async() { // Arrange var daMock = new Mock <IDacAccess>(); var loggerMock = new Mock <ILogger>(); daMock.Setup(m => m.GetDefaultConstraintsAsync("previousDacpacPath")) .ReturnsAsync(() => (new DefaultConstraint[0], new [] { "oldError1", "oldError2" })); daMock.Setup(m => m.GetDefaultConstraintsAsync("newDacpacPath")) .ReturnsAsync(() => (new DefaultConstraint[0], new[] { "newError1", "newError2" })); var project = new SqlProject("a", "b", "c"); var config = new ConfigurationModel { ArtifactsPath = "foobar", ReplaceUnnamedDefaultConstraintDrops = true, CommentOutUnnamedDefaultConstraintDrops = false, PublishProfilePath = "Test.publish.xml", VersionPattern = "1.2.3.4", CreateDocumentationWithScriptCreation = true, CustomHeader = "awesome header", CustomFooter = "lame footer", BuildBeforeScriptCreation = true, TrackDacpacVersion = false }; var directories = new DirectoryPaths("projectDirectory", "latestArtifactsDirectory", "newArtifactsDirectory"); var sourcePaths = new DeploySourcePaths("newDacpacPath", "publishProfilePath", "previousDacpacPath"); var targetPaths = new DeployTargetPaths("deployScriptPath", "deployReportPath"); var paths = new PathCollection(directories, sourcePaths, targetPaths); IScriptModifier modifier = new ReplaceUnnamedDefaultConstraintDropsModifier(daMock.Object, loggerMock.Object); var model = new ScriptModificationModel(MultipleDropDefaultConstraintStatements, project, config, paths, new Version(1, 0, 0), false); // Act await modifier.ModifyAsync(model); // Assert Assert.AreEqual(MultipleDropDefaultConstraintStatements, model.CurrentScript); loggerMock.Verify(m => m.LogErrorAsync("Failed to load the default constraints of the previous DACPAC:"), Times.Once); loggerMock.Verify(m => m.LogErrorAsync("oldError1"), Times.Once); loggerMock.Verify(m => m.LogErrorAsync("oldError2"), Times.Once); loggerMock.Verify(m => m.LogErrorAsync("Failed to load the default constraints of the current DACPAC:"), Times.Once); loggerMock.Verify(m => m.LogErrorAsync("newError1"), Times.Once); loggerMock.Verify(m => m.LogErrorAsync("newError2"), Times.Once); }
public void CurrentScript_Set_ArgumentNullException_WhenSetTotNull() { // Arrange var initialScript = "script"; var project = new SqlProject("a", "b", "c"); var configuration = new ConfigurationModel(); var directories = new DirectoryPaths("projectDirectory", "latestArtifactsDirectory", "newArtifactsDirectory"); var sourcePaths = new DeploySourcePaths("newDacpacPath", "publishProfilePath", "previousDacpacPath"); var targetPaths = new DeployTargetPaths("deployScriptPath", "deployReportPath"); var paths = new PathCollection(directories, sourcePaths, targetPaths); var previousVersion = new Version(1, 2, 0); var model = new ScriptModificationModel(initialScript, project, configuration, paths, previousVersion, true); // Act & Assert // ReSharper disable once AssignNullToNotNullAttribute Assert.Throws <ArgumentNullException>(() => model.CurrentScript = null); }
public async Task ModifyAsync_CorrectReplacement_OneRegexTimeout_Async() { // Arrange var schemaName = new string('a', 1_000_000) + '.'; var input = string.Format(MultipleDropDefaultConstraintStatementsWithPlaceholder, schemaName); var expectedOutput = string.Format(MultipleDropDefaultConstraintStatementsReplacedPartiallyWithPlaceholder, schemaName); var daMock = new Mock <IDacAccess>(); var loggerMock = new Mock <ILogger>(); daMock.Setup(m => m.GetDefaultConstraintsAsync("previousDacpacPath")) .ReturnsAsync(() => (new[] { new DefaultConstraint("dbo", "Author", "LastName", null), new DefaultConstraint("dbo", "Book", "Title", null), new DefaultConstraint("dbo", "Book", "RegisteredDate", "DF_RegisteredDate_Today") }, null)); daMock.Setup(m => m.GetDefaultConstraintsAsync("newDacpacPath")) .ReturnsAsync(() => (new DefaultConstraint[0], null)); var project = new SqlProject("a", "b", "c"); var config = new ConfigurationModel { ArtifactsPath = "foobar", ReplaceUnnamedDefaultConstraintDrops = true, CommentOutUnnamedDefaultConstraintDrops = false, PublishProfilePath = "Test.publish.xml", VersionPattern = "1.2.3.4", CreateDocumentationWithScriptCreation = true, CustomHeader = "awesome header", CustomFooter = "lame footer", BuildBeforeScriptCreation = true, TrackDacpacVersion = false }; var directories = new DirectoryPaths("projectDirectory", "latestArtifactsDirectory", "newArtifactsDirectory"); var sourcePaths = new DeploySourcePaths("newDacpacPath", "publishProfilePath", "previousDacpacPath"); var targetPaths = new DeployTargetPaths("deployScriptPath", "deployReportPath"); var paths = new PathCollection(directories, sourcePaths, targetPaths); IScriptModifier modifier = new ReplaceUnnamedDefaultConstraintDropsModifier(daMock.Object, loggerMock.Object); var model = new ScriptModificationModel(input, project, config, paths, new Version(1, 0, 0), false); // Act await modifier.ModifyAsync(model); // Assert Assert.AreEqual(expectedOutput, model.CurrentScript); loggerMock.Verify(m => m.LogWarningAsync($"{nameof(ReplaceUnnamedDefaultConstraintDropsModifier)}: Regular expression matching timed out 1 time(s)."), Times.Once); }
public async Task Modify_CorrectModification_Async() { // Arrange IScriptModifier modifier = new CommentOutUnnamedDefaultConstraintDropsModifier(); var project = new SqlProject("", "", ""); var configuration = new ConfigurationModel(); var directories = new DirectoryPaths("projectDirectory", "latestArtifactsDirectory", "newArtifactsDirectory"); var sourcePaths = new DeploySourcePaths("newDacpacPath", "publishProfilePath", "previousDacpacPath"); var targetPaths = new DeployTargetPaths("deployScriptPath", "deployReportPath"); var paths = new PathCollection(directories, sourcePaths, targetPaths); var model = new ScriptModificationModel(MultipleDropDefaultConstraintStatements, project, configuration, paths, new Version(1, 0, 0), false); // Act await modifier.ModifyAsync(model); // Assert Assert.AreEqual(MultipleDropDefaultConstraintStatementsCommented, model.CurrentScript); }
public void Modify_ArgumentException_ProjectPropertiesSqlTargetNameNull() { // Arrange IScriptModifier modifier = new TrackDacpacVersionModifier(); var project = new SqlProject("", "", ""); var configuration = new ConfigurationModel(); var directories = new DirectoryPaths("projectDirectory", "latestArtifactsDirectory", "newArtifactsDirectory"); var sourcePaths = new DeploySourcePaths("newDacpacPath", "publishProfilePath", "previousDacpacPath"); var targetPaths = new DeployTargetPaths("deployScriptPath", "deployReportPath"); var paths = new PathCollection(directories, sourcePaths, targetPaths); var model = new ScriptModificationModel(MultiLineInputWithFinalGo, project, configuration, paths, new Version(1, 0, 0), false); // Act var e = Assert.Throws <ArgumentException>(() => modifier.ModifyAsync(model)); // Assert Assert.IsNotNull(e); Assert.IsTrue(e.Message.Contains(nameof(SqlProjectProperties.SqlTargetName))); }
public async Task ModifyAsync_CorrectReplacement_Async() { // Arrange var daMock = new Mock <IDacAccess>(); var loggerMock = new Mock <ILogger>(); daMock.Setup(m => m.GetDefaultConstraintsAsync("previousDacpacPath")) .ReturnsAsync(() => (new[] { new DefaultConstraint("dbo", "Author", "LastName", null), new DefaultConstraint("dbo", "Book", "Title", null), new DefaultConstraint("dbo", "Book", "RegisteredDate", "DF_RegisteredDate_Today") }, null)); daMock.Setup(m => m.GetDefaultConstraintsAsync("newDacpacPath")) .ReturnsAsync(() => (new DefaultConstraint[0], null)); var project = new SqlProject("a", "b", "c"); var config = new ConfigurationModel { ArtifactsPath = "foobar", ReplaceUnnamedDefaultConstraintDrops = true, CommentOutUnnamedDefaultConstraintDrops = false, PublishProfilePath = "Test.publish.xml", VersionPattern = "1.2.3.4", CreateDocumentationWithScriptCreation = true, CustomHeader = "awesome header", CustomFooter = "lame footer", BuildBeforeScriptCreation = true, TrackDacpacVersion = false }; var directories = new DirectoryPaths("projectDirectory", "latestArtifactsDirectory", "newArtifactsDirectory"); var sourcePaths = new DeploySourcePaths("newDacpacPath", "publishProfilePath", "previousDacpacPath"); var targetPaths = new DeployTargetPaths("deployScriptPath", "deployReportPath"); var paths = new PathCollection(directories, sourcePaths, targetPaths); IScriptModifier modifier = new ReplaceUnnamedDefaultConstraintDropsModifier(daMock.Object, loggerMock.Object); var model = new ScriptModificationModel(MultipleDropDefaultConstraintStatements, project, config, paths, new Version(1, 0, 0), false); // Act await modifier.ModifyAsync(model); // Assert Assert.AreEqual(MultipleDropDefaultConstraintStatementsReplaced, model.CurrentScript); }
private async Task <bool> ApplyAllModifiers(SqlProject project, ConfigurationModel configuration, PathCollection paths, Version previousVersion, bool createLatest, IReadOnlyDictionary <ScriptModifier, IScriptModifier> modifiers) { string initialScript; try { initialScript = await _fileSystemAccess.ReadFileAsync(paths.DeployTargets.DeployScriptPath); } catch (Exception e) { await _logger.LogErrorAsync(e, "Failed to read the generated script"); return(false); } var model = new ScriptModificationModel(initialScript, project, configuration, paths, previousVersion, createLatest); foreach (var m in modifiers.OrderBy(m => m.Key)) { await _logger.LogInfoAsync($"Modifying script: {m.Key}"); await m.Value.ModifyAsync(model); } try { await _fileSystemAccess.WriteFileAsync(paths.DeployTargets.DeployScriptPath, model.CurrentScript); } catch (Exception e) { await _logger.LogErrorAsync(e, "Failed to write the modified script"); return(false); } return(true); }
public async Task Modify_CorrectModification_MajorMinorVersion_Async(string input) { // Arrange IScriptModifier modifier = new TrackDacpacVersionModifier(); var project = new SqlProject("", "", ""); project.ProjectProperties.SqlTargetName = "Database.TestProject"; project.ProjectProperties.DacVersion = new Version(500, 30); var configuration = new ConfigurationModel(); var directories = new DirectoryPaths("projectDirectory", "latestArtifactsDirectory", "newArtifactsDirectory"); var sourcePaths = new DeploySourcePaths("newDacpacPath", "publishProfilePath", "previousDacpacPath"); var targetPaths = new DeployTargetPaths("deployScriptPath", "deployReportPath"); var paths = new PathCollection(directories, sourcePaths, targetPaths); var model = new ScriptModificationModel(input, project, configuration, paths, new Version(1, 0, 0), false); // Act await modifier.ModifyAsync(model); // Assert Assert.AreEqual(FinalMultilineStatementMajorMinorVersion, model.CurrentScript); }
Task IScriptModifier.ModifyAsync(ScriptModificationModel model) { if (model == null) { throw new ArgumentNullException(nameof(model)); } model.CurrentScript = ForEachMatch(model.CurrentScript, "DROP CONSTRAINT ;", 1, range => { var lines = range.Split(new[] { Environment.NewLine }, StringSplitOptions.None); var newLines = lines.Select(m => string.IsNullOrWhiteSpace(m) ? m : $"-- {m}").ToArray(); var replacement = string.Join(Environment.NewLine, newLines); return(replacement); }); return(Task.CompletedTask); }
public async Task ModifyAsync_CorrectModification_Async(string input) { // Arrange IScriptModifier modifier = new RemoveSqlCmdStatementsModifier(); var project = new SqlProject("a", "b", "c"); project.ProjectProperties.DacVersion = new Version(1, 3, 0); var configuration = new ConfigurationModel { CustomFooter = "footer" }; var directories = new DirectoryPaths("projectDirectory", "latestArtifactsDirectory", "newArtifactsDirectory"); var sourcePaths = new DeploySourcePaths("newDacpacPath", "publishProfilePath", "previousDacpacPath"); var targetPaths = new DeployTargetPaths("deployScriptPath", "deployReportPath"); var paths = new PathCollection(directories, sourcePaths, targetPaths); var model = new ScriptModificationModel(input, project, configuration, paths, new Version(1, 2, 0), false); // Act await modifier.ModifyAsync(model); // Assert Assert.AreEqual(MultiLineInputWithoutSqlcmdStatements, model.CurrentScript); }
public void Constructor_CorrectInitialization() { // Arrange var initialScript = "script"; var project = new SqlProject("a", "b", "c"); var configuration = new ConfigurationModel(); var directories = new DirectoryPaths("projectDirectory", "latestArtifactsDirectory", "newArtifactsDirectory"); var sourcePaths = new DeploySourcePaths("newDacpacPath", "publishProfilePath", "previousDacpacPath"); var targetPaths = new DeployTargetPaths("deployScriptPath", "deployReportPath"); var paths = new PathCollection(directories, sourcePaths, targetPaths); var previousVersion = new Version(1, 2, 0); // Act var model = new ScriptModificationModel(initialScript, project, configuration, paths, previousVersion, true); // Assert Assert.AreEqual(initialScript, model.CurrentScript); Assert.AreSame(project, model.Project); Assert.AreSame(configuration, model.Configuration); Assert.AreSame(paths, model.Paths); Assert.AreSame(previousVersion, model.PreviousVersion); Assert.IsTrue(model.CreateLatest); }
Task IScriptModifier.ModifyAsync(ScriptModificationModel model) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (string.IsNullOrWhiteSpace(model.Configuration.CustomHeader)) { return(Task.CompletedTask); } var header = model.Configuration.CustomHeader; header = header.Replace(Constants.ScriptModificationSpecialKeywordPreviousVersion, model.PreviousVersion.ToString()); header = header.Replace(Constants.ScriptModificationSpecialKeywordNextVersion, model.CreateLatest ? "latest" : model.Project.ProjectProperties.DacVersion.ToString()); var sb = new StringBuilder(header); sb.AppendLine(); sb.Append(model.CurrentScript); model.CurrentScript = sb.ToString(); return(Task.CompletedTask); }
public async Task Modify_NoLeadingNewLineWhenNullOrWhiteSpace_Async(string customHeader) { // Arrange IScriptModifier s = new AddCustomHeaderModifier(); const string input = "foobar"; var project = new SqlProject("a", "b", "c"); var configuration = new ConfigurationModel { CustomHeader = customHeader }; var directories = new DirectoryPaths("projectDirectory", "latestArtifactsDirectory", "newArtifactsDirectory"); var sourcePaths = new DeploySourcePaths("newDacpacPath", "publishProfilePath", "previousDacpacPath"); var targetPaths = new DeployTargetPaths("deployScriptPath", "deployReportPath"); var paths = new PathCollection(directories, sourcePaths, targetPaths); var model = new ScriptModificationModel(input, project, configuration, paths, new Version(1, 0, 0), false); // Act await s.ModifyAsync(model); // Assert Assert.IsNotNull(model.CurrentScript); Assert.AreEqual("foobar", model.CurrentScript); }
Task IScriptModifier.ModifyAsync(ScriptModificationModel model) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (model.Project.ProjectProperties.SqlTargetName == null) { throw new ArgumentException($"{nameof(ScriptModificationModel.Project)}.{nameof(SqlProject.ProjectProperties)}.{nameof(SqlProjectProperties.SqlTargetName)} must be set.", nameof(model)); } if (model.Project.ProjectProperties.DacVersion == null) { throw new ArgumentException($"{nameof(ScriptModificationModel.Project)}.{nameof(SqlProject.ProjectProperties)}.{nameof(SqlProjectProperties.DacVersion)} must be set.", nameof(model)); } // Prepare format string var(createAndInsertStatement, updateStatement) = GetFinalStatementsFromTemplate(model.CurrentScript, model.Project); var createAndInsertStatementSet = false; var modifiedWithInsertAndCreateStatement = ForEachMatch(model.CurrentScript, "USE [$(DatabaseName)];", 0, s => { if (createAndInsertStatementSet) { return(s); } createAndInsertStatementSet = true; return(s + createAndInsertStatement); }); model.CurrentScript = modifiedWithInsertAndCreateStatement + updateStatement; return(Task.CompletedTask); }
private static Task RemoveSqlCmdStatementsInternal(ScriptModificationModel model) { model.CurrentScript = ForEachMatch(model.CurrentScript, "USE [$(DatabaseName)];", 0, s => string.Empty); model.CurrentScript = ForEachMatch(model.CurrentScript, "IF N'$(__IsSqlCmdEnabled)' NOT LIKE N'True'", 0, s => string.Empty); model.CurrentScript = ForEachMatch(model.CurrentScript, @":setvar __IsSqlCmdEnabled ""True""", 0, s => string.Empty); model.CurrentScript = ForEachMatch(model.CurrentScript, ":on error exit", 0, s => string.Empty); model.CurrentScript = ForEachMatch(model.CurrentScript, ":setvar DatabaseName", 0, s => string.Empty); return(Task.CompletedTask); }