Skip to content

Commit

Permalink
Task #504: Add --isuptodate feature
Browse files Browse the repository at this point in the history
  • Loading branch information
erikbra committed May 27, 2024
1 parent 7ef1608 commit 3e12911
Show file tree
Hide file tree
Showing 11 changed files with 324 additions and 37 deletions.
2 changes: 2 additions & 0 deletions src/grate.core/Configuration/GrateConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,6 @@ public record GrateConfiguration
/// Defer writing to the run tables until the end of the migration (only used in bootstrapping)
/// </summary>
internal bool DeferWritingToRunTables { get; set; }

public bool UpToDateCheck { get; set; }
}
45 changes: 18 additions & 27 deletions src/grate.core/Migration/DbMigrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,13 @@ public async Task<bool> RunSql(string sql, string scriptName, MigrationsFolder f

var type = folder.Type;

async Task<bool> LogAndRunSql()
async Task LogAndRunSql()
{
Logger.LogInformation(" Running '{ScriptName}'.", scriptName);

if (Configuration.DryRun)
{
return false;
}
else

if (!Configuration.DryRun)
{
await RunTheActualSql(sql, scriptName, type, versionId, connectionType, transactionHandling);
return true;
}
}

Expand Down Expand Up @@ -132,7 +127,8 @@ async Task<bool> LogAndRunSql()
case MigrationType.Once when changeHandling == ChangedScriptHandling.WarnAndRun:
LogScriptChangedWarning(scriptName);
Logger.LogDebug("Running script anyway due to WarnOnOneTimeScriptChanges option being set.");
theSqlWasRun = await LogAndRunSql();
await LogAndRunSql();
theSqlWasRun = true;
break;

case MigrationType.Once when changeHandling == ChangedScriptHandling.WarnAndIgnore:
Expand All @@ -143,7 +139,8 @@ async Task<bool> LogAndRunSql()

case MigrationType.AnyTime:
case MigrationType.EveryTime:
theSqlWasRun = await LogAndRunSql();
await LogAndRunSql();
theSqlWasRun = true;
break;
}
}
Expand All @@ -154,7 +151,8 @@ async Task<bool> LogAndRunSql()
}
else
{
theSqlWasRun = await LogAndRunSql();
await LogAndRunSql();
theSqlWasRun = true;
}

return theSqlWasRun;
Expand All @@ -167,21 +165,6 @@ public async Task<bool> RunSqlWithoutLogging(
ConnectionType connectionType,
TransactionHandling transactionHandling)
{
async Task<bool> PrintLogAndRunSql()
{
Logger.LogInformation(" Running '{ScriptName}'.", scriptName);

if (Configuration.DryRun)
{
return false;
}
else
{
await RunTheActualSqlWithoutLogging(sql, scriptName, connectionType, transactionHandling);
return true;
}
}

if (!InCorrectEnvironment(scriptName, environment))
{
return false;
Expand All @@ -191,7 +174,15 @@ async Task<bool> PrintLogAndRunSql()
{
sql = ReplaceTokensIn(sql);
}
return await PrintLogAndRunSql();

Logger.LogInformation(" Running '{ScriptName}'.", scriptName);

if (!Configuration.DryRun)
{
await RunTheActualSqlWithoutLogging(sql, scriptName, connectionType, transactionHandling);
}

return true;
}


Expand Down
33 changes: 29 additions & 4 deletions src/grate.core/Migration/GrateMigrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ private init
DbMigrator.Database = value;
}
}


public MigrationResult MigrationResult { get; } = new();

public IGrateMigrator WithConfiguration(GrateConfiguration configuration)
{
return this with { Configuration = configuration };
Expand Down Expand Up @@ -225,6 +227,18 @@ public async Task Migrate()
// Ignore!
}
}

// If it's an up-to-date check, we output on the console if it's up-to-date or not.
if (config.UpToDateCheck)
{
var logger = _loggerFactory.CreateLogger(LogCategory + ".IsUpToDate");

logger.LogInformation("Up to date: {IsUpToDate}", MigrationResult.IsUpToDate);
foreach (var script in MigrationResult.ScriptsRun)
{
logger.LogDebug("Changed script: {ScriptName}", script);
}
}

_logger.LogInformation(
"\n\ngrate v{Version} (build date {BuildDate}) has grated your database ({DatabaseName})! You are now at version {NewVersion}. All changes and backups can be found at \"{ChangeDropFolder}\".",
Expand All @@ -235,8 +249,6 @@ public async Task Migrate()
changeDropFolder);

Separator(' ');


}

