User ParticipantService linear ancestor scopes

In this commit we're replacing the recursive ancestors scope in
the `ParticipantService` class, for their linear version.

Changelog: performance
parent 532e3e3e
...@@ -36,14 +36,17 @@ module Projects ...@@ -36,14 +36,17 @@ module Projects
private private
def project_members_through_invited_groups def project_members_through_invited_groups
groups_with_ancestors_ids = Gitlab::ObjectHierarchy groups_with_ancestors = if ::Feature.enabled?(:linear_participants_service_ancestor_scopes, current_user, default_enabled: :yaml)
.new(visible_groups) visible_groups.self_and_ancestors
.base_and_ancestors else
.pluck_primary_key Gitlab::ObjectHierarchy
.new(visible_groups)
.base_and_ancestors
end
GroupMember GroupMember
.active_without_invites_and_requests .active_without_invites_and_requests
.with_source_id(groups_with_ancestors_ids) .with_source_id(groups_with_ancestors.pluck_primary_key)
end end
def visible_groups def visible_groups
......
---
name: linear_participants_service_ancestor_scopes
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70684
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/341348
milestone: '14.4'
type: development
group: group::access
default_enabled: false
...@@ -104,104 +104,116 @@ RSpec.describe Projects::ParticipantsService do ...@@ -104,104 +104,116 @@ RSpec.describe Projects::ParticipantsService do
describe '#project_members' do describe '#project_members' do
subject(:usernames) { service.project_members.map { |member| member[:username] } } subject(:usernames) { service.project_members.map { |member| member[:username] } }
context 'when there is a project in group namespace' do shared_examples 'return project members' do
let_it_be(:public_group) { create(:group, :public) } context 'when there is a project in group namespace' do
let_it_be(:public_project) { create(:project, :public, namespace: public_group)} let_it_be(:public_group) { create(:group, :public) }
let_it_be(:public_project) { create(:project, :public, namespace: public_group)}
let_it_be(:public_group_owner) { create(:user) } let_it_be(:public_group_owner) { create(:user) }
let(:service) { described_class.new(public_project, create(:user)) } let(:service) { described_class.new(public_project, create(:user)) }
before do before do
public_group.add_owner(public_group_owner) public_group.add_owner(public_group_owner)
end end
it 'returns members of a group' do it 'returns members of a group' do
expect(usernames).to include(public_group_owner.username) expect(usernames).to include(public_group_owner.username)
end
end end
end
context 'when there is a private group and a public project' do
let_it_be(:public_group) { create(:group, :public) }
let_it_be(:private_group) { create(:group, :private, :nested) }
let_it_be(:public_project) { create(:project, :public, namespace: public_group)}
let_it_be(:project_issue) { create(:issue, project: public_project)} context 'when there is a private group and a public project' do
let_it_be(:public_group) { create(:group, :public) }
let_it_be(:private_group) { create(:group, :private, :nested) }
let_it_be(:public_project) { create(:project, :public, namespace: public_group)}
let_it_be(:public_group_owner) { create(:user) } let_it_be(:project_issue) { create(:issue, project: public_project)}
let_it_be(:private_group_member) { create(:user) }
let_it_be(:public_project_maintainer) { create(:user) }
let_it_be(:private_group_owner) { create(:user) }
let_it_be(:group_ancestor_owner) { create(:user) } let_it_be(:public_group_owner) { create(:user) }
let_it_be(:private_group_member) { create(:user) }
let_it_be(:public_project_maintainer) { create(:user) }
let_it_be(:private_group_owner) { create(:user) }
before_all do let_it_be(:group_ancestor_owner) { create(:user) }
public_group.add_owner public_group_owner
private_group.add_developer private_group_member
public_project.add_maintainer public_project_maintainer
private_group.add_owner private_group_owner
private_group.parent.add_owner group_ancestor_owner
end
context 'when the private group is invited to the public project' do
before_all do before_all do
create(:project_group_link, group: private_group, project: public_project) public_group.add_owner public_group_owner
end private_group.add_developer private_group_member
public_project.add_maintainer public_project_maintainer
context 'when a user who is outside the public project and the private group is signed in' do private_group.add_owner private_group_owner
let(:service) { described_class.new(public_project, create(:user)) } private_group.parent.add_owner group_ancestor_owner
end
it 'does not return the private group' do context 'when the private group is invited to the public project' do
expect(usernames).not_to include(private_group.name) before_all do
create(:project_group_link, group: private_group, project: public_project)
end end
it 'does not return private group members' do context 'when a user who is outside the public project and the private group is signed in' do
expect(usernames).not_to include(private_group_member.username) let(:service) { described_class.new(public_project, create(:user)) }
end
it 'returns the project maintainer' do it 'does not return the private group' do
expect(usernames).to include(public_project_maintainer.username) expect(usernames).not_to include(private_group.name)
end end
it 'returns project members from an invited public group' do it 'does not return private group members' do
invited_public_group = create(:group, :public) expect(usernames).not_to include(private_group_member.username)
invited_public_group.add_owner create(:user) end
create(:project_group_link, group: invited_public_group, project: public_project) it 'returns the project maintainer' do
expect(usernames).to include(public_project_maintainer.username)
end
expect(usernames).to include(invited_public_group.users.first.username) it 'returns project members from an invited public group' do
end invited_public_group = create(:group, :public)
invited_public_group.add_owner create(:user)
it 'does not return ancestors of the private group' do create(:project_group_link, group: invited_public_group, project: public_project)
expect(usernames).not_to include(group_ancestor_owner.username)
end
end
context 'when private group owner is signed in' do expect(usernames).to include(invited_public_group.users.first.username)
let(:service) { described_class.new(public_project, private_group_owner) } end
it 'returns private group members' do it 'does not return ancestors of the private group' do
expect(usernames).to include(private_group_member.username) expect(usernames).not_to include(group_ancestor_owner.username)
end
end end
it 'returns ancestors of the the private group' do context 'when private group owner is signed in' do
expect(usernames).to include(group_ancestor_owner.username) let(:service) { described_class.new(public_project, private_group_owner) }
end
end
context 'when the namespace owner of the public project is signed in' do it 'returns private group members' do
let(:service) { described_class.new(public_project, public_group_owner) } expect(usernames).to include(private_group_member.username)
end
it 'returns private group members' do it 'returns ancestors of the the private group' do
expect(usernames).to include(private_group_member.username) expect(usernames).to include(group_ancestor_owner.username)
end
end end
it 'does not return members of the ancestral groups of the private group' do context 'when the namespace owner of the public project is signed in' do
expect(usernames).to include(group_ancestor_owner.username) let(:service) { described_class.new(public_project, public_group_owner) }
it 'returns private group members' do
expect(usernames).to include(private_group_member.username)
end
it 'does not return members of the ancestral groups of the private group' do
expect(usernames).to include(group_ancestor_owner.username)
end
end end
end end
end end
end end
it_behaves_like 'return project members'
context 'when feature flag :linear_participants_service_ancestor_scopes is disabled' do
before do
stub_feature_flags(linear_participants_service_ancestor_scopes: false)
end
it_behaves_like 'return project members'
end
end end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment