diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs index bc4db38c84..9208357d4a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs @@ -40,6 +40,7 @@ namespace Volo.Abp.Cli options.Commands["translate"] = typeof(TranslateCommand); options.Commands["build"] = typeof(BuildCommand); options.Commands["bundle"] = typeof(BundleCommand); + options.Commands["create-migration-and-run-migrator"] = typeof(CreateMigrationAndRunMigrator); }); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigrator.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigrator.cs new file mode 100644 index 0000000000..fcc7fc4e86 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigrator.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Cli.Args; +using Volo.Abp.Cli.Utils; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.Commands +{ + public class CreateMigrationAndRunMigrator : IConsoleCommand, ITransientDependency + { + public virtual async Task ExecuteAsync(CommandLineArgs commandLineArgs) + { + if (commandLineArgs.Target.IsNullOrEmpty()) + { + throw new CliUsageException( + "DbMigrations folder path is missing!" + ); + } + + var dbMigratorProjectPath = GetDbMigratorProjectPath(commandLineArgs.Target); + + if (dbMigratorProjectPath == null) + { + throw new Exception("DbMigrator is not found!"); + } + + CmdHelper.RunCmd("cd \"" + commandLineArgs.Target + "\" && dotnet ef migrations add Initial -s " + dbMigratorProjectPath); + CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(dbMigratorProjectPath) + "\" && dotnet run"); + } + + private string GetDbMigratorProjectPath(string dbMigrationsFolderPath) + { + var srcFolder = Directory.GetParent(dbMigrationsFolderPath); + + var dbMigratorFolderPath = Directory.GetDirectories(srcFolder.FullName).FirstOrDefault(d => d.EndsWith(".DbMigrator")); + + if (dbMigratorFolderPath == null) + { + return null; + } + + return Directory.GetFiles(dbMigratorFolderPath).FirstOrDefault(f => f.EndsWith(".csproj")); + } + + public string GetUsageInfo() + { + return string.Empty; + } + + public string GetShortDescription() + { + return string.Empty; + } + } +} diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/Data/MyProjectNameDbMigrationService.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/Data/MyProjectNameDbMigrationService.cs index db5b9291a6..a339edde55 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/Data/MyProjectNameDbMigrationService.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/Data/MyProjectNameDbMigrationService.cs @@ -1,5 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -35,6 +39,19 @@ namespace MyCompanyName.MyProjectName.Data public async Task MigrateAsync() { + try + { + if (!await CheckMigrationsAsync()) + { + await AddInitialMigration(); + return; + } + } + catch (Exception e) + { + Logger.LogWarning("Couldn't determinate if any migrations exist : " + e.Message); + } + Logger.LogInformation("Started database migrations..."); await MigrateDatabaseSchemaAsync(); @@ -69,7 +86,8 @@ namespace MyCompanyName.MyProjectName.Data Logger.LogInformation($"Successfully completed {tenant.Name} tenant database migrations."); } - Logger.LogInformation("Successfully completed database migrations."); + Logger.LogInformation("Successfully completed all database migrations."); + Logger.LogInformation("You can stop this process safely, if it doesn't stop itself."); } private async Task MigrateDatabaseSchemaAsync(Tenant tenant = null) @@ -89,5 +107,81 @@ namespace MyCompanyName.MyProjectName.Data await _dataSeeder.SeedAsync(tenant?.Id); } + + private async Task CheckMigrationsAsync() + { + var dbMigrationsProjectFolder = GetDbMigrationsProjectFolderPath(); + + if (!Directory.Exists(Path.Combine(dbMigrationsProjectFolder, "migrations"))) + { + return false; + } + + return true; + } + + private async Task AddInitialMigration() + { + Logger.LogInformation("Creating initial migration..."); + + string argumentPrefix; + string fileName; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + argumentPrefix = "-c"; + fileName = "/bin/bash"; + } + else + { + argumentPrefix = "/C"; + fileName = "cmd.exe"; + } + + var procStartInfo = new ProcessStartInfo( fileName, + $"{argumentPrefix} \"abp create-migration-and-run-migrator {GetDbMigrationsProjectFolderPath()}\"" + ); + + try + { + Process.Start(procStartInfo); + } + catch (Exception) + { + throw new Exception("Couldn't run ABP CLI..."); + } + } + + private static string GetDbMigrationsProjectFolderPath() + { + var slnDirectoryPath = GetSolutionDirectoryPath(); + + if (slnDirectoryPath == null) + { + throw new Exception("Solution folder not found!"); + } + + var srcDirectoryPath = Path.Combine(slnDirectoryPath, "src"); + + return Directory.GetDirectories(srcDirectoryPath) + .FirstOrDefault(d => d.EndsWith(".DbMigrations")); + } + + private static string GetSolutionDirectoryPath() + { + var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory()); + + while (Directory.GetParent(currentDirectory.FullName) != null) + { + currentDirectory = Directory.GetParent(currentDirectory.FullName); + + if (Directory.GetFiles(currentDirectory.FullName).FirstOrDefault(f => f.EndsWith(".sln")) != null) + { + return currentDirectory.FullName; + } + } + + return null; + } } }