require "rake" require "rake/tasklib" module MigrationTools class Tasks < ::Rake::TaskLib def initialize define_migrate_list define_migrate_group define_convenience_tasks end def group return @group if defined?(@group) && @group @group = ENV["GROUP"].to_s raise "Invalid group \"#{@group}\"" if !@group.empty? && !MIGRATION_GROUPS.member?(@group) @group end def group=(group) @group = nil @pending_migrations = nil ENV["GROUP"] = group end def migrations_paths ActiveRecord::Migrator.migrations_paths end def migrator(target_version = nil) if ActiveRecord::VERSION::MAJOR == 7 && ActiveRecord::VERSION::MINOR == 1 migrate_up(ActiveRecord::MigrationContext.new( migrations_paths, ActiveRecord::Base.connection.schema_migration ).migrations, target_version) elsif ActiveRecord.gem_version >= Gem::Version.new("7.2") migrate_up(ActiveRecord::MigrationContext.new( migrations_paths, ActiveRecord::Base.connection_pool.schema_migration ).migrations, target_version) else migrate_up(ActiveRecord::MigrationContext.new( migrations_paths, ActiveRecord::SchemaMigration ).migrations, target_version) end end def migrate_up(migrations, target_version) if ActiveRecord::VERSION::MAJOR == 7 && ActiveRecord::VERSION::MINOR == 1 ActiveRecord::Migrator.new(:up, migrations, ActiveRecord::Base.connection.schema_migration, ActiveRecord::Base.connection.internal_metadata, target_version) elsif ActiveRecord.gem_version >= Gem::Version.new("7.2") ActiveRecord::Migrator.new(:up, migrations, ActiveRecord::Base.connection_pool.schema_migration, ActiveRecord::Base.connection_pool.internal_metadata, target_version) else ActiveRecord::Migrator.new(:up, migrations, ActiveRecord::SchemaMigration, target_version) end end def pending_migrations return @pending_migrations if defined?(@pending_migrations) && @pending_migrations @pending_migrations = migrator.pending_migrations @pending_migrations = @pending_migrations.select { |proxy| group.empty? || proxy.migration_group == group } @pending_migrations end def define_migrate_list namespace :db do namespace :migrate do desc "Lists pending migrations" task list: :environment do if pending_migrations.empty? notify "Your database schema is up to date", group else notify "You have #{pending_migrations.size} pending migrations", group pending_migrations.each do |migration| notify " %4d %s %s" % [migration.version, migration.migration_group.to_s[0..5].center(6), migration.name] end end end end end end def define_migrate_group namespace :db do namespace :migrate do desc "Runs pending migrations for a given group" task group: :environment do if group.empty? notify "Please specify a migration group" elsif pending_migrations.empty? notify "Your database schema is up to date" else pending_migrations.each do |migration| migrator(migration.version).run end schema_format = if ActiveRecord::VERSION::MAJOR >= 7 ActiveRecord.schema_format else ActiveRecord::Base.schema_format end Rake::Task["db:schema:dump"].invoke if schema_format == :ruby Rake::Task["db:structure:dump"].invoke if schema_format == :sql end end end end end def define_convenience_tasks namespace :db do namespace :migrate do [:list, :group].each do |ns| namespace ns do MigrationTools::MIGRATION_GROUPS.each do |migration_group| desc "#{(ns == :list) ? "Lists" : "Executes"} the migrations for group #{migration_group}" task migration_group => :environment do self.group = migration_group.to_s Rake::Task["db:migrate:#{ns}"].invoke Rake::Task["db:migrate:#{ns}"].reenable end end end end end namespace :abort_if_pending_migrations do MigrationTools::MIGRATION_GROUPS.each do |migration_group| desc "Raises an error if there are pending #{migration_group} migrations" task migration_group do self.group = migration_group.to_s Rake::Task["db:migrate:list"].invoke Rake::Task["db:migrate:list"].reenable if pending_migrations.any? abort "Run \"rake db:migrate\" to update your database then try again." end end end end end end def notify(string, group = "") if group.empty? puts string else puts "#{string} for group \"#{group}\"" end end end end