namespace :handcuffs do task :migrate, [:phase] => :environment do |t,args| phase = setup(args, 'handcuffs:migrate') patch_migrator!(phase) run_task('db:migrate') # load_config #active_record/railties/databases.rake:44 # ActiveRecord::Tasks::DatabaseTasks.migrate # dump_schema end task :rollback, [:phase] => :environment do |t,args| phase = setup(args, 'handcuffs:rollback') patch_migrator!(phase) # load_config run_task('db:rollback') #active_record/railsties/databases.rake:142 # step = ENV['STEP'] ? ENV['STEP'].to_i : 1 # ActiveRecord::Migrator.rollback(ActiveRecord::Tasks::DatabaseTasks.migrations_paths, step) # dump_schema end def setup(args, task) phase = args.phase raise RequiresPhaseArgumentError.new(task) unless phase.present? raise HandcuffsNotConfiguredError.new unless Handcuffs.config phase = phase.to_sym unless Handcuffs.config.phases.include?(phase) || phase == :all raise HandcuffsUnknownPhaseError.new(phase, Handcuffs.config.phases) end phase end def patch_migrator!(phase) ActiveRecord::Migrator.prepend(PendingFilter) ActiveRecord::Migrator.extend(PhaseAccessor) ActiveRecord::Migrator.handcuffs_phase = phase end def run_task(name) Rake::Task.clear # necessary to avoid tasks being loaded several times in dev mode Rails.application.load_tasks Rake::Task[name].reenable # in case you're going to invoke the same task second time. Rake::Task[name].invoke end # def load_config # #active_record/railties/databases.rake:5 # ActiveRecord::Base.configurations = ActiveRecord::Tasks::DatabaseTasks.database_configuration || {} # ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths # end # # def dump_schema # rake['db:structure:dump'].invoke # end module PendingFilter def runnable attempted_phase = self.class.handcuffs_phase if(@direction == :up) Handcuffs::PhaseFilter.new(attempted_phase, @direction).filter(super) else phase_migrations = Handcuffs::PhaseFilter.new(attempted_phase, @direction).filter(migrations) runnable = phase_migrations[start..finish] runnable.pop if target runnable.find_all { |m| ran?(m) } end end end module PhaseAccessor attr_accessor :handcuffs_phase end end