nonschema_migrations 6.5.1 → 6.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2e935824796ce13a066ffb1ae249e290b68fa98a0795b1b6030c5c29317d343
4
- data.tar.gz: 6e0570efd5a054f192dcd231b66b05b241e56b9f03e46ede56f2322416c5f501
3
+ metadata.gz: 100815f15b1c5bcfac2cd4fd1904f193ce2ba046dc733b7d43eb062747eb8e35
4
+ data.tar.gz: d5a5919d9f65337f9d514c9ba1be5467b4551a174a9cdaacd0245b34a9077b24
5
5
  SHA512:
6
- metadata.gz: 2d8f77a424fd97f377ea19cdb52b2ce8c9633452139c2e9102d9b6345195fa6e5ae25a78eb5753f4a23fd9ba847897caf8ac9cefd19cee6003dfac7b03d45c80
7
- data.tar.gz: 346ee88888703f2266f60588b5ac7ac0744740ce419c07b3c2fb464cd61fd330bc7289b8b722b655e642ebec456b3aa3b091759c5ad64a15c2f87203cea3688b
6
+ metadata.gz: 0d4708792141afdfab8455724bd8bfeb63a0a2ae1d89fe6cbeb828aed608b0b8087874f81f616c70bdb322c60091a5a8394f33925145aad73df5a2aa785ab244
7
+ data.tar.gz: 43bc32be4cd67f4156e2f26f3d9c457b6f1aed62a7f5cba1b3aac02b9df9a324147fdbfbd35342bfe8cdd54d796c1bb7b6ce37edff3a63538f6af676c25e2854
data/README.md CHANGED
@@ -4,16 +4,17 @@
4
4
 
5
5
  _Please use the version number of this gem in lockstep with your Rails version._
6
6
 
7
- | Rails Version | | Use Version of This Gem | |
8
- |--------------|------------------|---------------------------------------------|-----|
9
- | Rails 4.x, 4.1.x, 4.2 | | v1.0.1 (Released Jun 1, 2019) | |
10
- | Rails 5.0 | | v2.0.1 (Released Jun 1, 2019) | |
11
- | Rails 5.1 | | v3.0.1 (Released Jun 1, 2019) | |
12
- | Rails 5.2 | | v4.0.2 (Released Jun 2, 2019) | |
13
- | Rails 6.0 | | v5.1.2.1 (Released Nov 17, 2021) | |
14
- | Rails 7.0.0.alpha2 | | v6.0.alpha2 (Released Nov 17, 2021) | |
15
- | Rails 7 | | v6.5 (Released Jan 11, 2022) | |
16
-
7
+ | Rails Version | | Use Version of This Gem | |
8
+ |-----------------------|------------------|----------------------------------|-----|
9
+ | Rails 4.x, 4.1.x, 4.2 | | v1.0.1 (Released Jun 1, 2019) | |
10
+ | Rails 5.0 | | v2.0.1 (Released Jun 1, 2019) | |
11
+ | Rails 5.1 | | v3.0.1 (Released Jun 1, 2019) | |
12
+ | Rails 5.2 | | v4.0.2 (Released Jun 2, 2019) | |
13
+ | Rails 6.0 | | v5.1.2.1 (Released Nov 17, 2021) | |
14
+ | Rails 7.0 | | v6.5.1 (Released Jan 4, 2024), ~v6.5.0 (Released Jan 11, 2022)~ | |
15
+ | Rails 7.1 | | not yet compatible | |
16
+
17
+ Note: yanked version 6.5 was not compatible with Rails 7.1. For Rails 7.0 please bump this gem to 6.5.1.
17
18
 
18
19
  ## Introduction
19
20
 
@@ -99,9 +100,6 @@ Migrate up the specified versions.
99
100
  ## rails data:rollback
100
101
  Rollback the last version. Generally data migrations don't have any "down" associated with them so use this only under extreme circumstances.
101
102
 
102
-
103
- #
104
-
105
103
  By default your data migration will run in a single transaction (just like a schema migration).
106
104
 
107
105
  To turn this off, add `disable_ddl_transaction!` to the top of your migration, like so:
