diff options
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.rb | 116 |
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 |