require “active_record” require “diffy”
namespace :db do
namespace :migrate do desc "Check the reversibility of migration files" task check_reversibility: :load_config do require "active_record/schema_dumper" config = ActiveRecord::Base.configurations.fetch(Rails.env) current_version = ReversibilityChecker.current_version(config) target_versions = ReversibilityChecker.target_versions(config, current_version) migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths # Use a temporary database config["database"] += "_tmp" # Suppress messages from db tasks $stdout = Tempfile.new ActiveRecord::Tasks::DatabaseTasks.create(config) ActiveRecord::Base.establish_connection(config) at_exit { ActiveRecord::Tasks::DatabaseTasks.drop(config) ActiveRecord::Base.remove_connection } reversible = true base_version = current_version target_versions.each do |target_version| ActiveRecord::Base.connection.migration_context.up(base_version) base_schema = ReversibilityChecker.dump(config) ActiveRecord::Base.connection.migration_context.up(target_version) ActiveRecord::Base.connection.migration_context.down(base_version) rollbacked_schema = ReversibilityChecker.dump(config) diff = Diffy::Diff.new(base_schema, rollbacked_schema) if diff.count > 0 Object::STDOUT.puts "== +#{target_version} ============================================================" Object::STDOUT.puts diff.to_s(:color) Object::STDOUT.puts "== -#{base_version} ============================================================" Object::STDOUT.puts "" reversible = false end base_version = target_version end exit 1 unless reversible end end
end