prick 0.3.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/TODO +7 -0
- data/exe/prick +235 -163
- data/lib/ext/fileutils.rb +7 -0
- data/lib/prick.rb +7 -5
- data/lib/prick/builder.rb +31 -8
- data/lib/prick/cache.rb +34 -0
- data/lib/prick/constants.rb +106 -54
- data/lib/prick/database.rb +26 -20
- data/lib/prick/diff.rb +103 -25
- data/lib/prick/git.rb +31 -9
- data/lib/prick/head.rb +183 -0
- data/lib/prick/migration.rb +41 -181
- data/lib/prick/program.rb +255 -0
- data/lib/prick/project.rb +264 -0
- data/lib/prick/rdbms.rb +3 -12
- data/lib/prick/schema.rb +6 -11
- data/lib/prick/state.rb +129 -74
- data/lib/prick/version.rb +41 -28
- data/prick.gemspec +3 -1
- data/share/diff/diff.after-tables.sql +4 -0
- data/share/diff/diff.before-tables.sql +4 -0
- data/share/diff/diff.tables.sql +8 -0
- data/share/migration/diff.tables.sql +8 -0
- data/share/{release_migration → migration}/features.yml +0 -0
- data/share/migration/migrate.sql +3 -0
- data/share/{release_migration → migration}/migrate.yml +3 -0
- data/share/migration/tables.sql +3 -0
- data/share/{schemas → schema/schema}/build.yml +0 -0
- data/share/{schemas → schema/schema}/prick/build.yml +0 -0
- data/share/schema/schema/prick/data.sql +7 -0
- data/share/{schemas → schema/schema}/prick/schema.sql +0 -0
- data/share/{schemas → schema/schema}/prick/tables.sql +2 -2
- data/share/{schemas → schema/schema}/public/.keep +0 -0
- data/share/{schemas → schema/schema}/public/build.yml +0 -0
- data/share/{schemas → schema/schema}/public/schema.sql +0 -0
- data/test_refactor +34 -0
- metadata +23 -21
- data/file +0 -0
- data/lib/prick/build.rb +0 -376
- data/lib/prick/migra.rb +0 -22
- data/share/feature_migration/diff.sql +0 -2
- data/share/feature_migration/migrate.sql +0 -2
- data/share/release_migration/diff.sql +0 -3
- data/share/release_migration/migrate.sql +0 -5
- data/share/schemas/prick/data.sql +0 -7
data/lib/prick/diff.rb
CHANGED
@@ -1,47 +1,125 @@
|
|
1
1
|
module Prick
|
2
2
|
class Diff
|
3
|
+
# Diff as a list of lines
|
4
|
+
attr_reader :diff
|
5
|
+
|
6
|
+
# Subject of the diff
|
7
|
+
attr_reader :before_table_changes
|
8
|
+
attr_reader :table_changes
|
9
|
+
attr_reader :after_table_changes
|
10
|
+
|
3
11
|
def initialize(db1, db2)
|
4
12
|
@db1, @db2 = db1, db2
|
5
|
-
|
6
|
-
|
7
|
-
@result = nil
|
13
|
+
do_diff
|
14
|
+
split_on_table_changes
|
8
15
|
end
|
9
16
|
|
10
17
|
def self.same?(db1, db2) Diff.new(db1, db2).same? end
|
11
18
|
|
12
19
|
# Return true if the two databases are equal. Named #same? to avoid name
|
13
20
|
# collision with the built in #equal?
|
14
|
-
def same?
|
15
|
-
do_diff if @result.nil?
|
16
|
-
@result
|
17
|
-
end
|
21
|
+
def same?() diff.empty? end
|
18
22
|
|
19
|
-
#
|
20
|
-
|
21
|
-
|
23
|
+
# Write the diff between the databases to the given file(s). Return true if
|
24
|
+
# the databases are equal
|
25
|
+
def write_segments(file1, file2 = nil, file3 = nil, mark: true)
|
26
|
+
if file2.nil? && file3.nil?
|
27
|
+
file2 = file3 = file1
|
28
|
+
elsif file2.nil? ^ !file3.nil?
|
29
|
+
raise Internal, "Either none or both of `file2` and `file3` should be nil"
|
30
|
+
end
|
31
|
+
write_segment(file1, :before_table_changes, mark: mark)
|
32
|
+
write_segment(file2, :table_changes, mark: mark)
|
33
|
+
write_segment(file3, :after_table_changes, mark: mark)
|
22
34
|
end
|
23
35
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
IO.write(file, @diff)
|
36
|
+
def write_segment(file, segment, mark: true)
|
37
|
+
lines = self.send(segment)
|
38
|
+
if lines.empty?
|
39
|
+
FileUtils.rm_f(file) if file != "/dev/stdout"
|
29
40
|
else
|
30
|
-
|
41
|
+
File.open(file, "w") { |f|
|
42
|
+
f.puts "--" + segment.to_s.gsub("_", " ").upcase if mark
|
43
|
+
f.puts lines
|
44
|
+
}
|
31
45
|
end
|
32
|
-
@result
|
33
46
|
end
|
34
47
|
|
35
48
|
private
|
36
49
|
def do_diff(file = nil)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
50
|
+
command = "migra --unsafe --with-privileges postgres:///#{@db1} postgres:///#{@db2}"
|
51
|
+
@diff = Command.command(command, fail: false)
|
52
|
+
[0,2].include?(Command.status) or
|
53
|
+
raise Internal, "migrate command failed with status #{Command.status}: #{command}"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Initialize table change variables
|
57
|
+
def split_on_table_changes
|
58
|
+
@before_table_changes = []
|
59
|
+
@table_changes = []
|
60
|
+
@after_table_changes = []
|
61
|
+
|
62
|
+
before = true
|
63
|
+
tables = false
|
64
|
+
after = false
|
65
|
+
|
66
|
+
in_table = false
|
67
|
+
|
68
|
+
diff.each { |l|
|
69
|
+
if before
|
70
|
+
if l =~ /^alter table/
|
71
|
+
@table_changes << l
|
72
|
+
before = false
|
73
|
+
tables = true
|
74
|
+
elsif l =~ /^create table/
|
75
|
+
@table_changes << l
|
76
|
+
before = false
|
77
|
+
tables = true
|
78
|
+
in_table = true
|
79
|
+
elsif l =~ /^drop table/
|
80
|
+
@table_changes << l
|
81
|
+
before = false
|
82
|
+
tables = true
|
83
|
+
else
|
84
|
+
@before_table_changes << l
|
85
|
+
end
|
86
|
+
elsif tables
|
87
|
+
if in_table
|
88
|
+
if l =~ /^\)/
|
89
|
+
@table_changes << l
|
90
|
+
in_table = false
|
91
|
+
else
|
92
|
+
@table_changes << l
|
93
|
+
end
|
94
|
+
elsif l =~ /^alter table/
|
95
|
+
@table_changes << l
|
96
|
+
elsif l =~ /^create table/
|
97
|
+
@table_changes << l
|
98
|
+
in_table = true
|
99
|
+
elsif l =~ /^drop table/
|
100
|
+
@table_changes << l
|
101
|
+
elsif l =~ /^\s*$/
|
102
|
+
@table_changes << l
|
103
|
+
else
|
104
|
+
@after_table_changes << l
|
105
|
+
tables = false
|
106
|
+
after = true
|
107
|
+
end
|
108
|
+
else
|
109
|
+
@after_table_changes << l
|
110
|
+
end
|
111
|
+
}
|
45
112
|
end
|
46
113
|
end
|
47
114
|
end
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
|
data/lib/prick/git.rb
CHANGED
@@ -88,6 +88,11 @@ module Prick
|
|
88
88
|
Command.command "git branch #{name}"
|
89
89
|
end
|
90
90
|
|
91
|
+
# Rename a branch
|
92
|
+
def self.rename_branch(from, to)
|
93
|
+
Command.command "git branch -m #{from} #{to}"
|
94
|
+
end
|
95
|
+
|
91
96
|
# Destroy branch
|
92
97
|
def self.delete_branch(name)
|
93
98
|
Command.command "git branch -D #{name}", fail: false
|
@@ -127,9 +132,13 @@ module Prick
|
|
127
132
|
merge_branch(name, exclude_files: exclude_files, fail: fail)
|
128
133
|
end
|
129
134
|
|
130
|
-
# List branches
|
131
|
-
def self.list_branches
|
132
|
-
|
135
|
+
# List branches. Detached head "branches" are ignored unless :detached_head is true
|
136
|
+
def self.list_branches(detached_head: false)
|
137
|
+
if detached_head
|
138
|
+
Command.command "git branch --format='%(refname:short)'"
|
139
|
+
else
|
140
|
+
Command.command "git for-each-ref --format='%(refname:short)' refs/heads/*"
|
141
|
+
end
|
133
142
|
end
|
134
143
|
|
135
144
|
# Add a file to the index of the current branch
|
@@ -141,6 +150,14 @@ module Prick
|
|
141
150
|
}
|
142
151
|
end
|
143
152
|
|
153
|
+
def self.changed?(file)
|
154
|
+
Command.command("git status --porcelain").any? { |l| l =~ /^.M #{file}$/ }
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.added?(file)
|
158
|
+
Command.command("git status --porcelain").any? { |l| l =~ /^A. #{file}$/ }
|
159
|
+
end
|
160
|
+
|
144
161
|
# Return content of file in the given tag or branch. Defaults to HEAD
|
145
162
|
def self.readlines(file, tag: nil, branch: nil)
|
146
163
|
!(tag && branch) or raise Internal, "Can't use both tag: and branch: options"
|
@@ -163,15 +180,20 @@ module Prick
|
|
163
180
|
end.join("\n") + "\n"
|
164
181
|
end
|
165
182
|
|
166
|
-
def self.rm(
|
167
|
-
|
168
|
-
|
183
|
+
def self.rm(*files)
|
184
|
+
Array(files).flatten.each { |file|
|
185
|
+
Dir.chdir(File.dirname(file)) {
|
186
|
+
Command.command "git rm -f '#{File.basename(file)}'", fail: false
|
187
|
+
}
|
169
188
|
}
|
170
189
|
end
|
171
190
|
|
172
|
-
def self.rm_rf(
|
173
|
-
|
174
|
-
|
191
|
+
def self.rm_rf(*files)
|
192
|
+
Array(files).flatten.each { |file|
|
193
|
+
Dir.chdir(File.dirname(file)) {
|
194
|
+
next if file == ".keep"
|
195
|
+
Command.command "git rm -rf '#{File.basename(file)}'", fail: false
|
196
|
+
}
|
175
197
|
}
|
176
198
|
end
|
177
199
|
|
data/lib/prick/head.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
|
2
|
+
module Prick
|
3
|
+
class Head
|
4
|
+
def project_name() Prick.project.name end
|
5
|
+
|
6
|
+
# Usually equal to #version.to_s
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
# Version. This should be equal to schema.version
|
10
|
+
attr_reader :version
|
11
|
+
|
12
|
+
def base_version() @migration.base_version end
|
13
|
+
|
14
|
+
attr_reader :schema
|
15
|
+
|
16
|
+
attr_reader :migration
|
17
|
+
|
18
|
+
def clean?() Git::clean? end
|
19
|
+
|
20
|
+
def tag?() false end
|
21
|
+
def release_tag?() false end
|
22
|
+
def migration_tag?() false end
|
23
|
+
|
24
|
+
def branch?() false end
|
25
|
+
def release_branch?() false end
|
26
|
+
def prerelease_branch?() false end
|
27
|
+
def feature_branch?() false end
|
28
|
+
def migration_branch?() false end
|
29
|
+
|
30
|
+
def initialize(name, version, migration)
|
31
|
+
@name = name
|
32
|
+
@version = version
|
33
|
+
@schema = Schema.new
|
34
|
+
@migration = migration
|
35
|
+
end
|
36
|
+
|
37
|
+
# TODO: Handle migrations
|
38
|
+
def self.load(name)
|
39
|
+
version, tag = Version.parse(name)
|
40
|
+
if tag
|
41
|
+
ReleaseTag.load
|
42
|
+
else
|
43
|
+
if version.release?
|
44
|
+
ReleaseBranch.load
|
45
|
+
elsif version.prerelease?
|
46
|
+
PrereleaseBranch.load(version)
|
47
|
+
elsif version.feature?
|
48
|
+
FeatureBranch.load(version)
|
49
|
+
else
|
50
|
+
raise NotHere
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def create()
|
56
|
+
raise NotThis
|
57
|
+
end
|
58
|
+
|
59
|
+
def build(database)
|
60
|
+
schema.build(database)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.database_name(version)
|
64
|
+
version.truncate(:pre).to_s
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Tag < Head
|
69
|
+
def tag?() true end
|
70
|
+
|
71
|
+
def initialize(version, base_version, migration = nil)
|
72
|
+
migration ||= Migration.new(version, base_version)
|
73
|
+
super(version.to_s, version, migration)
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.load
|
77
|
+
state = Migration.load
|
78
|
+
self.new(state.version, state.base_version)
|
79
|
+
end
|
80
|
+
|
81
|
+
def create
|
82
|
+
initial_branch_name = "#{version}_initial"
|
83
|
+
clean? or raise Internal, "Repository is not clean"
|
84
|
+
!Git.detached? or raise Internal, "Not on a branch"
|
85
|
+
Git.create_branch(initial_branch_name)
|
86
|
+
Git.checkout_branch(initial_branch_name)
|
87
|
+
migration.update(version)
|
88
|
+
schema.version = version
|
89
|
+
Git.commit "Created release v#{version}"
|
90
|
+
Git.create_tag(version)
|
91
|
+
Git.checkout_tag(version)
|
92
|
+
self
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class ReleaseTag < Tag
|
97
|
+
def release_tag?() true end
|
98
|
+
end
|
99
|
+
|
100
|
+
# TODO
|
101
|
+
class PrereleaseTag < Tag
|
102
|
+
end
|
103
|
+
|
104
|
+
class MigrationTag < Tag
|
105
|
+
def migration_tag?() true end
|
106
|
+
end
|
107
|
+
|
108
|
+
class Branch < Head
|
109
|
+
def branch?() true end
|
110
|
+
|
111
|
+
def initialize(name, version, migration)
|
112
|
+
super(name, version, migration)
|
113
|
+
end
|
114
|
+
|
115
|
+
def create()
|
116
|
+
Git.create_branch(version)
|
117
|
+
Git.checkout_branch(version)
|
118
|
+
migration.create
|
119
|
+
self
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class ReleaseBranch < Branch
|
124
|
+
def release_branch?() true end
|
125
|
+
|
126
|
+
def initialize(fork = nil, base_version)
|
127
|
+
if fork
|
128
|
+
version = Version.new(base_version, fork: fork)
|
129
|
+
else
|
130
|
+
version = base_version
|
131
|
+
end
|
132
|
+
super(version.to_s, version, Migration.new(nil, base_version))
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.load
|
136
|
+
state = MigrationState.load
|
137
|
+
ReleaseBranch.new(nil, state.base_version)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class PrereleaseBranch < Branch
|
142
|
+
def prerelease_branch?() true end
|
143
|
+
|
144
|
+
def initialize(version, base_version)
|
145
|
+
target_version = version.truncate(:pre)
|
146
|
+
super(version.to_s, target_version, Migration.new(target_version, base_version))
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.load
|
150
|
+
state = MigrationState.load
|
151
|
+
PrereleaseBranch.new(state.version, state.base_version)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class FeatureBranch < Branch
|
156
|
+
def feature_branch?() true end
|
157
|
+
|
158
|
+
def initialize(feature_name, base_version)
|
159
|
+
name = Version.new(base_version, feature: feature_name).to_s
|
160
|
+
super(name, base_version, FeatureMigration.new(feature_name, base_version))
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.load
|
164
|
+
state = MigrationState.load
|
165
|
+
FeatureBranch.new(state.version.feature)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# TODO: Versioned migrations (or maybe not)
|
170
|
+
class MigrationBranch < Branch
|
171
|
+
def migrationn_branch?() true end
|
172
|
+
|
173
|
+
def initialize(version, base_version)
|
174
|
+
if (version.fork || "") == (base_version.fork || "")
|
175
|
+
name = version.to_s + "-" + base_version.semver.to_s
|
176
|
+
else
|
177
|
+
name = version.to_s + "-" + base_version.to_s
|
178
|
+
end
|
179
|
+
super(name, version, Migration.new(version, base_version))
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
data/lib/prick/migration.rb
CHANGED
@@ -1,210 +1,70 @@
|
|
1
1
|
|
2
2
|
module Prick
|
3
|
-
# A Migration consists of a .prick-features file, a .prick-migration file, and a
|
4
|
-
# set of SQL migration files. Features can be include as subdirectories
|
5
|
-
#
|
6
3
|
class Migration
|
7
|
-
|
8
|
-
|
9
|
-
def migration_dir() @migration_state && File.dirname(@migration_state.path) end
|
4
|
+
attr_reader :version
|
5
|
+
attr_reader :base_version
|
10
6
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# diff.sql, features.sql, features.yml, and the user-defined migrations.sql file
|
15
|
-
def features_dir() @features_state && File.dirname(@features_state.path) end
|
16
|
-
|
17
|
-
# Directory of the migration. Alias for #features_dir. It should be used in
|
18
|
-
# derived classes when the features and migration directory are the same
|
19
|
-
def dir() features_dir end
|
20
|
-
|
21
|
-
# Migration file
|
22
|
-
def migrations_file() File.join(dir, MIGRATIONS_FILE) end
|
23
|
-
|
24
|
-
# Version of the result of running this migration. `version` is nil for the
|
25
|
-
# current release and features that are not part of a pre-release. Needs to
|
26
|
-
# be redefined in subclasses where migration_dir is nil
|
27
|
-
forward_method :version, :version=, :@migration_state
|
28
|
-
|
29
|
-
# Base version of the migration. `base_version` is nil for the initial
|
30
|
-
# 0.0.0 migration. Needs to be redefined in subclasses where migration_dir
|
31
|
-
# is nil
|
32
|
-
forward_method :base_version, :base_version=, :@migration_state
|
33
|
-
|
34
|
-
# List of features in this migration. The features ordered in the same
|
35
|
-
# order as they're included
|
36
|
-
forward_method :features, :@features_state
|
37
|
-
|
38
|
-
# Note that migration_dir can be nil
|
39
|
-
def initialize(migration_dir, features_dir)
|
40
|
-
@migration_state = migration_dir && MigrationState.new(migration_dir)
|
41
|
-
@features_state = features_dir && FeaturesState.new(features_dir)
|
7
|
+
def initialize(version, base_version)
|
8
|
+
@version = version
|
9
|
+
@base_version = base_version
|
42
10
|
end
|
43
11
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
puts "migration_dir: #{migration_dir}"
|
48
|
-
puts "features_dir: #{features_dir}"
|
49
|
-
puts "version: #{version}"
|
50
|
-
puts "base_version: #{base_version}"
|
51
|
-
}
|
12
|
+
def self.load
|
13
|
+
state = MigrationState.load
|
14
|
+
Migration.new(state.version, state.base_version)
|
52
15
|
end
|
53
16
|
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
def load
|
59
|
-
@migration_state&.read
|
60
|
-
@features_state.read
|
61
|
-
self
|
17
|
+
# Remove content of the migration/ directory
|
18
|
+
def self.clear
|
19
|
+
FileUtils.empty!(MIGRATION_DIR)
|
62
20
|
end
|
63
21
|
|
64
|
-
def
|
65
|
-
@migration_state&.write
|
66
|
-
@features_state.write
|
67
|
-
Git.add(@migration_state.path) if @migration_state
|
68
|
-
Git.add(@features_state.path)
|
69
|
-
self
|
70
|
-
end
|
22
|
+
def exist?() MigrationState.exist? end
|
71
23
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
(@migration_state.nil? || @migration_state.exist?) && (initial? || @features_state.exist?)
|
77
|
-
end
|
78
|
-
|
79
|
-
def create(templates_pattern = nil)
|
80
|
-
if @migration_state && !@migration_state.exist?
|
81
|
-
FileUtils.mkdir_p(migration_dir) if migration_dir
|
82
|
-
@migration_state.create
|
83
|
-
Git.add(@migration_state.path)
|
84
|
-
end
|
85
|
-
if !initial? && !@features_state.exist?
|
86
|
-
FileUtils.mkdir_p(features_dir)
|
87
|
-
@features_state.create
|
88
|
-
Git.add(@features_state.path)
|
89
|
-
end
|
90
|
-
if !initial? && templates_pattern
|
91
|
-
files = Share.cp(templates_pattern, features_dir, clobber: false)
|
92
|
-
Git.add files
|
93
|
-
end
|
24
|
+
def create()
|
25
|
+
files = Share.cp "migration/*", MIGRATION_DIR
|
26
|
+
state = MigrationState.new.write(version: version, base_version: base_version)
|
27
|
+
Git.add files, state.path
|
94
28
|
self
|
95
29
|
end
|
96
30
|
|
97
|
-
def
|
98
|
-
|
99
|
-
@
|
100
|
-
|
101
|
-
|
31
|
+
def update(version)
|
32
|
+
state = MigrationState.new.read
|
33
|
+
@version = state.version = version
|
34
|
+
state.write
|
35
|
+
Git.add state.path
|
102
36
|
self
|
103
37
|
end
|
104
38
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
generate_features_yml
|
110
|
-
self
|
111
|
-
end
|
112
|
-
|
113
|
-
def generate_features_yml
|
114
|
-
features_yml_file = File.join(features_dir, "features.yml")
|
115
|
-
Share.cp("release_migration/features.yml", features_yml_file)
|
116
|
-
file = File.open(features_yml_file, "a")
|
117
|
-
features.each { |feature|
|
118
|
-
version = Version.new(feature)
|
119
|
-
if base_version == version.truncate(:pre)
|
120
|
-
file.puts "- #{version.feature}"
|
121
|
-
else
|
122
|
-
file.puts "- ../#{version.truncate(:pre)}/#{version.feature}"
|
123
|
-
end
|
124
|
-
}
|
125
|
-
end
|
126
|
-
|
127
|
-
def migrate(database)
|
128
|
-
MigrationBuilder.new(database, features_dir).build
|
129
|
-
Rdbms.exec_sql(database.name, "delete from prick.versions", user: database.user)
|
130
|
-
Rdbms.exec_file(database.name, File.join(PRICK_DIR, "data.sql"), user: database.user)
|
131
|
-
end
|
132
|
-
|
133
|
-
# This only migrates included features. It is used in pre-releases to migrate included features
|
134
|
-
# before creating a diff, so the diff only contains changes not defined in the features
|
135
|
-
def migrate_features(database)
|
136
|
-
MigrationBuilder.new(database, features_dir).build("features.yml")
|
39
|
+
def migrate(database)
|
40
|
+
base_version or raise Internal, "Can't migrate from nil to #{version}"
|
41
|
+
version or raise Internal, "Can't migrate from #{base_version} to nil"
|
42
|
+
MigrationBuilder.new(database, MIGRATION_DIR).build
|
137
43
|
end
|
138
44
|
end
|
139
45
|
|
140
|
-
class
|
141
|
-
|
142
|
-
def version=(v)
|
143
|
-
@migration_state ||= MigrationState.new(ReleaseMigration.migration_dir(v))
|
144
|
-
@migration_state.version = v
|
145
|
-
end
|
46
|
+
class FeatureMigration < Migration
|
47
|
+
attr_reader :feature
|
146
48
|
|
147
|
-
def
|
148
|
-
|
149
|
-
@
|
150
|
-
@migration_state.base_version = v
|
49
|
+
def initialize(feature, base_version)
|
50
|
+
super(base_version, base_version)
|
51
|
+
@feature = feature
|
151
52
|
end
|
152
53
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
super(migration_dir, features_dir)
|
158
|
-
if version
|
159
|
-
self.version = version
|
160
|
-
self.base_version = base_version
|
161
|
-
else
|
162
|
-
@base_migration_state = MigrationState.new(features_dir)
|
163
|
-
end
|
54
|
+
def self.load
|
55
|
+
migration_state = MigrationState.load
|
56
|
+
feature_state = FeatureState.load
|
57
|
+
FeatureMigration.new(feature_state.feature, migration_state.base_version)
|
164
58
|
end
|
165
59
|
|
166
|
-
def create()
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
features_dir = ReleaseMigration.features_dir(migration_state.base_version)
|
173
|
-
end
|
174
|
-
self.new(migration_state.version, migration_state.base_version)
|
175
|
-
end
|
176
|
-
|
177
|
-
def self.migration_dir(version) version && File.join(RELEASES_DIR, version.to_s) end
|
178
|
-
def self.features_dir(base_version) migration_dir(base_version) end
|
179
|
-
|
180
|
-
|
181
|
-
end
|
182
|
-
|
183
|
-
class MigrationMigration < Migration
|
184
|
-
attr_reader :name
|
185
|
-
|
186
|
-
def initialize(version, base_version)
|
187
|
-
@name = "#{base_version}_#{version}"
|
188
|
-
dir = File.join(MIGRATIONS_DIR, name)
|
189
|
-
super(dir, dir)
|
190
|
-
self.version = version
|
191
|
-
self.base_version = base_version
|
60
|
+
def create()
|
61
|
+
super
|
62
|
+
files = Share.cp "migration", File.join(MIGRATION_DIR, feature)
|
63
|
+
state = FeatureState.write(feature: feature)
|
64
|
+
Git.add files, state.path
|
65
|
+
self
|
192
66
|
end
|
193
|
-
|
194
|
-
def create() super("release_migration/*") end
|
195
67
|
end
|
68
|
+
end
|
196
69
|
|
197
|
-
class FeatureMigration < Migration
|
198
|
-
attr_reader :name
|
199
|
-
|
200
|
-
def initialize(name, base_version)
|
201
|
-
@name = name
|
202
|
-
dir = File.join(RELEASES_DIR, base_version.to_s, name)
|
203
|
-
super(dir, dir)
|
204
|
-
self.version = Version.new(base_version, feature: name)
|
205
|
-
self.base_version = base_version
|
206
|
-
end
|
207
70
|
|
208
|
-
def create() super("feature_migration/*") end
|
209
|
-
end
|
210
|
-
end
|