@@ -138,29 +136,34 @@ advantage: your app is down only for schema migrations and you can let the data
138
136
  1. Deploy to heroku with preboot on
139
137
  2. Heroku switches the incoming requests to use the new app
140
138
  3. Run data migrations (while new app is up & running)
141
-
142
139
  advantage: your app is never down and you can run data migrations in the background
143
140
 
144
-
145
-
146
141
  ## Heroku Pipeline
147
-
148
-
149
- Release tasks should dbe **db:migrate**
150
- in `release-tasks.sh`
142
+ To use data migrations on the pipeline, the `release-tasks.sh` file should contain only the db:migrate
151
143
  ```
152
- bundle exec rails db:migrate
144
+ # Step to execute
145
+ bundle exec rails db:migrate
146
+ # check for a good exit
147
+ if [ 0 -ne 0 ]
148
+ then
149
+ puts '*** RELEASE COMMAND FAILED'
150
+ # something went wrong; convey that and exit
151
+ exit 1
152
+ fi
153
153
  ```
154
154
 
155
155
 
156
- The postdeply task shoul dbe **data:migrate**
156
+ The postdeply task should be **data:migrate**
157
157
  in `app.json`
158
158
  ```
159
159
  "scripts": {
160
160
  "postdeploy": "bundle exec rails data:migrate"
161
161
  }
162
162
  ```
163
- Using data migration is like seed data.
164
-
165
- However, the above setup will run only for REVIEW APPS. You will still need to manually run the data migration for staging + production.
163
+ The above setup will run data migtrations only for REVIEW APPS.
164
+ You will still need to manually run the data migration for staging + production.
166
165
 
166
+ If you want to use the data migrations for staging + production, remove the postdeploy script from `app.json` and change release-tasks.sh to :
167
+ ```
168
+ bundle exec rails db:migrate data:migrate
169
+ ```
@@ -4,6 +4,21 @@ require 'active_record/base'
4
4
 
5
5
  module ActiveRecord
6
6
  class DataMigration < ActiveRecord::Base
7
+ def initialize(migrations)
8
+
9
+ @migration_struct = migrations
10
+ end
11
+
12
+
13
+ def up
14
+ Migrator.new(:up, @migration_struct).migrate
15
+ end
16
+
17
+ def down
18
+ Migrator.new(:down, @migration_struct).migrate
19
+ end
20
+
21
+
7
22
  class << self
8
23
  def primary_key
9
24
  nil
@@ -49,4 +64,4 @@ module ActiveRecord
49
64
  super.to_i
50
65
  end
51
66
  end
