Created
June 19, 2019 09:02
-
-
Save Grinderofl/147b7cd867fb55cdb9fbd0492043220a to your computer and use it in GitHub Desktop.
Specify starting migration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#addin nuget:?package=Newtonsoft.Json&version=12.0.1 | |
using Newtonsoft.Json; | |
public class EfMigration | |
{ | |
public string Id { get; set; } | |
public string Name { get; set; } | |
public string SafeName { get; set; } | |
} | |
public class EfContext | |
{ | |
public string FullName { get; set; } | |
public string SafeName { get; set; } | |
public string Name { get; set; } | |
public string AssemblyQualifiedName { get; set; } | |
} | |
public class EfMigrationConfiguration | |
{ | |
public EfMigrationConfiguration(string contextName, string fromMigration = null) | |
{ | |
ContextName = contextName; | |
From = fromMigration; | |
} | |
public string ContextName { get; } | |
public string From { get; set; } | |
} | |
public partial class Configuration | |
{ | |
public List<EfMigrationConfiguration> MigrationConfigurations { get; } = new List<EfMigrationConfiguration>(); | |
public Configuration MigrateContext(string contextName, string fromMigration = null) | |
{ | |
MigrationConfigurations.Add(new EfMigrationConfiguration(contextName, fromMigration)); | |
context.Information("Added Migration From {0} for context {1}", fromMigration, contextName); | |
return this; | |
} | |
} | |
// known issue workaround https://github.com/aspnet/Home/releases/tag/2.1.3#known-issues | |
// and mysterious EF tool log messages | |
string SanitizeToolOutput(string toolOutput) | |
{ | |
var lines = toolOutput.Split('\n'); | |
var lineIndex = 0; | |
for (; lineIndex < lines.Length; lineIndex++) | |
{ | |
var line = lines[lineIndex]; | |
if (line.StartsWith("{") || line.StartsWith("[")) { break; } | |
} | |
return string.Join( "\n", lines.Skip(lineIndex)); | |
} | |
var schemaFinder = new System.Text.RegularExpressions.Regex("N\'(.*)'"); | |
string TransactionalizeMigration(string contents) | |
{ | |
var lines = contents.Split('\n'); | |
var output = new List<string>(); | |
var currentTransaction = ""; | |
foreach (var line in lines) | |
{ | |
if (line.Contains("IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId]")) | |
{ | |
var transaction = schemaFinder.Match(line).Groups[1].Value; | |
if(!string.IsNullOrWhiteSpace(currentTransaction) && !currentTransaction.Equals(transaction)) | |
{ | |
output.Add("COMMIT\n"); | |
currentTransaction = ""; | |
} | |
if (string.IsNullOrWhiteSpace(currentTransaction)) | |
{ | |
currentTransaction = transaction; | |
output.Add("BEGIN TRANSACTION\n"); | |
} | |
} | |
var lineToAdd = !string.IsNullOrWhiteSpace(currentTransaction) ? $"\t{line}" : line; | |
output.Add(lineToAdd); | |
} | |
if (!string.IsNullOrWhiteSpace(currentTransaction)) | |
{ | |
output.Add("COMMIT"); | |
} | |
return string.Join("\n", output); | |
} | |
IEnumerable<EfContext> GetAllDbContexts(DirectoryPath workingDirectory, string configuration) | |
{ | |
var settings = new ProcessSettings() | |
{ | |
WorkingDirectory = workingDirectory, | |
RedirectStandardOutput = true | |
}; | |
settings.Arguments = string.Format("ef dbcontext list --configuration {0} --json", configuration); | |
var list = Enumerable.Empty<EfContext>(); | |
using(var process = StartAndReturnProcess("dotnet", settings)) | |
{ | |
process.WaitForExit(); | |
if(process.GetExitCode() == 0) | |
{ | |
try | |
{ | |
var outputAsJson = SanitizeToolOutput(string.Join(Environment.NewLine, process.GetStandardOutput())); | |
list = JsonConvert.DeserializeObject<List<EfContext>>(outputAsJson); | |
Verbose("Found {0} Db contexts", list.Count()); | |
} | |
catch(Exception exception) | |
{ | |
Error("Unable to determine db context's for {0} : {1}", workingDirectory, exception.Message); | |
} | |
} | |
} | |
return list.ToList(); | |
} | |
IEnumerable<EfMigration> GetMigrationsForContext(string dbContext, DirectoryPath workingDirectory, string configuration) | |
{ | |
var settings = new ProcessSettings() | |
{ | |
WorkingDirectory = workingDirectory, | |
RedirectStandardOutput = true | |
}; | |
settings.Arguments = string.Format("ef migrations list --configuration {0} --context {1} --json", configuration, dbContext); | |
var list = Enumerable.Empty<EfMigration>(); | |
using(var process = StartAndReturnProcess("dotnet", settings)) | |
{ | |
process.WaitForExit(); | |
if(process.GetExitCode() == 0) | |
{ | |
try | |
{ | |
var outputAsJson = SanitizeToolOutput(string.Join(Environment.NewLine, process.GetStandardOutput())); | |
list = JsonConvert.DeserializeObject<List<EfMigration>>(outputAsJson); | |
} | |
catch(Exception exception) | |
{ | |
Error("Unable to determine db migration list for {0} : {1}", dbContext, exception.Message); | |
} | |
} | |
} | |
return list; | |
} | |
Task("Artifacts:DotNetCore:Ef:Migration-Script") | |
.IsDependentOn("Build") | |
.IsDependeeOf("Publish") | |
.Does<Configuration>(config => | |
{ | |
var efProjects = config.Solution.Projects.ToList(); | |
Information("Generating scripts for {0} projects", efProjects.Count()); | |
foreach(var project in efProjects) { | |
var assemblyName = config.Solution.GetProjectName(project); | |
var workingDirectory = project.ProjectFilePath.GetDirectory(); | |
var availableDbContexts = GetAllDbContexts(workingDirectory, config.Solution.BuildConfiguration).ToList(); | |
Information("Generating scripts for {0} containing {1} contexts", assemblyName, availableDbContexts.Count); | |
foreach(var dbContext in availableDbContexts) | |
{ | |
Information("Generating Sql Script for {0}", dbContext.SafeName); | |
var migrations = GetMigrationsForContext(dbContext.SafeName, workingDirectory, config.Solution.BuildConfiguration); | |
var sqlScript = MakeAbsolute(File($"{config.Artifacts.Root}/sql/{dbContext.SafeName}.sql")); | |
if(FileExists(sqlScript)) { | |
DeleteFile(sqlScript); | |
} | |
var settings = new ProcessSettings() | |
{ | |
WorkingDirectory = workingDirectory | |
}; | |
var migrationConfiguration = config.MigrationConfigurations.FirstOrDefault(x => x.ContextName == dbContext.SafeName); | |
if(migrationConfiguration != null) | |
{ | |
Information("Migrating {0} from {1}", migrationConfiguration.ContextName, migrationConfiguration.From); | |
settings.Arguments = string.Format("ef migrations script -i -o {0} --configuration {1} --context {2} {3}", sqlScript, config.Solution.BuildConfiguration, dbContext.SafeName, migrationConfiguration.From); | |
} | |
else | |
{ | |
settings.Arguments = string.Format("ef migrations script -i -o {0} --configuration {1} --context {2}", sqlScript, config.Solution.BuildConfiguration, dbContext.SafeName); | |
} | |
using(var process = StartAndReturnProcess("dotnet", settings)) | |
{ | |
process.WaitForExit(); | |
Verbose("Exit code: {0}", process.GetExitCode()); | |
} | |
config.Artifacts.Add(ArtifactTypeOption.Other, sqlScript.GetFilename().ToString(), sqlScript); | |
} | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#load ".cake/Configuration.cake" | |
/**********************************************************/ | |
Setup<Configuration>(ctx => Configuration | |
.Create(ctx, "*.sln", c => {}) | |
.MigrateContext("DataContext", "20181213073236_MigrateFromMe") | |
); | |
/**********************************************************/ | |
#load ".cake/CI.cake" | |
// -- DotNetCore | |
#load ".cake/Npm-RunScript.cake" | |
#load ".cake/Restore-DotNetCore.cake" | |
#load ".cake/Build-DotNetCore.cake" | |
#load ".cake/Test-DotNetCore.cake" | |
#load ".cake/Test-Success.cake" | |
#load ".cake/Publish-Zip-DotNetCore.cake" | |
#load ".cake/Artifacts-DotNetCore-Ef.cake" | |
#load ".cake/Artifacts-Sql.cake" | |
#load ".cake/Artifacts-ARM.cake" | |
// ------------- | |
RunTarget(Argument("target", Argument("Target", "Default"))); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment