public string GetConnectionString( DatabaseInfo DatabaseInfo )
 {
     if ( !string.IsNullOrEmpty( DatabaseInfo.ConnectionStringSource ) ) {
         return this.GetFirstConnectionStringFromConfigFiles( DatabaseInfo.ConnectionStringSource );
     } else {
         return this.BuildConnectionString( DatabaseInfo );
     }
 }
Exemple #2
0
        public static int Main( string[] args )
        {
            string basePath = new Uri( Assembly.GetExecutingAssembly().CodeBase ).LocalPath;
            string migrationFilesSourcePath = null;
            DatabaseInfo databaseInfo = new DatabaseInfo();
            string currentAppVersion = null;
            string migrationScriptFile = null;
            bool wait = false;
            bool verbose = false;
            bool showHelp = false;

            var arguments = new List<ArgParameter> {
                new ArgParameter( "migrationFilesSourcePath", v => migrationFilesSourcePath = v.FirstOrDefault() ),
                new ArgParameter( "connectionStringSource", v => databaseInfo.ConnectionStringSource = v.FirstOrDefault() ),
                new ArgParameter( "server", "S", v => databaseInfo.Server = v.FirstOrDefault() ),
                new ArgParameter( "database", "d", v => databaseInfo.Database = v.FirstOrDefault() ),
                new ArgParameter( "username", "U", v => databaseInfo.Username = v.FirstOrDefault() ),
                new ArgParameter( "password", "P", v => databaseInfo.Password = v.FirstOrDefault() ),
                new ArgParameter( "trustedConnection", "E", v => databaseInfo.TrustedConnection = true ),
                new ArgParameter( "currentAppVersion", v => currentAppVersion = v.FirstOrDefault() ),
                new ArgParameter( "migrationScriptFile", v => migrationScriptFile = v.FirstOrDefault() ),
                new ArgParameter( "wait", "w", v => wait = true ),
                new ArgParameter( "verbose", "v", v => verbose = true ),
                new ArgParameter( "help", "?", v => showHelp = true )
            };

            int matchedArgs = CommandLineParser.ParseCommandLineArguments( args, arguments );
            if ( matchedArgs != args.Length ) {
                showHelp = true;
            }

            if ( showHelp ) {
                string helpContent = CommandLineParser.GetHelpText( arguments );
                Console.WriteLine( "NAnt.DbMigrations.Tasks" );
                Console.Write( helpContent );
                return (int)ExitReason.InvalidArguments;
            }

            ILogger logger = new ConsoleLogger();

            // Lame DI solution here to avoid multiple dll dependencies for this tool
            IHashCalculator hashCalculator = new HashCalculator();
            ISqlHelper sqlHelper = new SqlHelper();
            IConfigRepository configRepository = new ConfigRepository();
            IMigrationDbRepository migrationDbRepository = new MigrationDbRepository( sqlHelper );
            IMigrationFileRepository migrationFileRepository = new MigrationFileRepository();
            ISqlCmdHelper sqlCmdHelper = new SqlCmdHelper( sqlHelper );
            IMigrationOutputFileRepository migrationOutputFileRepository = new MigrationOutputFileRepository();
            IMigrationFileParser migrationFileParser = new MigrationFileParser();
            IMigrationFileService migrationFileService = new MigrationFileService( hashCalculator, migrationFileRepository, migrationFileParser );
            IConnectionStringService connectionStringService = new ConnectionStringService( configRepository );
            IPathService pathService = new PathService();
            App app = new App( logger, migrationDbRepository, migrationFileRepository, sqlCmdHelper, migrationOutputFileRepository, migrationFileService, connectionStringService, pathService );

            ExitReason result = app.RunMigrations( basePath, verbose, migrationFilesSourcePath, databaseInfo, currentAppVersion, migrationScriptFile );

            if ( wait ) {
                Console.WriteLine( "Migration complete, push any key to exit" );
                Console.ReadKey();
            }
            return (int)result;
        }
