Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
fb4ad51b
Commit
fb4ad51b
authored
Jun 17, 2020
by
Kerri Miller
Committed by
Mayra Cabrera
Jun 17, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[RUN AS-IF-FOSS] Update indices on ApprovalMergeRequestRule
parent
fbe55cad
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
306 additions
and
4 deletions
+306
-4
changelogs/unreleased/215194-add-section-to-index_approval_rule_name_for_code_owners_rule_type.yml
...to-index_approval_rule_name_for_code_owners_rule_type.yml
+5
-0
db/migrate/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type.rb
...ate_index_approval_rule_name_for_code_owners_rule_type.rb
+116
-0
db/structure.sql
db/structure.sql
+5
-2
ee/spec/models/approval_merge_request_rule_spec.rb
ee/spec/models/approval_merge_request_rule_spec.rb
+2
-2
spec/migrations/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type_spec.rb
...ndex_approval_rule_name_for_code_owners_rule_type_spec.rb
+178
-0
No files found.
changelogs/unreleased/215194-add-section-to-index_approval_rule_name_for_code_owners_rule_type.yml
0 → 100644
View file @
fb4ad51b
---
title
:
Add :section to approval_merge_request_rule unique index
merge_request
:
34680
author
:
type
:
other
db/migrate/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type.rb
0 → 100644
View file @
fb4ad51b
# 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
db/structure.sql
View file @
fb4ad51b
...
@@ -9157,7 +9157,7 @@ CREATE UNIQUE INDEX any_approver_merge_request_rule_type_unique_index ON public.
...
@@ -9157,7 +9157,7 @@ CREATE UNIQUE INDEX any_approver_merge_request_rule_type_unique_index ON public.
CREATE
UNIQUE
INDEX
any_approver_project_rule_type_unique_index
ON
public
.
approval_project_rules
USING
btree
(
project_id
)
WHERE
(
rule_type
=
3
);
CREATE
UNIQUE
INDEX
any_approver_project_rule_type_unique_index
ON
public
.
approval_project_rules
USING
btree
(
project_id
)
WHERE
(
rule_type
=
3
);
CREATE
UNIQUE
INDEX
approval_rule_name_index_for_code_owners
ON
public
.
approval_merge_request_rules
USING
btree
(
merge_request_id
,
code_owner
,
name
)
WHERE
(
code_owner
=
true
);
CREATE
UNIQUE
INDEX
approval_rule_name_index_for_code_owners
ON
public
.
approval_merge_request_rules
USING
btree
(
merge_request_id
,
code_owner
,
name
)
WHERE
(
(
code_owner
=
true
)
AND
(
section
IS
NULL
)
);
CREATE
INDEX
ci_builds_gitlab_monitor_metrics
ON
public
.
ci_builds
USING
btree
(
status
,
created_at
,
project_id
)
WHERE
((
type
)::
text
=
'Ci::Build'
::
text
);
CREATE
INDEX
ci_builds_gitlab_monitor_metrics
ON
public
.
ci_builds
USING
btree
(
status
,
created_at
,
project_id
)
WHERE
((
type
)::
text
=
'Ci::Build'
::
text
);
...
@@ -9335,7 +9335,9 @@ CREATE UNIQUE INDEX index_approval_project_rules_users_1 ON public.approval_proj
...
@@ -9335,7 +9335,9 @@ CREATE UNIQUE INDEX index_approval_project_rules_users_1 ON public.approval_proj
CREATE
INDEX
index_approval_project_rules_users_2
ON
public
.
approval_project_rules_users
USING
btree
(
user_id
);
CREATE
INDEX
index_approval_project_rules_users_2
ON
public
.
approval_project_rules_users
USING
btree
(
user_id
);
CREATE
UNIQUE
INDEX
index_approval_rule_name_for_code_owners_rule_type
ON
public
.
approval_merge_request_rules
USING
btree
(
merge_request_id
,
name
)
WHERE
(
rule_type
=
2
);
CREATE
UNIQUE
INDEX
index_approval_rule_name_for_code_owners_rule_type
ON
public
.
approval_merge_request_rules
USING
btree
(
merge_request_id
,
name
)
WHERE
((
rule_type
=
2
)
AND
(
section
IS
NULL
));
CREATE
UNIQUE
INDEX
index_approval_rule_name_for_sectional_code_owners_rule_type
ON
public
.
approval_merge_request_rules
USING
btree
(
merge_request_id
,
name
,
section
)
WHERE
(
rule_type
=
2
);
CREATE
INDEX
index_approval_rules_code_owners_rule_type
ON
public
.
approval_merge_request_rules
USING
btree
(
merge_request_id
)
WHERE
(
rule_type
=
2
);
CREATE
INDEX
index_approval_rules_code_owners_rule_type
ON
public
.
approval_merge_request_rules
USING
btree
(
merge_request_id
)
WHERE
(
rule_type
=
2
);
...
@@ -13962,6 +13964,7 @@ COPY "schema_migrations" (version) FROM STDIN;
...
@@ -13962,6 +13964,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200526153844
20200526153844
20200526164946
20200526164946
20200526164947
20200526164947
20200526231421
20200527092027
20200527092027
20200527094322
20200527094322
20200527095401
20200527095401
...
...
ee/spec/models/approval_merge_request_rule_spec.rb
View file @
fb4ad51b
...
@@ -45,9 +45,9 @@ RSpec.describe ApprovalMergeRequestRule do
...
@@ -45,9 +45,9 @@ RSpec.describe ApprovalMergeRequestRule do
end
end
it
'is invalid when reusing the same name within the same merge request'
do
it
'is invalid when reusing the same name within the same merge request'
do
existing
=
create
(
:code_owner_rule
,
name:
'*.rb'
,
merge_request:
merge_request
)
existing
=
create
(
:code_owner_rule
,
name:
'*.rb'
,
merge_request:
merge_request
,
section:
'section'
)
new
=
build
(
:code_owner_rule
,
merge_request:
existing
.
merge_request
,
name:
'*.rb'
)
new
=
build
(
:code_owner_rule
,
merge_request:
existing
.
merge_request
,
name:
'*.rb'
,
section:
'section'
)
expect
(
new
).
not_to
be_valid
expect
(
new
).
not_to
be_valid
expect
{
new
.
save!
(
validate:
false
)
}.
to
raise_error
(
ActiveRecord
::
RecordNotUnique
)
expect
{
new
.
save!
(
validate:
false
)
}.
to
raise_error
(
ActiveRecord
::
RecordNotUnique
)
...
...
spec/migrations/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type_spec.rb
0 → 100644
View file @
fb4ad51b
# frozen_string_literal: true
require
'spec_helper'
require
Rails
.
root
.
join
(
'db'
,
'migrate'
,
'20200526231421_update_index_approval_rule_name_for_code_owners_rule_type.rb'
)
describe
UpdateIndexApprovalRuleNameForCodeOwnersRuleType
do
let
(
:migration
)
{
described_class
.
new
}
let
(
:approval_rules
)
{
table
(
:approval_merge_request_rules
)
}
let
(
:namespace
)
{
table
(
:namespaces
).
create!
(
name:
'gitlab'
,
path:
'gitlab'
)
}
let
(
:project
)
do
table
(
:projects
).
create!
(
namespace_id:
namespace
.
id
,
name:
'gitlab'
,
path:
'gitlab'
)
end
let
(
:merge_request
)
do
table
(
:merge_requests
).
create!
(
target_project_id:
project
.
id
,
source_project_id:
project
.
id
,
target_branch:
'feature'
,
source_branch:
'master'
)
end
let
(
:index_names
)
do
ActiveRecord
::
Base
.
connection
.
indexes
(
:approval_merge_request_rules
)
.
collect
(
&
:name
)
end
def
create_sectional_approval_rules
approval_rules
.
create!
(
merge_request_id:
merge_request
.
id
,
name:
"*.rb"
,
code_owner:
true
,
rule_type:
2
,
section:
"First Section"
)
approval_rules
.
create!
(
merge_request_id:
merge_request
.
id
,
name:
"*.rb"
,
code_owner:
true
,
rule_type:
2
,
section:
"Second Section"
)
end
def
create_two_matching_nil_section_approval_rules
2
.
times
do
approval_rules
.
create!
(
merge_request_id:
merge_request
.
id
,
name:
"nil_section"
,
code_owner:
true
,
rule_type:
2
)
end
end
before
do
approval_rules
.
delete_all
end
describe
"#up"
do
it
"creates the new index and removes the 'legacy' indices"
do
# Confirm that existing legacy indices prevent duplicate entries
#
expect
{
create_sectional_approval_rules
}
.
to
raise_exception
(
ActiveRecord
::
RecordNotUnique
)
expect
{
create_two_matching_nil_section_approval_rules
}
.
to
raise_exception
(
ActiveRecord
::
RecordNotUnique
)
approval_rules
.
delete_all
disable_migrations_output
{
migrate!
}
# After running the migration, expect `section == nil` rules to still
# be blocked by the legacy indices, but sectional rules are allowed.
#
expect
{
create_sectional_approval_rules
}
.
to
change
{
approval_rules
.
count
}.
by
(
2
)
expect
{
create_two_matching_nil_section_approval_rules
}
.
to
raise_exception
(
ActiveRecord
::
RecordNotUnique
)
# Attempt to rerun the creation of sectional rules, and see that sectional
# rules are unique by section
#
expect
{
create_sectional_approval_rules
}
.
to
raise_exception
(
ActiveRecord
::
RecordNotUnique
)
expect
(
index_names
).
to
include
(
described_class
::
SECTIONAL_INDEX_NAME
,
described_class
::
LEGACY_INDEX_NAME_RULE_TYPE
,
described_class
::
LEGACY_INDEX_NAME_CODE_OWNERS
)
end
end
describe
"#down"
do
context
"run as FOSS"
do
before
do
expect
(
Gitlab
).
to
receive
(
:ee?
).
twice
.
and_return
(
false
)
end
it
"recreates legacy indices, but does not invoke EE-specific code"
do
disable_migrations_output
{
migrate!
}
expect
(
index_names
).
to
include
(
described_class
::
SECTIONAL_INDEX_NAME
,
described_class
::
LEGACY_INDEX_NAME_RULE_TYPE
,
described_class
::
LEGACY_INDEX_NAME_CODE_OWNERS
)
# Since ApprovalMergeRequestRules are EE-specific, we expect none to
# be deleted during the migration.
#
expect
{
disable_migrations_output
{
migration
.
down
}
}
.
not_to
change
{
approval_rules
.
count
}
index_names
=
ActiveRecord
::
Base
.
connection
.
indexes
(
:approval_merge_request_rules
)
.
collect
(
&
:name
)
expect
(
index_names
).
not_to
include
(
described_class
::
SECTIONAL_INDEX_NAME
)
expect
(
index_names
).
to
include
(
described_class
::
LEGACY_INDEX_NAME_RULE_TYPE
,
described_class
::
LEGACY_INDEX_NAME_CODE_OWNERS
)
end
end
context
"EE"
do
it
"recreates 'legacy' indices and removes duplicate code owner approval rules"
do
skip
(
"This test is skipped under FOSS"
)
unless
Gitlab
.
ee?
disable_migrations_output
{
migrate!
}
expect
{
create_sectional_approval_rules
}
.
to
change
{
approval_rules
.
count
}.
by
(
2
)
expect
{
create_two_matching_nil_section_approval_rules
}
.
to
raise_exception
(
ActiveRecord
::
RecordNotUnique
)
# Run the down migration. This will remove the 2 approval rules we create
# above, and call MergeRequests::SyncCodeOwnerApprovalRules to recreate
# new ones.
#
expect
(
MergeRequests
::
SyncCodeOwnerApprovalRules
)
.
to
receive
(
:new
).
with
(
MergeRequest
.
find
(
merge_request
.
id
)).
once
.
and_call_original
# We expect approval_rules.count to be changed by -2 as we're deleting the
# 3 rules created above, and MergeRequests::SyncCodeOwnerApprovalRules
# will not be able to create new one with an empty (or missing)
# CODEOWNERS file.
#
expect
{
disable_migrations_output
{
migration
.
down
}
}
.
to
change
{
approval_rules
.
count
}.
by
(
-
3
)
# Test that the index does not allow us to create the same rules as the
# previous sectional index.
#
expect
{
create_sectional_approval_rules
}
.
to
raise_exception
(
ActiveRecord
::
RecordNotUnique
)
expect
{
create_two_matching_nil_section_approval_rules
}
.
to
raise_exception
(
ActiveRecord
::
RecordNotUnique
)
expect
(
index_names
).
not_to
include
(
described_class
::
SECTIONAL_INDEX_NAME
)
expect
(
index_names
).
to
include
(
described_class
::
LEGACY_INDEX_NAME_RULE_TYPE
,
described_class
::
LEGACY_INDEX_NAME_CODE_OWNERS
)
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment