handcuffs 1.4.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/ISSUE_TEMPLATE/bug.yml +66 -0
  4. data/.github/ISSUE_TEMPLATE/config.yml +1 -0
  5. data/.github/ISSUE_TEMPLATE/docs.yml +18 -0
  6. data/.github/ISSUE_TEMPLATE/feature-request.yml +36 -0
  7. data/.github/ISSUE_TEMPLATE/question-support.yml +18 -0
  8. data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  9. data/.github/dependabot.yaml +36 -0
  10. data/.github/workflows/auto-assign-author.yaml +15 -0
  11. data/.github/workflows/codeql.yaml +35 -0
  12. data/.github/workflows/release.yaml +43 -0
  13. data/.github/workflows/stale.yaml +34 -0
  14. data/.github/workflows/test.yaml +52 -0
  15. data/.gitignore +2 -1
  16. data/Appraisals +6 -27
  17. data/CHANGELOG.md +43 -0
  18. data/CODE_OF_CONDUCT.md +117 -36
  19. data/CONTRIBUTING.md +37 -0
  20. data/README.md +92 -59
  21. data/SECURITY.md +19 -0
  22. data/gemfiles/rails_6.1.gemfile +1 -1
  23. data/gemfiles/{rails_5.2.gemfile → rails_7.0.gemfile} +1 -1
  24. data/gemfiles/{rails_6.gemfile → rails_7.1.gemfile} +1 -1
  25. data/handcuffs.gemspec +9 -5
  26. data/lib/handcuffs/configuration.rb +4 -2
  27. data/lib/handcuffs/errors.rb +1 -1
  28. data/lib/handcuffs/extensions.rb +4 -4
  29. data/lib/handcuffs/pending_filter_ext.rb +19 -0
  30. data/lib/handcuffs/phase_filter.rb +2 -2
  31. data/lib/handcuffs/phases.rb +41 -0
  32. data/lib/handcuffs/version.rb +3 -1
  33. data/lib/tasks/handcuffs.rake +26 -31
  34. metadata +50 -21
  35. data/.circleci/config.yml +0 -98
  36. data/gemfiles/rails_4.gemfile +0 -8
  37. data/gemfiles/rails_5.1.gemfile +0 -8
  38. data/gemfiles/rails_5.gemfile +0 -8
  39. /data/{LICENSE.txt → LICENSE.md} +0 -0
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,37 @@
1
+ # Contributing to Procore Projects
2
+
3
+ This document explains the common procedures expected by contributors while submitting code to Procore open source projects.
4
+
5
+ ## Code of Conduct
6
+
7
+ Please read and abide by the [Code of Conduct](CODE_OF_CONDUCT.md)
8
+
9
+ ## General workflow
10
+
11
+ Once a GitHub issue is accepted and assigned to you, please follow general workflow in order to submit your contribution:
12
+
13
+ 1. Fork the target repository under your GitHub username.
14
+ 2. Create a branch in your forked repository for the changes you are about to make.
15
+ 3. Commit your changes in the branch you created in step 2. All commits need to be signed-off. Check the [legal](#legal) section bellow for more details.
16
+ 4. Push your commits to your remote fork.
17
+ 5. Create a Pull Request from your remote fork pointing to the HEAD branch (usually `main` branch) of the target repository.
18
+ 6. Check the GitHub build and ensure that all checks are green.
19
+
20
+ ## Legal
21
+
22
+ Procore projects use Developer Certificate of Origin ([DCO](https://GitHub.com/apps/dco/)).
23
+
24
+ Please sign-off your contributions by doing ONE of the following:
25
+
26
+ * Use `git commit -s ...` with each commit to add the sign-off or
27
+ * Manually add a `Signed-off-by: Your Name <your.email@example.com>` to each commit message.
28
+
29
+ The email address must match your primary GitHub email. You do NOT need cryptographic (e.g. gpg) signing.
30
+
31
+ * Use `git commit -s --amend ...` to add a sign-off to the latest commit, if you forgot.
32
+
33
+ *Note*: Some projects will provide specific configuration to ensure all commits are signed-off. Please check the project's documentation for more details.
34
+
35
+ ## Tests
36
+
37
+ Make sure your changes are properly covered by automated tests. We aim to build an efficient test suite that is low cost to maintain and bring value to project. Prefer writing unit-tests over heavy end-to-end (e2e) tests. However, sometimes e2e tests are necessary. If you aren't sure, ask one of the maintainers about the requirements for your pull-request.
data/README.md CHANGED
@@ -1,114 +1,147 @@
1
1
  # Handcuffs
2
2
 
3
- [![Circle CI](https://circleci.com/gh/procore/handcuffs.svg?style=svg)](https://circleci.com/gh/procore/handcuffs)
3
+ [![Test](https://github.com/procore-oss/handcuffs/actions/workflows/test.yaml/badge.svg?branch=main)](https://github.com/procore-oss/handcuffs/actions/workflows/test.yaml)
4
+ [![Gem Version](https://badge.fury.io/rb/handcuffs.svg)](https://badge.fury.io/rb/handcuffs)
5
+ [![Discord](https://img.shields.io/badge/Chat-EDEDED?logo=discord)](https://discord.gg/PbntEMmWws)
4
6
 
5
- Handcuffs provides an easy way to run migrations in phases in your [Ruby on
6
- Rails](https://rubyonrails.org/) application.
7
+ Handcuffs provides an easy way to run [Ruby on Rails](https://rubyonrails.org/) migrations in phases using a simple process:
7
8
 
8
- To configure, first create a handcuff initializer and define a configuration
9
+ 1. Define a set of named phases in the order in which they should be run
10
+ 2. Tag migrations with one of the defined phase names
11
+ 3. Run migrations by phase at start, end or outside of application deployment
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'handcuffs'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ ```bash
24
+ bundle
25
+ ```
26
+
27
+ Or install it directly on the current system using:
28
+
29
+ ```bash
30
+ gem install handcuffs
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ### Configuration
36
+
37
+ Create a handcuffs initializer and define the migration phases in the order in which they should be run. You should also define a default phase for pre-existing "untagged" migrations, or if you want the option to tag only custom phases.
38
+
39
+ The most basic configuration is an array of phase names, and using the first one as the default:
9
40
 
10
41
  ```ruby
11
42
  # config/initializers/handcuffs.rb
12
43
 
13
44
  Handcuffs.configure do |config|
45
+ # pre_restart migrations will/must run before post_restart migrations
14
46
  config.phases = [:pre_restart, :post_restart]
47
+ config.default_phase = :pre_restart
15
48
  end
16
49
  ```
17
50
 
18
- Then call `phase` from inside your migrations
51
+ If you have more complex or asynchrous workflows, you can use an alternate hash notation that allows prerequisite stages to be specified explicitly:
19
52
 
20
53
  ```ruby
21
- # db/migrate/20160318230933_add_on_sale_column.rb
54
+ # config/initializers/handcuffs.rb
22
55
 
23
- class AddOnSaleColumn < ActiveRecord::Migration
56
+ Handcuffs.configure do |config|
57
+ config.phases = {
58
+ # Prevent running post_restart migrations if there are outstanding
59
+ # pre_restart migrations
60
+ post_restart: [:pre_restart],
61
+ # Require pre_restarts before data_migrations, but do not enforce ordering
62
+ # between data_migrations and post_restarts
63
+ data_migrations: [:pre_restart],
64
+ # pre_restarts have no prerequisite phases
65
+ pre_restart: []
66
+ }
67
+ end
68
+ ```
69
+ The default phase order in this case is determined by [Tsort](https://github.com/ruby/tsort) (topological sort). In order to validate the configuration and expected phase order it is recommended that you check the phase configuration after any changes using the rake task:
70
+
71
+ ```ruby
72
+ rake handcuffs:phase_order
73
+ ```
74
+
75
+ This will display the default order in which phases will be run and list the prerequisites of each phase. It will raise an error if there are any circular dependencies or if any prerequisite is not a valid phase name.
76
+
77
+ ### Tagging Migrations
78
+
79
+ Once configured, you can assign each migration to one of the defined phases using the `phase` setter method:
80
+
81
+ ```ruby
82
+ # db/migrate/20240318230933_add_on_sale_column.rb
83
+
84
+ class AddOnSaleColumn < ActiveRecord::Migration[7.0]
24
85
 
25
86
  phase :pre_restart
26
87
 
27
- def up
88
+ def change
28
89
  add_column :products, :on_sale, :boolean
29
90
  end
30
-
31
- def down
32
- remove_column :products, :on_sale
33
- end
34
-
35
91
  end
36
92
  ```
37
93
 
38
94
  ```ruby
39
- # db/migrate/20160318230988_add_on_sale_index
95
+ # db/migrate/20240318230988_add_on_sale_index
40
96
 
41
- class AddOnSaleIndex < ActiveRecord::Migration
97
+ class AddOnSaleIndex < ActiveRecord::Migration[7.0]
42
98
 
43
99
  phase :post_restart
44
100
 
45
- def up
101
+ def change
46
102
  add_index :products, :on_sale, algorithm: :concurrently
47
103
  end
48
-
49
- def down
50
- remove_index :products, :on_sale
51
- end
52
-
53
104
  end
54
105
  ```
106
+ ### Running Migrations In Phases
107
+
108
+ After Handcuffs is configured and migrations are properly tagged, you can then run migrations in phases using the `handcuffs:migrate` rake task with the specific phase to be run:
55
109
 
56
- You can then run your migrations in phases using
57
110
  ```bash
58
111
  rake 'handcuffs:migrate[pre_restart]'
59
112
  ```
113
+
60
114
  or
115
+
61
116
  ```bash
62
117
  rake 'handcuffs:migrate[post_restart]'
63
118
  ```
64
119
 
65
- You can run all migrations using
66
- ```bash
67
- rake 'handcuffs:migrate[all]'
68
- ```
120
+ *Note:* If you run phases out of order, or attempt to run a phase before outstanding migrations with a prerequisite phase have been run, a `HandcuffsPhaseOutOfOrderError` will be raised.
69
121
 
70
- This differs from running `rake db:migrate` in that migrations will be run in
71
- the _order that the phases are defined in the handcuffs config_.
122
+ ### Running All Migrations
72
123
 
73
- If you run a handcuffs rake task and any migration does not have a phase
74
- defined, an error will be raised before any migrations are run. To prevent this
75
- error, you can define a default phase for migrations that don't define one.
76
- ```ruby
77
- # config/initializers/handcuffs.rb
124
+ In CI and local developement you may want to run all phases at one time.
78
125
 
79
- Handcuffs.configure do |config|
80
- config.phases = [:pre_restart, :post_restart]
81
- config.default_phase = :pre_restart
82
- end
83
- ```
84
-
85
- ## Installation
86
-
87
- Add this line to your application's Gemfile:
126
+ Handcuffs offers a single command that will run all migrations in phases and in the configured order:
88
127
 
89
- ```ruby
90
- gem 'handcuffs'
128
+ ```bash
129
+ rake 'handcuffs:migrate[all]'
91
130
  ```
92
131
 
93
- And then execute:
94
-
95
- $ bundle
96
-
97
- Or install it yourself as:
132
+ This differs from running `rake db:migrate` in that migrations will be run in batches corresponding to the _order that the phases are defined in the handcuffs config_. Again, you can use `rake handcuffs:phase_order` to preview the order ahead of time.
98
133
 
99
- $ gem install handcuffs
134
+ Of course, you can always run `rake db:migrate` at any time to run all migrations using the Rails default ordering and without regard to Handcuffs phase if you wish.
100
135
 
101
- ## Running specs
136
+ ## Contributing
102
137
 
103
- The specs for handcuffs are in the dummy application at `/spec/dummy/spec`. The
104
- spec suite requires PostgreSQL. To run it you will have to set the environment
105
- variables `POSTGRES_DB_USERNAME` and `POSTGRES_DB_PASSWORD`. You can then run
106
- the suite using `rake spec`
138
+ Bug reports and pull requests are welcome on GitHub at <https://github.com/procore-oss/handcuffs>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
107
139
 
108
- ## Contributing
140
+ ## Running Tests Locally
109
141
 
110
- Bug reports and pull requests are welcome on GitHub at https://github.com/procore/handcuffs. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
142
+ The specs for handcuffs are in the dummy application at `/spec/dummy/spec`. The spec suite requires PostgreSQL. To run it you will have to set the environment variables `POSTGRES_DB_USERNAME` and `POSTGRES_DB_PASSWORD`.
111
143
 
144
+ We use [appraisal](https://github.com/thoughtbot/appraisal) to run our test suite against all Rails versions that we support, as a means of quickly identifying potential regressions. To do this locally, first run `bundle exec appraisal install` to ensure all required dependencies are setup, and then run `bundle exec appraisal rspec`.
112
145
 
113
146
  ## License
114
147
 
@@ -117,8 +150,8 @@ The gem is available as open source under the terms of the [MIT License](http://
117
150
  ## About Procore
118
151
 
119
152
  <img
120
- src="https://www.procore.com/images/procore_logo.png"
121
- alt="Procore Logo"
153
+ src="https://raw.githubusercontent.com/procore-oss/.github/main/procorelightlogo.png"
154
+ alt="Procore Open Source"
122
155
  width="250px"
123
156
  />
124
157
 
data/SECURITY.md ADDED
@@ -0,0 +1,19 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ Ruby versions that are currently being supported with security updates.
6
+
7
+ | Version | Supported |
8
+ | ------- | ------------------ |
9
+ | <=2.7 | :x: |
10
+ | 3.0 | :white_check_mark: |
11
+ | 3.1 | :white_check_mark: |
12
+ | 3.2 | :white_check_mark: |
13
+ | 3.3 | :white_check_mark: |
14
+
15
+ ## Reporting a Vulnerability
16
+
17
+ Please click the `Report a vulnerability` button [here](https://github.com/procore-oss/handcuffs/security) to report a vulnerability.
18
+
19
+ A maintainer will respond to you as soon as possible and discuss the process to get the vulnerability fixed.
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 6.1"
5
+ gem "rails", "~> 6.1.0"
6
6
 
7
7
  gemspec path: "../"
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 5.2.3"
5
+ gem "rails", "~> 7.0.0"
6
6
 
7
7
  gemspec path: "../"
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 6.0.1"
5
+ gem "rails", "~> 7.1.0"
6
6
 
7
7
  gemspec path: "../"
data/handcuffs.gemspec CHANGED
@@ -6,18 +6,21 @@ require 'handcuffs/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "handcuffs"
8
8
  spec.version = Handcuffs::VERSION
9
- spec.authors = ["Brad Urani"]
10
- spec.email = ["bradurani@gmail.com", "opensource@procore.com"]
9
+ spec.authors = ["Procore Technologies, Inc."]
10
+ spec.email = ["opensource@procore.com"]
11
11
 
12
12
  spec.summary = %q{A Ruby gem for running Active Record migrations in phases}
13
13
  spec.description = %q{Allows you to define a phase on Active Record migrations and provides rake tasks for running only migrations tagged with a certain phase}
14
- spec.homepage = "https://github.com/procore/handcuffs/"
14
+ spec.homepage = "https://github.com/procore-oss/handcuffs/"
15
15
  spec.license = "MIT"
16
+ spec.required_ruby_version = Gem::Requirement.new('>= 3.0')
16
17
 
17
18
  # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
19
  # delete this section to allow pushing this gem to any host.
19
20
  if spec.respond_to?(:metadata)
20
21
  spec.metadata['allowed_push_host'] = "https://rubygems.org"
22
+ spec.metadata['rubygems_mfa_required'] = 'true'
23
+ spec.metadata['homepage_uri'] = spec.homepage
21
24
  else
22
25
  raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
26
  end
@@ -31,7 +34,8 @@ Gem::Specification.new do |spec|
31
34
  spec.add_development_dependency "pg"
32
35
  spec.add_development_dependency "pry"
33
36
  spec.add_development_dependency "pry-byebug"
34
- spec.add_development_dependency "rspec-rails", "~> 3.0"
37
+ spec.add_development_dependency "rspec-rails", "~> 6.1"
38
+ spec.add_development_dependency "simplecov"
35
39
 
36
- spec.add_runtime_dependency "rails", ">= 4.0"
40
+ spec.add_runtime_dependency "rails", ">= 6.1"
37
41
  end
@@ -10,7 +10,7 @@ module Handcuffs
10
10
  end
11
11
 
12
12
  class Configurator
13
- attr_accessor :phases
13
+ attr_reader :phases
14
14
  attr_accessor :default_phase
15
15
 
16
16
  def initialize
@@ -18,7 +18,9 @@ module Handcuffs
18
18
  @default_phase = nil
19
19
  end
20
20
 
21
+ def phases=(phases)
22
+ @phases = Phases.new(phases)
23
+ end
21
24
  end
22
-
23
25
  end
24
26
 
@@ -44,7 +44,7 @@
44
44
  class HandcuffsPhaseOutOfOrderError < HandcuffsError
45
45
  def initialize(not_run_phase, attempted_phase)
46
46
  msg = <<-MESSAGE
47
- Your tried to run #{attempted_phase.to_s}, but #{not_run_phase.to_s} has not been run
47
+ You tried to run #{attempted_phase.to_s}, but #{not_run_phase.to_s} has not been run
48
48
  MESSAGE
49
49
  super msg
50
50
  end
@@ -1,12 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Handcuffs
4
+ # Extended by ActiveRecord::Migrator in order to track the current phase
2
5
  module Extensions
3
-
4
- attr_reader :handcuffs_phase
6
+ attr_accessor :handcuffs_phase
5
7
 
6
8
  def phase(phase)
7
9
  @handcuffs_phase = phase
8
10
  end
9
-
10
11
  end
11
12
  end
12
-
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Handcuffs
4
+ # PendingFilter is prepended to ActiveRecord::Migrator in the rake tasks
5
+ # in order to check the current phase before it is run
6
+ module PendingFilterExt
7
+ def runnable
8
+ attempted_phase = self.class.handcuffs_phase
9
+ if @direction == :up
10
+ Handcuffs::PhaseFilter.new(attempted_phase, @direction).filter(super)
11
+ else
12
+ phase_migrations = Handcuffs::PhaseFilter.new(attempted_phase, @direction).filter(migrations)
13
+ runnable = phase_migrations[start..finish]
14
+ runnable.pop if target
15
+ runnable.find_all { |m| ran?(m) }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -41,7 +41,7 @@ class Handcuffs::PhaseFilter
41
41
  end
42
42
 
43
43
  def check_order_up!(by_phase, defined_phases)
44
- defined_phases.take_while { |defined_phase| defined_phase != attempted_phase }
44
+ defined_phases.prereqs(attempted_phase)
45
45
  .detect { |defined_phase| by_phase.key?(defined_phase) }
46
46
  .tap do |defined_phase|
47
47
  raise HandcuffsPhaseOutOfOrderError.new(defined_phase, attempted_phase) if defined_phase
@@ -58,7 +58,7 @@ class Handcuffs::PhaseFilter
58
58
  end
59
59
 
60
60
  def all_phases_by_configuration_order(by_phase, defined_phases)
61
- defined_phases.reduce([]) do |acc, phase|
61
+ defined_phases.in_order.reduce([]) do |acc, phase|
62
62
  acc | Array(by_phase[phase])
63
63
  end.map { |mh| mh[:proxy] }
64
64
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tsort'
4
+
5
+ module Handcuffs
6
+ # Phases encapsulates the list of phases and any interdependencies
7
+ class Phases
8
+ def initialize(phases)
9
+ @phases = case phases
10
+ when Hash
11
+ phases.each_with_object({}) do |phase, acc|
12
+ acc[phase[0].to_sym] = Array(phase[1]).map(&:to_sym)
13
+ end
14
+ else
15
+ # Assume each entry depends on all entries before it
16
+ phases.map(&:to_sym).each_with_object({}) do |phase, acc|
17
+ acc[phase] = phases.take_while { |defined_phase| defined_phase != phase }
18
+ end
19
+ end
20
+ end
21
+
22
+ def to_sentence
23
+ @phases.keys.to_sentence
24
+ end
25
+
26
+ def include?(phase)
27
+ @phases.include?(phase)
28
+ end
29
+
30
+ def in_order
31
+ TSort.tsort(
32
+ @phases.method(:each_key),
33
+ ->(phase, &block) { @phases.fetch(phase).each(&block) }
34
+ )
35
+ end
36
+
37
+ def prereqs(attempted_phase)
38
+ @phases.fetch(attempted_phase, [])
39
+ end
40
+ end
41
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Handcuffs
2
- VERSION = "1.4.1"
4
+ VERSION = '2.1.0'
3
5
  end
@@ -1,56 +1,51 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :handcuffs do
2
- task :migrate, [:phase] => :environment do |t,args|
4
+ task :migrate, [:phase] => :environment do |_t, args|
3
5
  phase = setup(args, 'handcuffs:migrate')
4
6
  patch_migrator!(phase)
5
7
  run_task('db:migrate')
6
8
  end
7
9
 
8
- task :rollback, [:phase] => :environment do |t,args|
10
+ task :rollback, [:phase] => :environment do |_t, args|
9
11
  phase = setup(args, 'handcuffs:rollback')
10
12
  patch_migrator!(phase)
11
13
  run_task('db:rollback')
12
14
  end
13
15
 
16
+ task phase_order: :environment do
17
+ raise HandcuffsNotConfiguredError unless Handcuffs.config
18
+
19
+ puts 'Configured Handcuffs phases, in order, are:'
20
+ phases = Handcuffs.config.phases || return
21
+
22
+ phases.in_order.each_with_index do |phase, idx|
23
+ puts (idx + 1).to_s.rjust(3) + ". #{phase}, requires: #{phases.prereqs(phase).join(', ').presence || '(nothing)'}"
24
+ end
25
+ end
26
+
14
27
  def setup(args, task)
15
- phase = args.phase
28
+ phase = args.phase.presence&.to_sym
29
+
16
30
  raise RequiresPhaseArgumentError.new(task) unless phase.present?
17
- raise HandcuffsNotConfiguredError.new unless Handcuffs.config
18
- phase = phase.to_sym
19
- unless Handcuffs.config.phases.include?(phase) || phase == :all
20
- raise HandcuffsUnknownPhaseError.new(phase, Handcuffs.config.phases)
21
- end
22
- phase
31
+
32
+ raise HandcuffsNotConfiguredError unless Handcuffs.config
33
+
34
+ return phase if Handcuffs.config.phases.include?(phase) || phase == :all
35
+
36
+ raise HandcuffsUnknownPhaseError.new(phase, Handcuffs.config.phases)
23
37
  end
24
38
 
25
39
  def patch_migrator!(phase)
26
- ActiveRecord::Migrator.prepend(PendingFilter)
27
- ActiveRecord::Migrator.extend(PhaseAccessor)
40
+ ActiveRecord::Migrator.extend(Handcuffs::Extensions)
41
+ ActiveRecord::Migrator.prepend(Handcuffs::PendingFilterExt)
28
42
  ActiveRecord::Migrator.handcuffs_phase = phase
29
43
  end
30
44
 
31
45
  def run_task(name)
32
46
  Rake::Task.clear # necessary to avoid tasks being loaded several times in dev mode
33
- Rails.application.load_tasks
47
+ Rails.application.load_tasks
34
48
  Rake::Task[name].reenable # in case you're going to invoke the same task second time.
35
49
  Rake::Task[name].invoke
36
50
  end
37
-
38
- module PendingFilter
39
- def runnable
40
- attempted_phase = self.class.handcuffs_phase
41
- if(@direction == :up)
42
- Handcuffs::PhaseFilter.new(attempted_phase, @direction).filter(super)
43
- else
44
- phase_migrations = Handcuffs::PhaseFilter.new(attempted_phase, @direction).filter(migrations)
45
- runnable = phase_migrations[start..finish]
46
- runnable.pop if target
47
- runnable.find_all { |m| ran?(m) }
48
- end
49
- end
50
- end
51
-
52
- module PhaseAccessor
53
- attr_accessor :handcuffs_phase
54
- end
55
-
56
51
  end