mince_migrator 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|