52
- end
67
+ end
@@ -0,0 +1,91 @@
1
+
2
+ # frozen_string_literal: true
3
+
4
+ require "active_record/database_configurations"
5
+
6
+ module ActiveRecord
7
+ module Tasks # :nodoc:
8
+ class DatabaseNotSupported < StandardError; end # :nodoc:
9
+
10
+
11
+ module DataTasks
12
+ ##
13
+ # :singleton-method:
14
+ # Extra flags passed to database CLI tool (mysqldump/pg_dump) when calling db:schema:dump
15
+ # It can be used as a string/array (the typical case) or a hash (when you use multiple adapters)
16
+ # Example:
17
+ # ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = {
18
+ # mysql2: ['--no-defaults', '--skip-add-drop-table'],
19
+ # postgres: '--no-tablespaces'
20
+ # }
21
+ mattr_accessor :structure_dump_flags, instance_accessor: false
22
+
23
+ ##
24
+ # :singleton-method:
25
+ # Extra flags passed to database CLI tool when calling db:schema:load
26
+ # It can be used as a string/array (the typical case) or a hash (when you use multiple adapters)
27
+ mattr_accessor :structure_load_flags, instance_accessor: false
28
+
29
+ extend self
30
+
31
+ attr_writer :data_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader
32
+ attr_accessor :database_configuration
33
+
34
+
35
+ def self.data_migrations_table_name
36
+ "data_migrations"
37
+ end
38
+
39
+ def check_protected_environments!(environment = env)
40
+ return if ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"]
41
+
42
+ configs_for(env_name: environment).each do |db_config|
43
+ check_current_protected_environment!(db_config)
44
+ end
45
+ end
46
+
47
+ def data_dir
48
+ @data_dir ||= Rails.application.config.paths["data"].first
49
+ end
50
+
51
+ def migrations_paths
52
+ @migrations_paths ||= Rails.application.paths["data/migrate"].to_a
53
+ end
54
+
55
+ def parse_migration_filename(filename)
56
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
57
+ end
58
+
59
+ def migration_files
60
+ paths = Array(Rails.root.join('db', 'data_migrate'))
61
+ Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
62
+ end
63
+
64
+ def migrate(version = nil)
65
+ # get all data migrations in data/migrations
66
+ # get list of data migrations in database
67
+ already_done = ActiveRecord::Base.connection.execute("SELECT version FROM data_migrations").map { |record| record['version'].to_i }
68
+
69
+ data_migrations = migration_files.map do |file|
70
+ version, name, scope = parse_migration_filename(file)
71
+ raise IllegalMigrationNameError.new(file) unless version
72
+ version = version.to_i
73
+ name = name.camelize
74
+
75
+ MigrationProxy.new(name, version, file, scope)
76
+ end
77
+ data_migrations.reject! do |mig|
78
+ already_done.include?(mig.version)
79
+ end
80
+ data_migrations.each do |migration|
81
+ require migration.filename
82
+ (eval(migration.name).new).migrate(:up)
83
+
84
+ # push the migration into the database
85
+ ActiveRecord::Base.connection.execute("INSERT INTO data_migrations (version) VALUES (#{migration.version})")
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+
@@ -1,3 +1,3 @@
1
1
  module NonSchemaMigrations
2
- VERSION = "6.5.1"
2
+ VERSION = "6.6"
3
3
  end
@@ -1,179 +1,211 @@
1
- class NonschemaMigrator < ActiveRecord::Migrator
2
- # This class related to data migration.
3
- # Used in rake tasks (rake data:[migrate|rollback|up|down])
4
-
5
- def initialize(direction, migrations, no_op, target_version = nil)
6
- @direction = direction
7
- @target_version = target_version
8
- @migrated_versions = nil
9
- @migrations = migrations
10
-
11
- validate(@migrations)
12
-
13
- ActiveRecord::InternalMetadata.create_table
14
- end
15
-
16
- if defined?(ActiveRecord::MigrationContext)
17
- class NonSchemaMigration < ActiveRecord::SchemaMigration
18
- def self.table_name
19
- NonschemaMigrator.schema_migrations_table_name
20
- end
21
- end
22
-
23
- class MigrationContext < ActiveRecord::MigrationContext
24
- def initialize(migrations_paths, data_migration)
25
-
26
- # super(migrations_paths, data_migration)
27
- @migrations_paths = migrations_paths
28
-
29
- @schema_migration = NonschemaMigrator::NonSchemaMigration
30
- end
31
-
32
- def new_migrator(*args)
33
- result = NonschemaMigrator.new(*args)
34
- result.migration_context = self
35
- result
36
- end
37
-
38
- # these methods are copied from ActiveRecord::Migrator
39
- # replaced:
40
- # 1.) ActiveRecord::NonSchemaMigration with @schema_migration
41
- # 2.) ActiveRecord::Migrator.new with new_migrator
42
-
43
- def get_all_versions
44
- if @schema_migration.table_exists?
45
- @schema_migration.all_versions.map(&:to_i)
46
- else
47
- []
48
- end
49
- end
50
-
51
- def migrations_status
52
- db_list = @schema_migration.normalized_versions
53
-
54
- file_list = migration_files.map do |file|
55
- version, name, scope = parse_migration_filename(file)
56
- raise IllegalMigrationNameError.new(file) unless version
57
- version = @schema_migration.normalize_migration_number(version)
58
- status = db_list.delete(version) ? "up" : "down"
59
- [status, version, (name + scope).humanize]
60
- end.compact
61
-
62
- db_list.map! do |version|
63
- ["up", version, "********** NO FILE **********"]
64
- end
65
-
66
- (db_list + file_list).sort_by { |_, version, _| version }
67
- end
68
-
69
- def rollback(steps)
70
- move(:down, steps)
71
- end
1
+ require_relative "./active_record/data_tasks.rb"
72
2
 
