1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
module Gitlab
# Checks if a set of migrations requires downtime or not.
class DowntimeCheck
# The constant containing the boolean that indicates if downtime is needed
# or not.
DOWNTIME_CONST = :DOWNTIME
# The constant that specifies the reason for the migration requiring
# downtime.
DOWNTIME_REASON_CONST = :DOWNTIME_REASON
# Checks the given migration paths and returns an Array of
# `Gitlab::DowntimeCheck::Message` instances.
#
# migrations - The migration file paths to check.
def check(migrations)
migrations.map do |path|
require(path)
migration_class = class_for_migration_file(path)
unless migration_class.const_defined?(DOWNTIME_CONST)
raise "The migration in #{path} does not specify if it requires " \
"downtime or not"
end
if online?(migration_class)
Message.new(path)
else
reason = downtime_reason(migration_class)
unless reason
raise "The migration in #{path} requires downtime but no reason " \
"was given"
end
Message.new(path, true, reason)
end
end
end
# Checks the given migrations and prints the results to STDOUT/STDERR.
#
# migrations - The migration file paths to check.
def check_and_print(migrations)
check(migrations).each do |message|
puts message.to_s # rubocop: disable Rails/Output
end
end
# Returns the class for the given migration file path.
def class_for_migration_file(path)
File.basename(path, File.extname(path)).split('_', 2).last.camelize
.constantize
end
# Returns true if the given migration can be performed without downtime.
def online?(migration)
migration.const_get(DOWNTIME_CONST) == false
end
# Returns the downtime reason, or nil if none was defined.
def downtime_reason(migration)
if migration.const_defined?(DOWNTIME_REASON_CONST)
migration.const_get(DOWNTIME_REASON_CONST)
else
nil
end
end
end
end