private async Task EnsureConnectionIsOpen(ConnectionType connectionType)
Expand Down Expand Up @@ -408,6 +420,7 @@ private async ValueTask<bool> Process(DirectoryInfo root, MigrationsFolder folde
if (theSqlRan)
{
anySqlRun = true;
AddScriptRunToResult(folder, fileNameToLog);
try
{
CopyToChangeDropFolder(path.Parent!, file, changeDropFolder);
Expand Down Expand Up @@ -460,6 +473,7 @@ private async ValueTask<bool> ProcessWithoutLogging(DirectoryInfo root, Migratio
if (theSqlRan)
{
anySqlRun = true;
AddScriptRunToResult(folder, fileNameToLog);
try
{
CopyToChangeDropFolder(path.Parent!, file, changeDropFolder);
Expand All @@ -471,7 +485,7 @@ private async ValueTask<bool> ProcessWithoutLogging(DirectoryInfo root, Migratio
}
}

if (!anySqlRun)
if (!anySqlRun && !DbMigrator.Configuration.DryRun)
{
_logger.LogInformation(" No sql run, either an empty folder, or all files run against destination previously.");
}
Expand All @@ -481,6 +495,7 @@ private async ValueTask<bool> ProcessWithoutLogging(DirectoryInfo root, Migratio
}



private void CopyToChangeDropFolder(DirectoryInfo migrationRoot, FileSystemInfo file, string changeDropFolder)
{
var relativePath = Path.GetRelativePath(migrationRoot.ToString(), file.FullName);
Expand Down Expand Up @@ -663,6 +678,16 @@ await Bootstrapping.WriteBootstrapScriptsToFolder(
sqlFolderNamePrefix);
return internalMigrationFolders;
}

private void AddScriptRunToResult(MigrationsFolder folder, string fileNameToLog)
{
MigrationResult.AddScriptRun(fileNameToLog);
// If we (would have) run a script that is not an EveryTime script, we were not up to date.
if (folder.Type != MigrationType.EveryTime)
{
MigrationResult.IsUpToDate = false;
}
}

public async ValueTask DisposeAsync()
{
Expand Down
12 changes: 12 additions & 0 deletions src/grate.core/Migration/MigrationResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace grate.Migration;

// ReSharper disable once ClassNeverInstantiated.Global
internal record MigrationResult
{
private readonly List<string> _scriptsRun = [];

public IReadOnlyList<string> ScriptsRun => _scriptsRun.AsReadOnly();
public bool IsUpToDate { get; set; } = true;

public void AddScriptRun(string scriptName) => _scriptsRun.Add(scriptName);
}
5 changes: 5 additions & 0 deletions src/grate/Commands/MigrateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public MigrateCommand(IGrateMigrator mi) : base("Migrates the database")
Add(DryRun());
Add(Restore());
Add(IgnoreDirectoryNames());
Add(UpToDateCheck());

Handler = CommandHandler.Create(
async () =>
Expand Down Expand Up @@ -334,4 +335,8 @@ private static Option<bool> IgnoreDirectoryNames() =>
new[] { "--ignoredirectorynames", "--searchallinsteadoftraverse", "--searchallsubdirectoriesinsteadoftraverse" },
"IgnoreDirectoryNames - By default, scripts are ordered by relative path including subdirectories. This option searches subdirectories, but order is based on filename alone."
);

internal static Option<bool> UpToDateCheck() => new(
["--uptodatecheck", "--isuptodate"],
"Outputs whether the database is up to date or not (whether any non-everytime scripts would be run)");
}
18 changes: 14 additions & 4 deletions src/grate/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,19 @@ public static class Program

public static async Task<int> Main(string[] args)
{
// Temporarily parse the configuration, to get the verbosity level
// Temporarily parse the configuration, to get the verbosity level, and potentially set parameters
// to support the "IsUpToDate" check.
var cfg = await ParseGrateConfiguration(args);
if (cfg.UpToDateCheck)
{
cfg = cfg with { Verbosity = LogLevel.Critical, DryRun = true };
}

_serviceProvider = BuildServiceProvider(cfg).CreateAsyncScope().ServiceProvider;

var rootCommand = Create<MigrateCommand>();
rootCommand.Add(Verbosity());

rootCommand.Description = $"grate v{GetVersion()} - sql for the 20s";

var parser = new CommandLineBuilder(rootCommand)
Expand Down Expand Up @@ -79,7 +85,10 @@ private static async Task<CommandLineGrateConfiguration> ParseGrateConfiguration
CommandLineGrateConfiguration cfg = new CommandLineGrateConfiguration();
var handler = CommandHandler.Create((CommandLineGrateConfiguration config) => cfg = config);

var cmd = new MigrateCommand(null!) { Verbosity() };
var cmd = new MigrateCommand(null!)
{
Verbosity(),
};

ParseResult p =
new Parser(cmd).Parse(commandline);
Expand Down Expand Up @@ -126,6 +135,7 @@ private static ServiceProvider BuildServiceProvider(CommandLineGrateConfiguratio
options.LogToStandardErrorThreshold = LogLevel.Warning;
})
.AddFilter("Grate.Migration.Internal", LogLevel.Critical)
.AddFilter("Grate.Migration.IsUpToDate", LogLevel.Information)
.SetMinimumLevel(config.Verbosity)
.AddConsoleFormatter<GrateConsoleFormatter, SimpleConsoleFormatterOptions>());

Expand All @@ -145,7 +155,7 @@ private static ServiceProvider BuildServiceProvider(CommandLineGrateConfiguratio
}

internal static Option<LogLevel> Verbosity() => new(
new[] { "-v", "--verbosity" },
["-v", "--verbosity"],
"Verbosity level (as defined here: https://docs.microsoft.com/dotnet/api/Microsoft.Extensions.Logging.LogLevel)");

private static T Create<T>() where T : notnull => _serviceProvider.GetRequiredService<T>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,18 @@ public async Task IgnoreDirectoryNames(string args, bool expected)
var cfg = await ParseGrateConfiguration(args);
cfg?.IgnoreDirectoryNames.Should().Be(expected);
}

[Theory]
[InlineData("", false)]
[InlineData("--isuptodate", true)]
[InlineData("--isuptodate false", false)]
[InlineData("--uptodatecheck", true)]
[InlineData("--uptodatecheck false", false)]
public async Task UpToDateCheck(string args, bool expected)
{
var cfg = await ParseGrateConfiguration(args);
cfg?.UpToDateCheck.Should().Be(expected);
}

private static async Task<CommandLineGrateConfiguration?> ParseGrateConfiguration(string commandline)
{
Expand Down
Loading

0 comments on commit 3e12911

Please sign in to comment.