73
- def move(direction, steps)
74
- migrator = new_migrator(direction, migrations, nil, schema_migration)
3
+ class NonschemaMigrator
75
4
 
76
- if current_version != 0 && !migrator.current_migration
77
- raise UnknownMigrationVersionError.new(current_version)
78
- end
5
+ # include ActiveRecord::Tasks::DatabaseTasks
79
6
 
80
- start_index =
81
- if current_version == 0
82
- 0
83
- else
84
- migrator.migrations.index(migrator.current_migration)
85
- end
86
-
87
- finish = migrator.migrations[start_index + steps]
88
- version = finish ? finish.version : 0
89
- send(direction, version)
90
- end
91
-
92
- def up(target_version = nil)
93
- selected_migrations = if block_given?
94
- migrations.select { |m| yield m }
95
- else
96
- migrations
97
- end
98
-
99
- new_migrator(:up, selected_migrations, nil, target_version).migrate
100
- end
101
-
102
- def down(target_version = nil)
103
- selected_migrations = if block_given?
104
- migrations.select { |m| yield m }
105
- else
106
- migrations
107
- end
108
-
109
- new_migrator(:down, selected_migrations, nil, target_version).migrate
110
- end
111
- end
112
-
113
- class << self
114
- def context(path)
115
- NonschemaMigrator::MigrationContext.new(path, ActiveRecord::DataMigration)
116
- end
117
-
118
- def new_migrator(path, *args)
119
- result = self.new(*args)
120
- result.migration_context=context(path)
121
- result
122
- end
123
-
124
- def migrate(path)
125
- context(path).migrate()
126
- end
127
-
128
- def rollback(path, steps = 1)
129
- context(path).rollback(steps)
130
- end
131
-
132
- def run(direction, path, target_version)
133
- new_migrator(path, direction, context(path).migrations, nil, target_version).run
134
- end
135
- end
7
+ # This class related to data migration.
8
+ # Used in rake tasks (rake data:[migrate|rollback|up|down])
136
9
 
137
- def migration_context=(context)
138
- @migration_context = context
139
- end
140
10
 
141
- def load_migrated
142
- @migrated_versions = Set.new(@migration_context.get_all_versions)
143
- end
11
+ def self.migrate(version = nil)
12
+ ActiveRecord::Tasks::DataTasks.migrate(version)
144
13
  end
145
14
 
146
- def record_version_state_after_migrating(version)
147
- if down?
148
- migrated.delete(version)
149
- ActiveRecord::DataMigration.where(:version => version.to_s).delete_all
150
- else
151
- migrated << version
152
- ActiveRecord::DataMigration.create!(:version => version.to_s)
153
- end
15
+ def self.rollback
16
+ ActiveRecord::Tasks::DataTasks.rollback
154
17
  end
155
18
 
156
-
157
- class <<self
158
- def migrations_path
159
- MIGRATIONS_PATH
160
- end
161
-
162
- def schema_migrations_table_name
163
- 'data_migrations'
164
- end
165
-
166
- def schema_migrations_table_name
167
- ActiveRecord::DataMigration.table_name
168
- end
169
-
170
- def get_all_versions(connection = ActiveRecord::Base.connection)
171
- if connection.table_exists?(schema_migrations_table_name)
172
- ActiveRecord::DataMigration.all.map { |x| x.version.to_i }.sort
173
- else
174
- []
175
- end
176
- end
19
+ def initialize(direction, migrations, no_op, target_version = nil)
20
+ # @direction = direction
21
+ # @target_version = target_version
22
+ # @migrated_versions = nil
23
+ # @migrations = migrations
24
+ #
25
+ # validate(@migrations)
26
+ #
27
+ # ActiveRecord::DataMigration.create_table
177
28
  end
