prick 0.18.0 → 0.20.2
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/Gemfile +10 -4
- data/README.md +7 -7
- data/Rakefile +3 -1
- data/TODO +13 -11
- data/bin/console +2 -1
- data/doc/build-yml.txt +14 -0
- data/exe/prick +264 -28
- data/lib/builder/batch.rb +147 -0
- data/lib/builder/builder.rb +122 -0
- data/lib/builder/node.rb +189 -0
- data/lib/builder/node_pool.rb +105 -0
- data/lib/builder/parser.rb +120 -0
- data/lib/local/command.rb +193 -0
- data/lib/{prick → local}/git.rb +148 -22
- data/lib/local/timer.rb +98 -0
- data/lib/prick/constants.rb +54 -66
- data/lib/prick/diff.rb +28 -18
- data/lib/prick/prick_version.rb +161 -0
- data/lib/prick/state.rb +80 -165
- data/lib/prick/version.rb +2 -163
- data/lib/prick.rb +43 -27
- data/lib/share/init/.gitignore +10 -0
- data/lib/share/init/.prick-context +2 -0
- data/lib/share/init/.rspec +3 -0
- data/{share/schema/schema/public → lib/share/init/migration}/.keep +0 -0
- data/lib/share/init/prick.yml +6 -0
- data/lib/share/init/schema/.keep +0 -0
- data/lib/share/init/schema/build.yml +2 -0
- data/lib/share/init/schema/prick/.keep +0 -0
- data/lib/share/init/schema/prick/build.yml +5 -0
- data/lib/share/init/schema/prick/data.sql +6 -0
- data/{share/schema → lib/share/init}/schema/prick/tables.sql +2 -3
- data/lib/share/init/schema/public/.keep +0 -0
- data/lib/share/init/spec/prick_helper.rb +1 -0
- data/lib/share/init/spec/prick_spec.rb +6 -0
- data/lib/share/init/spec/spec_helper.rb +50 -0
- data/lib/share/migrate/migration/build.yml +4 -0
- data/lib/share/migrate/migration/diff.after-tables.sql +0 -0
- data/lib/share/migrate/migration/diff.before-tables.sql +0 -0
- data/lib/share/migrate/migration/diff.tables.sql +0 -0
- data/lib/subcommand/prick-build.rb +55 -0
- data/lib/subcommand/prick-create.rb +78 -0
- data/lib/subcommand/prick-drop.rb +25 -0
- data/lib/subcommand/prick-fox.rb +62 -0
- data/lib/subcommand/prick-init.rb +46 -0
- data/lib/subcommand/prick-make.rb +202 -0
- data/lib/subcommand/prick-migrate.rb +37 -0
- data/lib/subcommand/prick-release.rb +23 -0
- data/lib/subcommand/prick-setup.rb +20 -0
- data/lib/subcommand/prick-teardown.rb +18 -0
- data/prick.gemspec +43 -16
- metadata +161 -72
- data/.gitignore +0 -29
- data/.travis.yml +0 -7
- data/doc/create_release.txt +0 -17
- data/doc/flow.txt +0 -98
- data/doc/migra +0 -1
- data/doc/migrations.txt +0 -172
- data/doc/notes.txt +0 -116
- data/doc/prick.txt +0 -114
- data/doc/sh.prick +0 -316
- data/lib/ext/algorithm.rb +0 -14
- data/lib/ext/fileutils.rb +0 -26
- data/lib/ext/forward_method.rb +0 -18
- data/lib/ext/pg.rb +0 -18
- data/lib/ext/shortest_path.rb +0 -44
- data/lib/prick/archive.rb +0 -124
- data/lib/prick/branch.rb +0 -254
- data/lib/prick/builder.rb +0 -205
- data/lib/prick/cache.rb +0 -34
- data/lib/prick/command.rb +0 -102
- data/lib/prick/database.rb +0 -82
- data/lib/prick/dsort.rb +0 -151
- data/lib/prick/ensure.rb +0 -119
- data/lib/prick/exceptions.rb +0 -25
- data/lib/prick/head.rb +0 -183
- data/lib/prick/migration.rb +0 -70
- data/lib/prick/program.rb +0 -506
- data/lib/prick/project.rb +0 -626
- data/lib/prick/rdbms.rb +0 -137
- data/lib/prick/schema.rb +0 -27
- data/lib/prick/share.rb +0 -64
- data/libexec/strip-comments +0 -33
- data/make_releases +0 -72
- data/make_schema +0 -10
- data/share/diff/diff.after-tables.sql +0 -4
- data/share/diff/diff.before-tables.sql +0 -4
- data/share/diff/diff.tables.sql +0 -8
- data/share/features/diff.sql +0 -2
- data/share/features/feature/diff.sql +0 -2
- data/share/features/feature/migrate.sql +0 -2
- data/share/features/features.sql +0 -2
- data/share/features/features.yml +0 -2
- data/share/features/migrations.sql +0 -4
- data/share/gitignore +0 -2
- data/share/migration/diff.tables.sql +0 -8
- data/share/migration/features.yml +0 -6
- data/share/migration/migrate.sql +0 -3
- data/share/migration/migrate.yml +0 -8
- data/share/migration/tables.sql +0 -3
- data/share/schema/build.yml +0 -14
- data/share/schema/schema/build.yml +0 -3
- data/share/schema/schema/prick/build.yml +0 -14
- data/share/schema/schema/prick/data.sql +0 -7
- data/share/schema/schema/prick/schema.sql +0 -3
- data/share/schema/schema/public/build.yml +0 -13
- data/share/schema/schema.sql +0 -3
- data/test_assorted +0 -192
- data/test_feature +0 -112
- data/test_refactor +0 -34
- data/test_single_dev +0 -83
data/lib/prick/project.rb
DELETED
|
@@ -1,626 +0,0 @@
|
|
|
1
|
-
require "prick/state.rb"
|
|
2
|
-
|
|
3
|
-
require "tmpdir"
|
|
4
|
-
|
|
5
|
-
module Prick
|
|
6
|
-
class Project
|
|
7
|
-
attr_reader :name
|
|
8
|
-
attr_reader :user # Database user
|
|
9
|
-
attr_reader :head # Current branch/tag
|
|
10
|
-
attr_reader :schema
|
|
11
|
-
|
|
12
|
-
# Return the versioned database or the project database if `version` is nil
|
|
13
|
-
def database(version = nil)
|
|
14
|
-
version ? Database.new("#{name}-#{version}", user) : @database
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
attr_reader :cache
|
|
18
|
-
|
|
19
|
-
def initialize(name, user, head)
|
|
20
|
-
@name = name
|
|
21
|
-
@user = user || ENV['USER']
|
|
22
|
-
@head = head
|
|
23
|
-
@schema = Schema.new
|
|
24
|
-
@database = Database.new(name, user)
|
|
25
|
-
@cache = Cache.new
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
forward_methods :version, :base_version, :@head
|
|
29
|
-
forward_methods :clean?, :@head
|
|
30
|
-
forward_methods :tag?, :release_tag?, :migration_tag?, :@head
|
|
31
|
-
forward_methods :branch?, :release_branch?, :prerelease_branch?, :feature_branch?, :migration_branch?, :@head
|
|
32
|
-
|
|
33
|
-
def self.exist?(directory)
|
|
34
|
-
File.directory?(directory) && Dir.chdir(directory) { ProjectState.new.exist? }
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def self.create(name, user, directory)
|
|
38
|
-
user ||= ENV['USER']
|
|
39
|
-
|
|
40
|
-
FileUtils.mkdir(directory) if directory != "."
|
|
41
|
-
|
|
42
|
-
Dir.chdir(directory) {
|
|
43
|
-
# Initialize git instance
|
|
44
|
-
Git.init
|
|
45
|
-
|
|
46
|
-
# Create prick version file
|
|
47
|
-
PrickVersion.new.write(VERSION)
|
|
48
|
-
|
|
49
|
-
# Create project state file
|
|
50
|
-
ProjectState.new(name: name, user: user).write
|
|
51
|
-
|
|
52
|
-
# Directories
|
|
53
|
-
FileUtils.mkdir_p(DIRS)
|
|
54
|
-
DIRS.each { |dir| FileUtils.touch("#{dir}/.keep") }
|
|
55
|
-
|
|
56
|
-
# Copy default gitignore and schema files
|
|
57
|
-
Share.cp("gitignore", ".gitignore")
|
|
58
|
-
Share.cp("schema/schema", ".")
|
|
59
|
-
|
|
60
|
-
# Add .prick-migration file
|
|
61
|
-
MigrationState.new(version: Version.zero).create
|
|
62
|
-
|
|
63
|
-
# Add everything so far
|
|
64
|
-
Git.add(".")
|
|
65
|
-
Git.commit("Initial import")
|
|
66
|
-
|
|
67
|
-
# Rename branch "master"/"main" to "0.0.0_initial"
|
|
68
|
-
from_branch = Git.branch?("master") ? "master" : "main"
|
|
69
|
-
Git.rename_branch(from_branch, "0.0.0_initial")
|
|
70
|
-
|
|
71
|
-
# Create schema
|
|
72
|
-
schema = Schema.new
|
|
73
|
-
schema.version = Version.zero
|
|
74
|
-
Git.add schema.version_file
|
|
75
|
-
|
|
76
|
-
# Create release
|
|
77
|
-
Git.commit "Created release v0.0.0"
|
|
78
|
-
Git.create_tag(Version.zero)
|
|
79
|
-
Git.checkout_tag(Version.zero)
|
|
80
|
-
}
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
# Initialize from disk
|
|
84
|
-
#
|
|
85
|
-
# TODO Handle migrations
|
|
86
|
-
def self.load
|
|
87
|
-
if Git.detached?
|
|
88
|
-
name = "v#{Git.current_tag}"
|
|
89
|
-
else
|
|
90
|
-
name = Git.current_branch
|
|
91
|
-
end
|
|
92
|
-
begin
|
|
93
|
-
branch = Head.load(name)
|
|
94
|
-
rescue Version::FormatError
|
|
95
|
-
raise Fail, "Illegal branch name: #{name}"
|
|
96
|
-
end
|
|
97
|
-
state = ProjectState.new.read
|
|
98
|
-
Project.new(state.name, state.user, branch)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def build(database = self.database, version: nil)
|
|
102
|
-
database.clean
|
|
103
|
-
if version
|
|
104
|
-
FileUtils.mkdir_p(TMP_DIR)
|
|
105
|
-
Dir.mktmpdir("clone-", TMP_DIR) { |dir|
|
|
106
|
-
Command.command "git clone . #{dir}"
|
|
107
|
-
Dir.chdir(dir) {
|
|
108
|
-
Git.checkout_tag(version)
|
|
109
|
-
project = Project.load
|
|
110
|
-
project.head.build(database)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
else
|
|
114
|
-
head.build(database)
|
|
115
|
-
end
|
|
116
|
-
self
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def load(database = self.database, version: nil, file: nil)
|
|
120
|
-
version.nil? ^ file.nil? or raise Internal, "Need exactly one of :file and :version to be defined"
|
|
121
|
-
database.clean
|
|
122
|
-
if version
|
|
123
|
-
cache.exist?(version) or raise Internal, "Can't find cache file for database #{database}"
|
|
124
|
-
cache.load(database, version)
|
|
125
|
-
else
|
|
126
|
-
database.load(file)
|
|
127
|
-
end
|
|
128
|
-
self
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def save(database = nil, file: nil)
|
|
132
|
-
!database.nil? || file or raise Internal, "Need a database when saving to file"
|
|
133
|
-
database ||= self.database
|
|
134
|
-
if file
|
|
135
|
-
database.save(file)
|
|
136
|
-
else
|
|
137
|
-
cache.save(database)
|
|
138
|
-
end
|
|
139
|
-
self
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# Create a schema diff between two database versions. to_version defaults to the
|
|
143
|
-
# current version. Returns the Diff object
|
|
144
|
-
def diff(from_version, to_version)
|
|
145
|
-
begin
|
|
146
|
-
from_db = Database.new("#{name}-base", user)
|
|
147
|
-
to_db = Database.new("#{name}-next", user)
|
|
148
|
-
from_version ||= version
|
|
149
|
-
build(from_db, version: from_version)
|
|
150
|
-
build(to_db, version: to_version)
|
|
151
|
-
Diff.new(from_db, to_db)
|
|
152
|
-
ensure
|
|
153
|
-
from_db&.drop
|
|
154
|
-
to_db&.drop
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def prepare_release(fork = nil)
|
|
159
|
-
check_clean(:release_tag)
|
|
160
|
-
@head = ReleaseBranch.new(fork, version).create
|
|
161
|
-
submit "Prepared new release based on v#{version}", true
|
|
162
|
-
self
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
def prepare_schema(name, commit: true)
|
|
166
|
-
path = File.join(SCHEMA_DIR, name)
|
|
167
|
-
FileUtils.mkdir_p(path)
|
|
168
|
-
Git.add Share.cp("schema/schema.sql", path, clobber: false, templates: { 'SCHEMA' => name })
|
|
169
|
-
Git.add Share.cp("schema/build.yml", path, clobber: false)
|
|
170
|
-
File.open(Schema.yml_file, "a") { |f| f.write("- #{name}\n") }
|
|
171
|
-
Git.add(Schema.yml_file)
|
|
172
|
-
submit "Added schema #{name}", commit
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def prepare_diff(from_version = version)
|
|
176
|
-
begin
|
|
177
|
-
from_name = "#{name}-base"
|
|
178
|
-
from_db = Database.new(from_name, user)
|
|
179
|
-
build(from_db, version: from_version)
|
|
180
|
-
|
|
181
|
-
to_name = "#{name}-next"
|
|
182
|
-
to_db = Database.new(to_name, user)
|
|
183
|
-
build(to_db)
|
|
184
|
-
|
|
185
|
-
if prerelease_branch?
|
|
186
|
-
head.migrate_features(from_db)
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
diff = Diff.new(from_db, to_db)
|
|
190
|
-
for path, lines, tables in [
|
|
191
|
-
[BEFORE_TABLES_DIFF_PATH, diff.before_table_changes, false],
|
|
192
|
-
[TABLES_DIFF_PATH, diff.table_changes, true],
|
|
193
|
-
[AFTER_TABLES_DIFF_PATH, diff.after_table_changes, false]]
|
|
194
|
-
if lines.empty?
|
|
195
|
-
if File.exist?(path)
|
|
196
|
-
if tables
|
|
197
|
-
Share.cp(File.join("diff", File.basename(path)), path)
|
|
198
|
-
Git.add(path)
|
|
199
|
-
else
|
|
200
|
-
Git.rm(path)
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
else
|
|
204
|
-
Share.cp(File.join("diff", File.basename(path)), path)
|
|
205
|
-
File.open(path, "a") { |f| f.puts lines }
|
|
206
|
-
Git.add(path) if !tables
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
self
|
|
210
|
-
ensure
|
|
211
|
-
from_db&.drop
|
|
212
|
-
to_db&.drop
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
def create_release(new_version)
|
|
217
|
-
check_clean(:release_branch)
|
|
218
|
-
head = ReleaseTag.new(new_version, version)
|
|
219
|
-
check_migration(head.migration)
|
|
220
|
-
(@head = head).create
|
|
221
|
-
self
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
def generate_schema
|
|
225
|
-
build = SchemaBuilder.new(database, SCHEMA_DIR).build(execute: false)
|
|
226
|
-
puts build.lines
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
def generate_migration
|
|
230
|
-
build = MigrationBuilder.new(database, MIGRATION_DIR).build(execute: false)
|
|
231
|
-
puts build.lines
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
private
|
|
235
|
-
def check(kind) self.send(:"#{kind}?") end
|
|
236
|
-
def check_clean(kind = nil)
|
|
237
|
-
clean? or raise Internal, "Dirty repository"
|
|
238
|
-
kind.nil? || check(kind) or raise Internal, "Not on a #{kind} tag/branh"
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def check_branch() branch? or raise Internal, "Not on a branch" end
|
|
242
|
-
def check_tag() tag? or raise Internal, "Not on a tag" end
|
|
243
|
-
|
|
244
|
-
# FIXME: Use Cache::file
|
|
245
|
-
def cache_file(version) File.join(CACHE_DIR, "#{database(version)}.sql.gz") end
|
|
246
|
-
|
|
247
|
-
def submit(msg, commit = true)
|
|
248
|
-
Git.commit msg if commit
|
|
249
|
-
@message = msg
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
def clean(database) # FIXME: Use Database#clean
|
|
253
|
-
if database.exist?
|
|
254
|
-
database.recreate if database.loaded?
|
|
255
|
-
else
|
|
256
|
-
database.create
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
def check_migration(migration)
|
|
261
|
-
begin
|
|
262
|
-
from_version = migration.base_version
|
|
263
|
-
from_db = Database.new("#{name}-base", user)
|
|
264
|
-
to_db = Database.new("#{name}-next", user)
|
|
265
|
-
build(from_db, version: from_version)
|
|
266
|
-
build(to_db)
|
|
267
|
-
migration.migrate(from_db)
|
|
268
|
-
Diff.new(from_db, to_db).same? or raise Error, "Schema/migration mismatch"
|
|
269
|
-
ensure
|
|
270
|
-
from_db&.drop
|
|
271
|
-
to_db&.drop
|
|
272
|
-
end
|
|
273
|
-
end
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
__END__
|
|
278
|
-
|
|
279
|
-
module Prick
|
|
280
|
-
class Project
|
|
281
|
-
# Name of project. Persisted in the project state file
|
|
282
|
-
attr_reader :name
|
|
283
|
-
|
|
284
|
-
# Name of Postgresql user that owns the databases. Defaults to #name.
|
|
285
|
-
# Persisted in the project state file. TODO: Make writable
|
|
286
|
-
attr_reader :user
|
|
287
|
-
|
|
288
|
-
# Current branch
|
|
289
|
-
attr :branch
|
|
290
|
-
|
|
291
|
-
# Version of the current branch. If is defined as #branch.version
|
|
292
|
-
def version() branch.version end
|
|
293
|
-
|
|
294
|
-
# Project (default) database
|
|
295
|
-
def database(version = nil)
|
|
296
|
-
version ? Database.new("#{name}-#{version.truncate(:pre)}", user) : @database
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
# Last commit message. TODO: Move to git.rb
|
|
300
|
-
attr_reader :message
|
|
301
|
-
|
|
302
|
-
# True if we're on a tag
|
|
303
|
-
def tag?() Git.detached? end
|
|
304
|
-
def self.tag?() Git.detached? end
|
|
305
|
-
|
|
306
|
-
# Classifiers
|
|
307
|
-
forward_methods :release?, :prerelease?, :feature?, :migration?, :@branch
|
|
308
|
-
|
|
309
|
-
def initialize(name, user, branch)
|
|
310
|
-
@name = name
|
|
311
|
-
@user = user
|
|
312
|
-
@branch = branch
|
|
313
|
-
@database = Database.new(name, user)
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
def self.load
|
|
317
|
-
name = Git.current_branch || Git.current_tag
|
|
318
|
-
if name =~ MIGRATION_RE
|
|
319
|
-
branch = MigrationRelease.load(name)
|
|
320
|
-
else
|
|
321
|
-
begin
|
|
322
|
-
version = Version.new(name)
|
|
323
|
-
rescue Version::FormatError
|
|
324
|
-
raise Fail, "Illegal branch name: #{name}"
|
|
325
|
-
end
|
|
326
|
-
if version.release?
|
|
327
|
-
branch = Release.load(name)
|
|
328
|
-
elsif version.pre?
|
|
329
|
-
branch = PreRelease.load(name, version)
|
|
330
|
-
elsif version.feature?
|
|
331
|
-
branch = Feature.load(name)
|
|
332
|
-
else
|
|
333
|
-
raise Oops
|
|
334
|
-
end
|
|
335
|
-
end
|
|
336
|
-
state = ProjectState.new.read
|
|
337
|
-
Project.new(state.name, state.user, branch)
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
def self.initialized?(directory)
|
|
341
|
-
File.directory?(directory) && Dir.chdir(directory) { ProjectState.new.exist? }
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
def self.initialize_directory(name, user, directory)
|
|
345
|
-
FileUtils.mkdir_p(directory)
|
|
346
|
-
Dir.chdir(directory) {
|
|
347
|
-
# Initialize git instance
|
|
348
|
-
Git.init
|
|
349
|
-
|
|
350
|
-
# Create prick version file
|
|
351
|
-
PrickVersion.new.write(VERSION)
|
|
352
|
-
|
|
353
|
-
# Create project state file
|
|
354
|
-
ProjectState.new(name: name, user: user).write
|
|
355
|
-
|
|
356
|
-
# Directories
|
|
357
|
-
DIRS.each { |dir|
|
|
358
|
-
!File.exist?(dir) or raise Fail, "Already initialized: Directory '#{dir}' exists"
|
|
359
|
-
}
|
|
360
|
-
FileUtils.mkdir_p(DIRS)
|
|
361
|
-
DIRS.each { |dir| FileUtils.touch("#{dir}/.keep") }
|
|
362
|
-
|
|
363
|
-
# Copy default gitignore and schema files
|
|
364
|
-
Share.cp("gitignore", ".gitignore")
|
|
365
|
-
Share.cp("schemas", ".")
|
|
366
|
-
|
|
367
|
-
# Add everything so far
|
|
368
|
-
Git.add(".")
|
|
369
|
-
Git.commit("Initial import")
|
|
370
|
-
|
|
371
|
-
# Create initial release
|
|
372
|
-
release = Release.new(Version.zero, nil)
|
|
373
|
-
release.create
|
|
374
|
-
|
|
375
|
-
schema = Schema.new(SCHEMAS_DIR)
|
|
376
|
-
schema.version = release.version
|
|
377
|
-
Git.add schema.version_file
|
|
378
|
-
|
|
379
|
-
Git.commit "Release 0.0.0"
|
|
380
|
-
release.tag!
|
|
381
|
-
|
|
382
|
-
# Kill master branch
|
|
383
|
-
Git.delete_branch("master")
|
|
384
|
-
}
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
def build(database: self.database, version: nil)
|
|
388
|
-
clean(database)
|
|
389
|
-
if version
|
|
390
|
-
FileUtils.mkdir_p(TMP_DIR)
|
|
391
|
-
Dir.mktmpdir("clone-", TMP_DIR) { |dir|
|
|
392
|
-
Command.command "git clone . #{dir}"
|
|
393
|
-
Dir.chdir(dir) {
|
|
394
|
-
Git.checkout_tag(version)
|
|
395
|
-
project = Project.load
|
|
396
|
-
project.branch.build(database)
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
else
|
|
400
|
-
branch.build(database)
|
|
401
|
-
end
|
|
402
|
-
self
|
|
403
|
-
end
|
|
404
|
-
|
|
405
|
-
def load(file, database: self.database)
|
|
406
|
-
clean(database)
|
|
407
|
-
database.load(file)
|
|
408
|
-
self
|
|
409
|
-
end
|
|
410
|
-
|
|
411
|
-
def save(file, database: self.database)
|
|
412
|
-
database.save(file)
|
|
413
|
-
self
|
|
414
|
-
end
|
|
415
|
-
|
|
416
|
-
def cache_file(version) File.join(CACHE_DIR, "#{database(version)}.sql.gz") end
|
|
417
|
-
|
|
418
|
-
def make(database, subject)
|
|
419
|
-
Schema.built? or raise Error, "Schema is not built into project database"
|
|
420
|
-
Schema.make(database, subject)
|
|
421
|
-
end
|
|
422
|
-
|
|
423
|
-
def backup(path = nil)
|
|
424
|
-
save path || File.join(SPOOL_DIR, "#{name}-#{Time.now.utc.strftime("%Y%m%d-%H%M%S")}.sql.gz")
|
|
425
|
-
end
|
|
426
|
-
|
|
427
|
-
def restore(path = nil)
|
|
428
|
-
load path || Dir.glob(File.join(SPOOL_DIR, "#{name}-*.sql.gz")).sort.last
|
|
429
|
-
end
|
|
430
|
-
|
|
431
|
-
def prepare_release(commit: true)
|
|
432
|
-
release = ReleaseMigration.new(nil, branch.version).create
|
|
433
|
-
submit "Prepared new release based on #{version}", commit
|
|
434
|
-
release
|
|
435
|
-
end
|
|
436
|
-
|
|
437
|
-
def prepare_schema(name, commit: true)
|
|
438
|
-
path = File.join(SCHEMAS_DIR, name)
|
|
439
|
-
FileUtils.mkdir_p(path)
|
|
440
|
-
Git.add Share.cp("schema/*", path, clobber: false, templates: { 'SCHEMA' => name })
|
|
441
|
-
File.open(branch.schema.yml_file, "a") { |f| f.write("- #{name}\n") }
|
|
442
|
-
Git.add(branch.schema.yml_file)
|
|
443
|
-
submit "Added schema #{name}", commit
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
def prepare_diff(from_version)
|
|
447
|
-
to_database = nil
|
|
448
|
-
begin
|
|
449
|
-
from_name = "#{name}-base"
|
|
450
|
-
from_database = Database.new(from_name, user)
|
|
451
|
-
build(database: from_database, version: from_version)
|
|
452
|
-
|
|
453
|
-
to_name = "#{name}-next"
|
|
454
|
-
to_database = Database.new(to_name, user)
|
|
455
|
-
build(database: to_database)
|
|
456
|
-
|
|
457
|
-
# Helpful double-check
|
|
458
|
-
Diff.same?(to_database.name, database.name) or
|
|
459
|
-
raise Error, "Schema and project database are not synchronized"
|
|
460
|
-
|
|
461
|
-
if release?
|
|
462
|
-
dir = branch.migration.migration_dir
|
|
463
|
-
else
|
|
464
|
-
dir = branch.migration.features_dir
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
# dir = branch.migration.features_dir || branch.migration.migration_dir
|
|
468
|
-
to_file = File.join(dir, DIFF_FILE)
|
|
469
|
-
|
|
470
|
-
if prerelease?
|
|
471
|
-
branch.migrate_features(from_database)
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
Diff.new(from_name, to_name).write(to_file)
|
|
475
|
-
ensure
|
|
476
|
-
from_database&.drop
|
|
477
|
-
to_database&.drop
|
|
478
|
-
end
|
|
479
|
-
end
|
|
480
|
-
|
|
481
|
-
def prepare_migration(from, commit: true)
|
|
482
|
-
to = branch.version
|
|
483
|
-
migration_release = MigrationRelease.new(to, from)
|
|
484
|
-
migration_release.create
|
|
485
|
-
submit "Prepared migration from #{from} to #{to}", commit
|
|
486
|
-
migration_release
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
def create_release(version, commit: true)
|
|
490
|
-
check_migration(branch.version) or raise Error, "Schema/migration mismatch"
|
|
491
|
-
release = Release.new(version, branch.version)
|
|
492
|
-
release.create
|
|
493
|
-
submit "Created release #{version}", commit
|
|
494
|
-
release.tag!
|
|
495
|
-
build
|
|
496
|
-
release
|
|
497
|
-
end
|
|
498
|
-
|
|
499
|
-
def cancel_release(version, commit: true)
|
|
500
|
-
Git.cancel_tag(version)
|
|
501
|
-
end
|
|
502
|
-
|
|
503
|
-
def create_release_from_prerelease(commit: true)
|
|
504
|
-
check_migration(branch.base_version) or raise Error, "Schema/migration mismatch"
|
|
505
|
-
release = Release.new(branch.version.truncate(:pre), branch.base_version)
|
|
506
|
-
release.create
|
|
507
|
-
submit "Released #{release.version}", commit
|
|
508
|
-
release.tag!
|
|
509
|
-
build
|
|
510
|
-
release
|
|
511
|
-
end
|
|
512
|
-
|
|
513
|
-
def create_prerelease(version, commit: true)
|
|
514
|
-
prerelease = PreRelease.new(version.increment(:pre), branch.version)
|
|
515
|
-
prerelease.create
|
|
516
|
-
submit "Created pre-release #{prerelease.version}", commit
|
|
517
|
-
build
|
|
518
|
-
prerelease
|
|
519
|
-
end
|
|
520
|
-
|
|
521
|
-
def increment_prerelease(commit: true)
|
|
522
|
-
prerelease = branch.increment
|
|
523
|
-
prerelease.create
|
|
524
|
-
submit "Created pre-release #{prerelease.version}", commit
|
|
525
|
-
build
|
|
526
|
-
prerelease
|
|
527
|
-
end
|
|
528
|
-
|
|
529
|
-
# # Turned out to be a bad idea
|
|
530
|
-
# def retarget_migration(version, commit: true)
|
|
531
|
-
# branch.retarget(version)
|
|
532
|
-
# commit "Retargeted to #{version}" if commit
|
|
533
|
-
# branch
|
|
534
|
-
# end
|
|
535
|
-
|
|
536
|
-
def create_feature(name, commit: true)
|
|
537
|
-
feature = Feature.new(name, version)
|
|
538
|
-
feature.create
|
|
539
|
-
submit "Created feature #{name}", commit
|
|
540
|
-
end
|
|
541
|
-
|
|
542
|
-
def include_feature(feature_version, commit: false)
|
|
543
|
-
Git.merge_branch(feature_version, exclude_files: [branch.schema.version_file], fail: true)
|
|
544
|
-
branch.include(feature_version)
|
|
545
|
-
end
|
|
546
|
-
|
|
547
|
-
# Checks that the migration of the current branch takes the database from
|
|
548
|
-
# the base version to the content of the schema
|
|
549
|
-
def check_migration(from_version)
|
|
550
|
-
begin
|
|
551
|
-
from_db = Database.new("#{name}-base", user)
|
|
552
|
-
to_db = Database.new("#{name}-next", user)
|
|
553
|
-
build(database: from_db, version: from_version)
|
|
554
|
-
build(database: to_db)
|
|
555
|
-
migration = # FIXME: This may be a repeated pattern
|
|
556
|
-
if migration?
|
|
557
|
-
branch.migration
|
|
558
|
-
elsif prerelease?
|
|
559
|
-
branch.migration
|
|
560
|
-
else
|
|
561
|
-
Migration.new(nil, branch.directory)
|
|
562
|
-
end
|
|
563
|
-
migration.migrate(from_db)
|
|
564
|
-
Diff.new(from_db, to_db).same?
|
|
565
|
-
ensure
|
|
566
|
-
from_db&.drop
|
|
567
|
-
to_db&.drop
|
|
568
|
-
end
|
|
569
|
-
end
|
|
570
|
-
|
|
571
|
-
# TODO: Make production-only and add a to-argument
|
|
572
|
-
def upgrade
|
|
573
|
-
branches = list_upgrades(database.version, branch.version)
|
|
574
|
-
FileUtils.mkdir_p(TMP_DIR)
|
|
575
|
-
Dir.mktmpdir("clone-", TMP_DIR) { |dir|
|
|
576
|
-
Command.command "git clone . #{dir}"
|
|
577
|
-
Dir.chdir(dir) {
|
|
578
|
-
branches.each { |branch|
|
|
579
|
-
branch.checkout_release
|
|
580
|
-
project = Project.load
|
|
581
|
-
project.branch.migrate(project.database)
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
end
|
|
586
|
-
|
|
587
|
-
def list_releases(all: false)
|
|
588
|
-
Git.list_tags(include_cancelled: all).grep(RELEASE_RE) { |tag|
|
|
589
|
-
version = $2
|
|
590
|
-
dir = File.join(RELEASES_DIR, version)
|
|
591
|
-
migration_state = MigrationState.new(dir).read(tag: tag)
|
|
592
|
-
Release.new(migration_state.version, migration_state.base_version)
|
|
593
|
-
}
|
|
594
|
-
end
|
|
595
|
-
|
|
596
|
-
# TODO
|
|
597
|
-
# list_migrations(all: false)
|
|
598
|
-
def list_migrations
|
|
599
|
-
Git.list_branches.grep(MIGRATION_RE) { |branch|
|
|
600
|
-
from_version = Version.new($1)
|
|
601
|
-
to_version = Version.new($4)
|
|
602
|
-
MigrationRelease.new(to_version, from_version)
|
|
603
|
-
}
|
|
604
|
-
end
|
|
605
|
-
|
|
606
|
-
def list_upgrades(from, to)
|
|
607
|
-
edges = (list_releases + list_migrations).map { |branch| [branch.base_version, branch.version, branch] }
|
|
608
|
-
(Algorithm.shortest_path(edges, from, to) || []).map(&:last)
|
|
609
|
-
end
|
|
610
|
-
|
|
611
|
-
private
|
|
612
|
-
def submit(msg, commit = true)
|
|
613
|
-
Git.commit msg if commit
|
|
614
|
-
@message = msg
|
|
615
|
-
end
|
|
616
|
-
|
|
617
|
-
def clean(database)
|
|
618
|
-
if database.exist?
|
|
619
|
-
database.recreate if database.loaded?
|
|
620
|
-
else
|
|
621
|
-
database.create
|
|
622
|
-
end
|
|
623
|
-
end
|
|
624
|
-
end
|
|
625
|
-
end
|
|
626
|
-
|