Exemple #3
0
        protected override void ExecuteTask()
        {
            ILogger logger = new ActionLogger( this.Log );

            // Lame DI solution here to avoid multiple dll dependencies for this tool
            IHashCalculator hashCalculator = new HashCalculator();
            ISqlHelper sqlHelper = new SqlHelper();
            IConfigRepository configRepository = new ConfigRepository();
            IMigrationDbRepository migrationDbRepository = new MigrationDbRepository( sqlHelper );
            IMigrationFileRepository migrationFileRepository = new MigrationFileRepository();
            ISqlCmdHelper sqlCmdHelper = new SqlCmdHelper( sqlHelper );
            IMigrationOutputFileRepository migrationOutputFileRepository = new MigrationOutputFileRepository();
            IMigrationFileParser migrationFileParser = new MigrationFileParser();
            IMigrationFileService migrationFileService = new MigrationFileService( hashCalculator, migrationFileRepository, migrationFileParser );
            IConnectionStringService connectionStringService = new ConnectionStringService( configRepository );
            IPathService pathService = new PathService();
            App app = new App( logger, migrationDbRepository, migrationFileRepository, sqlCmdHelper, migrationOutputFileRepository, migrationFileService, connectionStringService, pathService );

            DatabaseInfo databaseInfo = new DatabaseInfo {
                ConnectionStringSource = this.ConnectionStringSource,
                Server = this.Server,
                Database = this.Database,
                Username = this.Username,
                Password = this.Password,
                TrustedConnection = this.TrustedConnection
            };

            ExitReason result = app.RunMigrations( this.Project.BaseDirectory, this.Verbose, this.MigrationFilesSourcePath, databaseInfo, this.CurrentAppVersion, this.MigrationScriptFile );

            if ( this.FailOnError && result != ExitReason.Success ) {
                throw new BuildException( "Error in db-migration: "+result.ToString() );
            }
        }
 private string BuildConnectionString( DatabaseInfo DatabaseInfo )
 {
     SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder();
     connectionStringBuilder.DataSource = DatabaseInfo.Server;
     connectionStringBuilder.InitialCatalog = DatabaseInfo.Database;
     if ( DatabaseInfo.TrustedConnection ) {
         connectionStringBuilder.IntegratedSecurity = true;
     } else {
         connectionStringBuilder.UserID = DatabaseInfo.Username;
         connectionStringBuilder.Password = DatabaseInfo.Password;
     }
     return connectionStringBuilder.ConnectionString;
 }
