data_migrate 3.5.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.ruby-style.yml +2 -0
- data/.travis.yml +1 -1
- data/Appraisals +5 -5
- data/Changelog.md +6 -0
- data/Gemfile.rails5.2 +5 -0
- data/README.md +4 -10
- data/data_migrate.gemspec +1 -1
- data/gemfiles/rails_5.2.gemfile +7 -0
- data/lib/data_migrate.rb +19 -4
- data/lib/data_migrate/data_migrator.rb +5 -0
- data/lib/data_migrate/data_migrator_five.rb +84 -0
- data/lib/data_migrate/data_schema.rb +29 -9
- data/lib/data_migrate/data_schema_migration.rb +1 -0
- data/lib/data_migrate/database_tasks.rb +69 -0
- data/lib/data_migrate/migration.rb +1 -1
- data/lib/data_migrate/migration_context.rb +90 -0
- data/lib/data_migrate/schema_dumper.rb +1 -3
- data/lib/data_migrate/schema_migration.rb +31 -0
- data/lib/data_migrate/schema_migration_five.rb +31 -0
- data/lib/data_migrate/status_service.rb +1 -1
- data/lib/data_migrate/status_service_five.rb +48 -0
- data/lib/data_migrate/tasks/data_migrate_tasks.rb +25 -0
- data/lib/data_migrate/version.rb +1 -1
- data/lib/generators/data_migration/data_migration_generator.rb +3 -1
- data/spec/data_migrate/data_migrator_spec.rb +1 -13
- data/spec/data_migrate/{data_schema_spec.rb → data_spec.rb} +7 -5
- data/spec/data_migrate/database_tasks_spec.rb +96 -0
- data/spec/data_migrate/migration_context_spec.rb +107 -0
- data/spec/data_migrate/schema_dumper_spec.rb +5 -3
- data/spec/data_migrate/schema_migration_spec.rb +69 -0
- data/spec/data_migrate/status_service_spec.rb +15 -18
- data/spec/data_migrate/tasks/data_migrate_tasks_spec.rb +50 -0
- data/spec/db/4.2/20091231235959_some_name.rb +9 -0
- data/spec/db/4.2/20171231235959_super_update.rb +9 -0
- data/spec/db/5.0/20091231235959_some_name.rb +9 -0
- data/spec/db/5.0/20171231235959_super_update.rb +9 -0
- data/spec/db/data/20091231235959_some_name.rb +9 -0
- data/spec/db/data/20171231235959_super_update.rb +9 -0
- data/spec/db/migrate/4.2/20131111111111_late_migration.rb +9 -0
- data/spec/db/migrate/4.2/20202020202011_db_migration.rb +9 -0
- data/spec/db/migrate/5.0/20131111111111_late_migration.rb +9 -0
- data/spec/db/migrate/5.0/20202020202011_db_migration.rb +9 -0
- data/spec/db/migrate/5.2/20131111111111_late_migration.rb +9 -0
- data/spec/db/migrate/5.2/20202020202011_db_migration.rb +9 -0
- data/spec/spec_helper.rb +4 -0
- metadata +41 -7
@@ -30,9 +30,7 @@ module DataMigrate
|
|
30
30
|
|
31
31
|
def initialize(connection)
|
32
32
|
@connection = connection
|
33
|
-
all_versions =
|
34
|
-
x.version.to_i
|
35
|
-
end
|
33
|
+
all_versions = DataSchemaMigration.normalized_versions
|
36
34
|
|
37
35
|
@version = begin
|
38
36
|
all_versions.max
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module DataMigrate
|
2
|
+
# Helper class to getting access to db schema
|
3
|
+
# to allow data/schema combiation tasks
|
4
|
+
class SchemaMigration
|
5
|
+
def self.pending_schema_migrations
|
6
|
+
all_migrations = DataMigrate::DataMigrator.migrations(migrations_paths)
|
7
|
+
sort_migrations(
|
8
|
+
ActiveRecord::Migrator.new(:up, all_migrations).
|
9
|
+
pending_migrations.
|
10
|
+
map {|m| { version: m.version, kind: :schema }}
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.run(direction, migration_paths, version)
|
15
|
+
ActiveRecord::Migrator.run(direction, migration_paths, version)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.sort_migrations(set1, set2 = nil)
|
19
|
+
migrations = set1 + (set2 || [])
|
20
|
+
migrations.sort {|a, b| sort_string(a) <=> sort_string(b)}
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.migrations_paths
|
24
|
+
Rails.application.config.paths["db/migrate"].to_a
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.sort_string(migration)
|
28
|
+
"#{migration[:version]}_#{migration[:kind] == :data ? 1 : 0}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module DataMigrate
|
2
|
+
# Helper class to getting access to db schema
|
3
|
+
# to allow data/schema combiation tasks
|
4
|
+
class SchemaMigration
|
5
|
+
def self.pending_schema_migrations
|
6
|
+
all_migrations = ActiveRecord::MigrationContext.new(migrations_paths).migrations
|
7
|
+
sort_migrations(
|
8
|
+
ActiveRecord::Migrator.new(:up, all_migrations).
|
9
|
+
pending_migrations.
|
10
|
+
map {|m| { version: m.version, kind: :schema }}
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.run(direction, migration_paths, version)
|
15
|
+
ActiveRecord::MigrationContext.new(migration_paths).run(direction, version)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.sort_migrations(set1, set2 = nil)
|
19
|
+
migrations = set1 + (set2 || [])
|
20
|
+
migrations.sort {|a, b| sort_string(a) <=> sort_string(b)}
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.migrations_paths
|
24
|
+
Rails.application.config.paths["db/migrate"].to_a
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.sort_string(migration)
|
28
|
+
"#{migration[:version]}_#{migration[:kind] == :data ? 1 : 0}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module DataMigrate
|
2
|
+
class StatusService
|
3
|
+
class << self
|
4
|
+
def dump(connection = ActiveRecord::Base.connection, stream = STDOUT)
|
5
|
+
new(connection).dump(stream)
|
6
|
+
stream
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(connection)
|
11
|
+
@connection = connection
|
12
|
+
end
|
13
|
+
|
14
|
+
def root_folder
|
15
|
+
Rails.root
|
16
|
+
end
|
17
|
+
|
18
|
+
def dump(stream)
|
19
|
+
output(stream)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def table_name
|
25
|
+
DataMigrate::DataSchemaMigration.table_name
|
26
|
+
end
|
27
|
+
|
28
|
+
def output(stream)
|
29
|
+
unless DataMigrate::DataSchemaMigration.table_exists?
|
30
|
+
stream.puts "Data migrations table does not exist yet."
|
31
|
+
return
|
32
|
+
end
|
33
|
+
|
34
|
+
# output
|
35
|
+
stream.puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
|
36
|
+
stream.puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
37
|
+
stream.puts "-" * 50
|
38
|
+
db_list.each do |status, version, name|
|
39
|
+
stream.puts "#{status.center(8)} #{version.ljust(14)} #{name}"
|
40
|
+
end
|
41
|
+
stream.puts
|
42
|
+
end
|
43
|
+
|
44
|
+
def db_list
|
45
|
+
DataMigrate::DataMigrator.migrations_status
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module DataMigrate
|
2
|
+
module Tasks
|
3
|
+
module DataMigrateTasks
|
4
|
+
extend self
|
5
|
+
def migrations_paths
|
6
|
+
@migrations_paths ||= begin
|
7
|
+
if Rails.application && Rails.application.paths["data/migrate"]
|
8
|
+
Rails.application.paths["data/migrate"].to_a
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def migrate
|
14
|
+
DataMigrate::DataMigrator.assure_data_schema_table
|
15
|
+
target_version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
16
|
+
if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR == 2
|
17
|
+
DataMigrate::MigrationContext.new(migrations_paths).migrate(target_version)
|
18
|
+
else
|
19
|
+
paths = migrations_paths || "db/data/"
|
20
|
+
DataMigrate::DataMigrator.migrate(paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/data_migrate/version.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "generators/data_migrate"
|
2
2
|
require "rails/generators"
|
3
3
|
require "rails/generators/active_record/migration"
|
4
|
+
require "rails/generators/migration"
|
4
5
|
|
5
6
|
module DataMigrate
|
6
7
|
module Generators
|
@@ -8,7 +9,6 @@ module DataMigrate
|
|
8
9
|
namespace "data_migration"
|
9
10
|
include ActiveRecord::Generators::Migration
|
10
11
|
|
11
|
-
|
12
12
|
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
13
13
|
|
14
14
|
def create_data_migration
|
@@ -28,6 +28,8 @@ module DataMigrate
|
|
28
28
|
def migration_base_class_name
|
29
29
|
if ActiveRecord.version >= Gem::Version.new("5.0")
|
30
30
|
"ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]"
|
31
|
+
elsif ActiveRecord.version >= Gem::Version.new("5.2")
|
32
|
+
"DataMigrate::MigrationContext"
|
31
33
|
else
|
32
34
|
"ActiveRecord::Migration"
|
33
35
|
end
|
@@ -11,7 +11,7 @@ describe DataMigrate::DataMigrator do
|
|
11
11
|
|
12
12
|
describe :assure_data_schema_table do
|
13
13
|
before do
|
14
|
-
|
14
|
+
allow(subject).to receive(:db_config) { db_config }.at_least(:once)
|
15
15
|
ActiveRecord::Base.establish_connection(db_config)
|
16
16
|
end
|
17
17
|
|
@@ -30,18 +30,6 @@ describe DataMigrate::DataMigrator do
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
describe :schema_migrations_table_name do
|
34
|
-
it "returns correct table name" do
|
35
|
-
expect(subject.schema_migrations_table_name).to eq("data_migrations")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
describe :migrations_path do
|
40
|
-
it "returns correct migrations path" do
|
41
|
-
expect(subject.migrations_path).to eq("db/data")
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
33
|
describe :match do
|
46
34
|
context "when the file does not match" do
|
47
35
|
it "returns nil" do
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "spec_helper"
|
4
|
+
|
3
5
|
describe DataMigrate::Data do
|
4
6
|
let(:subject) { DataMigrate::Data }
|
5
7
|
let(:db_config) do
|
@@ -27,10 +29,10 @@ describe DataMigrate::Data do
|
|
27
29
|
|
28
30
|
describe :define do
|
29
31
|
before do
|
30
|
-
|
31
|
-
to receive(:db_config) { db_config }
|
32
|
+
allow(DataMigrate::DataMigrator).
|
33
|
+
to receive(:db_config) { db_config }
|
32
34
|
ActiveRecord::Base.establish_connection(db_config)
|
33
|
-
ActiveRecord::
|
35
|
+
ActiveRecord::SchemaMigration.create_table
|
34
36
|
end
|
35
37
|
|
36
38
|
after do
|
@@ -66,11 +68,11 @@ describe DataMigrate::Data do
|
|
66
68
|
|
67
69
|
sql_select = <<-SQL
|
68
70
|
SELECT version
|
69
|
-
FROM #{DataMigrate::
|
71
|
+
FROM #{DataMigrate::DataSchemaMigration.table_name}
|
70
72
|
SQL
|
71
73
|
|
72
74
|
db_list_data = ActiveRecord::Base.connection.
|
73
|
-
|
75
|
+
select_values(sql_select).map(&:to_i)
|
74
76
|
expect(db_list_data).to match_array(
|
75
77
|
[fixture_file_timestamps[0], fixture_file_timestamps[1]].map(&:to_i)
|
76
78
|
)
|
@@ -1,7 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "spec_helper"
|
4
|
+
|
3
5
|
describe DataMigrate::DatabaseTasks do
|
4
6
|
let(:subject) { DataMigrate::DatabaseTasks }
|
7
|
+
let(:migration_path) {
|
8
|
+
if Rails::VERSION::MAJOR == 5
|
9
|
+
if Rails::VERSION::MINOR == 2
|
10
|
+
"spec/db/migrate/5.2"
|
11
|
+
else
|
12
|
+
"spec/db/migrate/5.0"
|
13
|
+
end
|
14
|
+
else
|
15
|
+
"spec/db/migrate/4.2"
|
16
|
+
end
|
17
|
+
}
|
18
|
+
let(:data_migrations_path) {
|
19
|
+
if Rails::VERSION::MAJOR == 5
|
20
|
+
if Rails::VERSION::MINOR == 2
|
21
|
+
"spec/db/data"
|
22
|
+
else
|
23
|
+
"spec/db/5.0"
|
24
|
+
end
|
25
|
+
else
|
26
|
+
"spec/db/4.2"
|
27
|
+
end
|
28
|
+
}
|
29
|
+
let(:db_config) do
|
30
|
+
{
|
31
|
+
adapter: "sqlite3",
|
32
|
+
database: "spec/db/test.db"
|
33
|
+
}
|
34
|
+
end
|
5
35
|
|
6
36
|
before do
|
7
37
|
# In a normal Rails installation, db_dir would defer to
|
@@ -10,9 +40,75 @@ describe DataMigrate::DatabaseTasks do
|
|
10
40
|
allow(subject).to receive(:db_dir).and_return("db")
|
11
41
|
end
|
12
42
|
|
43
|
+
before do
|
44
|
+
allow(DataMigrate::Tasks::DataMigrateTasks).to receive(:migrations_paths) {
|
45
|
+
data_migrations_path
|
46
|
+
}
|
47
|
+
allow(DataMigrate::DataMigrator).to receive(:db_config) { db_config }
|
48
|
+
ActiveRecord::Base.establish_connection(db_config)
|
49
|
+
end
|
50
|
+
|
13
51
|
describe :data_schema_file do
|
14
52
|
it "returns the correct data schema file path" do
|
15
53
|
expect(subject.data_schema_file).to eq "db/data_schema.rb"
|
16
54
|
end
|
17
55
|
end
|
56
|
+
|
57
|
+
context "migrations" do
|
58
|
+
after do
|
59
|
+
begin
|
60
|
+
ActiveRecord::Migration.drop_table("data_migrations")
|
61
|
+
rescue ActiveRecord::StatementInvalid
|
62
|
+
end
|
63
|
+
ActiveRecord::Migration.drop_table("schema_migrations")
|
64
|
+
end
|
65
|
+
|
66
|
+
before do
|
67
|
+
ActiveRecord::Base.establish_connection(db_config)
|
68
|
+
ActiveRecord::SchemaMigration.create_table
|
69
|
+
|
70
|
+
allow(DataMigrate::SchemaMigration).to receive(:migrations_paths) {
|
71
|
+
migration_path
|
72
|
+
}
|
73
|
+
allow(DataMigrate::DatabaseTasks).to receive(:data_migrations_path) {
|
74
|
+
data_migrations_path
|
75
|
+
}.at_least(:once)
|
76
|
+
allow(DataMigrate::DatabaseTasks).to receive(:schema_migrations_path) {
|
77
|
+
migration_path
|
78
|
+
}.at_least(:once)
|
79
|
+
end
|
80
|
+
|
81
|
+
describe :past_migrations do
|
82
|
+
it do
|
83
|
+
subject.forward
|
84
|
+
m = subject.past_migrations
|
85
|
+
expect(m.count).to eq 1
|
86
|
+
expect(m.first[:version]).to eq 20091231235959
|
87
|
+
end
|
88
|
+
|
89
|
+
it "shows nothing without any migrations" do
|
90
|
+
m = subject.past_migrations
|
91
|
+
expect(m.count).to eq 0
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe :forward do
|
96
|
+
|
97
|
+
it "run forward default amount of times" do
|
98
|
+
subject.forward
|
99
|
+
versions = DataMigrate::DataSchemaMigration.normalized_versions
|
100
|
+
expect(versions.count).to eq(1)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "run forward defined number of times" do
|
104
|
+
subject.forward(2)
|
105
|
+
versions = DataMigrate::DataSchemaMigration.normalized_versions
|
106
|
+
expect(versions.count).to eq(1)
|
107
|
+
expect(versions.first).to eq "20091231235959"
|
108
|
+
versions = ActiveRecord::SchemaMigration.normalized_versions
|
109
|
+
expect(versions.count).to eq(1)
|
110
|
+
expect(versions.first).to eq "20131111111111"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
18
114
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe DataMigrate::DataMigrator do
|
4
|
+
let(:context) {
|
5
|
+
DataMigrate::MigrationContext.new("spec/db/data")
|
6
|
+
}
|
7
|
+
|
8
|
+
before do
|
9
|
+
unless Rails::VERSION::MAJOR == 5 and
|
10
|
+
Rails::VERSION::MINOR == 2
|
11
|
+
skip("Tests are only applicable for Rails 5.2")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
begin
|
17
|
+
ActiveRecord::Migration.drop_table("data_migrations")
|
18
|
+
rescue StandardError
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:db_config) do
|
24
|
+
{
|
25
|
+
adapter: "sqlite3",
|
26
|
+
database: "spec/db/test.db"
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
describe :migrate do
|
31
|
+
before do
|
32
|
+
ActiveRecord::Base.establish_connection(db_config)
|
33
|
+
ActiveRecord::SchemaMigration.create_table
|
34
|
+
end
|
35
|
+
|
36
|
+
it "migrates existing file" do
|
37
|
+
context.migrate(nil)
|
38
|
+
context.migrations_status
|
39
|
+
versions = DataMigrate::DataSchemaMigration.normalized_versions
|
40
|
+
expect(versions.count).to eq(2)
|
41
|
+
expect(versions).to include("20091231235959")
|
42
|
+
expect(versions).to include("20171231235959")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "undo migration" do
|
46
|
+
context.migrate(nil)
|
47
|
+
context.run(:down, 20171231235959)
|
48
|
+
versions = DataMigrate::DataSchemaMigration.normalized_versions
|
49
|
+
expect(versions.count).to eq(1)
|
50
|
+
expect(versions).to include("20091231235959")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "does not do anything if migration is undone twice" do
|
54
|
+
context.migrate(nil)
|
55
|
+
expect {
|
56
|
+
context.run(:down, 20171231235959)
|
57
|
+
}.to output(/Undoing SuperUpdate/).to_stdout
|
58
|
+
expect {
|
59
|
+
context.run(:down, 20171231235959)
|
60
|
+
}.not_to output(/Undoing SuperUpdate/).to_stdout
|
61
|
+
end
|
62
|
+
|
63
|
+
it "runs a specific migration" do
|
64
|
+
context.run(:up, 20171231235959)
|
65
|
+
versions = DataMigrate::DataSchemaMigration.normalized_versions
|
66
|
+
expect(versions.count).to eq(1)
|
67
|
+
expect(versions).to include("20171231235959")
|
68
|
+
end
|
69
|
+
|
70
|
+
it "does not do anything if migration is ran twice" do
|
71
|
+
expect {
|
72
|
+
context.run(:up, 20171231235959)
|
73
|
+
}.to output(/Doing SuperUpdate/).to_stdout
|
74
|
+
expect {
|
75
|
+
context.run(:down, 20171231235959)
|
76
|
+
}.not_to output(/Doing SuperUpdate/).to_stdout
|
77
|
+
end
|
78
|
+
|
79
|
+
it "alerts for an invalid specific migration" do
|
80
|
+
expect {
|
81
|
+
context.run(:up, 201712312)
|
82
|
+
}.to raise_error(
|
83
|
+
ActiveRecord::UnknownMigrationVersionError,
|
84
|
+
/No migration with version number 201712312/
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "rolls back latest migration" do
|
89
|
+
context.migrate(nil)
|
90
|
+
expect {
|
91
|
+
context.rollback
|
92
|
+
}.to output(/Undoing SuperUpdate/).to_stdout
|
93
|
+
versions = DataMigrate::DataSchemaMigration.normalized_versions
|
94
|
+
expect(versions.count).to eq(1)
|
95
|
+
expect(versions).to include("20091231235959")
|
96
|
+
end
|
97
|
+
|
98
|
+
it "rolls back 2 migrations" do
|
99
|
+
context.migrate(nil)
|
100
|
+
expect {
|
101
|
+
context.rollback(2)
|
102
|
+
}.to output(/Undoing SomeName/).to_stdout
|
103
|
+
versions = DataMigrate::DataSchemaMigration.normalized_versions
|
104
|
+
expect(versions.count).to eq(0)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|