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
ff0125e3
Commit
ff0125e3
authored
3 years ago
by
Francisco Javier López
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use linear versions of descendants in GroupDescendantsFinder
parent
adddc040
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
201 additions
and
170 deletions
+201
-170
app/finders/group_descendants_finder.rb
app/finders/group_descendants_finder.rb
+14
-4
config/feature_flags/development/linear_group_descendants_finder.yml
...ure_flags/development/linear_group_descendants_finder.yml
+8
-0
spec/finders/group_descendants_finder_spec.rb
spec/finders/group_descendants_finder_spec.rb
+179
-166
No files found.
app/finders/group_descendants_finder.rb
View file @
ff0125e3
...
@@ -87,9 +87,13 @@ class GroupDescendantsFinder
...
@@ -87,9 +87,13 @@ class GroupDescendantsFinder
visible_to_user
=
visible_to_user
.
or
(
authorized_to_user
)
visible_to_user
=
visible_to_user
.
or
(
authorized_to_user
)
end
end
hierarchy_for_parent
group_to_query
=
if
Feature
.
enabled?
(
:linear_group_descendants_finder
,
current_user
,
default_enabled: :yaml
)
.
descendants
parent_group
.
where
(
visible_to_user
)
else
hierarchy_for_parent
end
group_to_query
.
descendants
.
where
(
visible_to_user
)
# rubocop: enable CodeReuse/Finder
# rubocop: enable CodeReuse/Finder
end
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: enable CodeReuse/ActiveRecord
...
@@ -155,7 +159,13 @@ class GroupDescendantsFinder
...
@@ -155,7 +159,13 @@ class GroupDescendantsFinder
# rubocop: disable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def
projects_matching_filter
def
projects_matching_filter
# rubocop: disable CodeReuse/Finder
# rubocop: disable CodeReuse/Finder
projects_nested_in_group
=
Project
.
where
(
namespace_id:
hierarchy_for_parent
.
base_and_descendants
.
select
(
:id
))
objects_in_hierarchy
=
if
Feature
.
enabled?
(
:linear_group_descendants_finder
,
current_user
,
default_enabled: :yaml
)
parent_group
.
self_and_descendants
.
as_ids
else
hierarchy_for_parent
.
base_and_descendants
.
select
(
:id
)
end
projects_nested_in_group
=
Project
.
where
(
namespace_id:
objects_in_hierarchy
)
params_with_search
=
params
.
merge
(
search:
params
[
:filter
])
params_with_search
=
params
.
merge
(
search:
params
[
:filter
])
ProjectsFinder
.
new
(
params:
params_with_search
,
ProjectsFinder
.
new
(
params:
params_with_search
,
...
...
This diff is collapsed.
Click to expand it.
config/feature_flags/development/linear_group_descendants_finder.yml
0 → 100644
View file @
ff0125e3
---
name
:
linear_group_descendants_finder
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68954
rollout_issue_url
:
https://gitlab.com/gitlab-org/gitlab/-/issues/339440
milestone
:
'
14.6'
type
:
development
group
:
group::access
default_enabled
:
false
This diff is collapsed.
Click to expand it.
spec/finders/group_descendants_finder_spec.rb
View file @
ff0125e3
...
@@ -4,7 +4,12 @@ require 'spec_helper'
...
@@ -4,7 +4,12 @@ require 'spec_helper'
RSpec
.
describe
GroupDescendantsFinder
do
RSpec
.
describe
GroupDescendantsFinder
do
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:group
)
{
create
(
:group
)
}
let_it_be_with_reload
(
:group
)
do
create
(
:group
).
tap
do
|
g
|
g
.
add_owner
(
user
)
end
end
let
(
:params
)
{
{}
}
let
(
:params
)
{
{}
}
...
@@ -12,254 +17,262 @@ RSpec.describe GroupDescendantsFinder do
...
@@ -12,254 +17,262 @@ RSpec.describe GroupDescendantsFinder do
described_class
.
new
(
current_user:
user
,
parent_group:
group
,
params:
params
)
described_class
.
new
(
current_user:
user
,
parent_group:
group
,
params:
params
)
end
end
before
do
shared_examples
'group descentants finder examples'
do
group
.
add_owner
(
user
)
describe
'#has_children?'
do
end
describe
'#has_children?'
do
it
'is true when there are projects'
do
create
(
:project
,
namespace:
group
)
expect
(
finder
.
has_children?
).
to
be_truthy
end
context
'when there are subgroups'
do
it
'is true when there are projects'
do
it
'is true when there are projects'
do
create
(
:
group
,
parent
:
group
)
create
(
:
project
,
namespace
:
group
)
expect
(
finder
.
has_children?
).
to
be_truthy
expect
(
finder
.
has_children?
).
to
be_truthy
end
end
end
end
describe
'#execute
'
do
context
'when there are subgroups
'
do
it
'includes
projects'
do
it
'is true when there are
projects'
do
project
=
create
(
:project
,
namespace
:
group
)
create
(
:group
,
parent
:
group
)
expect
(
finder
.
execute
).
to
contain_exactly
(
project
)
expect
(
finder
.
has_children?
).
to
be_truthy
end
end
end
end
context
'when archived is `true`'
do
describe
'#execute'
do
let
(
:params
)
{
{
archived:
'true'
}
}
it
'includes projects'
do
it
'includes archived projects'
do
archived_project
=
create
(
:project
,
namespace:
group
,
archived:
true
)
project
=
create
(
:project
,
namespace:
group
)
project
=
create
(
:project
,
namespace:
group
)
expect
(
finder
.
execute
).
to
contain_exactly
(
archived_project
,
project
)
expect
(
finder
.
execute
).
to
contain_exactly
(
project
)
end
end
end
context
'when archived is `only
`'
do
context
'when archived is `true
`'
do
let
(
:params
)
{
{
archived:
'only
'
}
}
let
(
:params
)
{
{
archived:
'true
'
}
}
it
'includes only
archived projects'
do
it
'includes
archived projects'
do
archived_project
=
create
(
:project
,
namespace:
group
,
archived:
true
)
archived_project
=
create
(
:project
,
namespace:
group
,
archived:
true
)
_
project
=
create
(
:project
,
namespace:
group
)
project
=
create
(
:project
,
namespace:
group
)
expect
(
finder
.
execute
).
to
contain_exactly
(
archived_project
)
expect
(
finder
.
execute
).
to
contain_exactly
(
archived_project
,
project
)
end
end
end
end
it
'does not include archived projects
'
do
context
'when archived is `only`
'
do
_archived_project
=
create
(
:project
,
:archived
,
namespace:
group
)
let
(
:params
)
{
{
archived:
'only'
}
}
expect
(
finder
.
execute
).
to
be_empty
it
'includes only archived projects'
do
end
archived_project
=
create
(
:project
,
namespace:
group
,
archived:
true
)
_project
=
create
(
:project
,
namespace:
group
)
context
'with a filter'
do
expect
(
finder
.
execute
).
to
contain_exactly
(
archived_project
)
let
(
:params
)
{
{
filter:
'test'
}
}
end
end
it
'includes only projects matching the filter'
do
it
'does not include archived projects'
do
_other_project
=
create
(
:project
,
namespace:
group
)
_archived_project
=
create
(
:project
,
:archived
,
namespace:
group
)
matching_project
=
create
(
:project
,
namespace:
group
,
name:
'testproject'
)
expect
(
finder
.
execute
).
to
contain_exactly
(
matching_project
)
expect
(
finder
.
execute
).
to
be_empty
end
end
end
it
'sorts elements by name as default'
do
context
'with a filter'
do
project1
=
create
(
:project
,
namespace:
group
,
name:
'z'
)
let
(
:params
)
{
{
filter:
'test'
}
}
project2
=
create
(
:project
,
namespace:
group
,
name:
'a'
)
expect
(
subject
.
execute
).
to
eq
([
project2
,
project1
])
it
'includes only projects matching the filter'
do
end
_other_project
=
create
(
:project
,
namespace:
group
)
matching_project
=
create
(
:project
,
namespace:
group
,
name:
'testproject'
)
context
'sorting by name'
do
expect
(
finder
.
execute
).
to
contain_exactly
(
matching_project
)
let!
(
:project1
)
{
create
(
:project
,
namespace:
group
,
name:
'a'
,
path:
'project-a'
)
}
end
let!
(
:project2
)
{
create
(
:project
,
namespace:
group
,
name:
'z'
,
path:
'project-z'
)
}
let
(
:params
)
do
{
sort:
'name_asc'
}
end
end
it
'sorts elements by name'
do
it
'sorts elements by name as default'
do
expect
(
subject
.
execute
).
to
eq
(
project1
=
create
(
:project
,
namespace:
group
,
name:
'z'
)
[
project2
=
create
(
:project
,
namespace:
group
,
name:
'a'
)
project1
,
project2
expect
(
subject
.
execute
).
to
match_array
([
project2
,
project1
])
]
)
end
end
context
'with nested groups'
do
context
'sorting by name'
do
let!
(
:subgroup1
)
{
create
(
:group
,
parent:
group
,
name:
'a'
,
path:
'sub-a'
)
}
let!
(
:project1
)
{
create
(
:project
,
namespace:
group
,
name:
'a'
,
path:
'project-a'
)
}
let!
(
:subgroup2
)
{
create
(
:group
,
parent:
group
,
name:
'z'
,
path:
'sub-z'
)
}
let!
(
:project2
)
{
create
(
:project
,
namespace:
group
,
name:
'z'
,
path:
'project-z'
)
}
let
(
:params
)
do
{
sort:
'name_asc'
}
end
it
'sorts elements by name'
do
it
'sorts elements by name'
do
expect
(
subject
.
execute
).
to
eq
(
expect
(
subject
.
execute
).
to
eq
(
[
[
subgroup1
,
subgroup2
,
project1
,
project1
,
project2
project2
]
]
)
)
end
end
end
end
it
'does not include projects shared with the group'
do
project
=
create
(
:project
,
namespace:
group
)
other_project
=
create
(
:project
)
other_project
.
project_group_links
.
create!
(
group:
group
,
group_access:
Gitlab
::
Access
::
MAINTAINER
)
expect
(
finder
.
execute
).
to
contain_exactly
(
project
)
context
'with nested groups'
do
end
let!
(
:subgroup1
)
{
create
(
:group
,
parent:
group
,
name:
'a'
,
path:
'sub-a'
)
}
end
let!
(
:subgroup2
)
{
create
(
:group
,
parent:
group
,
name:
'z'
,
path:
'sub-z'
)
}
it
'sorts elements by name'
do
expect
(
subject
.
execute
).
to
eq
(
[
subgroup1
,
subgroup2
,
project1
,
project2
]
)
end
end
end
context
'with shared groups'
do
it
'does not include projects shared with the group'
do
let_it_be
(
:other_group
)
{
create
(
:group
)
}
project
=
create
(
:project
,
namespace:
group
)
let_it_be
(
:shared_group_link
)
do
other_project
=
create
(
:project
)
create
(
:group_group_link
,
other_project
.
project_group_links
.
create!
(
group:
group
,
shared_group:
group
,
group_access:
Gitlab
::
Access
::
MAINTAINER
)
shared_with_group:
other_group
)
end
context
'without common ancestor'
do
expect
(
finder
.
execute
).
to
contain_exactly
(
project
)
it
{
expect
(
finder
.
execute
).
to
be_empty
}
end
end
end
context
'with common ancestor'
do
context
'with shared groups'
do
let_it_be
(
:common_ancestor
)
{
create
(
:group
)
}
let_it_be
(
:other_group
)
{
create
(
:group
)
}
let_it_be
(
:other_group
)
{
create
(
:group
,
parent:
common_ancestor
)
}
let_it_be
(
:shared_group_link
)
do
let_it_be
(
:group
)
{
create
(
:group
,
parent:
common_ancestor
)
}
create
(
:group_group_link
,
shared_group:
group
,
shared_with_group:
other_group
)
end
context
'
querying under the
common ancestor'
do
context
'
without
common ancestor'
do
it
{
expect
(
finder
.
execute
).
to
be_empty
}
it
{
expect
(
finder
.
execute
).
to
be_empty
}
end
end
context
'querying the common ancestor'
do
context
'with common ancestor'
do
subject
(
:finder
)
do
let_it_be
(
:common_ancestor
)
{
create
(
:group
)
}
described_class
.
new
(
current_user:
user
,
parent_group:
common_ancestor
,
params:
params
)
let_it_be
(
:other_group
)
{
create
(
:group
,
parent:
common_ancestor
)
}
let_it_be
(
:group
)
{
create
(
:group
,
parent:
common_ancestor
)
}
context
'querying under the common ancestor'
do
it
{
expect
(
finder
.
execute
).
to
be_empty
}
end
end
it
'contains shared subgroups'
do
context
'querying the common ancestor'
do
expect
(
finder
.
execute
).
to
contain_exactly
(
group
,
other_group
)
subject
(
:finder
)
do
described_class
.
new
(
current_user:
user
,
parent_group:
common_ancestor
,
params:
params
)
end
it
'contains shared subgroups'
do
expect
(
finder
.
execute
).
to
contain_exactly
(
group
,
other_group
)
end
end
end
end
end
end
end
end
context
'with nested groups'
do
context
'with nested groups'
do
let!
(
:project
)
{
create
(
:project
,
namespace:
group
)
}
let!
(
:project
)
{
create
(
:project
,
namespace:
group
)
}
let!
(
:subgroup
)
{
create
(
:group
,
:private
,
parent:
group
)
}
let!
(
:subgroup
)
{
create
(
:group
,
:private
,
parent:
group
)
}
describe
'#execute'
do
describe
'#execute'
do
it
'contains projects and subgroups'
do
it
'contains projects and subgroups'
do
expect
(
finder
.
execute
).
to
contain_exactly
(
subgroup
,
project
)
expect
(
finder
.
execute
).
to
contain_exactly
(
subgroup
,
project
)
end
end
it
'does not include subgroups the user does not have access to'
do
it
'does not include subgroups the user does not have access to'
do
subgroup
.
update!
(
visibility_level:
Gitlab
::
VisibilityLevel
::
PRIVATE
)
subgroup
.
update!
(
visibility_level:
Gitlab
::
VisibilityLevel
::
PRIVATE
)
public_subgroup
=
create
(
:group
,
:public
,
parent:
group
,
path:
'public-group'
)
public_subgroup
=
create
(
:group
,
:public
,
parent:
group
,
path:
'public-group'
)
other_subgroup
=
create
(
:group
,
:private
,
parent:
group
,
path:
'visible-private-group'
)
other_subgroup
=
create
(
:group
,
:private
,
parent:
group
,
path:
'visible-private-group'
)
other_user
=
create
(
:user
)
other_user
=
create
(
:user
)
other_subgroup
.
add_developer
(
other_user
)
other_subgroup
.
add_developer
(
other_user
)
finder
=
described_class
.
new
(
current_user:
other_user
,
parent_group:
group
)
finder
=
described_class
.
new
(
current_user:
other_user
,
parent_group:
group
)
expect
(
finder
.
execute
).
to
contain_exactly
(
public_subgroup
,
other_subgroup
)
expect
(
finder
.
execute
).
to
contain_exactly
(
public_subgroup
,
other_subgroup
)
end
end
it
'only includes public groups when no user is given'
do
it
'only includes public groups when no user is given'
do
public_subgroup
=
create
(
:group
,
:public
,
parent:
group
)
public_subgroup
=
create
(
:group
,
:public
,
parent:
group
)
_private_subgroup
=
create
(
:group
,
:private
,
parent:
group
)
_private_subgroup
=
create
(
:group
,
:private
,
parent:
group
)
finder
=
described_class
.
new
(
current_user:
nil
,
parent_group:
group
)
finder
=
described_class
.
new
(
current_user:
nil
,
parent_group:
group
)
expect
(
finder
.
execute
).
to
contain_exactly
(
public_subgroup
)
expect
(
finder
.
execute
).
to
contain_exactly
(
public_subgroup
)
end
end
context
'when archived is `true`'
do
context
'when archived is `true`'
do
let
(
:params
)
{
{
archived:
'true'
}
}
let
(
:params
)
{
{
archived:
'true'
}
}
it
'includes archived projects in the count of subgroups'
do
it
'includes archived projects in the count of subgroups'
do
create
(
:project
,
namespace:
subgroup
,
archived:
true
)
create
(
:project
,
namespace:
subgroup
,
archived:
true
)
expect
(
finder
.
execute
.
first
.
preloaded_project_count
).
to
eq
(
1
)
expect
(
finder
.
execute
.
first
.
preloaded_project_count
).
to
eq
(
1
)
end
end
end
end
context
'with a filter'
do
context
'with a filter'
do
let
(
:params
)
{
{
filter:
'test'
}
}
let
(
:params
)
{
{
filter:
'test'
}
}
it
'contains only matching projects and subgroups'
do
it
'contains only matching projects and subgroups'
do
matching_project
=
create
(
:project
,
namespace:
group
,
name:
'Testproject'
)
matching_project
=
create
(
:project
,
namespace:
group
,
name:
'Testproject'
)
matching_subgroup
=
create
(
:group
,
name:
'testgroup'
,
parent:
group
)
matching_subgroup
=
create
(
:group
,
name:
'testgroup'
,
parent:
group
)
expect
(
finder
.
execute
).
to
contain_exactly
(
matching_subgroup
,
matching_project
)
expect
(
finder
.
execute
).
to
contain_exactly
(
matching_subgroup
,
matching_project
)
end
end
it
'does not include subgroups the user does not have access to'
do
it
'does not include subgroups the user does not have access to'
do
_invisible_subgroup
=
create
(
:group
,
:private
,
parent:
group
,
name:
'test1'
)
_invisible_subgroup
=
create
(
:group
,
:private
,
parent:
group
,
name:
'test1'
)
other_subgroup
=
create
(
:group
,
:private
,
parent:
group
,
name:
'test2'
)
other_subgroup
=
create
(
:group
,
:private
,
parent:
group
,
name:
'test2'
)
public_subgroup
=
create
(
:group
,
:public
,
parent:
group
,
name:
'test3'
)
public_subgroup
=
create
(
:group
,
:public
,
parent:
group
,
name:
'test3'
)
other_subsubgroup
=
create
(
:group
,
:private
,
parent:
other_subgroup
,
name:
'test4'
)
other_subsubgroup
=
create
(
:group
,
:private
,
parent:
other_subgroup
,
name:
'test4'
)
other_user
=
create
(
:user
)
other_user
=
create
(
:user
)
other_subgroup
.
add_developer
(
other_user
)
other_subgroup
.
add_developer
(
other_user
)
finder
=
described_class
.
new
(
current_user:
other_user
,
finder
=
described_class
.
new
(
current_user:
other_user
,
parent_group:
group
,
parent_group:
group
,
params:
params
)
params:
params
)
expect
(
finder
.
execute
).
to
contain_exactly
(
other_subgroup
,
public_subgroup
,
other_subsubgroup
)
expect
(
finder
.
execute
).
to
contain_exactly
(
other_subgroup
,
public_subgroup
,
other_subsubgroup
)
end
end
context
'with matching children'
do
context
'with matching children'
do
it
'includes a group that has a subgroup matching the query and its parent'
do
it
'includes a group that has a subgroup matching the query and its parent'
do
matching_subgroup
=
create
(
:group
,
:private
,
name:
'testgroup'
,
parent:
subgroup
)
matching_subgroup
=
create
(
:group
,
:private
,
name:
'testgroup'
,
parent:
subgroup
)
expect
(
finder
.
execute
).
to
contain_exactly
(
subgroup
,
matching_subgroup
)
expect
(
finder
.
execute
).
to
contain_exactly
(
subgroup
,
matching_subgroup
)
end
end
it
'includes the parent of a matching project'
do
it
'includes the parent of a matching project'
do
matching_project
=
create
(
:project
,
namespace:
subgroup
,
name:
'Testproject'
)
matching_project
=
create
(
:project
,
namespace:
subgroup
,
name:
'Testproject'
)
expect
(
finder
.
execute
).
to
contain_exactly
(
subgroup
,
matching_project
)
expect
(
finder
.
execute
).
to
contain_exactly
(
subgroup
,
matching_project
)
end
end
context
'with a small page size'
do
context
'with a small page size'
do
let
(
:params
)
{
{
filter:
'test'
,
per_page:
1
}
}
let
(
:params
)
{
{
filter:
'test'
,
per_page:
1
}
}
it
'contains all the ancestors of a matching subgroup regardless the page size'
do
it
'contains all the ancestors of a matching subgroup regardless the page size'
do
subgroup
=
create
(
:group
,
:private
,
parent:
group
)
subgroup
=
create
(
:group
,
:private
,
parent:
group
)
matching
=
create
(
:group
,
:private
,
name:
'testgroup'
,
parent:
subgroup
)
matching
=
create
(
:group
,
:private
,
name:
'testgroup'
,
parent:
subgroup
)
expect
(
finder
.
execute
).
to
contain_exactly
(
subgroup
,
matching
)
expect
(
finder
.
execute
).
to
contain_exactly
(
subgroup
,
matching
)
end
end
end
end
it
'does not include the parent itself'
do
it
'does not include the parent itself'
do
group
.
update!
(
name:
'test'
)
group
.
update!
(
name:
'test'
)
expect
(
finder
.
execute
).
not_to
include
(
group
)
expect
(
finder
.
execute
).
not_to
include
(
group
)
end
end
end
end
end
end
end
end
end
end
end
it_behaves_like
'group descentants finder examples'
context
'when feature flag :linear_group_descendants_finder is disabled'
do
before
do
stub_feature_flags
(
linear_group_descendants_finder:
false
)
end
it_behaves_like
'group descentants finder examples'
end
end
end
This diff is collapsed.
Click to expand it.
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