Exemple #5
0
        // TODO: This method is doing too much
        /// <param name="BaseDirectory">Normalize other paths to this directory</param>
        /// <param name="MigrationFilesSourcePath">Directory to pull migration files from</param>
        /// <param name="DatabaseInfo">Database connection details</param>
        /// <param name="CurrentAppVersion">The current git hash</param>
        /// <param name="MigrationScriptFile">The file to write the consolidated migration file into</param>
        /// <returns>The reason for exiting: success or failure</returns>
        public ExitReason RunMigrations( string BaseDirectory, bool Verbose, string MigrationFilesSourcePath, DatabaseInfo DatabaseInfo, string CurrentAppVersion, string MigrationScriptFile )
        {
            if ( DatabaseInfo == null ) {
                this.logger.Log( "No connection string details sent" );
                return ExitReason.NoConnectionString;
            }

            string migrationFilesSourcePath = this.pathService.NormalizePath( BaseDirectory, MigrationFilesSourcePath );
            DatabaseInfo.ConnectionStringSource = this.pathService.NormalizePath( BaseDirectory, DatabaseInfo.ConnectionStringSource );
            string migrationScriptFile = this.pathService.NormalizePath( BaseDirectory, MigrationScriptFile );

            // Invalid config source
            if ( !this.migrationFileRepository.PathExists( migrationFilesSourcePath ) ) {
                this.logger.Log( "Migration files source path is not found" );
                return ExitReason.InvalidMigrationFileSourcePath;
            }

            // Get the db connection string
            string connnectionString = this.connectionStringService.GetConnectionString( DatabaseInfo );
            if ( string.IsNullOrEmpty( connnectionString ) ) {
                this.logger.Log( "No valid connection string found in the target configs" );
                return ExitReason.NoConnectionString;
            }

            if ( Verbose ) {
                this.logger.Info( "migrationFilesSourcePath: " + migrationFilesSourcePath );
                this.logger.Info( "currentAppVersion: " + CurrentAppVersion );
                this.logger.Info( "migrationScriptFile: " + migrationScriptFile );
                if ( !string.IsNullOrEmpty( DatabaseInfo.ConnectionStringSource ) ) {
                    this.logger.Info( "connectionStringSource: " + DatabaseInfo.ConnectionStringSource );
                }
                this.logger.Info( "connectionString: " + connnectionString );
            }

            // Are both source paths valid?
            string connectTest = this.migrationDbRepository.TestConnection( connnectionString );
            if ( !string.IsNullOrEmpty(connectTest) ) {
                this.logger.Log( "Unable to connect to target database: " + connectTest );
                return ExitReason.InvalidDatabase;
            }

            // Ensure migration table exists
            // FRAGILE: Must be outside TransactionScope to query it, thus if the migrations fail, the table creation won't get rolled back
            this.migrationDbRepository.EnsureMigrationsTableExists( connnectionString );

            // Get all migrations from both db and files
            List<MigrationHistory> dbMigrations = this.migrationDbRepository.GetAllMigrations( connnectionString ) ?? new List<MigrationHistory>();
            List<MigrationFile> fileMigrations = this.migrationFileService.GetAllMigrations( migrationFilesSourcePath ) ?? new List<MigrationFile>();

            // Decide which migrations to process
            List<MigrationHistory> toRemove = this.MigrationsToRemove( dbMigrations, fileMigrations );
            List<MigrationFile> toAdd = this.MigrationsToAdd( fileMigrations, dbMigrations );

            // The output file
            StringBuilder migrationScript = new StringBuilder();

            // Create transaction scope
            using ( TransactionScope transaction = new TransactionScope() ) {
                try {

                    if ( toRemove != null && toRemove.Count > 0 ) {
                        foreach ( MigrationHistory row in toRemove ) {
                            try {
                                migrationScript.AppendLine( "-- Remove Migration " + row.Filename );

                                if ( !string.IsNullOrEmpty( row.DownScript ) ) {
                                    // Run Down Migration
                                    this.sqlCmdHelper.RunSqlCommand( connnectionString, row.DownScript );
                                    migrationScript.AppendLine( row.DownScript );
                                    migrationScript.AppendLine( "GO" );
                                }

                                string deleteContent = this.migrationDbRepository.RemoveMigration( connnectionString, row );
                                migrationScript.AppendLine( deleteContent );
                                migrationScript.AppendLine( "GO" );
                                migrationScript.AppendLine();

                                this.logger.Info( "Successfully removed " + row.Filename );
                            } catch {
                                this.logger.Log( "Error removing " + row.Filename );
                                throw;
                            }
                        }
                    }

                    if ( toAdd != null && toAdd.Count > 0 ) {
                        foreach ( MigrationFile file in toAdd ) {
                            try {
                                // Run Migration
                                this.sqlCmdHelper.RunSqlCommand( connnectionString, file.FileContent );

                                // Log that migration was run
                                string addContent = this.migrationDbRepository.AddMigration( connnectionString, new MigrationHistory {
                                    Filename = file.Filename,
                                    FileHash = file.FileHash,
                                    ExecutionDate = DateTime.Now,
                                    Version = CurrentAppVersion,
                                    DownScript = file.DownScript,
                                } );

                                migrationScript.AppendLine( "-- Add Migration " + file.Filename );
                                migrationScript.AppendLine( file.FileContent );
                                migrationScript.AppendLine( "GO" );
                                migrationScript.AppendLine( addContent );
                                migrationScript.AppendLine( "GO" );
                                migrationScript.AppendLine();

                                this.logger.Info( "Successfully added " + file.Filename );
                            } catch {
                                this.logger.Log( "Error adding " + file.Filename );
                                throw;
                            }
                        }
                    }

                    transaction.Complete(); // Success
                } catch ( Exception ex ) {
                    transaction.Dispose(); // Fail
                    this.logger.Log( ex );
                    return ExitReason.DatabaseError; // Probably
                }
            }

            string migrationScriptContent = migrationScript.ToString();
            if ( !string.IsNullOrEmpty( migrationScriptFile ) ) {
                // Create migration output script file
                // FRAGILE: ASSUME: it'll run the same as running them individually
                this.migrationOutputFileRepository.WriteFile( migrationScriptFile, migrationScriptContent );
            }
            return ExitReason.Success;
        }