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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
# frozen_string_literal: true
module MigrationsHelpers
def active_record_base
ActiveRecord::Base
end
def table(name)
Class.new(active_record_base) do
self.table_name = name
self.inheritance_column = :_type_disabled
def self.name
table_name.singularize.camelcase
end
end
end
def migrations_paths
ActiveRecord::Migrator.migrations_paths
end
def migration_context
ActiveRecord::MigrationContext.new(migrations_paths)
end
def migrations
migration_context.migrations
end
def clear_schema_cache!
active_record_base.connection_pool.connections.each do |conn|
conn.schema_cache.clear!
end
end
def foreign_key_exists?(source, target = nil, column: nil)
ActiveRecord::Base.connection.foreign_keys(source).any? do |key|
if column
key.options[:column].to_s == column.to_s
else
key.to_table.to_s == target.to_s
end
end
end
def reset_column_in_all_models
clear_schema_cache!
# Reset column information for the most offending classes **after** we
# migrated the schema up, otherwise, column information could be
# outdated. We have a separate method for this so we can override it in EE.
active_record_base.descendants.each(&method(:reset_column_information))
end
def refresh_attribute_methods
# Without this, we get errors because of missing attributes, e.g.
# super: no superclass method `elasticsearch_indexing' for #<ApplicationSetting:0x00007f85628508d8>
# attr_encrypted also expects ActiveRecord attribute methods to be
# defined, or it will override the accessors:
# https://gitlab.com/gitlab-org/gitlab-ee/issues/8234#note_113976421
[ApplicationSetting, SystemHook].each do |model|
model.define_attribute_methods
end
end
def reset_column_information(klass)
klass.reset_column_information
end
# In some migration tests, we're using factories to create records,
# however those models might be depending on a schema version which
# doesn't have the columns we want in application_settings.
# In these cases, we'll need to use the fake application settings
# as if we have migrations pending
def use_fake_application_settings
# We stub this way because we can't stub on
# `current_application_settings` due to `method_missing` is
# depending on current_application_settings...
allow(ActiveRecord::Base.connection)
.to receive(:active?)
.and_return(false)
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
end
def previous_migration
migrations.each_cons(2) do |previous, migration|
break previous if migration.name == described_class.name
end
end
def migration_schema_version
metadata_schema = self.class.metadata[:schema]
if metadata_schema == :latest
migrations.last.version
else
metadata_schema || previous_migration.version
end
end
def schema_migrate_down!
disable_migrations_output do
migration_context.down(migration_schema_version)
end
reset_column_in_all_models
end
def schema_migrate_up!
reset_column_in_all_models
disable_migrations_output do
migration_context.up
end
reset_column_in_all_models
refresh_attribute_methods
end
def disable_migrations_output
ActiveRecord::Migration.verbose = false
yield
ensure
ActiveRecord::Migration.verbose = true
end
def migrate!
migration_context.up do |migration|
migration.name == described_class.name
end
end
end
|