feat: add support for applying migrations automatically
All checks were successful
Update changelog / changelog (push) Successful in 25s

This commit is contained in:
2025-12-17 01:07:05 +01:00
parent f5df949a4c
commit ac2b6aba6e
4 changed files with 102 additions and 12 deletions

View File

@@ -21,6 +21,10 @@ public class Seeder
Console.WriteLine($"You're running Shadow, commit {ThisAssembly.Git.Commit} of branch {ThisAssembly.Git.Branch} ({ThisAssembly.Git.CommitDate})\n");
// Check migration status. If we can't proceed, exit now.
bool migrationSucceeded = EnsureMigrations(db);
if (!migrationSucceeded) return true;
// Check if this is a clean, first run. If so, run the setup wizard.
Global? lastVersion = db.Globals.FirstOrDefault(c => c.Key == "lastVersion");
Global? runs = db.Globals.FirstOrDefault(g => g.Key == "runs");
@@ -104,4 +108,73 @@ public class Seeder
return shutdown;
}
public static bool EnsureMigrations(ApplicationDbContext dbContext)
{
// Returns true if migrations have been successfully applied.
// Otherwise returns false.
bool migrationSuccess = false;
List<string> availableMigrations = dbContext.Database.GetMigrations().ToList();
List<string> appliedMigrations = dbContext.Database.GetAppliedMigrations().ToList();
bool hasMissingMigrations = availableMigrations.Count > appliedMigrations.Count;
bool doMigrationsMatch = availableMigrations.SequenceEqual(appliedMigrations);
if (hasMissingMigrations)
{
bool userMigrationConsent = false;
Console.WriteLine("\n" +
"========================================\n" +
"[Warn] Database migrations missing!\n" +
"========================================");
if (appliedMigrations.Count == 0)
{
Console.WriteLine( "Empty database detected. Applying migrations is recommended, and required if this is the first run of Shadow.");
userMigrationConsent = Cli.YesNoPrompt("Do you want to apply migrations automatically? [Y/n]: ", true);
}
else
{
Console.WriteLine($"Detected existing {appliedMigrations.Count} migrations. Backing up the database before applying migrations is recommended.");
userMigrationConsent = Cli.YesNoPrompt("Do you want to apply migrations automatically? [y/N]: ", false);
}
// Do we have user permission to perform migration?
if (userMigrationConsent)
{
dbContext.Database.Migrate();
dbContext.SaveChanges();
}
else
{
Console.WriteLine("Exiting...");
return migrationSuccess;
}
// Check if migrations match afterwards
List<string> newlyAppliedMigrations = dbContext.Database.GetAppliedMigrations().ToList();
bool doNewlyAppliedMigrationsMatch = availableMigrations.SequenceEqual(newlyAppliedMigrations);
if (doNewlyAppliedMigrationsMatch)
{
Console.WriteLine("\n" +
"==============================\n" +
"Migration success!\n" +
"==============================\n");
migrationSuccess = true;
}
else
{
// An error ocurred when applying migrations automatically
Console.WriteLine("\n" +
"==================================================\n" +
"[Error] Failed applying migrations automatically!\n" +
"==================================================\n");
Console.WriteLine("The list of newly applied migrations does not match the list of planned migrations.\n" +
"Shadow cannot operate with missing migrations. Please manually revise the database structure and create backups before altering it.\n");
migrationSuccess = false;
}
}
else migrationSuccess = true;
return migrationSuccess;
}
}