29
+
30
+ # if defined?(ActiveRecord::MigrationContext)
31
+ # class NonSchemaMigration < ActiveRecord::SchemaMigration
32
+ # def self.table_name
33
+ # NonschemaMigrator.schema_migrations_table_name
34
+ # end
35
+ #
36
+ # def self.get_all_versions
37
+ # versions
38
+ # end
39
+ #
40
+ # def versions
41
+ # sm = Arel::SelectManager.new(arel_table)
42
+ # sm.project(arel_table[primary_key])
43
+ # sm.order(arel_table[primary_key].asc)
44
+ #
45
+ # connection.select_values(sm, "#{self.class} Load")
46
+ # end
47
+ # end
48
+ #
49
+ # class MigrationContext < ActiveRecord::MigrationContext
50
+ # def initialize(migrations_paths, data_migration)
51
+ #
52
+ # # super(migrations_paths, data_migration)
53
+ # @migrations_paths = migrations_paths
54
+ #
55
+ # @schema_migration = NonschemaMigrator::NonSchemaMigration
56
+ # end
57
+ #
58
+ # def new_migrator(*args)
59
+ # result = NonschemaMigrator.new(*args)
60
+ # result.migration_context = self
61
+ # result
62
+ # end
63
+ #
64
+ # def schema_migrations_table_name
65
+ # 'data_migrations'
66
+ # end
67
+ #
68
+ # # these methods are copied from ActiveRecord::Migrator
69
+ # # replaced:
70
+ # # 1.) ActiveRecord::NonSchemaMigration with @schema_migration
71
+ # # 2.) ActiveRecord::Migrator.new with new_migrator
72
+ #
73
+ # def get_all_versions
74
+ # byebug
75
+ # if connection.table_exists?(schema_migrations_table_name)
76
+ # @schema_migration.all_versions.map(&:to_i)
77
+ # else
78
+ # []
79
+ # end
80
+ # end
81
+ #
82
+ # def migrations_status
83
+ # db_list = @schema_migration.normalized_versions
84
+ #
85
+ # file_list = migration_files.map do |file|
86
+ # version, name, scope = parse_migration_filename(file)
87
+ # raise IllegalMigrationNameError.new(file) unless version
88
+ # version = @schema_migration.normalize_migration_number(version)
89
+ # status = db_list.delete(version) ? "up" : "down"
90
+ # [status, version, (name + scope).humanize]
91
+ # end.compact
92
+ #
93
+ # db_list.map! do |version|
94
+ # ["up", version, "********** NO FILE **********"]
95
+ # end
96
+ #
97
+ # (db_list + file_list).sort_by { |_, version, _| version }
98
+ # end
99
+ #
100
+ # def rollback(steps)
101
+ # move(:down, steps)
102
+ # end
103
+ #
104
+ # def move(direction, steps)
105
+ # migrator = new_migrator(direction, migrations, nil, schema_migration)
106
+ #
107
+ # if current_version != 0 && !migrator.current_migration
108
+ # raise UnknownMigrationVersionError.new(current_version)
109
+ # end
110
+ #
111
+ # start_index =
112
+ # if current_version == 0
113
+ # 0
114
+ # else
115
+ # migrator.migrations.index(migrator.current_migration)
116
+ # end
117
+ #
118
+ # finish = migrator.migrations[start_index + steps]
119
+ # version = finish ? finish.version : 0
120
+ # send(direction, version)
121
+ # end
122
+ #
123
+ # def up(target_version = nil)
124
+ # selected_migrations = if block_given?
125
+ # migrations.select { |m| yield m }
126
+ # else
127
+ # migrations
128
+ # end
129
+ #
130
+ # new_migrator(:up, selected_migrations, nil, target_version).migrate
131
+ # end
132
+ #
133
+ # def down(target_version = nil)
134
+ # selected_migrations = if block_given?
135
+ # migrations.select { |m| yield m }
136
+ # else
137
+ # migrations
138
+ # end
139
+ #
140
+ # new_migrator(:down, selected_migrations, nil, target_version).migrate
141
+ # end
142
+ # end
143
+ #
144
+ # class << self
145
+ # def context(path)
146
+ # NonschemaMigrator::MigrationContext.new(path, ActiveRecord::DataMigration)
147
+ # end
148
+ #
149
+ # def new_migrator(path, *args)
150
+ # result = self.new(*args)
151
+ # result.migration_context=context(path)
152
+ # result
153
+ # end
154
+ #
155
+ # def migrate(path)
156
+ # context(path).migrate()
157
+ # end
158
+ #
159
+ # def rollback(path, steps = 1)
160
+ # context(path).rollback(steps)
161
+ # end
162
+ #
163
+ # def run(direction, path, target_version)
164
+ # new_migrator(path, direction, context(path).migrations, nil, target_version).run
165
+ # end
166
+ # end
167
+ #
168
+ # def migration_context=(context)
169
+ # @migration_context = context
170
+ # end
171
+ #
172
+ # def load_migrated
173
+ # @migrated_versions = Set.new(@migration_context.get_all_versions)
174
+ # end
175
+ #
176
+ # def schema_migrations_table_name
177
+ # 'data_migrations'
178
+ # end
179
+ #
180
+ # end
181
+ #
182
+ # def record_version_state_after_migrating(version)
183
+ # if down?
184
+ # migrated.delete(version)
185
+ # ActiveRecord::DataMigration.where(:version => version.to_s).delete_all
186
+ # else
187
+ # migrated << version
188
+ # ActiveRecord::DataMigration.create!(:version => version.to_s)
189
+ # end
190
+ # end
191
+ #
192
+ #
193
+ # class <<self
194
+ # def migrations_path
195
+ # MIGRATIONS_PATH
196
+ # end
197
+ #
198
+ # def schema_migrations_table_name
199
+ # 'data_migrations'
200
+ # end
201
+ #
202
+ # def get_all_versions(connection = ActiveRecord::Base.connection)
203
+ # if connection.table_exists?(schema_migrations_table_name)
204
+ # ActiveRecord::DataMigration.all.map { |x| x.version.to_i }.sort
205
+ # else
206
+ # []
207
+ # end
208
+ # end
209
+ # end
178
210
  end
