Commit 1b7e01d5 authored by Lin Jen-Shin's avatar Lin Jen-Shin

Merge branch 'remove-nested-groups-checks-ee' into 'master'

[EE] Remove code related to object hierarchy in MySQL

See merge request gitlab-org/gitlab-ee!14820
parents f0601d51 e218a8df
...@@ -421,7 +421,7 @@ class ApplicationController < ActionController::Base ...@@ -421,7 +421,7 @@ class ApplicationController < ActionController::Base
end end
def manifest_import_enabled? def manifest_import_enabled?
Group.supports_nested_objects? && Gitlab::CurrentSettings.import_sources.include?('manifest') Gitlab::CurrentSettings.import_sources.include?('manifest')
end end
def phabricator_import_enabled? def phabricator_import_enabled?
......
...@@ -32,7 +32,6 @@ module GroupTree ...@@ -32,7 +32,6 @@ module GroupTree
def filtered_groups_with_ancestors(groups) def filtered_groups_with_ancestors(groups)
filtered_groups = groups.search(params[:filter]).page(params[:page]) filtered_groups = groups.search(params[:filter]).page(params[:page])
if Group.supports_nested_objects?
# We find the ancestors by ID of the search results here. # We find the ancestors by ID of the search results here.
# Otherwise the ancestors would also have filters applied, # Otherwise the ancestors would also have filters applied,
# which would cause them not to be preloaded. # which would cause them not to be preloaded.
...@@ -41,9 +40,6 @@ module GroupTree ...@@ -41,9 +40,6 @@ module GroupTree
# make sure ancestors are not cut off by pagination. # make sure ancestors are not cut off by pagination.
Gitlab::ObjectHierarchy.new(Group.where(id: filtered_groups.select(:id))) Gitlab::ObjectHierarchy.new(Group.where(id: filtered_groups.select(:id)))
.base_and_ancestors .base_and_ancestors
else
filtered_groups
end
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
end end
...@@ -132,8 +132,6 @@ class GroupDescendantsFinder ...@@ -132,8 +132,6 @@ class GroupDescendantsFinder
end end
def subgroups def subgroups
return Group.none unless Group.supports_nested_objects?
# When filtering subgroups, we want to find all matches within the tree of # When filtering subgroups, we want to find all matches within the tree of
# descendants to show to the user # descendants to show to the user
groups = if params[:filter] groups = if params[:filter]
......
...@@ -14,12 +14,10 @@ module Types ...@@ -14,12 +14,10 @@ module Types
group.avatar_url(only_path: false) group.avatar_url(only_path: false)
end end
if ::Group.supports_nested_objects?
field :parent, GroupType, field :parent, GroupType,
null: true, null: true,
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.parent_id).find } resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.parent_id).find }
end end
end
end end
Types::GroupType.prepend(EE::Types::GroupType) Types::GroupType.prepend(EE::Types::GroupType)
...@@ -127,10 +127,6 @@ module GroupsHelper ...@@ -127,10 +127,6 @@ module GroupsHelper
groups.to_json groups.to_json
end end
def supports_nested_groups?
Group.supports_nested_objects?
end
private private
def get_group_sidebar_links def get_group_sidebar_links
......
# frozen_string_literal: true
module Descendant
extend ActiveSupport::Concern
class_methods do
def supports_nested_objects?
Gitlab::Database.postgresql?
end
end
end
...@@ -10,7 +10,6 @@ class Group < Namespace ...@@ -10,7 +10,6 @@ class Group < Namespace
include Referable include Referable
include SelectForProjectAuthorization include SelectForProjectAuthorization
include LoadedInGroupList include LoadedInGroupList
include Descendant
include GroupDescendant include GroupDescendant
include TokenAuthenticatable include TokenAuthenticatable
include WithUploads include WithUploads
......
...@@ -332,8 +332,6 @@ class Namespace < ApplicationRecord ...@@ -332,8 +332,6 @@ class Namespace < ApplicationRecord
end end
def force_share_with_group_lock_on_descendants def force_share_with_group_lock_on_descendants
return unless Group.supports_nested_objects?
# We can't use `descendants.update_all` since Rails will throw away the WITH # We can't use `descendants.update_all` since Rails will throw away the WITH
# RECURSIVE statement. We also can't use WHERE EXISTS since we can't use # RECURSIVE statement. We also can't use WHERE EXISTS since we can't use
# different table aliases, hence we're just using WHERE IN. Since we have a # different table aliases, hence we're just using WHERE IN. Since we have a
......
...@@ -16,8 +16,6 @@ class GroupPolicy < BasePolicy ...@@ -16,8 +16,6 @@ class GroupPolicy < BasePolicy
condition(:maintainer) { access_level >= GroupMember::MAINTAINER } condition(:maintainer) { access_level >= GroupMember::MAINTAINER }
condition(:reporter) { access_level >= GroupMember::REPORTER } condition(:reporter) { access_level >= GroupMember::REPORTER }
condition(:nested_groups_supported, scope: :global) { Group.supports_nested_objects? }
condition(:has_parent, scope: :subject) { @subject.has_parent? } condition(:has_parent, scope: :subject) { @subject.has_parent? }
condition(:share_with_group_locked, scope: :subject) { @subject.share_with_group_lock? } condition(:share_with_group_locked, scope: :subject) { @subject.share_with_group_lock? }
condition(:parent_share_with_group_locked, scope: :subject) { @subject.parent&.share_with_group_lock? } condition(:parent_share_with_group_locked, scope: :subject) { @subject.parent&.share_with_group_lock? }
...@@ -108,8 +106,8 @@ class GroupPolicy < BasePolicy ...@@ -108,8 +106,8 @@ class GroupPolicy < BasePolicy
enable :read_nested_project_resources enable :read_nested_project_resources
end end
rule { owner & nested_groups_supported }.enable :create_subgroup rule { owner }.enable :create_subgroup
rule { maintainer & maintainer_can_create_group & nested_groups_supported }.enable :create_subgroup rule { maintainer & maintainer_can_create_group }.enable :create_subgroup
rule { public_group | logged_in_viewable }.enable :view_globally rule { public_group | logged_in_viewable }.enable :view_globally
......
...@@ -18,10 +18,6 @@ module Groups ...@@ -18,10 +18,6 @@ module Groups
return namespace return namespace
end end
if group_path.include?('/') && !Group.supports_nested_objects?
raise 'Nested groups are not supported on MySQL'
end
create_group_path create_group_path
end end
......
...@@ -43,7 +43,6 @@ module Groups ...@@ -43,7 +43,6 @@ module Groups
def ensure_allowed_transfer def ensure_allowed_transfer
raise_transfer_error(:group_is_already_root) if group_is_already_root? raise_transfer_error(:group_is_already_root) if group_is_already_root?
raise_transfer_error(:database_not_supported) unless Group.supports_nested_objects?
raise_transfer_error(:same_parent_as_current) if same_parent? raise_transfer_error(:same_parent_as_current) if same_parent?
raise_transfer_error(:invalid_policies) unless valid_policies? raise_transfer_error(:invalid_policies) unless valid_policies?
raise_transfer_error(:namespace_with_same_path) if namespace_with_same_path? raise_transfer_error(:namespace_with_same_path) if namespace_with_same_path?
......
...@@ -31,7 +31,7 @@ module Members ...@@ -31,7 +31,7 @@ module Members
return unless member.is_a?(GroupMember) && member.user && member.group return unless member.is_a?(GroupMember) && member.user && member.group
delete_project_members(member) delete_project_members(member)
delete_subgroup_members(member) if Group.supports_nested_objects? delete_subgroup_members(member)
end end
def delete_project_members(member) def delete_project_members(member)
......
...@@ -102,13 +102,7 @@ module Users ...@@ -102,13 +102,7 @@ module Users
end end
def fresh_authorizations def fresh_authorizations
klass = if Group.supports_nested_objects? Gitlab::ProjectAuthorizations.new(user).calculate
Gitlab::ProjectAuthorizations::WithNestedGroups
else
Gitlab::ProjectAuthorizations::WithoutNestedGroups
end
klass.new(user).calculate
end end
end end
end end
...@@ -23,8 +23,7 @@ ...@@ -23,8 +23,7 @@
= f.submit 'Change group path', class: 'btn btn-warning' = f.submit 'Change group path', class: 'btn btn-warning'
- if supports_nested_groups? .sub-section
.sub-section
%h4.warning-title Transfer group %h4.warning-title Transfer group
= form_for @group, url: transfer_group_path(@group), method: :put do |f| = form_for @group, url: transfer_group_path(@group), method: :put do |f|
.form-group .form-group
......
...@@ -25,7 +25,6 @@ export default { ...@@ -25,7 +25,6 @@ export default {
'canUpdate', 'canUpdate',
'canDestroy', 'canDestroy',
'canAdmin', 'canAdmin',
'subepicsSupported',
'initialTitleHtml', 'initialTitleHtml',
'initialTitleText', 'initialTitleText',
'initialDescriptionHtml', 'initialDescriptionHtml',
...@@ -64,7 +63,7 @@ export default { ...@@ -64,7 +63,7 @@ export default {
/> />
</div> </div>
<related-items <related-items
v-if="subepicsSupported && !isEpicTreeEnabled" v-if="!isEpicTreeEnabled"
:endpoint="epicLinksEndpoint" :endpoint="epicLinksEndpoint"
:can-admin="canAdmin" :can-admin="canAdmin"
:can-reorder="canAdmin" :can-reorder="canAdmin"
......
...@@ -21,7 +21,6 @@ export default () => ({ ...@@ -21,7 +21,6 @@ export default () => ({
canUpdate: false, canUpdate: false,
canDestroy: false, canDestroy: false,
canAdmin: false, canAdmin: false,
subepicsSupported: false,
// Epic Information // Epic Information
epicId: 0, epicId: 0,
......
...@@ -3,8 +3,6 @@ ...@@ -3,8 +3,6 @@
class Groups::EpicLinksController < Groups::ApplicationController class Groups::EpicLinksController < Groups::ApplicationController
include EpicRelations include EpicRelations
before_action :check_nested_support!
def update def update
result = EpicLinks::UpdateService.new(child_epic, current_user, params[:epic]).execute result = EpicLinks::UpdateService.new(child_epic, current_user, params[:epic]).execute
...@@ -30,8 +28,4 @@ class Groups::EpicLinksController < Groups::ApplicationController ...@@ -30,8 +28,4 @@ class Groups::EpicLinksController < Groups::ApplicationController
def child_epic def child_epic
@child_epic ||= Epic.find(params[:id]) @child_epic ||= Epic.find(params[:id])
end end
def check_nested_support!
render_404 unless Epic.supports_nested_objects?
end
end end
...@@ -21,7 +21,6 @@ module EE ...@@ -21,7 +21,6 @@ module EE
if parent.is_a?(Group) if parent.is_a?(Group)
data[:issueLinksEndpoint] = group_epic_issues_path(parent, issuable) data[:issueLinksEndpoint] = group_epic_issues_path(parent, issuable)
data[:epicLinksEndpoint] = group_epic_links_path(parent, issuable) data[:epicLinksEndpoint] = group_epic_links_path(parent, issuable)
data[:subepicsSupported] = ::Epic.supports_nested_objects?
data[:fullPath] = parent.full_path data[:fullPath] = parent.full_path
end end
......
...@@ -12,7 +12,6 @@ module EE ...@@ -12,7 +12,6 @@ module EE
include Referable include Referable
include Awardable include Awardable
include LabelEventable include LabelEventable
include Descendant
include RelativePositioning include RelativePositioning
enum state: { opened: 1, closed: 2 } enum state: { opened: 1, closed: 2 }
...@@ -164,8 +163,6 @@ module EE ...@@ -164,8 +163,6 @@ module EE
# epic2 - parent: epic1 # epic2 - parent: epic1
# Returns: 2 # Returns: 2
def deepest_relationship_level def deepest_relationship_level
return unless supports_nested_objects?
::Gitlab::ObjectHierarchy.new(self.where(parent_id: nil)).max_descendants_depth ::Gitlab::ObjectHierarchy.new(self.where(parent_id: nil)).max_descendants_depth
end end
......
...@@ -82,7 +82,7 @@ module EE ...@@ -82,7 +82,7 @@ module EE
end end
def action_allowed? def action_allowed?
::Epic.supports_nested_objects? && quick_action_target.group&.feature_available?(:epics) && quick_action_target.group&.feature_available?(:epics) &&
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target) current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
end end
end end
......
...@@ -141,12 +141,9 @@ module EE ...@@ -141,12 +141,9 @@ module EE
projects_with_packages: count(::Packages::Package.select('distinct project_id')), projects_with_packages: count(::Packages::Package.select('distinct project_id')),
projects_with_prometheus_alerts: count(PrometheusAlert.distinct_projects), projects_with_prometheus_alerts: count(PrometheusAlert.distinct_projects),
projects_with_tracing_enabled: count(ProjectTracingSetting) projects_with_tracing_enabled: count(ProjectTracingSetting)
}).merge(service_desk_counts).merge(security_products_usage) }).merge(service_desk_counts)
.merge(security_products_usage)
# MySql does not support recursive queries so we can't retrieve epics relationship depth .merge(epics_deepest_relationship_level)
if ::Group.supports_nested_objects?
usage_data[:counts] = usage_data[:counts].merge(epics_deepest_relationship_level)
end
usage_data usage_data
end end
......
# frozen_string_literal: true # frozen_string_literal: true
require 'spec_helper' require 'spec_helper'
describe Admin::Geo::NodesController, :postgresql do describe Admin::Geo::NodesController do
shared_examples 'unlicensed geo action' do shared_examples 'unlicensed geo action' do
it 'redirects to the license page' do it 'redirects to the license page' do
expect(response).to redirect_to(admin_license_path) expect(response).to redirect_to(admin_license_path)
......
...@@ -93,7 +93,7 @@ describe EE::RoutableActions::SsoEnforcementRedirect do ...@@ -93,7 +93,7 @@ describe EE::RoutableActions::SsoEnforcementRedirect do
it_behaves_like 'a routable SSO url' it_behaves_like 'a routable SSO url'
end end
context 'with a nested group', :nested_groups do context 'with a nested group' do
subject { described_class.new(nested_group) } subject { described_class.new(nested_group) }
it_behaves_like 'a routable SSO url' it_behaves_like 'a routable SSO url'
...@@ -105,7 +105,7 @@ describe EE::RoutableActions::SsoEnforcementRedirect do ...@@ -105,7 +105,7 @@ describe EE::RoutableActions::SsoEnforcementRedirect do
it_behaves_like 'a routable SSO url' it_behaves_like 'a routable SSO url'
end end
context 'with a nested project', :nested_groups do context 'with a nested project' do
subject { described_class.new(nested_project) } subject { described_class.new(nested_project) }
it_behaves_like 'a routable SSO url' it_behaves_like 'a routable SSO url'
......
...@@ -58,7 +58,7 @@ describe RoutableActions do ...@@ -58,7 +58,7 @@ describe RoutableActions do
include_examples 'sso redirects' include_examples 'sso redirects'
end end
describe 'for a nested group', :nested_groups do describe 'for a nested group' do
let(:routable) { create(:group, :private, parent: root_group) } let(:routable) { create(:group, :private, parent: root_group) }
include_examples 'sso redirects' include_examples 'sso redirects'
...@@ -70,7 +70,7 @@ describe RoutableActions do ...@@ -70,7 +70,7 @@ describe RoutableActions do
include_examples 'sso redirects' include_examples 'sso redirects'
end end
describe 'for a nested project', :nested_groups do describe 'for a nested project' do
let(:routable) { create(:project, :private, group: create(:group, :private, parent: root_group)) } let(:routable) { create(:project, :private, group: create(:group, :private, parent: root_group)) }
include_examples 'sso redirects' include_examples 'sso redirects'
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Groups::EpicLinksController, :postgresql do describe Groups::EpicLinksController do
let(:group) { create(:group, :public) } let(:group) { create(:group, :public) }
let(:parent_epic) { create(:epic, group: group) } let(:parent_epic) { create(:epic, group: group) }
let(:epic1) { create(:epic, group: group) } let(:epic1) { create(:epic, group: group) }
......
...@@ -96,7 +96,7 @@ describe Groups::SamlProvidersController do ...@@ -96,7 +96,7 @@ describe Groups::SamlProvidersController do
expect(assigns(:scim_token_url)).to eq("http://localhost/api/scim/v2/groups/#{group.full_path}") expect(assigns(:scim_token_url)).to eq("http://localhost/api/scim/v2/groups/#{group.full_path}")
end end
context 'not on a top level group', :nested_groups do context 'not on a top level group' do
let(:group) { create(:group, :nested) } let(:group) { create(:group, :nested) }
it_behaves_like '404 status' it_behaves_like '404 status'
......
...@@ -158,7 +158,7 @@ describe 'Billing plan pages', :feature do ...@@ -158,7 +158,7 @@ describe 'Billing plan pages', :feature do
end end
end end
context 'on sub-group', :nested_groups do context 'on sub-group' do
let(:user2) { create(:user) } let(:user2) { create(:user) }
let(:user3) { create(:user) } let(:user3) { create(:user) }
let(:group) { create(:group, plan: :bronze_plan) } let(:group) { create(:group, plan: :bronze_plan) }
......
...@@ -55,7 +55,7 @@ describe 'Epic Issues', :js do ...@@ -55,7 +55,7 @@ describe 'Epic Issues', :js do
expect(page).not_to have_selector('.related-items-tree-container .js-add-issues-button') expect(page).not_to have_selector('.related-items-tree-container .js-add-issues-button')
end end
it 'user cannot add new epics to the epic', :postgresql do it 'user cannot add new epics to the epic' do
expect(page).not_to have_selector('.related-items-tree-container .js-add-epics-button') expect(page).not_to have_selector('.related-items-tree-container .js-add-epics-button')
end end
end end
...@@ -109,7 +109,7 @@ describe 'Epic Issues', :js do ...@@ -109,7 +109,7 @@ describe 'Epic Issues', :js do
end end
end end
it 'user can see all epics of the group and delete the associations', :postgresql do it 'user can see all epics of the group and delete the associations' do
within('.related-items-tree-container ul.related-items-list') do within('.related-items-tree-container ul.related-items-list') do
expect(page).to have_selector('li.js-item-type-epic', count: 2) expect(page).to have_selector('li.js-item-type-epic', count: 2)
expect(page).to have_content(nested_epics[0].title) expect(page).to have_content(nested_epics[0].title)
...@@ -146,7 +146,7 @@ describe 'Epic Issues', :js do ...@@ -146,7 +146,7 @@ describe 'Epic Issues', :js do
end end
end end
it 'user can add new epics to the epic', :postgresql do it 'user can add new epics to the epic' do
references = "#{epic_to_add.to_reference(full: true)}" references = "#{epic_to_add.to_reference(full: true)}"
add_epics(references) add_epics(references)
......
...@@ -148,7 +148,7 @@ describe 'Edit group settings' do ...@@ -148,7 +148,7 @@ describe 'Edit group settings' do
end end
end end
context 'when custom_project_templates feature', :postgresql do context 'when custom_project_templates feature' do
let!(:subgroup) { create(:group, :public, parent: group) } let!(:subgroup) { create(:group, :public, parent: group) }
let!(:subgroup_1) { create(:group, :public, parent: subgroup) } let!(:subgroup_1) { create(:group, :public, parent: subgroup) }
......
require 'spec_helper' require 'spec_helper'
describe 'Labels Hierarchy', :js, :nested_groups do describe 'Labels Hierarchy', :js do
let!(:user) { create(:user) } let!(:user) { create(:user) }
let!(:grandparent) { create(:group) } let!(:grandparent) { create(:group) }
let!(:parent) { create(:group, parent: grandparent) } let!(:parent) { create(:group, parent: grandparent) }
......
...@@ -104,7 +104,7 @@ describe 'Project > Members > Invite group and members', :js do ...@@ -104,7 +104,7 @@ describe 'Project > Members > Invite group and members', :js do
end end
end end
context 'for a project in a subgroup', :nested_groups do context 'for a project in a subgroup' do
let(:root_group) { create(:group) } let(:root_group) { create(:group) }
let(:subgroup) { create(:group, parent: root_group) } let(:subgroup) { create(:group, parent: root_group) }
let(:project) { create(:project, namespace: subgroup) } let(:project) { create(:project, namespace: subgroup) }
......
...@@ -177,7 +177,7 @@ describe 'New project' do ...@@ -177,7 +177,7 @@ describe 'New project' do
end end
end end
context 'Group-level project templates', :js, :postgresql do context 'Group-level project templates', :js do
def visit_create_from_group_template_tab def visit_create_from_group_template_tab
visit url visit url
click_link 'Create from template' click_link 'Create from template'
......
...@@ -18,7 +18,7 @@ describe Boards::MilestonesFinder do ...@@ -18,7 +18,7 @@ describe Boards::MilestonesFinder do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:finder) { described_class.new(board, user) } let(:finder) { described_class.new(board, user) }
context 'when project board', :nested_groups do context 'when project board' do
let(:board) { create(:board, project: nested_group_project, group: nil) } let(:board) { create(:board, project: nested_group_project, group: nil) }
it 'returns milestones from board project and ancestors groups' do it 'returns milestones from board project and ancestors groups' do
...@@ -32,7 +32,7 @@ describe Boards::MilestonesFinder do ...@@ -32,7 +32,7 @@ describe Boards::MilestonesFinder do
end end
end end
context 'when group board', :nested_groups do context 'when group board' do
let(:board) { create(:board, project: nil, group: nested_group) } let(:board) { create(:board, project: nil, group: nested_group) }
it 'returns milestones from board group and its ancestors' do it 'returns milestones from board group and its ancestors' do
......
...@@ -110,7 +110,7 @@ describe EpicsFinder do ...@@ -110,7 +110,7 @@ describe EpicsFinder do
end end
end end
context 'when subgroups are supported', :nested_groups do context 'when subgroups are supported' do
let(:subgroup) { create(:group, :private, parent: group) } let(:subgroup) { create(:group, :private, parent: group) }
let(:subgroup2) { create(:group, :private, parent: subgroup) } let(:subgroup2) { create(:group, :private, parent: subgroup) }
let!(:subepic1) { create(:epic, group: subgroup) } let!(:subepic1) { create(:epic, group: subgroup) }
......
require 'spec_helper' require 'spec_helper'
describe Geo::RepositoryVerificationFinder, :postgresql do describe Geo::RepositoryVerificationFinder do
set(:project) { create(:project) } set(:project) { create(:project) }
describe '#find_failed_repositories' do describe '#find_failed_repositories' do
......
...@@ -60,7 +60,7 @@ describe Resolvers::EpicResolver do ...@@ -60,7 +60,7 @@ describe Resolvers::EpicResolver do
end end
end end
context 'with subgroups', :nested_groups do context 'with subgroups' do
let(:sub_group) { create(:group, parent: group) } let(:sub_group) { create(:group, parent: group) }
let(:iids) { [epic1, epic2].map(&:iid) } let(:iids) { [epic1, epic2].map(&:iid) }
let!(:epic3) { create(:epic, group: sub_group, iid: epic1.iid) } let!(:epic3) { create(:epic, group: sub_group, iid: epic1.iid) }
......
...@@ -35,8 +35,7 @@ describe IssuablesHelper do ...@@ -35,8 +35,7 @@ describe IssuablesHelper do
initialTitleText: epic.title, initialTitleText: epic.title,
initialDescriptionHtml: '<p dir="auto">epic text</p>', initialDescriptionHtml: '<p dir="auto">epic text</p>',
initialDescriptionText: 'epic text', initialDescriptionText: 'epic text',
initialTaskStatus: '0 of 0 tasks completed', initialTaskStatus: '0 of 0 tasks completed'
subepicsSupported: Gitlab::Database.postgresql?
} }
expect(helper.issuable_initial_data(epic)).to eq(expected_data) expect(helper.issuable_initial_data(epic)).to eq(expected_data)
end end
......
# frozen_string_literal: true # frozen_string_literal: true
require 'spec_helper' require 'spec_helper'
describe EE::NamespacesHelper, :postgresql do describe EE::NamespacesHelper do
let!(:admin) { create(:admin) } let!(:admin) { create(:admin) }
let!(:admin_project_creation_level) { nil } let!(:admin_project_creation_level) { nil }
let!(:admin_group) do let!(:admin_group) do
......
require 'spec_helper' require 'spec_helper'
describe EE::API::Entities::GeoNodeStatus, :postgresql do describe EE::API::Entities::GeoNodeStatus do
include ::EE::GeoHelpers include ::EE::GeoHelpers
let(:geo_node_status) { build(:geo_node_status) } let(:geo_node_status) { build(:geo_node_status) }
......
...@@ -83,7 +83,7 @@ describe Gitlab::CustomFileTemplates do ...@@ -83,7 +83,7 @@ describe Gitlab::CustomFileTemplates do
end end
end end
context 'in a subgroup', :nested_groups do context 'in a subgroup' do
set(:subgroup) { create(:group, parent: group) } set(:subgroup) { create(:group, parent: group) }
set(:subproject) { create(:project, namespace: subgroup) } set(:subproject) { create(:project, namespace: subgroup) }
set(:subgroup_template_project) { create(:project, :custom_repo, namespace: subgroup, files: template_files('subgroup')) } set(:subgroup_template_project) { create(:project, :custom_repo, namespace: subgroup, files: template_files('subgroup')) }
...@@ -151,7 +151,7 @@ describe Gitlab::CustomFileTemplates do ...@@ -151,7 +151,7 @@ describe Gitlab::CustomFileTemplates do
end end
end end
context 'in a subgroup', :nested_groups do context 'in a subgroup' do
let(:subgroup) { create(:group, parent: group) } let(:subgroup) { create(:group, parent: group) }
let(:subproject) { create(:project, namespace: subgroup) } let(:subproject) { create(:project, namespace: subgroup) }
let(:subgroup_template_project) { create(:project, :custom_repo, namespace: subgroup, files: template_files('subgroup')) } let(:subgroup_template_project) { create(:project, :custom_repo, namespace: subgroup, files: template_files('subgroup')) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Database::LoadBalancing::Host, :postgresql do describe Gitlab::Database::LoadBalancing::Host do
let(:load_balancer) do let(:load_balancer) do
Gitlab::Database::LoadBalancing::LoadBalancer.new(%w[localhost]) Gitlab::Database::LoadBalancing::LoadBalancer.new(%w[localhost])
end end
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Daemon, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Daemon, :clean_gitlab_redis_shared_state do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers include ExclusiveLeaseHelpers
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::EventLogs, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::EventLogs, :clean_gitlab_redis_shared_state do
subject { described_class.new } subject { described_class.new }
describe '#fetch_in_batches' do describe '#fetch_in_batches' do
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::CacheInvalidationEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::CacheInvalidationEvent, :clean_gitlab_redis_shared_state do
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
let(:event_log) { create(:geo_event_log, :cache_invalidation_event) } let(:event_log) { create(:geo_event_log, :cache_invalidation_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::HashedStorageAttachmentsEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::HashedStorageAttachmentsEvent, :clean_gitlab_redis_shared_state do
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
let(:event_log) { create(:geo_event_log, :hashed_storage_attachments_event) } let(:event_log) { create(:geo_event_log, :hashed_storage_attachments_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::HashedStorageMigratedEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::HashedStorageMigratedEvent, :clean_gitlab_redis_shared_state do
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
let(:event_log) { create(:geo_event_log, :hashed_storage_migration_event) } let(:event_log) { create(:geo_event_log, :hashed_storage_migration_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::JobArtifactDeletedEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::JobArtifactDeletedEvent, :clean_gitlab_redis_shared_state do
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
let(:event_log) { create(:geo_event_log, :job_artifact_deleted_event) } let(:event_log) { create(:geo_event_log, :job_artifact_deleted_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::LfsObjectDeletedEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::LfsObjectDeletedEvent, :clean_gitlab_redis_shared_state do
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
let(:event_log) { create(:geo_event_log, :lfs_object_deleted_event) } let(:event_log) { create(:geo_event_log, :lfs_object_deleted_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::RepositoriesChangedEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::RepositoriesChangedEvent, :clean_gitlab_redis_shared_state do
include ::EE::GeoHelpers include ::EE::GeoHelpers
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::RepositoryCreatedEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::RepositoryCreatedEvent, :clean_gitlab_redis_shared_state do
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
let(:project) { create(:project) } let(:project) { create(:project) }
let(:repository_created_event) { create(:geo_repository_created_event, project: project) } let(:repository_created_event) { create(:geo_repository_created_event, project: project) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::RepositoryDeletedEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::RepositoryDeletedEvent, :clean_gitlab_redis_shared_state do
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
let(:event_log) { create(:geo_event_log, :deleted_event) } let(:event_log) { create(:geo_event_log, :deleted_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::RepositoryRenamedEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::RepositoryRenamedEvent, :clean_gitlab_redis_shared_state do
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
let(:event_log) { create(:geo_event_log, :renamed_event) } let(:event_log) { create(:geo_event_log, :renamed_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::RepositoryUpdatedEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::RepositoryUpdatedEvent, :clean_gitlab_redis_shared_state do
include ::EE::GeoHelpers include ::EE::GeoHelpers
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::ResetChecksumEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::ResetChecksumEvent, :clean_gitlab_redis_shared_state do
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
let(:event_log) { create(:geo_event_log, :reset_checksum_event) } let(:event_log) { create(:geo_event_log, :reset_checksum_event) }
let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) } let!(:event_log_state) { create(:geo_event_log_state, event_id: event_log.id - 1) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Geo::LogCursor::Events::UploadDeletedEvent, :postgresql, :clean_gitlab_redis_shared_state do describe Gitlab::Geo::LogCursor::Events::UploadDeletedEvent, :clean_gitlab_redis_shared_state do
let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) } let(:logger) { Gitlab::Geo::LogCursor::Logger.new(described_class, Logger::INFO) }
let(:project) { create(:project) } let(:project) { create(:project) }
let(:upload_deleted_event) { create(:geo_upload_deleted_event, project: project) } let(:upload_deleted_event) { create(:geo_upload_deleted_event, project: project) }
......
...@@ -166,7 +166,7 @@ RSpec.describe Gitlab::Insights::Finders::IssuableFinder do ...@@ -166,7 +166,7 @@ RSpec.describe Gitlab::Insights::Finders::IssuableFinder do
end end
end end
context 'for a group with subgroups', :nested_groups do context 'for a group with subgroups' do
include_examples 'group tests' do include_examples 'group tests' do
let(:project) { create(:project, :public, group: create(:group, parent: entity)) } let(:project) { create(:project, :public, group: create(:group, parent: entity)) }
end end
......
...@@ -94,7 +94,7 @@ describe Gitlab::UsageData do ...@@ -94,7 +94,7 @@ describe Gitlab::UsageData do
expect(count_data[:feature_flags]).to eq(1) expect(count_data[:feature_flags]).to eq(1)
end end
it 'gathers deepest epic relationship level', :postgresql do it 'gathers deepest epic relationship level' do
expect(count_data.keys).to include(:epics_deepest_relationship_level) expect(count_data.keys).to include(:epics_deepest_relationship_level)
end end
......
...@@ -169,7 +169,7 @@ describe Burndown do ...@@ -169,7 +169,7 @@ describe Burndown do
let(:parent_group_milestone) { create(:milestone, project: nil, group: parent_group, start_date: start_date, due_date: due_date) } let(:parent_group_milestone) { create(:milestone, project: nil, group: parent_group, start_date: start_date, due_date: due_date) }
let(:group_milestone) { create(:milestone, group: group, start_date: start_date, due_date: due_date) } let(:group_milestone) { create(:milestone, group: group, start_date: start_date, due_date: due_date) }
context 'when nested group milestone', :nested_groups do context 'when nested group milestone' do
before do before do
parent_group.add_developer(user) parent_group.add_developer(user)
end end
......
...@@ -74,7 +74,7 @@ describe Project, :elastic do ...@@ -74,7 +74,7 @@ describe Project, :elastic do
end end
end end
it 'indexes only projects under the group', :nested_groups do it 'indexes only projects under the group' do
Sidekiq::Testing.inline! do Sidekiq::Testing.inline! do
create :project, name: 'test1', group: create(:group, parent: group) create :project, name: 'test1', group: create(:group, parent: group)
create :project, name: 'test2', description: 'awesome project' create :project, name: 'test2', description: 'awesome project'
......
...@@ -118,7 +118,7 @@ describe Epic do ...@@ -118,7 +118,7 @@ describe Epic do
expect(epic.valid_parent?).to be_falsey expect(epic.valid_parent?).to be_falsey
end end
it 'returns false when level is too deep', :nested_groups do it 'returns false when level is too deep' do
epic1 = create(:epic, group: group) epic1 = create(:epic, group: group)
epic2 = create(:epic, group: group, parent: epic1) epic2 = create(:epic, group: group, parent: epic1)
epic3 = create(:epic, group: group, parent: epic2) epic3 = create(:epic, group: group, parent: epic2)
...@@ -142,7 +142,7 @@ describe Epic do ...@@ -142,7 +142,7 @@ describe Epic do
expect(epic.valid_parent?).to be_truthy expect(epic.valid_parent?).to be_truthy
end end
it 'returns false when total depth after adding would exceed limit', :nested_groups do it 'returns false when total depth after adding would exceed limit' do
child_epic2 = create(:epic, group: group, parent: child_epic1) child_epic2 = create(:epic, group: group, parent: child_epic1)
child_epic3 = create(:epic, group: group, parent: child_epic2) child_epic3 = create(:epic, group: group, parent: child_epic2)
child_epic4 = create(:epic, group: group, parent: child_epic3) child_epic4 = create(:epic, group: group, parent: child_epic3)
...@@ -166,7 +166,7 @@ describe Epic do ...@@ -166,7 +166,7 @@ describe Epic do
expect(epic.valid_parent?).to be_truthy expect(epic.valid_parent?).to be_truthy
end end
it 'returns false when total depth after adding would exceed limit', :nested_groups do it 'returns false when total depth after adding would exceed limit' do
root_epic.update(parent: create(:epic, group: group)) root_epic.update(parent: create(:epic, group: group))
create(:epic, group: group, parent: child_epic1) create(:epic, group: group, parent: child_epic1)
...@@ -185,14 +185,14 @@ describe Epic do ...@@ -185,14 +185,14 @@ describe Epic do
expect(epic.valid_parent?).to be_falsey expect(epic.valid_parent?).to be_falsey
end end
it 'returns false when child epic is parent of the given parent', :nested_groups do it 'returns false when child epic is parent of the given parent' do
epic1 = create(:epic, group: group, parent: epic) epic1 = create(:epic, group: group, parent: epic)
epic.parent = epic1 epic.parent = epic1
expect(epic.valid_parent?).to be_falsey expect(epic.valid_parent?).to be_falsey
end end
it 'returns false when child epic is an ancestor of the given parent', :nested_groups do it 'returns false when child epic is an ancestor of the given parent' do
epic1 = create(:epic, group: group, parent: epic) epic1 = create(:epic, group: group, parent: epic)
epic2 = create(:epic, group: group, parent: epic1) epic2 = create(:epic, group: group, parent: epic1)
epic.parent = epic2 epic.parent = epic2
...@@ -207,7 +207,7 @@ describe Epic do ...@@ -207,7 +207,7 @@ describe Epic do
let(:epic2) { create(:epic, group: group, parent: epic1) } let(:epic2) { create(:epic, group: group, parent: epic1) }
let(:epic3) { create(:epic, group: group, parent: epic2) } let(:epic3) { create(:epic, group: group, parent: epic2) }
describe '#ancestors', :nested_groups do describe '#ancestors' do
it 'returns all ancestors for an epic' do it 'returns all ancestors for an epic' do
expect(epic3.ancestors).to eq [epic2, epic1] expect(epic3.ancestors).to eq [epic2, epic1]
end end
...@@ -217,7 +217,7 @@ describe Epic do ...@@ -217,7 +217,7 @@ describe Epic do
end end
end end
describe '#descendants', :nested_groups do describe '#descendants' do
it 'returns all descendants for an epic' do it 'returns all descendants for an epic' do
expect(epic1.descendants).to match_array([epic2, epic3]) expect(epic1.descendants).to match_array([epic2, epic3])
end end
...@@ -576,7 +576,7 @@ describe Epic do ...@@ -576,7 +576,7 @@ describe Epic do
end end
end end
describe '.deepest_relationship_level', :postgresql do describe '.deepest_relationship_level' do
context 'when there are no epics' do context 'when there are no epics' do
it 'returns nil' do it 'returns nil' do
expect(described_class.deepest_relationship_level).to be_nil expect(described_class.deepest_relationship_level).to be_nil
......
...@@ -48,14 +48,14 @@ describe GitlabSubscription do ...@@ -48,14 +48,14 @@ describe GitlabSubscription do
expect(gitlab_subscription.seats_in_use).to eq(1) expect(gitlab_subscription.seats_in_use).to eq(1)
end end
it 'also counts users from subgroups', :postgresql do it 'also counts users from subgroups' do
group.add_developer(user_1) group.add_developer(user_1)
subgroup_1.add_developer(user_2) subgroup_1.add_developer(user_2)
expect(gitlab_subscription.seats_in_use).to eq(2) expect(gitlab_subscription.seats_in_use).to eq(2)
end end
it 'does not count duplicated members', :postgresql do it 'does not count duplicated members' do
group.add_developer(user_1) group.add_developer(user_1)
subgroup_1.add_developer(user_2) subgroup_1.add_developer(user_2)
subgroup_2.add_developer(user_2) subgroup_2.add_developer(user_2)
......
...@@ -213,7 +213,6 @@ describe Namespace do ...@@ -213,7 +213,6 @@ describe Namespace do
end end
end end
if Group.supports_nested_objects?
context 'when license is applied to parent group' do context 'when license is applied to parent group' do
let(:child_group) { create :group, parent: group } let(:child_group) { create :group, parent: group }
...@@ -222,7 +221,6 @@ describe Namespace do ...@@ -222,7 +221,6 @@ describe Namespace do
end end
end end
end end
end
context 'when feature not available in the plan' do context 'when feature not available in the plan' do
let(:feature) { :deploy_board } let(:feature) { :deploy_board }
...@@ -460,7 +458,7 @@ describe Namespace do ...@@ -460,7 +458,7 @@ describe Namespace do
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
context 'when is subgroup', :nested_groups do context 'when is subgroup' do
before do before do
namespace.parent = build(:group) namespace.parent = build(:group)
end end
...@@ -478,7 +476,7 @@ describe Namespace do ...@@ -478,7 +476,7 @@ describe Namespace do
describe '#shared_runners_enabled?' do describe '#shared_runners_enabled?' do
subject { namespace.shared_runners_enabled? } subject { namespace.shared_runners_enabled? }
context 'subgroup with shared runners enabled project', :nested_groups do context 'subgroup with shared runners enabled project' do
let(:subgroup) { create(:group, parent: namespace) } let(:subgroup) { create(:group, parent: namespace) }
let!(:subproject) { create(:project, namespace: subgroup, shared_runners_enabled: true) } let!(:subproject) { create(:project, namespace: subgroup, shared_runners_enabled: true) }
...@@ -776,7 +774,7 @@ describe Namespace do ...@@ -776,7 +774,7 @@ describe Namespace do
end end
end end
describe '#membership_lock with subgroups', :nested_groups do describe '#membership_lock with subgroups' do
context 'when creating a subgroup' do context 'when creating a subgroup' do
let(:subgroup) { create(:group, parent: root_group) } let(:subgroup) { create(:group, parent: root_group) }
......
require 'spec_helper' require 'spec_helper'
describe PgReplicationSlot, :postgresql do describe PgReplicationSlot do
if Gitlab::Database.replication_slots_supported? if Gitlab::Database.replication_slots_supported?
describe 'with replication slot support' do describe 'with replication slot support' do
it '#max_replication_slots' do it '#max_replication_slots' do
expect(described_class.max_replication_slots).to be >= 0 expect(described_class.max_replication_slots).to be >= 0
end end
skip_examples = PgReplicationSlot.max_replication_slots <= PgReplicationSlot.count skip_examples = described_class.max_replication_slots <= described_class.count
context 'with enough slots available' do context 'with enough slots available' do
before(:all) do before(:all) do
skip('max_replication_slots too small') if skip_examples skip('max_replication_slots too small') if skip_examples
...@@ -37,11 +37,11 @@ describe PgReplicationSlot, :postgresql do ...@@ -37,11 +37,11 @@ describe PgReplicationSlot, :postgresql do
end end
it '#max_retained_wal' do it '#max_retained_wal' do
expect(PgReplicationSlot.max_retained_wal).not_to be_nil expect(described_class.max_retained_wal).not_to be_nil
end end
it '#slots_retained_bytes' do it '#slots_retained_bytes' do
slot = PgReplicationSlot.slots_retained_bytes.find {|x| x['slot_name'] == 'test_slot' } slot = described_class.slots_retained_bytes.find {|x| x['slot_name'] == 'test_slot' }
expect(slot).not_to be_nil expect(slot).not_to be_nil
expect(slot['retained_bytes']).to be_nil expect(slot['retained_bytes']).to be_nil
......
...@@ -598,7 +598,7 @@ describe Project do ...@@ -598,7 +598,7 @@ describe Project do
subject { project.root_namespace } subject { project.root_namespace }
context 'when namespace has parent group', :nested_groups do context 'when namespace has parent group' do
let(:root_ancestor) { create(:group) } let(:root_ancestor) { create(:group) }
let(:parent) { create(:group, parent: root_ancestor) } let(:parent) { create(:group, parent: root_ancestor) }
...@@ -616,7 +616,7 @@ describe Project do ...@@ -616,7 +616,7 @@ describe Project do
end end
end end
describe '#shared_runners_limit_namespace', :nested_groups do describe '#shared_runners_limit_namespace' do
set(:root_ancestor) { create(:group) } set(:root_ancestor) { create(:group) }
set(:group) { create(:group, parent: root_ancestor) } set(:group) { create(:group, parent: root_ancestor) }
let(:project) { create(:project, namespace: group) } let(:project) { create(:project, namespace: group) }
......
...@@ -329,7 +329,7 @@ describe User do ...@@ -329,7 +329,7 @@ describe User do
end end
end end
describe '#available_subgroups_with_custom_project_templates', :postgresql do describe '#available_subgroups_with_custom_project_templates' do
let(:user) { create(:user) } let(:user) { create(:user) }
context 'without Groups with custom project templates' do context 'without Groups with custom project templates' do
......
...@@ -348,7 +348,7 @@ describe GroupPolicy do ...@@ -348,7 +348,7 @@ describe GroupPolicy do
end end
end end
describe 'private nested group use the highest access level from the group and inherited permissions', :nested_groups do describe 'private nested group use the highest access level from the group and inherited permissions' do
let(:nested_group) { create(:group, :private, parent: group) } let(:nested_group) { create(:group, :private, parent: group) }
before do before do
......
...@@ -29,7 +29,7 @@ describe EpicPresenter do ...@@ -29,7 +29,7 @@ describe EpicPresenter do
expect(presenter.show_data.keys).to match_array([:initial, :meta]) expect(presenter.show_data.keys).to match_array([:initial, :meta])
end end
it 'has correct ancestors', :nested_groups do it 'has correct ancestors' do
metadata = JSON.parse(presenter.show_data[:meta]) metadata = JSON.parse(presenter.show_data[:meta])
ancestor_url = metadata['ancestors'].first['url'] ancestor_url = metadata['ancestors'].first['url']
...@@ -48,7 +48,7 @@ describe EpicPresenter do ...@@ -48,7 +48,7 @@ describe EpicPresenter do
expect(data[:meta]).to match_schema('epic_meta_data', dir: 'ee') expect(data[:meta]).to match_schema('epic_meta_data', dir: 'ee')
end end
it 'avoids N+1 database queries', :nested_groups do it 'avoids N+1 database queries' do
group1 = create(:group) group1 = create(:group)
group2 = create(:group, parent: group1) group2 = create(:group, parent: group1)
epic1 = create(:epic, group: group1) epic1 = create(:epic, group: group1)
......
...@@ -244,7 +244,7 @@ describe API::Geo do ...@@ -244,7 +244,7 @@ describe API::Geo do
end end
end end
describe 'POST /geo/status', :postgresql do describe 'POST /geo/status' do
let(:geo_base_request) { Gitlab::Geo::BaseRequest.new(scope: ::Gitlab::Geo::API_SCOPE) } let(:geo_base_request) { Gitlab::Geo::BaseRequest.new(scope: ::Gitlab::Geo::API_SCOPE) }
let(:data) do let(:data) do
......
...@@ -308,7 +308,7 @@ describe API::V3::Github do ...@@ -308,7 +308,7 @@ describe API::V3::Github do
end end
end end
context 'nested group namespace', :nested_groups do context 'nested group namespace' do
let(:group) { create(:group, :nested) } let(:group) { create(:group, :nested) }
let!(:parent_group_project) { create(:project, group: group.parent, name: 'parent_group_project') } let!(:parent_group_project) { create(:project, group: group.parent, name: 'parent_group_project') }
let!(:child_group_project) { create(:project, group: group, name: 'child_group_project') } let!(:child_group_project) { create(:project, group: group, name: 'child_group_project') }
......
...@@ -91,7 +91,7 @@ describe GroupsController, type: :request do ...@@ -91,7 +91,7 @@ describe GroupsController, type: :request do
end end
end end
context 'subgroup', :nested_groups do context 'subgroup' do
let(:group) { create(:group, :nested) } let(:group) { create(:group, :nested) }
it 'does not create ip restriction' do it 'does not create ip restriction' do
......
require 'spec_helper' require 'spec_helper'
describe GeoProjectRegistryEntity, :postgresql do describe GeoProjectRegistryEntity do
let(:registry) { create(:geo_project_registry, :synced) } let(:registry) { create(:geo_project_registry, :synced) }
let(:entity) do let(:entity) do
......
require 'spec_helper' require 'spec_helper'
describe StorageShardEntity, :postgresql do describe StorageShardEntity do
let(:entity) { described_class.new(StorageShard.new, request: double) } let(:entity) { described_class.new(StorageShard.new, request: double) }
subject { entity.as_json } subject { entity.as_json }
......
...@@ -86,7 +86,7 @@ describe Ci::RegisterJobService do ...@@ -86,7 +86,7 @@ describe Ci::RegisterJobService do
end end
end end
context 'when group is subgroup', :nested_groups do context 'when group is subgroup' do
let!(:root_ancestor) { create(:group) } let!(:root_ancestor) { create(:group) }
let!(:group) { create(:group, parent: root_ancestor) } let!(:group) { create(:group, parent: root_ancestor) }
let!(:project) { create :project, shared_runners_enabled: true, group: group } let!(:project) { create :project, shared_runners_enabled: true, group: group }
......
...@@ -152,7 +152,7 @@ describe EpicIssues::CreateService do ...@@ -152,7 +152,7 @@ describe EpicIssues::CreateService do
include_examples 'returns success' include_examples 'returns success'
end end
context 'when a link of an issue in a subgroup is given', :nested_groups do context 'when a link of an issue in a subgroup is given' do
let(:subgroup) { create(:group, parent: group) } let(:subgroup) { create(:group, parent: group) }
let(:project2) { create(:project, group: subgroup) } let(:project2) { create(:project, group: subgroup) }
let(:issue) { create(:issue, project: project2) } let(:issue) { create(:issue, project: project2) }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe EpicLinks::CreateService, :postgresql do describe EpicLinks::CreateService do
describe '#execute' do describe '#execute' do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:user) { create(:user) } let(:user) { create(:user) }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe EpicLinks::DestroyService, :postgresql do describe EpicLinks::DestroyService do
describe '#execute' do describe '#execute' do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:user) { create(:user) } let(:user) { create(:user) }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe EpicLinks::ListService, :postgresql do describe EpicLinks::ListService do
let(:user) { create :user } let(:user) { create :user }
let(:group) { create(:group, :public) } let(:group) { create(:group, :public) }
let(:parent_epic) { create(:epic, group: group) } let(:parent_epic) { create(:epic, group: group) }
......
...@@ -54,7 +54,7 @@ describe Groups::AutocompleteService do ...@@ -54,7 +54,7 @@ describe Groups::AutocompleteService do
end end
end end
describe '#issues', :nested_groups do describe '#issues' do
let(:project) { create(:project, group: group) } let(:project) { create(:project, group: group) }
let(:sub_group_project) { create(:project, group: sub_group) } let(:sub_group_project) { create(:project, group: sub_group) }
...@@ -67,7 +67,7 @@ describe Groups::AutocompleteService do ...@@ -67,7 +67,7 @@ describe Groups::AutocompleteService do
end end
end end
describe '#merge_requests', :nested_groups do describe '#merge_requests' do
let(:project) { create(:project, :repository, group: group) } let(:project) { create(:project, :repository, group: group) }
let(:sub_group_project) { create(:project, :repository, group: sub_group) } let(:sub_group_project) { create(:project, :repository, group: sub_group) }
...@@ -104,10 +104,10 @@ describe Groups::AutocompleteService do ...@@ -104,10 +104,10 @@ describe Groups::AutocompleteService do
end end
it 'returns available commands' do it 'returns available commands' do
available_commands = [:todo, :unsubscribe, :award, :shrug, :tableflip, :cc, :title, :close] available_commands = [
if ::Epic.supports_nested_objects? :todo, :unsubscribe, :award, :shrug, :tableflip, :cc, :title, :close,
available_commands += [:child_epic, :remove_child_epic, :parent_epic, :remove_parent_epic] :child_epic, :remove_child_epic, :parent_epic, :remove_parent_epic
end ]
expect(subject.commands(epic).map { |c| c[:name] }).to match_array(available_commands) expect(subject.commands(epic).map { |c| c[:name] }).to match_array(available_commands)
end end
...@@ -131,7 +131,7 @@ describe Groups::AutocompleteService do ...@@ -131,7 +131,7 @@ describe Groups::AutocompleteService do
subgroup_milestone.update(group: public_subgroup) subgroup_milestone.update(group: public_subgroup)
end end
it 'returns milestones from groups and subgroups', :nested_groups do it 'returns milestones from groups and subgroups' do
subject = described_class.new(public_subgroup, user) subject = described_class.new(public_subgroup, user)
expect(subject.milestones.map(&:iid)).to contain_exactly(group_milestone.iid, subgroup_milestone.iid) expect(subject.milestones.map(&:iid)).to contain_exactly(group_milestone.iid, subgroup_milestone.iid)
...@@ -144,14 +144,14 @@ describe Groups::AutocompleteService do ...@@ -144,14 +144,14 @@ describe Groups::AutocompleteService do
expect(subject.milestones.map(&:title)).to contain_exactly(group_milestone.title) expect(subject.milestones.map(&:title)).to contain_exactly(group_milestone.title)
end end
it 'returns milestones from groups and subgroups', :nested_groups do it 'returns milestones from groups and subgroups' do
milestones = described_class.new(sub_group, user).milestones milestones = described_class.new(sub_group, user).milestones
expect(milestones.map(&:iid)).to contain_exactly(group_milestone.iid, subgroup_milestone.iid) expect(milestones.map(&:iid)).to contain_exactly(group_milestone.iid, subgroup_milestone.iid)
expect(milestones.map(&:title)).to contain_exactly(group_milestone.title, subgroup_milestone.title) expect(milestones.map(&:title)).to contain_exactly(group_milestone.title, subgroup_milestone.title)
end end
it 'returns only milestones that user can read', :nested_groups do it 'returns only milestones that user can read' do
user = create(:user) user = create(:user)
sub_group.add_guest(user) sub_group.add_guest(user)
......
...@@ -47,7 +47,7 @@ describe Groups::ParticipantsService do ...@@ -47,7 +47,7 @@ describe Groups::ParticipantsService do
end end
end end
describe '#group_members', :nested_groups do describe '#group_members' do
let(:parent_group) { create(:group) } let(:parent_group) { create(:group) }
let(:group) { create(:group, parent: parent_group) } let(:group) { create(:group, parent: parent_group) }
let(:subgroup) { create(:group_with_members, parent: group) } let(:subgroup) { create(:group_with_members, parent: group) }
......
...@@ -108,7 +108,7 @@ describe Groups::UpdateService, '#execute' do ...@@ -108,7 +108,7 @@ describe Groups::UpdateService, '#execute' do
expect(group.errors[:file_template_project_id]).to include('is invalid') expect(group.errors[:file_template_project_id]).to include('is invalid')
end end
context 'in a subgroup', :nested_groups do context 'in a subgroup' do
let(:parent_group) { create(:group) } let(:parent_group) { create(:group) }
let(:hidden_project) { create(:project, :private, namespace: parent_group) } let(:hidden_project) { create(:project, :private, namespace: parent_group) }
let(:group) { create(:group, parent: parent_group) } let(:group) { create(:group, parent: parent_group) }
......
...@@ -113,7 +113,7 @@ describe Projects::CreateFromTemplateService do ...@@ -113,7 +113,7 @@ describe Projects::CreateFromTemplateService do
it_behaves_like 'creates project from custom template', nil it_behaves_like 'creates project from custom template', nil
it_behaves_like 'creates project from custom template', '' it_behaves_like 'creates project from custom template', ''
describe 'creating project from a Group project template', :postgresql do describe 'creating project from a Group project template' do
let(:project_name) { project_template.name } let(:project_name) { project_template.name }
let(:group_with_project_templates_id) { subgroup_1_2.id } let(:group_with_project_templates_id) { subgroup_1_2.id }
let(:group2) { create(:group) } let(:group2) { create(:group) }
......
...@@ -298,7 +298,7 @@ describe QuickActions::InterpretService do ...@@ -298,7 +298,7 @@ describe QuickActions::InterpretService do
end end
end end
context 'child_epic command', :nested_groups do context 'child_epic command' do
let(:subgroup) { create(:group, parent: group) } let(:subgroup) { create(:group, parent: group) }
let(:another_group) { create(:group) } let(:another_group) { create(:group) }
let(:merge_request) { create(:merge_request, source_project: project) } let(:merge_request) { create(:merge_request, source_project: project) }
...@@ -427,7 +427,7 @@ describe QuickActions::InterpretService do ...@@ -427,7 +427,7 @@ describe QuickActions::InterpretService do
end end
end end
context 'remove_child_epic command', :nested_groups do context 'remove_child_epic command' do
let(:subgroup) { create(:group, parent: group) } let(:subgroup) { create(:group, parent: group) }
let(:another_group) { create(:group) } let(:another_group) { create(:group) }
let(:merge_request) { create(:merge_request, source_project: project) } let(:merge_request) { create(:merge_request, source_project: project) }
......
...@@ -43,7 +43,7 @@ describe UpdateBuildMinutesService do ...@@ -43,7 +43,7 @@ describe UpdateBuildMinutesService do
end end
end end
context 'when namespace is subgroup', :nested_groups do context 'when namespace is subgroup' do
let(:root_ancestor) { create(:group, shared_runners_minutes_limit: 100) } let(:root_ancestor) { create(:group, shared_runners_minutes_limit: 100) }
let(:namespace) { create(:namespace, parent: root_ancestor) } let(:namespace) { create(:namespace, parent: root_ancestor) }
......
...@@ -31,7 +31,7 @@ shared_examples_for 'member validations' do ...@@ -31,7 +31,7 @@ shared_examples_for 'member validations' do
expect(member.errors.messages[:user]).to eq(['is not linked to a SAML account']) expect(member.errors.messages[:user]).to eq(['is not linked to a SAML account'])
end end
context 'subgroups', :nested_groups do context 'subgroups' do
let!(:subgroup) { create(:group, parent: group) } let!(:subgroup) { create(:group, parent: group) }
before do before do
......
...@@ -10,7 +10,7 @@ describe 'admin/groups/_form' do ...@@ -10,7 +10,7 @@ describe 'admin/groups/_form' do
allow(view).to receive(:visibility_level) { group.visibility_level } allow(view).to receive(:visibility_level) { group.visibility_level }
end end
context 'when sub group is used', :nested_groups do context 'when sub group is used' do
let(:root_ancestor) { create(:group) } let(:root_ancestor) { create(:group) }
let(:group) { build(:group, parent: root_ancestor) } let(:group) { build(:group, parent: root_ancestor) }
......
...@@ -33,7 +33,7 @@ describe 'groups/edit.html.haml' do ...@@ -33,7 +33,7 @@ describe 'groups/edit.html.haml' do
end end
end end
context 'subgroup', :nested_groups do context 'subgroup' do
let(:group) { create(:group, :nested) } let(:group) { create(:group, :nested) }
before do before do
......
...@@ -48,7 +48,7 @@ describe ClearSharedRunnersMinutesWorker do ...@@ -48,7 +48,7 @@ describe ClearSharedRunnersMinutesWorker do
end end
end end
context 'when namespace has extra shared runner minutes', :postgresql do context 'when namespace has extra shared runner minutes' do
let!(:namespace) do let!(:namespace) do
create(:namespace, shared_runners_minutes_limit: 100, extra_shared_runners_minutes_limit: 10 ) create(:namespace, shared_runners_minutes_limit: 100, extra_shared_runners_minutes_limit: 10 )
end end
......
require 'spec_helper' require 'spec_helper'
describe Geo::RepositoryVerification::Primary::BatchWorker, :postgresql, :clean_gitlab_redis_cache do describe Geo::RepositoryVerification::Primary::BatchWorker, :clean_gitlab_redis_cache do
include ::EE::GeoHelpers include ::EE::GeoHelpers
set(:healthy_not_verified) { create(:project) } set(:healthy_not_verified) { create(:project) }
......
require 'spec_helper' require 'spec_helper'
describe Geo::RepositoryVerification::Primary::ShardWorker, :postgresql, :clean_gitlab_redis_cache do describe Geo::RepositoryVerification::Primary::ShardWorker, :clean_gitlab_redis_cache do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers include ExclusiveLeaseHelpers
......
require 'spec_helper' require 'spec_helper'
describe Geo::RepositoryVerification::Primary::SingleWorker, :postgresql, :clean_gitlab_redis_cache do describe Geo::RepositoryVerification::Primary::SingleWorker, :clean_gitlab_redis_cache do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers include ExclusiveLeaseHelpers
......
require 'spec_helper' require 'spec_helper'
describe Geo::RepositoryVerification::Secondary::SchedulerWorker, :postgresql, :clean_gitlab_redis_cache do describe Geo::RepositoryVerification::Secondary::SchedulerWorker, :clean_gitlab_redis_cache do
include ::EE::GeoHelpers include ::EE::GeoHelpers
set(:healthy_not_verified) { create(:project) } set(:healthy_not_verified) { create(:project) }
......
require 'spec_helper' require 'spec_helper'
describe Geo::RepositoryVerification::Secondary::SingleWorker, :postgresql, :clean_gitlab_redis_cache do describe Geo::RepositoryVerification::Secondary::SingleWorker, :clean_gitlab_redis_cache do
include ::EE::GeoHelpers include ::EE::GeoHelpers
include ExclusiveLeaseHelpers include ExclusiveLeaseHelpers
......
require 'spec_helper' require 'spec_helper'
describe UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker, :postgresql do describe UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker do
subject { described_class.new } subject { described_class.new }
let!(:user) { create(:user) } let!(:user) { create(:user) }
......
...@@ -366,10 +366,7 @@ module API ...@@ -366,10 +366,7 @@ module API
end end
expose :request_access_enabled expose :request_access_enabled
expose :full_name, :full_path expose :full_name, :full_path
if ::Group.supports_nested_objects?
expose :parent_id expose :parent_id
end
expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes
......
...@@ -114,10 +114,7 @@ module API ...@@ -114,10 +114,7 @@ module API
params do params do
requires :name, type: String, desc: 'The name of the group' requires :name, type: String, desc: 'The name of the group'
requires :path, type: String, desc: 'The path of the group' requires :path, type: String, desc: 'The path of the group'
if ::Group.supports_nested_objects?
optional :parent_id, type: Integer, desc: 'The parent group id for creating nested group' optional :parent_id, type: Integer, desc: 'The parent group id for creating nested group'
end
use :optional_params use :optional_params
end end
......
...@@ -32,11 +32,6 @@ module Gitlab ...@@ -32,11 +32,6 @@ module Gitlab
# Returns the maximum depth starting from the base # Returns the maximum depth starting from the base
# A base object with no children has a maximum depth of `1` # A base object with no children has a maximum depth of `1`
def max_descendants_depth def max_descendants_depth
unless hierarchy_supported?
# This makes the return value consistent with the case where hierarchy is supported
return descendants_base.exists? ? 1 : nil
end
base_and_descendants(with_depth: true).maximum(DEPTH_COLUMN) base_and_descendants(with_depth: true).maximum(DEPTH_COLUMN)
end end
...@@ -66,8 +61,6 @@ module Gitlab ...@@ -66,8 +61,6 @@ module Gitlab
# each parent. # each parent.
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def base_and_ancestors(upto: nil, hierarchy_order: nil) def base_and_ancestors(upto: nil, hierarchy_order: nil)
return ancestors_base unless hierarchy_supported?
recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all) recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all)
recursive_query = recursive_query.order(depth: hierarchy_order) if hierarchy_order recursive_query = recursive_query.order(depth: hierarchy_order) if hierarchy_order
...@@ -81,10 +74,6 @@ module Gitlab ...@@ -81,10 +74,6 @@ module Gitlab
# When `with_depth` is `true`, a `depth` column is included where it starts with `1` for the base objects # When `with_depth` is `true`, a `depth` column is included where it starts with `1` for the base objects
# and incremented as we go down the descendant tree # and incremented as we go down the descendant tree
def base_and_descendants(with_depth: false) def base_and_descendants(with_depth: false)
unless hierarchy_supported?
return with_depth ? descendants_base.select("1 as #{DEPTH_COLUMN}", objects_table[Arel.star]) : descendants_base
end
read_only(base_and_descendants_cte(with_depth: with_depth).apply_to(model.all)) read_only(base_and_descendants_cte(with_depth: with_depth).apply_to(model.all))
end end
...@@ -112,8 +101,6 @@ module Gitlab ...@@ -112,8 +101,6 @@ module Gitlab
# If nested objects are not supported, ancestors_base is returned. # If nested objects are not supported, ancestors_base is returned.
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def all_objects def all_objects
return ancestors_base unless hierarchy_supported?
ancestors = base_and_ancestors_cte ancestors = base_and_ancestors_cte
descendants = base_and_descendants_cte descendants = base_and_descendants_cte
...@@ -135,10 +122,6 @@ module Gitlab ...@@ -135,10 +122,6 @@ module Gitlab
private private
def hierarchy_supported?
Gitlab::Database.postgresql?
end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def base_and_ancestors_cte(stop_id = nil, hierarchy_order = nil) def base_and_ancestors_cte(stop_id = nil, hierarchy_order = nil)
cte = SQL::RecursiveCTE.new(:base_and_ancestors) cte = SQL::RecursiveCTE.new(:base_and_ancestors)
......
# frozen_string_literal: true
# This class relies on Common Table Expressions to efficiently get all data,
# including data for nested groups.
module Gitlab
class ProjectAuthorizations
attr_reader :user
# user - The User object for which to calculate the authorizations.
def initialize(user)
@user = user
end
def calculate
cte = recursive_cte
cte_alias = cte.table.alias(Group.table_name)
projects = Project.arel_table
links = ProjectGroupLink.arel_table
relations = [
# The project a user has direct access to.
user.projects.select_for_project_authorization,
# The personal projects of the user.
user.personal_projects.select_as_maintainer_for_project_authorization,
# Projects that belong directly to any of the groups the user has
# access to.
Namespace
.unscoped
.select([alias_as_column(projects[:id], 'project_id'),
cte_alias[:access_level]])
.from(cte_alias)
.joins(:projects),
# Projects shared with any of the namespaces the user has access to.
Namespace
.unscoped
.select([
links[:project_id],
least(cte_alias[:access_level], links[:group_access], 'access_level')
])
.from(cte_alias)
.joins('INNER JOIN project_group_links ON project_group_links.group_id = namespaces.id')
.joins('INNER JOIN projects ON projects.id = project_group_links.project_id')
.joins('INNER JOIN namespaces p_ns ON p_ns.id = projects.namespace_id')
.where('p_ns.share_with_group_lock IS FALSE')
]
ProjectAuthorization
.unscoped
.with
.recursive(cte.to_arel)
.select_from_union(relations)
end
private
# Builds a recursive CTE that gets all the groups the current user has
# access to, including any nested groups.
def recursive_cte
cte = Gitlab::SQL::RecursiveCTE.new(:namespaces_cte)
members = Member.arel_table
namespaces = Namespace.arel_table
# Namespaces the user is a member of.
cte << user.groups
.select([namespaces[:id], members[:access_level]])
.except(:order)
# Sub groups of any groups the user is a member of.
cte << Group.select([
namespaces[:id],
greatest(members[:access_level], cte.table[:access_level], 'access_level')
])
.joins(join_cte(cte))
.joins(join_members)
.except(:order)
cte
end
# Builds a LEFT JOIN to join optional memberships onto the CTE.
def join_members
members = Member.arel_table
namespaces = Namespace.arel_table
cond = members[:source_id]
.eq(namespaces[:id])
.and(members[:source_type].eq('Namespace'))
.and(members[:requested_at].eq(nil))
.and(members[:user_id].eq(user.id))
Arel::Nodes::OuterJoin.new(members, Arel::Nodes::On.new(cond))
end
# Builds an INNER JOIN to join namespaces onto the CTE.
def join_cte(cte)
namespaces = Namespace.arel_table
cond = cte.table[:id].eq(namespaces[:parent_id])
Arel::Nodes::InnerJoin.new(cte.table, Arel::Nodes::On.new(cond))
end
def greatest(left, right, column_alias)
sql_function('GREATEST', [left, right], column_alias)
end
def least(left, right, column_alias)
sql_function('LEAST', [left, right], column_alias)
end
def sql_function(name, args, column_alias)
alias_as_column(Arel::Nodes::NamedFunction.new(name, args), column_alias)
end
def alias_as_column(value, alias_to)
Arel::Nodes::As.new(value, Arel::Nodes::SqlLiteral.new(alias_to))
end
end
end
# frozen_string_literal: true
module Gitlab
module ProjectAuthorizations
# Calculating new project authorizations when supporting nested groups.
#
# This class relies on Common Table Expressions to efficiently get all data,
# including data for nested groups. As a result this class can only be used
# on PostgreSQL.
class WithNestedGroups
attr_reader :user
# user - The User object for which to calculate the authorizations.
def initialize(user)
@user = user
end
def calculate
cte = recursive_cte
cte_alias = cte.table.alias(Group.table_name)
projects = Project.arel_table
links = ProjectGroupLink.arel_table
relations = [
# The project a user has direct access to.
user.projects.select_for_project_authorization,
# The personal projects of the user.
user.personal_projects.select_as_maintainer_for_project_authorization,
# Projects that belong directly to any of the groups the user has
# access to.
Namespace
.unscoped
.select([alias_as_column(projects[:id], 'project_id'),
cte_alias[:access_level]])
.from(cte_alias)
.joins(:projects),
# Projects shared with any of the namespaces the user has access to.
Namespace
.unscoped
.select([links[:project_id],
least(cte_alias[:access_level],
links[:group_access],
'access_level')])
.from(cte_alias)
.joins('INNER JOIN project_group_links ON project_group_links.group_id = namespaces.id')
.joins('INNER JOIN projects ON projects.id = project_group_links.project_id')
.joins('INNER JOIN namespaces p_ns ON p_ns.id = projects.namespace_id')
.where('p_ns.share_with_group_lock IS FALSE')
]
ProjectAuthorization
.unscoped
.with
.recursive(cte.to_arel)
.select_from_union(relations)
end
private
# Builds a recursive CTE that gets all the groups the current user has
# access to, including any nested groups.
def recursive_cte
cte = Gitlab::SQL::RecursiveCTE.new(:namespaces_cte)
members = Member.arel_table
namespaces = Namespace.arel_table
# Namespaces the user is a member of.
cte << user.groups
.select([namespaces[:id], members[:access_level]])
.except(:order)
# Sub groups of any groups the user is a member of.
cte << Group.select([namespaces[:id],
greatest(members[:access_level],
cte.table[:access_level], 'access_level')])
.joins(join_cte(cte))
.joins(join_members)
.except(:order)
cte
end
# Builds a LEFT JOIN to join optional memberships onto the CTE.
def join_members
members = Member.arel_table
namespaces = Namespace.arel_table
cond = members[:source_id]
.eq(namespaces[:id])
.and(members[:source_type].eq('Namespace'))
.and(members[:requested_at].eq(nil))
.and(members[:user_id].eq(user.id))
Arel::Nodes::OuterJoin.new(members, Arel::Nodes::On.new(cond))
end
# Builds an INNER JOIN to join namespaces onto the CTE.
def join_cte(cte)
namespaces = Namespace.arel_table
cond = cte.table[:id].eq(namespaces[:parent_id])
Arel::Nodes::InnerJoin.new(cte.table, Arel::Nodes::On.new(cond))
end
def greatest(left, right, column_alias)
sql_function('GREATEST', [left, right], column_alias)
end
def least(left, right, column_alias)
sql_function('LEAST', [left, right], column_alias)
end
def sql_function(name, args, column_alias)
alias_as_column(Arel::Nodes::NamedFunction.new(name, args), column_alias)
end
def alias_as_column(value, alias_to)
Arel::Nodes::As.new(value, Arel::Nodes::SqlLiteral.new(alias_to))
end
end
end
end
# frozen_string_literal: true
module Gitlab
module ProjectAuthorizations
# Calculating new project authorizations when not supporting nested groups.
class WithoutNestedGroups
attr_reader :user
# user - The User object for which to calculate the authorizations.
def initialize(user)
@user = user
end
def calculate
relations = [
# Projects the user is a direct member of
user.projects.select_for_project_authorization,
# Personal projects
user.personal_projects.select_as_maintainer_for_project_authorization,
# Projects of groups the user is a member of
user.groups_projects.select_for_project_authorization,
# Projects shared with groups the user is a member of
user.groups.joins(:shared_projects).select_for_project_authorization
]
ProjectAuthorization
.unscoped
.select_from_union(relations)
end
end
end
end
...@@ -85,7 +85,7 @@ describe Boards::IssuesController do ...@@ -85,7 +85,7 @@ describe Boards::IssuesController do
expect { list_issues(user: user, board: group_board, list: list3) }.not_to exceed_query_limit(control_count + (2 * 8 - 1)) expect { list_issues(user: user, board: group_board, list: list3) }.not_to exceed_query_limit(control_count + (2 * 8 - 1))
end end
it 'avoids N+1 database queries when adding a subgroup, project, and issue', :nested_groups do it 'avoids N+1 database queries when adding a subgroup, project, and issue' do
create(:project, group: sub_group_1) create(:project, group: sub_group_1)
create(:labeled_issue, project: project, labels: [development]) create(:labeled_issue, project: project, labels: [development])
control_count = ActiveRecord::QueryRecorder.new { list_issues(user: user, board: group_board, list: list3) }.count control_count = ActiveRecord::QueryRecorder.new { list_issues(user: user, board: group_board, list: list3) }.count
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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