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
|
# frozen_string_literal: true
class UpdateIndexApprovalRuleNameForCodeOwnersRuleType < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
LEGACY_INDEX_NAME_RULE_TYPE = "index_approval_rule_name_for_code_owners_rule_type"
LEGACY_INDEX_NAME_CODE_OWNERS = "approval_rule_name_index_for_code_owners"
SECTIONAL_INDEX_NAME = "index_approval_rule_name_for_sectional_code_owners_rule_type"
CODE_OWNER_RULE_TYPE = 2
def up
unless index_exists_by_name?(:approval_merge_request_rules, SECTIONAL_INDEX_NAME)
# Ensure only 1 code_owner rule with the same name and section per merge_request
#
add_concurrent_index(
:approval_merge_request_rules,
[:merge_request_id, :name, :section],
unique: true,
where: "rule_type = #{CODE_OWNER_RULE_TYPE}",
name: SECTIONAL_INDEX_NAME
)
end
remove_concurrent_index_by_name :approval_merge_request_rules, LEGACY_INDEX_NAME_RULE_TYPE
remove_concurrent_index_by_name :approval_merge_request_rules, LEGACY_INDEX_NAME_CODE_OWNERS
add_concurrent_index(
:approval_merge_request_rules,
[:merge_request_id, :name],
unique: true,
where: "rule_type = #{CODE_OWNER_RULE_TYPE} AND section IS NULL",
name: LEGACY_INDEX_NAME_RULE_TYPE
)
add_concurrent_index(
:approval_merge_request_rules,
[:merge_request_id, :code_owner, :name],
unique: true,
where: "code_owner = true AND section IS NULL",
name: LEGACY_INDEX_NAME_CODE_OWNERS
)
end
def down
# In a rollback situation, we can't guarantee that there will not be
# records that were allowed under the more specific SECTIONAL_INDEX_NAME
# index but would cause uniqueness violations under both the
# LEGACY_INDEX_NAME_RULE_TYPE and LEGACY_INDEX_NAME_CODE_OWNERS indices.
# Therefore, we need to first find all the MergeRequests with
# ApprovalMergeRequestRules that would violate these "new" indices and
# delete those approval rules, then create the new index, then finally
# recreate the approval rules for those merge requests.
#
# First, find all MergeRequests with ApprovalMergeRequestRules that will
# violate the new index.
#
if Gitlab.ee?
merge_request_ids = ApprovalMergeRequestRule
.select(:merge_request_id)
.where(rule_type: CODE_OWNER_RULE_TYPE)
.group(:merge_request_id, :rule_type, :name)
.includes(:merge_request)
.having("count(*) > 1")
.collect(&:merge_request_id)
# Delete ALL their code_owner approval rules
#
merge_request_ids.each_slice(10) do |ids|
ApprovalMergeRequestRule.where(merge_request_id: ids).code_owner.delete_all
end
end
# Remove legacy partial indices that only apply to `section IS NULL` records
#
remove_concurrent_index_by_name :approval_merge_request_rules, LEGACY_INDEX_NAME_RULE_TYPE
remove_concurrent_index_by_name :approval_merge_request_rules, LEGACY_INDEX_NAME_CODE_OWNERS
# Reconstruct original "legacy" indices
#
add_concurrent_index(
:approval_merge_request_rules,
[:merge_request_id, :name],
unique: true,
where: "rule_type = #{CODE_OWNER_RULE_TYPE}",
name: LEGACY_INDEX_NAME_RULE_TYPE
)
add_concurrent_index(
:approval_merge_request_rules,
[:merge_request_id, :code_owner, :name],
unique: true,
where: "code_owner = true",
name: LEGACY_INDEX_NAME_CODE_OWNERS
)
# MergeRequest::SyncCodeOwnerApprovalRules recreates the code_owner rules
# from scratch, adding them to the index. Duplicates will be rejected.
#
if Gitlab.ee?
merge_request_ids.each_slice(10) do |ids|
MergeRequest.where(id: ids).each do |merge_request|
MergeRequests::SyncCodeOwnerApprovalRules.new(merge_request).execute
end
end
end
remove_concurrent_index_by_name :approval_merge_request_rules, SECTIONAL_INDEX_NAME
end
end
|