179
211
 
data/lib/tasks/data.rb CHANGED
@@ -12,15 +12,9 @@ namespace :data do
12
12
 
13
13
  desc "rollback data migration (#{MIGRATIONS_PATH})"
14
14
  task :rollback => :data_migration_dependencies do
15
- NonschemaMigrator.rollback(MIGRATIONS_PATH)
15
+ NonschemaMigrator.rollback
16
16
  end
17
17
 
18
- desc "honeybear (#{MIGRATIONS_PATH})"
19
- task :honeybear => :data_migration_dependencies do
20
- puts "hello honeybear"
21
- end
22
-
23
-
24
18
  namespace :migrate do
25
19
  desc %Q{runs the "up" for a given _data_ migration VERSION}
26
20
  task :up => :data_migration_dependencies do
metadata CHANGED
@@ -1,33 +1,33 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nonschema_migrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.5.1
4
+ version: '6.6'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Fleetwood-Boldt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-04 00:00:00.000000000 Z
11
+ date: 2024-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">"
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.1'
20
- - - "<"
19
+ version: '7.1'
20
+ - - ">="
21
21
  - !ruby/object:Gem::Version
22
22
  version: '7.1'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - ">"
27
+ - - "~>"
28
28
  - !ruby/object:Gem::Version
29
- version: '5.1'
30
- - - "<"
29
+ version: '7.1'
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: '7.1'
33
33
  description: Separate schema-only migrations from nonschema (data) migrations in your
@@ -62,6 +62,7 @@ files:
62
62
  - gemfiles/rails_5_2.gemfile.lock
63
63
  - gemfiles/rails_6_0.gemfile
64
64
  - lib/active_record/data_migration.rb
65
+ - lib/active_record/data_tasks.rb
65
66
  - lib/generators/data_migration_generator.rb
66
67
  - lib/generators/data_migrations/install_generator.rb
67
68
  - lib/generators/data_migrations/templates/create_data_migrations.rb