summaryrefslogtreecommitdiff
path: root/db/migrate/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type.rb
diff options
context:
space:
mode:
Diffstat (limited to 'db/migrate/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type.rb')
-rw-r--r--db/migrate/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type.rb116
1 files changed, 116 insertions, 0 deletions
diff --git a/db/migrate/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type.rb b/db/migrate/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type.rb
new file mode 100644
index 00000000000..2483ff7f8fa
--- /dev/null
+++ b/db/migrate/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type.rb
@@ -0,0 +1,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