prick 0.3.0 → 0.8.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 +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
|