salsify-data_migrate 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.rspec +3 -0
- data/.travis.yml +18 -0
- data/Appraisals +17 -0
- data/Changelog.md +20 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +155 -0
- data/Rakefile +2 -0
- data/data_migrate.gemspec +36 -0
- data/gemfiles/rails_4.0.gemfile +7 -0
- data/gemfiles/rails_4.1.gemfile +7 -0
- data/gemfiles/rails_4.2.gemfile +8 -0
- data/gemfiles/rails_5.0.gemfile +7 -0
- data/lib/capistrano/data_migrate.rb +3 -0
- data/lib/capistrano/data_migrate/migrate.rb +42 -0
- data/lib/data_migrate.rb +3 -0
- data/lib/data_migrate/data_migrator.rb +76 -0
- data/lib/data_migrate/data_schema_migration.rb +14 -0
- data/lib/data_migrate/railtie.rb +7 -0
- data/lib/data_migrate/version.rb +3 -0
- data/lib/generators/data_migrate.rb +10 -0
- data/lib/generators/data_migration/data_migration_generator.rb +46 -0
- data/lib/generators/data_migration/templates/data_migration.rb +8 -0
- data/lib/salsify-data_migrate.rb +1 -0
- data/spec/data_migrate/data_migrator_spec.rb +17 -0
- data/spec/data_migrate/data_schema_migration_spec.rb +16 -0
- data/spec/generators/data_migration/data_migration_generator_spec.rb +27 -0
- data/spec/spec_helper.rb +5 -0
- data/tasks/.gitkeep +0 -0
- data/tasks/databases.rake +375 -0
- metadata +200 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4c5d2c5936fa5ca3ad371d24e17e328cf1a50593
|
4
|
+
data.tar.gz: 302aaf6f189cd511e5df5f8d65d64adc3f2975bf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 43ca1c6ea6fb04997078d51c254bb0700d9ec18a3c31338df08146f2d228e24fecc91fcdc44134c948909a398e25174b1f040df00a0c54d2d4f3f7e17b04b5de
|
7
|
+
data.tar.gz: d0b3256efc688a7259132147914ecf21e2001386162db390b847da253d31a365526a5d87ce28da13c245b1d570184f5fc46350bc62b59401286ad29279c0abf3
|
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.0.0-p648
|
4
|
+
- 2.1.10
|
5
|
+
- 2.2.6
|
6
|
+
- 2.3.4
|
7
|
+
script: bundle exec rspec
|
8
|
+
gemfile:
|
9
|
+
- gemfiles/rails_4.0.gemfile
|
10
|
+
- gemfiles/rails_4.1.gemfile
|
11
|
+
- gemfiles/rails_4.2.gemfile
|
12
|
+
- gemfiles/rails_5.0.gemfile
|
13
|
+
matrix:
|
14
|
+
exclude:
|
15
|
+
- rvm: 2.0.0-p648
|
16
|
+
gemfile: gemfiles/rails_5.0.gemfile
|
17
|
+
- rvm: 2.1.10
|
18
|
+
gemfile: gemfiles/rails_5.0.gemfile
|
data/Appraisals
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
appraise 'rails-4.0' do
|
2
|
+
gem 'rails', '4.0.13'
|
3
|
+
end
|
4
|
+
|
5
|
+
appraise 'rails-4.1' do
|
6
|
+
gem 'rails', '4.1.16'
|
7
|
+
end
|
8
|
+
|
9
|
+
appraise 'rails-4.2' do
|
10
|
+
gem 'rails', '4.2.8'
|
11
|
+
# Nokogiri 1.7+ requires Ruby 2.1+
|
12
|
+
gem 'nokogiri', '1.6.8.1'
|
13
|
+
end
|
14
|
+
|
15
|
+
appraise 'rails-5.0' do
|
16
|
+
gem 'rails', '5.0.3'
|
17
|
+
end
|
data/Changelog.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Changelog
|
2
|
+
=========
|
3
|
+
|
4
|
+
## 3.0.1
|
5
|
+
|
6
|
+
([gacha](https://github.com/gacha)) Capistrano fixes
|
7
|
+
|
8
|
+
## 3.0.0
|
9
|
+
|
10
|
+
`--skip-schema-migration` removed deprecated. This gem will no longer generate schema
|
11
|
+
migrations. It still supports running schema/data migrations with one command.
|
12
|
+
|
13
|
+
## 2.2.0
|
14
|
+
|
15
|
+
([bilby91](https://github.com/bilby91)) Capistrano support
|
16
|
+
|
17
|
+
## 2.1.0
|
18
|
+
|
19
|
+
User `Rails.application.config.paths["db/migrate"]` instead of hard coded
|
20
|
+
path to db migrations
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2011 Andrew J Vargo
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
Data Migrate
|
2
|
+
====
|
3
|
+
|
4
|
+
- [![Version](http://img.shields.io/gem/v/data_migrate.svg?style=flat-square)](https://rubygems.org/gems/data_migrate)
|
5
|
+
- [![License](http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](http://opensource.org/licenses/MIT)
|
6
|
+
- [![Travis](https://img.shields.io/travis/ilyakatz/data-migrate.svg)](https://travis-ci.org/ilyakatz/data-migrate)
|
7
|
+
|
8
|
+
|
9
|
+
Run data migrations alongside schema migrations.
|
10
|
+
|
11
|
+
Data migrations are stored in `db/data`. They act like schema
|
12
|
+
migrations, except they should be reserved for data migrations. For
|
13
|
+
instance, if you realize you need to titleize all your titles, this
|
14
|
+
is the place to do it.
|
15
|
+
|
16
|
+
Why should I use this?
|
17
|
+
----------------------
|
18
|
+
|
19
|
+
Its seems when a project hits a certain size, I get to manipulate data
|
20
|
+
outside the application itself. Changing defaults, new validations,
|
21
|
+
one-to-one to one-to-many... I found it a pain and dodgy to have to
|
22
|
+
step up migrations one by one, run a ruby script of some sort, then
|
23
|
+
resume migrations. It tanks a lot of the automation of deploy.
|
24
|
+
|
25
|
+
If you don't use the one off scripts, you could do it as a regular
|
26
|
+
migration. It'd be much better to keep concerns separate. The benefit
|
27
|
+
of having them separate has to do with your data model.
|
28
|
+
|
29
|
+
For instance, lets take an absurd example, to illustrate: You have
|
30
|
+
your infamous [Rails blog](http://media.rubyonrails.org/video/rails-0-5.mov)
|
31
|
+
that has posts with many comments. After some use, you decide you are
|
32
|
+
going to be a trend setter, and want only one comment per post, and
|
33
|
+
just the text. "Frist!!1!1" rules the day. Given that you:
|
34
|
+
- write a migration to add a comment column to Post
|
35
|
+
- write a migration to move the contents of the first comments to the Post
|
36
|
+
- drop the column_id column from Post
|
37
|
+
- drop the Comment model
|
38
|
+
- fix all your test/controller/view mojo.
|
39
|
+
|
40
|
+
You've just got bit. When you `rake setup:development`, the mess gets
|
41
|
+
mad at you after it creates your database, and starts cranking through
|
42
|
+
migrations. It gets to the part where you iterate over the comments
|
43
|
+
and it blows up. You don't have a comment model anymore for it to
|
44
|
+
even try and get 'all' from. You think you are smarter, and wrap the
|
45
|
+
AR call in a conditional based on the environment. That's fine until
|
46
|
+
you get that QA gal, and she wants her own thing. Then the UI people
|
47
|
+
get tired of waiting for the full stack to load on page refreshes, so
|
48
|
+
you have to edit past migrations...
|
49
|
+
|
50
|
+
With Data Migrate, you have the control. You can generate your
|
51
|
+
migrations as schema or data as you would as your work flow. For
|
52
|
+
setting tasks that don't require any intermediate AR activity, like
|
53
|
+
dev and test, you stick with db:migrate. For your prod, and qa, you
|
54
|
+
change their scripts to `db:migrate:with_data`. Of course you want to
|
55
|
+
test your migration, so you have the choice of `db:migrate:with_data` or
|
56
|
+
`data:migrate` to just capture that data change.
|
57
|
+
|
58
|
+
What's it do?
|
59
|
+
-------------
|
60
|
+
|
61
|
+
Data migrations are stored in `db/data`. They act like schema
|
62
|
+
migrations, except they should be reserved for data migrations. For
|
63
|
+
instance, if you realize you need to titleize all yours titles, this
|
64
|
+
is the place to do it. Running any of the provided rake tasks also
|
65
|
+
creates a data schema table to mirror the usual schema migrations
|
66
|
+
table to track all the goodness.
|
67
|
+
|
68
|
+
Rails Support
|
69
|
+
--------------------
|
70
|
+
|
71
|
+
Rails 3.1: Version 1.2 supports Rails 3.1.0 and higher **but** is no longer maintained.
|
72
|
+
|
73
|
+
Rails 4: Version 2.0 supports Rails 4.0 and higher
|
74
|
+
|
75
|
+
Rails 5: Not tested
|
76
|
+
|
77
|
+
### Important note
|
78
|
+
|
79
|
+
If you upgraded to Rails 4 while using `data_migrate` prior to version 2,
|
80
|
+
the gem wrote data migration versions into
|
81
|
+
`schema_migrations` table. After the fix, it was corrected to write into
|
82
|
+
`data_migrations`.
|
83
|
+
|
84
|
+
This may cause some unintended consequences. See [#22](https://github.com/ilyakatz/data-migrate/issues/22)
|
85
|
+
|
86
|
+
Installation
|
87
|
+
------------
|
88
|
+
Add the gem to your project
|
89
|
+
|
90
|
+
# Gemfile
|
91
|
+
gem 'data_migrate'
|
92
|
+
|
93
|
+
Then `bundle install` and you are ready to go.
|
94
|
+
|
95
|
+
So you know, when you use one of the provide rake tasks, a table
|
96
|
+
called 'data_migrations' will be created in your database. This
|
97
|
+
is to mirror the way the standard 'db' rake tasks work. If you've
|
98
|
+
installed previous to v1.1.0, you'll want to delete the
|
99
|
+
'create\_data\_migrations_table' migration.
|
100
|
+
|
101
|
+
Usage
|
102
|
+
-----
|
103
|
+
|
104
|
+
### Generating Migrations
|
105
|
+
|
106
|
+
You can generate a data migration as you would a schema migration:
|
107
|
+
|
108
|
+
rails g data_migration add_this_to_that
|
109
|
+
|
110
|
+
### Rake Tasks
|
111
|
+
|
112
|
+
$> rake -T data
|
113
|
+
rake data:forward # Pushes the schema to the next version (specify steps w/ STEP=n)
|
114
|
+
rake data:migrate # Migrate data migrations (options: VERSION=x, VERBOSE=false)
|
115
|
+
rake data:migrate:down # Runs the "down" for a given migration VERSION
|
116
|
+
rake data:migrate:redo # Rollbacks the database one migration and re migrate up (options: STEP=x, VERSIO...
|
117
|
+
rake data:migrate:status # Display status of data migrations
|
118
|
+
rake data:migrate:up # Runs the "up" for a given migration VERSION
|
119
|
+
rake data:rollback # Rolls the schema back to the previous version (specify steps w/ STEP=n)
|
120
|
+
rake data:version # Retrieves the current schema version number for data migrations
|
121
|
+
rake db:forward:with_data # Pushes the schema to the next version (specify steps w/ STEP=n)
|
122
|
+
rake db:migrate:down:with_data # Runs the "down" for a given migration VERSION
|
123
|
+
rake db:migrate:redo:with_data # Rollbacks the database one migration and re migrate up (options: STEP=x, VERSIO...
|
124
|
+
rake db:migrate:status:with_data # Display status of data and schema migrations
|
125
|
+
rake db:migrate:up:with_data # Runs the "up" for a given migration VERSION
|
126
|
+
rake db:migrate:with_data # Migrate the database data and schema (options: VERSION=x, VERBOSE=false)
|
127
|
+
rake db:rollback:with_data # Rolls the schema back to the previous version (specify steps w/ STEP=n)
|
128
|
+
rake db:version:with_data # Retrieves the current schema version numbers for data and schema migrations
|
129
|
+
|
130
|
+
Tasks work as they would with the 'vanilla' db version. The 'with_data' addition to the 'db' tasks will run the task in the context of both the data and schema migrations. That is, `rake db:rollback:with_data` will check to see if it was a schema or data migration invoked last, and do that. Tasks invoked in that space also have an additional line of output, indicating if the action is performed on data or schema.
|
131
|
+
|
132
|
+
With 'up' and 'down', you can specify the option 'BOTH', which defaults to false. Using true, will migrate both the data and schema (in the desired direction) if they both match the version provided. Again, going up, schema is given precedence. Down its data.
|
133
|
+
|
134
|
+
`rake db:migrate:status:with_data` provides and additional column to indicate which type of migration.
|
135
|
+
|
136
|
+
Capistrano Support
|
137
|
+
------------------
|
138
|
+
|
139
|
+
The gem comes with a capistrano task that can be used instead of `capistrano/rails/migrations`.
|
140
|
+
|
141
|
+
Just add this line to your Capfile:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
require 'capistrano/data_migrate'
|
145
|
+
```
|
146
|
+
|
147
|
+
From now on capistrano will run `rake db:migrate:with_data` in every deploy.
|
148
|
+
|
149
|
+
Thanks
|
150
|
+
------
|
151
|
+
[Andrew J Vargo](http://github.com/ajvargo) Andrew was the original creator and maintainer of this project!
|
152
|
+
|
153
|
+
[Jeremy Durham](http://jeremydurham.com/) for fleshing out the idea with me, and providing guidance.
|
154
|
+
|
155
|
+
You! Yes, you. Thanks for checking it out.
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "data_migrate/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "salsify-data_migrate"
|
7
|
+
s.version = DataMigrate::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Salsify, Inc']
|
10
|
+
s.email = ['engineering@salsify.com']
|
11
|
+
s.homepage = 'https://github.com/salsify/data-migrate'
|
12
|
+
s.summary = %q{Rake tasks to migrate data alongside schema changes.}
|
13
|
+
s.description = %q{Rake tasks to migrate data alongside schema changes.}
|
14
|
+
s.license = "MIT"
|
15
|
+
|
16
|
+
s.add_dependency('rails', '>= 4.0', '< 5.1')
|
17
|
+
s.add_development_dependency "appraisal"
|
18
|
+
s.add_development_dependency "rake"
|
19
|
+
s.add_development_dependency "rspec"
|
20
|
+
s.add_development_dependency "rspec-core"
|
21
|
+
s.add_development_dependency "pry"
|
22
|
+
s.add_development_dependency "sqlite3"
|
23
|
+
s.add_development_dependency "timecop"
|
24
|
+
|
25
|
+
|
26
|
+
s.files = `git ls-files`.split("\n")
|
27
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
28
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
29
|
+
s.require_paths = ["lib"]
|
30
|
+
|
31
|
+
s.post_install_message = <<-POST_INSTALL_MESSAGE
|
32
|
+
#{"*" * 80}
|
33
|
+
data-migrate: --skip-schema-migration option is no longer available as of version 3.0.0
|
34
|
+
#{"*" * 80}
|
35
|
+
POST_INSTALL_MESSAGE
|
36
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
namespace :deploy do
|
2
|
+
|
3
|
+
desc 'Runs rake data:migrate if migrations are set'
|
4
|
+
Rake::Task['deploy:migrate'].clear_actions
|
5
|
+
task :migrate => [:set_rails_env] do
|
6
|
+
on fetch(:migration_servers) do
|
7
|
+
conditionally_migrate = fetch(:conditionally_migrate)
|
8
|
+
info '[deploy:migrate] Checking changes in db/migrate or db/data' if conditionally_migrate
|
9
|
+
|
10
|
+
if conditionally_migrate && (
|
11
|
+
test("diff -q #{release_path}/db/migrate #{current_path}/db/migrate") ||
|
12
|
+
test("diff -q #{release_path}/db/data #{current_path}/db/data")
|
13
|
+
)
|
14
|
+
info '[deploy:migrate] Skip `deploy:migrate` (nothing changed in db/migrate or db/data)'
|
15
|
+
else
|
16
|
+
info '[deploy:migrate] Run `rake db:migrate:with_data`'
|
17
|
+
invoke :'deploy:migrating_with_data'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Runs rake db:migrate:with_data'
|
23
|
+
task migrating_with_data: [:set_rails_env] do
|
24
|
+
on fetch(:migration_servers) do
|
25
|
+
within release_path do
|
26
|
+
with rails_env: fetch(:rails_env) do
|
27
|
+
execute :rake, 'db:migrate:with_data'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
after 'deploy:updated', 'deploy:migrate'
|
34
|
+
end
|
35
|
+
|
36
|
+
namespace :load do
|
37
|
+
task :defaults do
|
38
|
+
set :conditionally_migrate, fetch(:conditionally_migrate, false)
|
39
|
+
set :migration_role, fetch(:migration_role, :db)
|
40
|
+
set :migration_servers, -> { primary(fetch(:migration_role)) }
|
41
|
+
end
|
42
|
+
end
|
data/lib/data_migrate.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module DataMigrate
|
4
|
+
|
5
|
+
class DataMigrator < ActiveRecord::Migrator
|
6
|
+
|
7
|
+
def record_version_state_after_migrating(version)
|
8
|
+
if down?
|
9
|
+
migrated.delete(version)
|
10
|
+
DataMigrate::DataSchemaMigration.where(:version => version.to_s).delete_all
|
11
|
+
else
|
12
|
+
migrated << version
|
13
|
+
DataMigrate::DataSchemaMigration.create!(:version => version.to_s)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def get_all_versions(connection = ActiveRecord::Base.connection)
|
19
|
+
if table_exists?(connection, schema_migrations_table_name)
|
20
|
+
# Certain versions of the gem wrote data migration versions into
|
21
|
+
# schema_migrations table. After the fix, it was corrected to write into
|
22
|
+
# data_migrations. However, not to break anything we are going to
|
23
|
+
# get versions from both tables.
|
24
|
+
#
|
25
|
+
# This may cause some problems:
|
26
|
+
# Eg. rake data:versions will show version from the schema_migrations table
|
27
|
+
# which may be a version of actual schema migration and not data migration
|
28
|
+
DataMigrate::DataSchemaMigration.all.map { |x| x.version.to_i }.sort +
|
29
|
+
ActiveRecord::SchemaMigration.all.map { |x| x.version.to_i }.sort
|
30
|
+
else
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def schema_migrations_table_name
|
36
|
+
ActiveRecord::Base.table_name_prefix + 'data_migrations' + ActiveRecord::Base.table_name_suffix
|
37
|
+
end
|
38
|
+
|
39
|
+
def migrations_path
|
40
|
+
'db/data'
|
41
|
+
end
|
42
|
+
|
43
|
+
def assure_data_schema_table
|
44
|
+
config = ActiveRecord::Base.configurations[Rails.env || 'development'] || ENV["DATABASE_URL"]
|
45
|
+
ActiveRecord::Base.establish_connection(config)
|
46
|
+
sm_table = DataMigrate::DataMigrator.schema_migrations_table_name
|
47
|
+
|
48
|
+
unless table_exists?(ActiveRecord::Base.connection, sm_table)
|
49
|
+
ActiveRecord::Base.connection.create_table(sm_table, :id => false) do |schema_migrations_table|
|
50
|
+
schema_migrations_table.column :version, :string, :null => false
|
51
|
+
end
|
52
|
+
|
53
|
+
suffix = ActiveRecord::Base.table_name_suffix
|
54
|
+
prefix = ActiveRecord::Base.table_name_prefix
|
55
|
+
index_name = "#{prefix}unique_data_migrations#{suffix}"
|
56
|
+
|
57
|
+
ActiveRecord::Base.connection.add_index sm_table, :version,
|
58
|
+
:unique => true,
|
59
|
+
:name => index_name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def table_exists?(connection, table_name)
|
66
|
+
# Avoid the warning that table_exists? prints in Rails 5.0 due a change in behavior between
|
67
|
+
# Rails 5.0 and Rails 5.1 of this method with respect to database views.
|
68
|
+
if ActiveRecord.version >= Gem::Version.new('5.0') && ActiveRecord.version < Gem::Version.new('5.1')
|
69
|
+
connection.data_source_exists?(table_name)
|
70
|
+
else
|
71
|
+
connection.table_exists?(schema_migrations_table_name)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module DataMigrate
|
2
|
+
class DataSchemaMigration < ::ActiveRecord::SchemaMigration
|
3
|
+
class << self
|
4
|
+
def table_name
|
5
|
+
ActiveRecord::Base.table_name_prefix + 'data_migrations' + ActiveRecord::Base.table_name_suffix
|
6
|
+
end
|
7
|
+
|
8
|
+
def index_name
|
9
|
+
"#{table_name_prefix}unique_data_migrations#{table_name_suffix}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'rails/generators/named_base'
|
2
|
+
module DataMigrate
|
3
|
+
module Generators
|
4
|
+
class DataMigrationGenerator < Rails::Generators::NamedBase #:nodoc:
|
5
|
+
def self.source_root
|
6
|
+
@_data_migrate_source_root ||= File.expand_path(File.join(File.dirname(__FILE__), generator_name, 'templates'))
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'generators/data_migrate'
|
2
|
+
require 'rails/generators'
|
3
|
+
require 'rails/generators/migration'
|
4
|
+
|
5
|
+
module DataMigrate
|
6
|
+
module Generators
|
7
|
+
class DataMigrationGenerator < Rails::Generators::NamedBase
|
8
|
+
namespace "data_migration"
|
9
|
+
include Rails::Generators::Migration
|
10
|
+
|
11
|
+
argument :attributes, type: :array, default: [], banner: 'field:type field:type'
|
12
|
+
|
13
|
+
def create_data_migration
|
14
|
+
set_local_assigns!
|
15
|
+
migration_template 'data_migration.rb', "db/data/#{file_name}.rb"
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
attr_reader :migration_action
|
21
|
+
|
22
|
+
def self.next_migration_number(dirname)
|
23
|
+
if ActiveRecord::Base.timestamped_migrations
|
24
|
+
Time.new.utc.strftime("%Y%m%d%H%M%S")
|
25
|
+
else
|
26
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_local_assigns!
|
31
|
+
if file_name =~ /^(add|remove)_.*_(?:to|from)_(.*)/
|
32
|
+
@migration_action = $1
|
33
|
+
@table_name = $2.pluralize
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def migration_base_class_name
|
38
|
+
if ActiveRecord.version >= Gem::Version.new('5.0')
|
39
|
+
"ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]"
|
40
|
+
else
|
41
|
+
'ActiveRecord::Migration'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'data_migrate'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataMigrate::DataMigrator do
|
4
|
+
let(:subject) { DataMigrate::DataMigrator }
|
5
|
+
describe :schema_migrations_table_name do
|
6
|
+
it "returns correct table name" do
|
7
|
+
expect(subject.schema_migrations_table_name).to eq("data_migrations")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe :migrations_path do
|
12
|
+
it "returns correct migrations path" do
|
13
|
+
expect(subject.migrations_path).to eq("db/data")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataMigrate::DataSchemaMigration do
|
4
|
+
let(:subject) { DataMigrate::DataSchemaMigration }
|
5
|
+
describe :table_name do
|
6
|
+
it "returns correct table name" do
|
7
|
+
expect(subject.table_name).to eq("data_migrations")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe :index_name do
|
12
|
+
it "returns correct index name" do
|
13
|
+
expect(subject.index_name).to eq("unique_data_migrations")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rails/generators'
|
3
|
+
require 'rails/generators/migration'
|
4
|
+
require 'generators/data_migration/data_migration_generator'
|
5
|
+
|
6
|
+
describe DataMigrate::Generators::DataMigrationGenerator do
|
7
|
+
let(:subject) { DataMigrate::Generators::DataMigrationGenerator }
|
8
|
+
describe :next_migration_number do
|
9
|
+
it "next migration" do
|
10
|
+
Timecop.freeze("2016-12-03 22:15:26 -0800") do
|
11
|
+
expect(ActiveRecord::Base).to receive(:timestamped_migrations) { true }
|
12
|
+
expect(subject.next_migration_number(1)).to eq("20161204061526")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe :migration_base_class_name do
|
18
|
+
let(:subject) { DataMigrate::Generators::DataMigrationGenerator.new(['my_migration']) }
|
19
|
+
it "returns the correct base class name" do
|
20
|
+
if ActiveRecord.version >= Gem::Version.new('5.0')
|
21
|
+
expect(subject.send(:migration_base_class_name)).to eq("ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]")
|
22
|
+
else
|
23
|
+
expect(subject.send(:migration_base_class_name)).to eq('ActiveRecord::Migration')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/tasks/.gitkeep
ADDED
File without changes
|
@@ -0,0 +1,375 @@
|
|
1
|
+
namespace :db do
|
2
|
+
namespace :migrate do
|
3
|
+
desc "Migrate the database data and schema (options: VERSION=x, VERBOSE=false)."
|
4
|
+
task :with_data => :environment do
|
5
|
+
assure_data_schema_table
|
6
|
+
|
7
|
+
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
8
|
+
target_version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
9
|
+
migrations = []
|
10
|
+
|
11
|
+
if target_version.nil?
|
12
|
+
migrations = pending_migrations.map{ |m| m.merge(:direction =>:up) }
|
13
|
+
else
|
14
|
+
current_schema_version = ActiveRecord::Migrator.current_version
|
15
|
+
schema_migrations = if target_version > current_schema_version
|
16
|
+
pending_schema_migrations.keep_if{ |m| m[:version] <= target_version }.map{ |m| m.merge(:direction =>:up) }
|
17
|
+
elsif target_version < current_schema_version
|
18
|
+
past_migrations.keep_if{ |m| m[:version] > target_version }.map{ |m| m.merge(:direction =>:down) }
|
19
|
+
else # ==
|
20
|
+
[]
|
21
|
+
end
|
22
|
+
|
23
|
+
current_data_version = ActiveRecord::Migrator.current_version
|
24
|
+
data_migrations = if target_version > current_data_version
|
25
|
+
pending_data_migrations.keep_if{ |m| m[:version] <= target_version }.map{ |m| m.merge(:direction =>:up) }
|
26
|
+
elsif target_version < current_data_version
|
27
|
+
past_migrations.keep_if{ |m| m[:version] > target_version }.map{ |m| m.merge(:direction =>:down) }
|
28
|
+
else # ==
|
29
|
+
[]
|
30
|
+
end
|
31
|
+
migrations = if schema_migrations.empty?
|
32
|
+
data_migrations
|
33
|
+
elsif data_migrations.empty?
|
34
|
+
schema_migrations
|
35
|
+
elsif target_version > current_data_version && target_version > current_schema_version
|
36
|
+
sort_migrations data_migrations, schema_migrations
|
37
|
+
elsif target_version < current_data_version && target_version < current_schema_version
|
38
|
+
sort_migrations(data_migrations, schema_migrations).reverse
|
39
|
+
elsif target_version > current_data_version && target_version < current_schema_version
|
40
|
+
schema_migrations + data_migrations
|
41
|
+
elsif target_version < current_data_version && target_version > current_schema_version
|
42
|
+
schema_migrations + data_migrations
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
migrations.each do |migration|
|
47
|
+
if migration[:kind] == :data
|
48
|
+
ActiveRecord::Migration.write("== %s %s" % ['Data', "=" * 71])
|
49
|
+
DataMigrate::DataMigrator.run(migration[:direction], "db/data/", migration[:version])
|
50
|
+
else
|
51
|
+
ActiveRecord::Migration.write("== %s %s" % ['Schema', "=" * 69])
|
52
|
+
ActiveRecord::Migrator.run(
|
53
|
+
migration[:direction],
|
54
|
+
Rails.application.config.paths["db/migrate"],
|
55
|
+
migration[:version]
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Rake::Task["db:_dump"].invoke
|
61
|
+
end
|
62
|
+
|
63
|
+
namespace :redo do
|
64
|
+
desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
|
65
|
+
task :with_data => :environment do
|
66
|
+
assure_data_schema_table
|
67
|
+
if ENV["VERSION"]
|
68
|
+
Rake::Task["db:migrate:down:with_data"].invoke
|
69
|
+
Rake::Task["db:migrate:up:with_data"].invoke
|
70
|
+
else
|
71
|
+
Rake::Task["db:rollback:with_data"].invoke
|
72
|
+
Rake::Task["db:migrate:with_data"].invoke
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
namespace :up do
|
78
|
+
desc 'Runs the "up" for a given migration VERSION. (options both=false)'
|
79
|
+
task :with_data => :environment do
|
80
|
+
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
81
|
+
raise "VERSION is required" unless version
|
82
|
+
assure_data_schema_table
|
83
|
+
run_both = ENV["BOTH"] == "true"
|
84
|
+
migrations = pending_migrations.keep_if{|m| m[:version] == version}
|
85
|
+
|
86
|
+
unless run_both || migrations.size < 2
|
87
|
+
migrations = migrations.slice(0,1)
|
88
|
+
end
|
89
|
+
|
90
|
+
migrations.each do |migration|
|
91
|
+
if migration[:kind] == :data
|
92
|
+
ActiveRecord::Migration.write("== %s %s" % ['Data', "=" * 71])
|
93
|
+
DataMigrate::DataMigrator.run(:up, "db/data/", migration[:version])
|
94
|
+
else
|
95
|
+
ActiveRecord::Migration.write("== %s %s" % ['Schema', "=" * 69])
|
96
|
+
ActiveRecord::Migrator.run(:up, "db/migrate/", migration[:version])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
Rake::Task["db:_dump"].invoke
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
namespace :down do
|
105
|
+
desc 'Runs the "down" for a given migration VERSION. (option BOTH=false)'
|
106
|
+
task :with_data => :environment do
|
107
|
+
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
108
|
+
raise "VERSION is required" unless version
|
109
|
+
assure_data_schema_table
|
110
|
+
run_both = ENV["BOTH"] == "true"
|
111
|
+
migrations = past_migrations.keep_if{|m| m[:version] == version}
|
112
|
+
|
113
|
+
unless run_both || migrations.size < 2
|
114
|
+
migrations = migrations.slice(0,1)
|
115
|
+
end
|
116
|
+
|
117
|
+
migrations.each do |migration|
|
118
|
+
if migration[:kind] == :data
|
119
|
+
ActiveRecord::Migration.write("== %s %s" % ['Data', "=" * 71])
|
120
|
+
DataMigrate::DataMigrator.run(:down, "db/data/", migration[:version])
|
121
|
+
else
|
122
|
+
ActiveRecord::Migration.write("== %s %s" % ['Schema', "=" * 69])
|
123
|
+
ActiveRecord::Migrator.run(:down, "db/migrate/", migration[:version])
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
Rake::Task["db:_dump"].invoke
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
namespace :status do
|
132
|
+
desc "Display status of data and schema migrations"
|
133
|
+
task :with_data => :environment do
|
134
|
+
config = connect_to_database
|
135
|
+
next unless config
|
136
|
+
|
137
|
+
db_list_data = ActiveRecord::Base.connection.select_values("SELECT version FROM #{DataMigrate::DataMigrator.schema_migrations_table_name}")
|
138
|
+
db_list_schema = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}")
|
139
|
+
file_list = []
|
140
|
+
|
141
|
+
Dir.foreach(File.join(Rails.root, 'db', 'data')) do |file|
|
142
|
+
# only files matching "20091231235959_some_name.rb" pattern
|
143
|
+
if match_data = /(\d{14})_(.+)\.rb/.match(file)
|
144
|
+
status = db_list_data.delete(match_data[1]) ? 'up' : 'down'
|
145
|
+
file_list << [status, match_data[1], match_data[2], 'data']
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
Dir.foreach(File.join(Rails.root, 'db', 'migrate')) do |file|
|
150
|
+
# only files matching "20091231235959_some_name.rb" pattern
|
151
|
+
if match_data = /(\d{14})_(.+)\.rb/.match(file)
|
152
|
+
status = db_list_schema.delete(match_data[1]) ? 'up' : 'down'
|
153
|
+
file_list << [status, match_data[1], match_data[2], 'schema']
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
file_list.sort!{|a,b| "#{a[1]}_#{a[3] == 'data' ? 1 : 0}" <=> "#{b[1]}_#{b[3] == 'data' ? 1 : 0}" }
|
158
|
+
|
159
|
+
# output
|
160
|
+
puts "\ndatabase: #{config['database']}\n\n"
|
161
|
+
puts "#{"Status".center(8)} #{"Type".center(8)} #{"Migration ID".ljust(14)} Migration Name"
|
162
|
+
puts "-" * 60
|
163
|
+
file_list.each do |file|
|
164
|
+
puts "#{file[0].center(8)} #{file[3].center(8)} #{file[1].ljust(14)} #{file[2].humanize}"
|
165
|
+
end
|
166
|
+
db_list_schema.each do |version|
|
167
|
+
puts "#{'up'.center(8)} #{version.ljust(14)} *** NO SCHEMA FILE ***"
|
168
|
+
end
|
169
|
+
db_list_data.each do |version|
|
170
|
+
puts "#{'up'.center(8)} #{version.ljust(14)} *** NO DATA FILE ***"
|
171
|
+
end
|
172
|
+
puts
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end # END OF MIGRATE NAME SPACE
|
176
|
+
|
177
|
+
namespace :rollback do
|
178
|
+
desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
|
179
|
+
task :with_data => :environment do
|
180
|
+
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
181
|
+
assure_data_schema_table
|
182
|
+
past_migrations[0..(step - 1)].each do | past_migration |
|
183
|
+
if past_migration[:kind] == :data
|
184
|
+
ActiveRecord::Migration.write("== %s %s" % ['Data', "=" * 71])
|
185
|
+
DataMigrate::DataMigrator.run(:down, "db/data/", past_migration[:version])
|
186
|
+
elsif past_migration[:kind] == :schema
|
187
|
+
ActiveRecord::Migration.write("== %s %s" % ['Schema', "=" * 69])
|
188
|
+
ActiveRecord::Migrator.run(:down, "db/migrate/", past_migration[:version])
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
Rake::Task["db:_dump"].invoke
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
namespace :forward do
|
197
|
+
desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
|
198
|
+
task :with_data => :environment do
|
199
|
+
assure_data_schema_table
|
200
|
+
# TODO: No worky for .forward
|
201
|
+
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
202
|
+
# DataMigrate::DataMigrator.forward('db/data/', step)
|
203
|
+
migrations = pending_migrations.reverse.pop(step).reverse
|
204
|
+
migrations.each do | pending_migration |
|
205
|
+
if pending_migration[:kind] == :data
|
206
|
+
ActiveRecord::Migration.write("== %s %s" % ['Data', "=" * 71])
|
207
|
+
DataMigrate::DataMigrator.run(:up, "db/data/", pending_migration[:version])
|
208
|
+
elsif pending_migration[:kind] == :schema
|
209
|
+
ActiveRecord::Migration.write("== %s %s" % ['Schema', "=" * 69])
|
210
|
+
ActiveRecord::Migrator.run(:up, "db/migrate/", pending_migration[:version])
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
Rake::Task["db:_dump"].invoke
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
namespace :version do
|
219
|
+
desc "Retrieves the current schema version numbers for data and schema migrations"
|
220
|
+
task :with_data => :environment do
|
221
|
+
assure_data_schema_table
|
222
|
+
puts "Current Schema version: #{ActiveRecord::Migrator.current_version}"
|
223
|
+
puts "Current Data version: #{DataMigrate::DataMigrator.current_version}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
namespace :data do
|
229
|
+
desc 'Migrate data migrations (options: VERSION=x, VERBOSE=false)'
|
230
|
+
task :migrate => :environment do
|
231
|
+
assure_data_schema_table
|
232
|
+
#ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
233
|
+
DataMigrate::DataMigrator.migrate("db/data/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
|
234
|
+
end
|
235
|
+
|
236
|
+
namespace :migrate do
|
237
|
+
desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
|
238
|
+
task :redo => :environment do
|
239
|
+
assure_data_schema_table
|
240
|
+
if ENV["VERSION"]
|
241
|
+
Rake::Task["data:migrate:down"].invoke
|
242
|
+
Rake::Task["data:migrate:up"].invoke
|
243
|
+
else
|
244
|
+
Rake::Task["data:rollback"].invoke
|
245
|
+
Rake::Task["data:migrate"].invoke
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
desc 'Runs the "up" for a given migration VERSION.'
|
250
|
+
task :up => :environment do
|
251
|
+
assure_data_schema_table
|
252
|
+
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
253
|
+
raise "VERSION is required" unless version
|
254
|
+
DataMigrate::DataMigrator.run(:up, "db/data/", version)
|
255
|
+
end
|
256
|
+
|
257
|
+
desc 'Runs the "down" for a given migration VERSION.'
|
258
|
+
task :down => :environment do
|
259
|
+
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
260
|
+
raise "VERSION is required" unless version
|
261
|
+
assure_data_schema_table
|
262
|
+
DataMigrate::DataMigrator.run(:down, "db/data/", version)
|
263
|
+
end
|
264
|
+
|
265
|
+
desc "Display status of data migrations"
|
266
|
+
task :status => :environment do
|
267
|
+
config = ActiveRecord::Base.configurations[Rails.env || 'development']
|
268
|
+
ActiveRecord::Base.establish_connection(config)
|
269
|
+
unless ActiveRecord::Base.connection.table_exists?(DataMigrate::DataMigrator.schema_migrations_table_name)
|
270
|
+
puts 'Data migrations table does not exist yet.'
|
271
|
+
next # means "return" for rake task
|
272
|
+
end
|
273
|
+
db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{DataMigrate::DataMigrator.schema_migrations_table_name}")
|
274
|
+
file_list = []
|
275
|
+
Dir.foreach(File.join(Rails.root, 'db', 'data')) do |file|
|
276
|
+
# only files matching "20091231235959_some_name.rb" pattern
|
277
|
+
if match_data = /(\d{14})_(.+)\.rb/.match(file)
|
278
|
+
status = db_list.delete(match_data[1]) ? 'up' : 'down'
|
279
|
+
file_list << [status, match_data[1], match_data[2]]
|
280
|
+
end
|
281
|
+
end
|
282
|
+
# output
|
283
|
+
puts "\ndatabase: #{config['database']}\n\n"
|
284
|
+
puts "#{"Status".center(8)} #{"Migration ID".ljust(14)} Migration Name"
|
285
|
+
puts "-" * 50
|
286
|
+
file_list.each do |file|
|
287
|
+
puts "#{file[0].center(8)} #{file[1].ljust(14)} #{file[2].humanize}"
|
288
|
+
end
|
289
|
+
db_list.each do |version|
|
290
|
+
puts "#{'up'.center(8)} #{version.ljust(14)} *** NO FILE ***"
|
291
|
+
end
|
292
|
+
puts
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
|
297
|
+
task :rollback => :environment do
|
298
|
+
assure_data_schema_table
|
299
|
+
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
300
|
+
DataMigrate::DataMigrator.rollback('db/data/', step)
|
301
|
+
end
|
302
|
+
|
303
|
+
desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
|
304
|
+
task :forward => :environment do
|
305
|
+
assure_data_schema_table
|
306
|
+
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
307
|
+
# TODO: No worky for .forward
|
308
|
+
# DataMigrate::DataMigrator.forward('db/data/', step)
|
309
|
+
migrations = pending_data_migrations.reverse.pop(step).reverse
|
310
|
+
migrations.each do | pending_migration |
|
311
|
+
DataMigrate::DataMigrator.run(:up, "db/data/", pending_migration[:version])
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
desc "Retrieves the current schema version number for data migrations"
|
316
|
+
task :version => :environment do
|
317
|
+
assure_data_schema_table
|
318
|
+
puts "Current data version: #{DataMigrate::DataMigrator.current_version}"
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def pending_migrations
|
323
|
+
sort_migrations pending_data_migrations, pending_schema_migrations
|
324
|
+
end
|
325
|
+
|
326
|
+
def pending_data_migrations
|
327
|
+
data_migrations = DataMigrate::DataMigrator.migrations('db/data')
|
328
|
+
sort_migrations DataMigrate::DataMigrator.new(:up, data_migrations ).
|
329
|
+
pending_migrations.map{|m| { :version => m.version, :kind => :data }}
|
330
|
+
end
|
331
|
+
|
332
|
+
def pending_schema_migrations
|
333
|
+
all_migrations = ActiveRecord::Migrator.migrations(Rails.application.config.paths["db/migrate"])
|
334
|
+
sort_migrations(
|
335
|
+
ActiveRecord::Migrator.new(:up, all_migrations).
|
336
|
+
pending_migrations.
|
337
|
+
map{|m| { :version => m.version, :kind => :schema }})
|
338
|
+
end
|
339
|
+
|
340
|
+
def sort_migrations set_1, set_2=nil
|
341
|
+
migrations = set_1 + (set_2 || [])
|
342
|
+
migrations.sort{|a,b| sort_string(a) <=> sort_string(b)}
|
343
|
+
end
|
344
|
+
|
345
|
+
def sort_string migration
|
346
|
+
"#{migration[:version]}_#{migration[:kind] == :data ? 1 : 0}"
|
347
|
+
end
|
348
|
+
|
349
|
+
def connect_to_database
|
350
|
+
config = ActiveRecord::Base.configurations[Rails.env || 'development']
|
351
|
+
ActiveRecord::Base.establish_connection(config)
|
352
|
+
|
353
|
+
unless ActiveRecord::Base.connection.table_exists?(DataMigrate::DataMigrator.schema_migrations_table_name)
|
354
|
+
puts 'Data migrations table does not exist yet.'
|
355
|
+
config = nil
|
356
|
+
end
|
357
|
+
unless ActiveRecord::Base.connection.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name)
|
358
|
+
puts 'Schema migrations table does not exist yet.'
|
359
|
+
config = nil
|
360
|
+
end
|
361
|
+
config
|
362
|
+
end
|
363
|
+
|
364
|
+
def past_migrations sort=nil
|
365
|
+
sort = sort.downcase if sort
|
366
|
+
db_list_data = ActiveRecord::Base.connection.select_values("SELECT version FROM #{DataMigrate::DataMigrator.schema_migrations_table_name}").sort
|
367
|
+
db_list_schema = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}").sort
|
368
|
+
migrations = db_list_data.map{|d| {:version => d.to_i, :kind => :data }} + db_list_schema.map{|d| {:version => d.to_i, :kind => :schema }}
|
369
|
+
|
370
|
+
sort == 'asc' ? sort_migrations(migrations) : sort_migrations(migrations).reverse
|
371
|
+
end
|
372
|
+
|
373
|
+
def assure_data_schema_table
|
374
|
+
DataMigrate::DataMigrator.assure_data_schema_table
|
375
|
+
end
|
metadata
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: salsify-data_migrate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 3.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Salsify, Inc
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-06-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5.1'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '4.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.1'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: appraisal
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rspec
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rspec-core
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: pry
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: sqlite3
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: timecop
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
description: Rake tasks to migrate data alongside schema changes.
|
132
|
+
email:
|
133
|
+
- engineering@salsify.com
|
134
|
+
executables: []
|
135
|
+
extensions: []
|
136
|
+
extra_rdoc_files: []
|
137
|
+
files:
|
138
|
+
- ".gitignore"
|
139
|
+
- ".rspec"
|
140
|
+
- ".travis.yml"
|
141
|
+
- Appraisals
|
142
|
+
- Changelog.md
|
143
|
+
- Gemfile
|
144
|
+
- LICENSE
|
145
|
+
- README.md
|
146
|
+
- Rakefile
|
147
|
+
- data_migrate.gemspec
|
148
|
+
- gemfiles/rails_4.0.gemfile
|
149
|
+
- gemfiles/rails_4.1.gemfile
|
150
|
+
- gemfiles/rails_4.2.gemfile
|
151
|
+
- gemfiles/rails_5.0.gemfile
|
152
|
+
- lib/capistrano/data_migrate.rb
|
153
|
+
- lib/capistrano/data_migrate/migrate.rb
|
154
|
+
- lib/data_migrate.rb
|
155
|
+
- lib/data_migrate/data_migrator.rb
|
156
|
+
- lib/data_migrate/data_schema_migration.rb
|
157
|
+
- lib/data_migrate/railtie.rb
|
158
|
+
- lib/data_migrate/version.rb
|
159
|
+
- lib/generators/data_migrate.rb
|
160
|
+
- lib/generators/data_migration/data_migration_generator.rb
|
161
|
+
- lib/generators/data_migration/templates/data_migration.rb
|
162
|
+
- lib/salsify-data_migrate.rb
|
163
|
+
- spec/data_migrate/data_migrator_spec.rb
|
164
|
+
- spec/data_migrate/data_schema_migration_spec.rb
|
165
|
+
- spec/generators/data_migration/data_migration_generator_spec.rb
|
166
|
+
- spec/spec_helper.rb
|
167
|
+
- tasks/.gitkeep
|
168
|
+
- tasks/databases.rake
|
169
|
+
homepage: https://github.com/salsify/data-migrate
|
170
|
+
licenses:
|
171
|
+
- MIT
|
172
|
+
metadata: {}
|
173
|
+
post_install_message: |
|
174
|
+
********************************************************************************
|
175
|
+
data-migrate: --skip-schema-migration option is no longer available as of version 3.0.0
|
176
|
+
********************************************************************************
|
177
|
+
rdoc_options: []
|
178
|
+
require_paths:
|
179
|
+
- lib
|
180
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
181
|
+
requirements:
|
182
|
+
- - ">="
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: '0'
|
185
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
requirements: []
|
191
|
+
rubyforge_project:
|
192
|
+
rubygems_version: 2.6.12
|
193
|
+
signing_key:
|
194
|
+
specification_version: 4
|
195
|
+
summary: Rake tasks to migrate data alongside schema changes.
|
196
|
+
test_files:
|
197
|
+
- spec/data_migrate/data_migrator_spec.rb
|
198
|
+
- spec/data_migrate/data_schema_migration_spec.rb
|
199
|
+
- spec/generators/data_migration/data_migration_generator_spec.rb
|
200
|
+
- spec/spec_helper.rb
|