mince_migrator 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +20 -58
- data/bin/mince_migrator +125 -0
- data/lib/mince_migrator/cli_helper.rb +72 -0
- data/lib/mince_migrator/config.rb +30 -0
- data/lib/mince_migrator/creator.rb +48 -0
- data/lib/mince_migrator/deleter.rb +42 -0
- data/lib/mince_migrator/list.rb +46 -0
- data/lib/mince_migrator/list_report.rb +67 -0
- data/lib/mince_migrator/migration.rb +66 -0
- data/lib/mince_migrator/migrations/file.rb +74 -0
- data/lib/mince_migrator/migrations/loader.rb +52 -0
- data/lib/mince_migrator/migrations/name.rb +48 -0
- data/lib/mince_migrator/migrations/runner.rb +39 -0
- data/lib/mince_migrator/migrations/runner_validator.rb +47 -0
- data/lib/mince_migrator/migrations/template.mustache +24 -0
- data/lib/mince_migrator/migrations/template.rb +16 -0
- data/lib/mince_migrator/migrations/versioned_file.rb +38 -0
- data/lib/mince_migrator/ran_migration.rb +27 -0
- data/lib/mince_migrator/reverter.rb +57 -0
- data/lib/mince_migrator/status_report.rb +41 -0
- data/lib/mince_migrator/version.rb +18 -1
- data/lib/mince_migrator.rb +5 -4
- data/spec/integration/create_a_migration_spec.rb +57 -0
- data/spec/integration/deleting_a_migration_spec.rb +40 -0
- data/spec/integration/list_all_migrations_spec.rb +57 -0
- data/spec/integration/reverting_a_migration_spec.rb +59 -0
- data/spec/integration/running_a_migration_spec.rb +66 -0
- data/spec/integration_helper.rb +17 -0
- data/spec/support/db/a_second_migration.rb +24 -0
- data/spec/support/db/a_second_migration_2.rb +24 -0
- data/spec/support/db/create_seeded_admin_users.rb +24 -0
- data/spec/support/db/first_migration.rb +24 -0
- data/spec/support/db/first_migration_2.rb +24 -0
- data/spec/support/db/first_migration_3.rb +24 -0
- data/spec/support/db/first_migration_4.rb +24 -0
- data/spec/support/db/name_of_migration.rb +24 -0
- data/spec/support/invalid_interface_migration.rb +7 -0
- data/spec/support/not_a_migration.rb +2 -0
- data/spec/support/test_migration.rb +30 -0
- data/spec/units/mince_migrator/cli_helper_spec.rb +147 -0
- data/spec/units/mince_migrator/creator_spec.rb +80 -0
- data/spec/units/mince_migrator/deleter_spec.rb +52 -0
- data/spec/units/mince_migrator/list_spec.rb +53 -0
- data/spec/units/mince_migrator/migration_spec.rb +119 -0
- data/spec/units/mince_migrator/migrations/file_spec.rb +85 -0
- data/spec/units/mince_migrator/migrations/loader_spec.rb +47 -0
- data/spec/units/mince_migrator/migrations/name_spec.rb +47 -0
- data/spec/units/mince_migrator/migrations/runner_spec.rb +70 -0
- data/spec/units/mince_migrator/migrations/runner_validator_spec.rb +46 -0
- data/spec/units/mince_migrator/migrations/template_spec.rb +42 -0
- data/spec/units/mince_migrator/migrations/versioned_file_spec.rb +48 -0
- data/spec/units/mince_migrator/ran_migration_spec.rb +60 -0
- data/spec/units/mince_migrator/reverter_spec.rb +78 -0
- metadata +298 -26
- data/.gitignore +0 -17
- data/Gemfile +0 -4
- data/Rakefile +0 -12
- data/mince_migrator.gemspec +0 -19
@@ -0,0 +1,52 @@
|
|
1
|
+
module MinceMigrator
|
2
|
+
module Migrations
|
3
|
+
class Loader
|
4
|
+
def initialize(options)
|
5
|
+
@klass_name = options[:klass_name]
|
6
|
+
@full_path = options[:full_path]
|
7
|
+
end
|
8
|
+
|
9
|
+
def klass
|
10
|
+
eval "::MinceMigrator::Migrations::#{@klass_name}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
if valid?
|
15
|
+
require @full_path
|
16
|
+
perform_post_load_validations
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def valid?
|
21
|
+
file_exists?
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def perform_post_load_validations
|
27
|
+
mince_migration? && has_valid_interface?
|
28
|
+
end
|
29
|
+
|
30
|
+
def mince_migration?
|
31
|
+
klass # Check that constant is valid and loaded
|
32
|
+
rescue NameError
|
33
|
+
raise 'invalid migration'
|
34
|
+
end
|
35
|
+
|
36
|
+
def has_valid_interface?
|
37
|
+
if !has_all_interfaces?
|
38
|
+
raise "migration does not have all required methods (:run, :revert, and :time_created)"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def has_all_interfaces?
|
43
|
+
%w(run revert time_created).all?{|a| klass.respond_to?(a) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def file_exists?
|
47
|
+
raise 'migration does not exist' unless ::File.exists?(@full_path)
|
48
|
+
true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module MinceMigrator
|
2
|
+
module Migrations
|
3
|
+
class Name
|
4
|
+
attr_reader :value
|
5
|
+
|
6
|
+
def initialize(value)
|
7
|
+
self.value = value if value
|
8
|
+
@errors = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def filename
|
12
|
+
@filename ||= "#{value.downcase.gsub(" ", "_")}.rb"
|
13
|
+
end
|
14
|
+
|
15
|
+
def value=(val)
|
16
|
+
normalized_string = normalized_string(val)
|
17
|
+
@value = capitalized_phrase(normalized_string)
|
18
|
+
end
|
19
|
+
|
20
|
+
def capitalized_phrase(val)
|
21
|
+
val.split(' ').each_with_index.map do |word, i|
|
22
|
+
i == 0 ? word.capitalize : word.downcase
|
23
|
+
end.join(" ")
|
24
|
+
end
|
25
|
+
|
26
|
+
def normalized_string(val)
|
27
|
+
val = val.gsub(/[-_]/, ' ') # convert dashes and underscores to spaces
|
28
|
+
pattern = /(^[0-9]|[^a-zA-Z0-9\s])/ # only allow letters and numbers, but do not allow numbers at the beginning
|
29
|
+
val.gsub(pattern, '')
|
30
|
+
end
|
31
|
+
|
32
|
+
def valid?
|
33
|
+
@errors = []
|
34
|
+
validate_value
|
35
|
+
@errors.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def reasons_for_failure
|
39
|
+
@errors.join(" ")
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate_value
|
43
|
+
@errors << "Name is invalid, it must start with a character from A-Z or a-z" if value.nil? || value == ''
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module MinceMigrator
|
2
|
+
module Migrations
|
3
|
+
require_relative '../migration'
|
4
|
+
require_relative 'runner_validator'
|
5
|
+
require 'mince/config'
|
6
|
+
|
7
|
+
class Runner
|
8
|
+
attr_reader :name, :validator
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
if options[:migration]
|
12
|
+
@migration = options[:migration]
|
13
|
+
@name = migration.name
|
14
|
+
elsif options[:name]
|
15
|
+
@name = options[:name]
|
16
|
+
end
|
17
|
+
@validator = RunnerValidator.new(migration)
|
18
|
+
end
|
19
|
+
|
20
|
+
def can_run_migration?
|
21
|
+
validator.call
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_migration
|
25
|
+
migration.run
|
26
|
+
RanMigration.create(name: migration.name)
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
def reasons_for_failure
|
31
|
+
validator.errors.join(" ")
|
32
|
+
end
|
33
|
+
|
34
|
+
def migration
|
35
|
+
@migration ||= Migration.find(name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module MinceMigrator
|
2
|
+
module Migrations
|
3
|
+
require_relative '../migration'
|
4
|
+
require_relative 'runner_validator'
|
5
|
+
require 'mince/config'
|
6
|
+
|
7
|
+
class RunnerValidator
|
8
|
+
attr_reader :migration, :errors
|
9
|
+
|
10
|
+
def initialize(migration)
|
11
|
+
@migration = migration
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
@errors = []
|
16
|
+
run_validations
|
17
|
+
errors.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
def run_validations
|
21
|
+
validate_mince_interface
|
22
|
+
validate_migration_exists
|
23
|
+
validate_migration_not_ran
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate_migration_not_ran
|
27
|
+
@errors << "Migration has already ran" if interface_is_set? && migration_exists? && migration.ran?
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate_migration_exists
|
31
|
+
@errors << "Migration does not exist" if interface_is_set? && !migration_exists?
|
32
|
+
end
|
33
|
+
|
34
|
+
def migration_exists?
|
35
|
+
!!migration
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate_mince_interface
|
39
|
+
@errors << "Mince interface is not set" unless interface_is_set?
|
40
|
+
end
|
41
|
+
|
42
|
+
def interface_is_set?
|
43
|
+
!!Mince::Config.interface
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module MinceMigrator
|
2
|
+
module Migrations
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
module {{klass_name}}
|
6
|
+
def self.run
|
7
|
+
# Actual migration goes here
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.revert
|
11
|
+
# In case you need to revert this one migration
|
12
|
+
end
|
13
|
+
|
14
|
+
# So you can change the order to run more easily
|
15
|
+
def self.time_created
|
16
|
+
Time.parse "{{time_created}}"
|
17
|
+
end
|
18
|
+
|
19
|
+
module Temporary
|
20
|
+
# Migration dependent classes go here
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module MinceMigrator
|
2
|
+
module Migrations
|
3
|
+
require 'mustache'
|
4
|
+
|
5
|
+
class Template < Mustache
|
6
|
+
self.template_file = File.expand_path('../template.mustache', __FILE__)
|
7
|
+
|
8
|
+
attr_reader :klass_name, :time_created
|
9
|
+
|
10
|
+
def initialize(klass_name)
|
11
|
+
@klass_name = klass_name
|
12
|
+
@time_created = Time.now.utc.to_s
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module MinceMigrator
|
2
|
+
module Migrations
|
3
|
+
require_relative 'file'
|
4
|
+
|
5
|
+
class VersionedFile
|
6
|
+
attr_reader :version
|
7
|
+
|
8
|
+
def initialize(name, version = 1)
|
9
|
+
@version = version
|
10
|
+
@name = name
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
version > 1 ? "#{@name}_#{version}" : @name
|
15
|
+
end
|
16
|
+
|
17
|
+
def file
|
18
|
+
@file ||= File.new(name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def next_unused_version
|
22
|
+
if file.persisted?
|
23
|
+
bump
|
24
|
+
next_unused_version
|
25
|
+
else
|
26
|
+
file
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def bump
|
33
|
+
@version += 1
|
34
|
+
@file = File.new(name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module MinceMigrator
|
2
|
+
require 'mince/model'
|
3
|
+
require 'mince/data_model'
|
4
|
+
|
5
|
+
class RanMigrationDataModel
|
6
|
+
include Mince::DataModel
|
7
|
+
|
8
|
+
data_collection :migrations
|
9
|
+
data_fields :name
|
10
|
+
end
|
11
|
+
|
12
|
+
class RanMigration
|
13
|
+
include Mince::Model
|
14
|
+
|
15
|
+
data_model RanMigrationDataModel
|
16
|
+
field :name
|
17
|
+
|
18
|
+
def self.find_by_name(name)
|
19
|
+
data = data_model.find_by_field(:name, name)
|
20
|
+
new data if data
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete
|
24
|
+
data_model.delete_by_params(name: name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module MinceMigrator
|
2
|
+
require_relative 'migrations/name'
|
3
|
+
require_relative 'migration'
|
4
|
+
require_relative 'config'
|
5
|
+
|
6
|
+
class Reverter
|
7
|
+
attr_reader :name, :migration_name
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
if options[:migration]
|
11
|
+
@migration = options[:migration]
|
12
|
+
@migration_name = Migrations::Name.new migration.name
|
13
|
+
elsif options[:name]
|
14
|
+
@migration_name = Migrations::Name.new options[:name]
|
15
|
+
end
|
16
|
+
@name = migration_name.value
|
17
|
+
@errors = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def can_revert_migration?
|
21
|
+
@errors = []
|
22
|
+
validate_migration
|
23
|
+
validate_ran_migration
|
24
|
+
@errors.empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate_ran_migration
|
28
|
+
@errors << "Migration has not ran" if migration_not_ran?
|
29
|
+
end
|
30
|
+
|
31
|
+
def validate_migration
|
32
|
+
@errors << "Migration does not exist with name '#{name}'" if migration.nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
def revert_migration
|
36
|
+
migration.revert
|
37
|
+
ran_migration.delete
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
def reasons_for_failure
|
42
|
+
@errors.join ", "
|
43
|
+
end
|
44
|
+
|
45
|
+
def migration
|
46
|
+
@migration ||= Migration.find(name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def migration_not_ran?
|
50
|
+
migration && !migration.ran?
|
51
|
+
end
|
52
|
+
|
53
|
+
def ran_migration
|
54
|
+
migration.ran_migration if migration
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module MinceMigrator
|
2
|
+
require 'command_line_reporter'
|
3
|
+
|
4
|
+
class StatusReport
|
5
|
+
include CommandLineReporter
|
6
|
+
|
7
|
+
attr_reader :migration
|
8
|
+
|
9
|
+
def initialize(migration)
|
10
|
+
@migration = migration
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
vertical_spacing 2
|
15
|
+
header title: "Migration Details for #{migration.name}", bold: true, rule: true, align: 'center', width: 70, timestamp: true
|
16
|
+
|
17
|
+
table border: false do
|
18
|
+
row do
|
19
|
+
column 'Name', width: 15
|
20
|
+
column migration.name, width: 30
|
21
|
+
end
|
22
|
+
row do
|
23
|
+
column 'Status'
|
24
|
+
if migration.status == 'not ran'
|
25
|
+
column migration.status, color: 'red'
|
26
|
+
else
|
27
|
+
column migration.status, color: 'green'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
row do
|
31
|
+
column 'Age'
|
32
|
+
column migration.age
|
33
|
+
end
|
34
|
+
row do
|
35
|
+
column 'Date Created'
|
36
|
+
column migration.time_created.strftime("%m/%d/%Y")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,3 +1,20 @@
|
|
1
1
|
module MinceMigrator
|
2
|
-
|
2
|
+
module Version
|
3
|
+
def self.major
|
4
|
+
1
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.minor
|
8
|
+
0
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.patch
|
12
|
+
0
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.version
|
17
|
+
[Version.major, Version.minor, Version.patch].join('.')
|
18
|
+
end
|
3
19
|
end
|
20
|
+
|
data/lib/mince_migrator.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "mince_migrator/version"
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
require "mince_migrator/reverter"
|
3
|
+
require "mince_migrator/creator"
|
4
|
+
require "mince_migrator/deleter"
|
5
|
+
require "mince_migrator/list"
|
6
|
+
require "mince_migrator/migrations/runner"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative '../integration_helper'
|
2
|
+
|
3
|
+
describe "The creation of a migration:" do
|
4
|
+
subject { MinceMigrator::Creator.new name }
|
5
|
+
|
6
|
+
context "when a name is not provided" do
|
7
|
+
let(:name) { nil }
|
8
|
+
|
9
|
+
it "returns reasons why a migration could not be created" do
|
10
|
+
subject.can_create_migration?.should be_false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "Creating a mince migration with a name" do
|
15
|
+
let(:name) { "Create seeded admin users" }
|
16
|
+
|
17
|
+
it "can create the migration" do
|
18
|
+
subject.can_create_migration?.should be_true
|
19
|
+
end
|
20
|
+
|
21
|
+
it "creates the migration file" do
|
22
|
+
subject.create_migration
|
23
|
+
|
24
|
+
relative_path = Dir.pwd
|
25
|
+
expected_migration_file_destination = ::File.join(MinceMigrator::Config.migration_dir, "create_seeded_admin_users.rb")
|
26
|
+
::File.open(expected_migration_file_destination, 'r') do |f|
|
27
|
+
expected_content = <<-eos
|
28
|
+
module MinceMigrator
|
29
|
+
module Migrations
|
30
|
+
require 'time'
|
31
|
+
|
32
|
+
module CreateSeededAdminUsers
|
33
|
+
def self.run
|
34
|
+
# Actual migration goes here
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.revert
|
38
|
+
# In case you need to revert this one migration
|
39
|
+
end
|
40
|
+
|
41
|
+
# So you can change the order to run more easily
|
42
|
+
def self.time_created
|
43
|
+
Time.parse "#{Time.now.utc.to_s}"
|
44
|
+
end
|
45
|
+
|
46
|
+
module Temporary
|
47
|
+
# Migration dependent classes go here
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
eos
|
53
|
+
f.read.should == expected_content
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative '../integration_helper'
|
2
|
+
|
3
|
+
describe 'Deleting a migration' do
|
4
|
+
subject { MinceMigrator::Deleter.new(name: name) }
|
5
|
+
|
6
|
+
let(:name) { 'name of migration' }
|
7
|
+
let(:expected_name) { 'Name of migration' }
|
8
|
+
|
9
|
+
context 'when the migration exists' do
|
10
|
+
before do
|
11
|
+
MinceMigrator::Creator.create(name)
|
12
|
+
end
|
13
|
+
|
14
|
+
its(:can_delete_migration?) { should be_true }
|
15
|
+
|
16
|
+
it 'deletes it from the file system' do
|
17
|
+
expected_migration_destination = ::File.join(MinceMigrator::Config.migration_dir, 'name_of_migration.rb')
|
18
|
+
subject.delete_migration
|
19
|
+
|
20
|
+
::File.exists?(expected_migration_destination).should be_false
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when the migration has ran' do
|
24
|
+
before do
|
25
|
+
MinceMigrator::Migrations::Runner.new(name: name).run_migration
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'deletes it from the database' do
|
29
|
+
subject.delete_migration
|
30
|
+
|
31
|
+
MinceMigrator::RanMigration.all.should be_empty
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when the migration does not exist' do
|
37
|
+
its(:can_delete_migration?) { should be_false }
|
38
|
+
its(:reasons_for_failure) { should == "Migration does not exist with name '#{expected_name}'" }
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative '../integration_helper'
|
2
|
+
|
3
|
+
describe 'List of migrations' do
|
4
|
+
subject { MinceMigrator::List.new }
|
5
|
+
|
6
|
+
context 'when there are not any migrations' do
|
7
|
+
its(:number_of_migrations) { should == 0 }
|
8
|
+
|
9
|
+
it 'is empty' do
|
10
|
+
subject.all.should be_empty
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when there is one migration' do
|
15
|
+
let(:migration_name) { "first migration" }
|
16
|
+
|
17
|
+
before do
|
18
|
+
MinceMigrator::Creator.create(migration_name)
|
19
|
+
end
|
20
|
+
|
21
|
+
its(:number_of_migrations) { should == 1 }
|
22
|
+
|
23
|
+
it 'contains a record of the migration' do
|
24
|
+
subject.all.size.should == 1
|
25
|
+
subject.all.first.name.should == "First migration"
|
26
|
+
subject.all.first.status.should == 'not ran'
|
27
|
+
subject.all.first.relative_path.should == File.join(MinceMigrator::Config.migration_relative_dir, 'first_migration.rb')
|
28
|
+
subject.all.first.path.should == File.join(MinceMigrator::Config.migration_dir, 'first_migration.rb')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when there are some migrations' do
|
33
|
+
let(:migration_1_name) { "first migration" }
|
34
|
+
let(:migration_2_name) { "a second migration" }
|
35
|
+
let(:migration_1) { MinceMigrator::Migration.find(migration_1_name) }
|
36
|
+
let(:migration_2) { MinceMigrator::Migration.find(migration_2_name) }
|
37
|
+
|
38
|
+
before do
|
39
|
+
MinceMigrator::Creator.create(migration_1_name)
|
40
|
+
MinceMigrator::Creator.create(migration_2_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
its(:number_of_migrations) { should == 2 }
|
44
|
+
|
45
|
+
it 'contains a record of those migrations' do
|
46
|
+
expected_migrations = [migration_2, migration_1]
|
47
|
+
subject.all.size.should == expected_migrations.size
|
48
|
+
subject.all.each_with_index do |migration, index|
|
49
|
+
expected_migration = expected_migrations.find{|a| a.name == migration.name }
|
50
|
+
migration.name.should == expected_migration.name
|
51
|
+
migration.status.should == 'not ran'
|
52
|
+
migration.relative_path.should == migration.relative_path
|
53
|
+
migration.path.should == migration.path
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative '../integration_helper'
|
2
|
+
|
3
|
+
describe 'Reverting a migration' do
|
4
|
+
subject { MinceMigrator::Reverter.new(name: name) }
|
5
|
+
|
6
|
+
let(:name) { 'name of migration' }
|
7
|
+
let(:expected_name) { 'Name of migration' }
|
8
|
+
|
9
|
+
context 'when the migration exists' do
|
10
|
+
let(:name) { "test migration" }
|
11
|
+
let(:spec_migration) { File.expand_path('../../support/test_migration.rb', __FILE__) }
|
12
|
+
let(:db_dir) { MinceMigrator::Config.migration_dir }
|
13
|
+
let(:data_model) { MinceMigrator::Migrations::TestMigration::Temporary::UserDataModel }
|
14
|
+
|
15
|
+
before do
|
16
|
+
FileUtils.mkdir_p(db_dir)
|
17
|
+
FileUtils.cp(spec_migration, db_dir)
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'and the migration has not yet been ran' do
|
21
|
+
before do
|
22
|
+
subject.can_revert_migration?
|
23
|
+
end
|
24
|
+
|
25
|
+
its(:reasons_for_failure) { should == "Migration has not ran" }
|
26
|
+
its(:can_revert_migration?) { should be_false }
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when the migration has ran' do
|
30
|
+
before do
|
31
|
+
MinceMigrator::Migrations::Runner.new(name: name).run_migration
|
32
|
+
end
|
33
|
+
|
34
|
+
its(:can_revert_migration?) { should be_true }
|
35
|
+
its(:reasons_for_failure) { should be_empty }
|
36
|
+
|
37
|
+
it 'reverts the migration' do
|
38
|
+
subject.revert_migration
|
39
|
+
|
40
|
+
data_model.all.size.should == 0
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'reverts it from the database' do
|
44
|
+
subject.revert_migration
|
45
|
+
|
46
|
+
MinceMigrator::RanMigration.all.should be_empty
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when the migration does not exist' do
|
52
|
+
before do
|
53
|
+
subject.can_revert_migration?
|
54
|
+
end
|
55
|
+
|
56
|
+
its(:can_revert_migration?) { should be_false }
|
57
|
+
its(:reasons_for_failure) { should == "Migration does not exist with name '#{expected_name}'" }
|
58
|
+
end
|
59
|
+
end
|