Commit f6ce7efd authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch 'move-allow-developers-to-create-projects-in-groups-to-core-ee' into 'master'

Move allow developers to create projects in groups to Core

See merge request gitlab-org/gitlab-ee!10057
parents b2cdc0be 9ca1d05d
......@@ -89,7 +89,8 @@ class Admin::GroupsController < Admin::ApplicationController
:request_access_enabled,
:visibility_level,
:require_two_factor_authentication,
:two_factor_grace_period
:two_factor_grace_period,
:project_creation_level
]
end
end
......
......@@ -187,7 +187,8 @@ class GroupsController < Groups::ApplicationController
:create_chat_team,
:chat_team_name,
:require_two_factor_authentication,
:two_factor_grace_period
:two_factor_grace_period,
:project_creation_level
]
end
......
......@@ -137,6 +137,7 @@ module ApplicationSettingsHelper
:default_artifacts_expire_in,
:default_branch_protection,
:default_group_visibility,
:default_project_creation,
:default_project_visibility,
:default_projects_limit,
:default_snippet_visibility,
......
......@@ -49,6 +49,13 @@ module NamespacesHelper
end
end
def namespaces_options_with_developer_maintainer_access(options = {})
selected = options.delete(:selected) || :current_user
options[:groups] = current_user.manageable_groups_with_routes(include_groups_with_developer_maintainer_access: true)
namespaces_options(selected, options)
end
private
# Many importers create a temporary Group, so use the real
......
......@@ -26,6 +26,7 @@ module ApplicationSettingImplementation
default_artifacts_expire_in: '30 days',
default_branch_protection: Settings.gitlab['default_branch_protection'],
default_group_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_project_creation: Settings.gitlab['default_project_creation'],
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_projects_limit: Settings.gitlab['default_projects_limit'],
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
......
......@@ -404,6 +404,10 @@ class Group < Namespace
Feature.enabled?(:group_clusters, root_ancestor, default_enabled: true)
end
def project_creation_level
super || ::Gitlab::CurrentSettings.default_project_creation
end
private
def update_two_factor_requirement
......
......@@ -105,6 +105,7 @@ class User < ApplicationRecord
has_many :groups, through: :group_members
has_many :owned_groups, -> { where(members: { access_level: Gitlab::Access::OWNER }) }, through: :group_members, source: :group
has_many :maintainers_groups, -> { where(members: { access_level: Gitlab::Access::MAINTAINER }) }, through: :group_members, source: :group
has_many :developer_groups, -> { where(members: { access_level: ::Gitlab::Access::DEVELOPER }) }, through: :group_members, source: :group
has_many :owned_or_maintainers_groups,
-> { where(members: { access_level: [Gitlab::Access::MAINTAINER, Gitlab::Access::OWNER] }) },
through: :group_members,
......@@ -883,7 +884,12 @@ class User < ApplicationRecord
# rubocop: enable CodeReuse/ServiceClass
def several_namespaces?
owned_groups.any? || maintainers_groups.any?
union_sql = ::Gitlab::SQL::Union.new(
[owned_groups,
maintainers_groups,
groups_with_developer_maintainer_project_access]).to_sql
::Group.from("(#{union_sql}) #{::Group.table_name}").any?
end
def namespace_id
......@@ -1169,12 +1175,24 @@ class User < ApplicationRecord
@manageable_namespaces ||= [namespace] + manageable_groups
end
def manageable_groups
Gitlab::ObjectHierarchy.new(owned_or_maintainers_groups).base_and_descendants
def manageable_groups(include_groups_with_developer_maintainer_access: false)
owned_and_maintainer_group_hierarchy = Gitlab::ObjectHierarchy.new(owned_or_maintainers_groups).base_and_descendants
if include_groups_with_developer_maintainer_access
union_sql = ::Gitlab::SQL::Union.new(
[owned_and_maintainer_group_hierarchy,
groups_with_developer_maintainer_project_access]).to_sql
::Group.from("(#{union_sql}) #{::Group.table_name}")
else
owned_and_maintainer_group_hierarchy
end
end
def manageable_groups_with_routes
manageable_groups.eager_load(:route).order('routes.path')
def manageable_groups_with_routes(include_groups_with_developer_maintainer_access: false)
manageable_groups(include_groups_with_developer_maintainer_access: include_groups_with_developer_maintainer_access)
.eager_load(:route)
.order('routes.path')
end
def namespaces
......@@ -1573,6 +1591,18 @@ class User < ApplicationRecord
ensure
Gitlab::ExclusiveLease.cancel(lease_key, uuid)
end
def groups_with_developer_maintainer_project_access
project_creation_levels = [::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS]
if ::Gitlab::CurrentSettings.default_project_creation == ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS
project_creation_levels << nil
end
developer_groups_hierarchy = ::Gitlab::ObjectHierarchy.new(developer_groups).base_and_descendants
::Group.where(id: developer_groups_hierarchy.select(:id),
project_creation_level: project_creation_levels)
end
end
User.prepend(EE::User)
......@@ -35,6 +35,14 @@ class GroupPolicy < BasePolicy
with_options scope: :subject, score: 0
condition(:request_access_enabled) { @subject.request_access_enabled }
condition(:create_projects_disabled) do
@subject.project_creation_level == ::Gitlab::Access::NO_ONE_PROJECT_ACCESS
end
condition(:developer_maintainer_access) do
@subject.project_creation_level == ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS
end
rule { public_group }.policy do
enable :read_group
enable :read_list
......@@ -115,6 +123,9 @@ class GroupPolicy < BasePolicy
rule { ~can_have_multiple_clusters & has_clusters }.prevent :add_cluster
rule { developer & developer_maintainer_access }.enable :create_projects
rule { create_projects_disabled }.prevent :create_projects
def access_level
return GroupMember::NO_ACCESS if @user.nil?
......
......@@ -5,7 +5,9 @@
.form-group
= f.label :default_branch_protection, class: 'label-bold'
= f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
= render_if_exists 'admin/application_settings/project_creation_level', form: f, application_setting: @application_setting
.form-group
= f.label s_('ProjectCreationLevel|Default project creation protection'), class: 'label-bold'
= f.select :default_project_creation, options_for_select(Gitlab::Access.project_creation_options, @application_setting.default_project_creation), {}, class: 'form-control'
.form-group.visibility-level-setting
= f.label :default_project_visibility, class: 'label-bold'
= render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: Project.new)
......
......@@ -9,8 +9,10 @@
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
%br/
%span.descr This setting can be overridden in each project.
= render partial: 'groups/ee/old_project_creation_level', locals: { form: f, group: @group }
.form-group.row
= f.label s_('ProjectCreationLevel|Allowed to create projects'), class: 'col-form-label col-sm-2'
.col-sm-10
= f.select :project_creation_level, options_for_select(::Gitlab::Access.project_creation_options, @group.project_creation_level), {}, class: 'form-control'
.form-group.row
= f.label :require_two_factor_authentication, 'Two-factor authentication', class: 'col-form-label col-sm-2 pt-0'
......
......@@ -18,7 +18,7 @@
%span.descr.text-muted= share_with_group_lock_help_text(@group)
= render 'groups/settings/lfs', f: f
= render partial: 'groups/ee/project_creation_level', locals: { form: f, group: @group }
= render 'groups/settings/project_creation_level', f: f, group: @group
= render 'groups/settings/two_factor_auth', f: f
= render_if_exists 'groups/member_lock_setting', f: f, group: @group
......
.form-group
= f.label s_('ProjectCreationLevel|Allowed to create projects'), class: 'label-bold'
= f.select :project_creation_level, options_for_select(::Gitlab::Access.project_creation_options, group.project_creation_level), {}, class: 'form-control'
---
title: Move allow developers to create projects in groups to Core
merge_request: 25975
author:
type: added
......@@ -137,7 +137,7 @@ Settings['issues_tracker'] ||= {}
# GitLab
#
Settings['gitlab'] ||= Settingslogic.new({})
Settings.gitlab['default_project_creation'] ||= ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS
Settings.gitlab['default_project_creation'] ||= ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS
Settings.gitlab['default_projects_limit'] ||= 100000
Settings.gitlab['default_branch_protection'] ||= 2
Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_can_create_group'].nil?
......
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddDefaultProjectCreationApplicationSetting < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
unless column_exists?(:application_settings, :default_project_creation)
add_column(:application_settings, :default_project_creation, :integer, default: 2, null: false)
end
end
def down
if column_exists?(:application_settings, :default_project_creation)
remove_column(:application_settings, :default_project_creation)
end
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddProjectCreationLevelToNamespaces < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
unless column_exists?(:namespaces, :project_creation_level)
add_column :namespaces, :project_creation_level, :integer
end
end
def down
unless column_exists?(:namespaces, :project_creation_level)
remove_column :namespaces, :project_creation_level, :integer
end
end
end
......@@ -179,7 +179,6 @@ ActiveRecord::Schema.define(version: 20190403161806) do
t.integer "gitaly_timeout_medium", default: 30, null: false
t.integer "gitaly_timeout_fast", default: 10, null: false
t.boolean "mirror_available", default: true, null: false
t.integer "default_project_creation", default: 2, null: false
t.boolean "password_authentication_enabled_for_web"
t.boolean "password_authentication_enabled_for_git", default: true, null: false
t.string "auto_devops_domain"
......@@ -218,6 +217,7 @@ ActiveRecord::Schema.define(version: 20190403161806) do
t.integer "local_markdown_version", default: 0, null: false
t.integer "first_day_of_week", default: 0, null: false
t.boolean "elasticsearch_limit_indexing", default: false, null: false
t.integer "default_project_creation", default: 2, null: false
t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id", using: :btree
t.index ["file_template_project_id"], name: "index_application_settings_on_file_template_project_id", using: :btree
t.index ["usage_stats_set_by_user_id"], name: "index_application_settings_on_usage_stats_set_by_user_id", using: :btree
......
......@@ -153,20 +153,20 @@ There are two different ways to add a new project to a group:
![Select group](img/select_group_dropdown.png)
### Default project creation level **[STARTER]**
### Default project creation level
> [Introduced][ee-2534] in [GitLab Premium][ee] 10.5.
> Brought to [GitLab Starter][ee] in 10.7.
> [Moved](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/25975) to [GitLab Core](https://about.gitlab.com/pricing/) in 11.10.
Group owners or administrators can set an option that will give users with the
Developer role the ability to create projects under groups.
Group owners or administrators can allow users with the
Developer role to create projects under groups.
By default, `Developers` and `Maintainers` are allowed to create projects under a
group, but this can be changed either within the group settings for a group, or
By default, [Developers and Maintainers](../permissions.md##group-members-permissions) can create projects under agroup, but this can be changed either within the group settings for a group, or
be set globally by a GitLab administrator in the Admin area
(**Settings > Visibility and Access Controls**).
at **Settings > General > Visibility and access controls**.
The setting can set to "None", "Maintainers", or "Developers + Maintainers".
Available settings are `No one`, `Maintainers`, or `Developers + Maintainers`.
## Transfer projects into groups
......
......@@ -10,10 +10,6 @@ module EE
attrs += EE::ApplicationSettingsHelper.repository_mirror_attributes
end
if License.feature_available?(:project_creation_level)
attrs << :default_project_creation
end
if License.feature_available?(:external_authorization_service)
attrs += EE::ApplicationSettingsHelper.external_authorization_service_attributes
end
......
......@@ -22,9 +22,7 @@ module EE
:repository_size_limit,
:shared_runners_minutes_limit,
gitlab_subscription_attributes: [:hosted_plan_id]
].tap do |params_ee|
params_ee << :project_creation_level if @group&.feature_available?(:project_creation_level)
end
]
end
end
end
......
......@@ -26,7 +26,6 @@ module EE
:repository_size_limit
].tap do |params_ee|
params_ee << { insight_attributes: :project_id } if current_group&.insights_available?
params_ee << :project_creation_level if current_group&.feature_available?(:project_creation_level)
params_ee << :file_template_project_id if current_group&.feature_available?(:custom_file_templates_for_namespace)
params_ee << :custom_project_templates_group_id if License.feature_available?(:custom_project_templates)
end
......
......@@ -68,16 +68,5 @@ module EE
namespace_shared_runner_usage_progress_bar(percent)
end
# rubocop: disable CodeReuse/ActiveRecord
def namespaces_options_with_developer_maintainer_access(options = {})
selected = options.delete(:selected) || :current_user
options[:groups] = current_user.manageable_groups(include_groups_with_developer_maintainer_access: true)
.eager_load(:route)
.order('routes.path')
namespaces_options(selected, options)
end
# rubocop: enable CodeReuse/ActiveRecord
end
end
......@@ -102,7 +102,6 @@ module EE
def defaults
super.merge(
allow_group_owners_to_manage_ldap: true,
default_project_creation: ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS,
elasticsearch_aws: false,
elasticsearch_aws_region: ENV['ELASTIC_REGION'] || 'us-east-1',
elasticsearch_url: ENV['ELASTIC_URL'] || 'http://localhost:9200',
......
......@@ -153,10 +153,6 @@ module EE
ensure_saml_discovery_token!
end
def project_creation_level
super || ::Gitlab::CurrentSettings.default_project_creation
end
override :multiple_issue_boards_available?
def multiple_issue_boards_available?
feature_available?(:multiple_group_issue_boards)
......
......@@ -167,43 +167,6 @@ module EE
super || DEFAULT_GROUP_VIEW
end
override :several_namespaces?
def several_namespaces?
union_sql = ::Gitlab::SQL::Union.new(
[owned_groups,
maintainers_groups,
groups_with_developer_maintainer_project_access]).to_sql
::Group.from("(#{union_sql}) #{::Group.table_name}").any?
end
override :manageable_groups
def manageable_groups(include_groups_with_developer_maintainer_access: false)
owned_and_maintainer_group_hierarchy = super()
if include_groups_with_developer_maintainer_access
union_sql = ::Gitlab::SQL::Union.new(
[owned_and_maintainer_group_hierarchy,
groups_with_developer_maintainer_project_access]).to_sql
::Group.from("(#{union_sql}) #{::Group.table_name}")
else
owned_and_maintainer_group_hierarchy
end
end
def groups_with_developer_maintainer_project_access
project_creation_levels = [::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS]
if ::Gitlab::CurrentSettings.default_project_creation == ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS
project_creation_levels << nil
end
developer_groups_hierarchy = ::Gitlab::ObjectHierarchy.new(developer_groups).base_and_descendants
::Group.where(id: developer_groups_hierarchy.select(:id),
project_creation_level: project_creation_levels)
end
def any_namespace_with_trial?
::Namespace
.from("(#{namespace_union(:trial_ends_on)}) #{::Namespace.table_name}")
......
......@@ -28,7 +28,6 @@ class License < ApplicationRecord
multiple_issue_assignees
multiple_project_issue_boards
push_rules
project_creation_level
protected_refs_for_users
related_issues
repository_mirrors
......
......@@ -12,16 +12,6 @@ module EE
@subject.feature_available?(:contribution_analytics)
end
condition(:project_creation_level_enabled) { @subject.feature_available?(:project_creation_level) }
condition(:create_projects_disabled) do
@subject.project_creation_level == ::EE::Gitlab::Access::NO_ONE_PROJECT_ACCESS
end
condition(:developer_maintainer_access) do
@subject.project_creation_level == ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS
end
condition(:can_owners_manage_ldap, scope: :global) do
::Gitlab::CurrentSettings.current_application_settings
.allow_group_owners_to_manage_ldap
......@@ -69,9 +59,6 @@ module EE
rule { ldap_synced & (admin | (can_owners_manage_ldap & owner)) }.enable :override_group_member
rule { project_creation_level_enabled & developer & developer_maintainer_access }.enable :create_projects
rule { project_creation_level_enabled & create_projects_disabled }.prevent :create_projects
rule { developer }.policy do
enable :read_group_security_dashboard
end
......
- return unless group.feature_available?(:project_creation_level)
- form = local_assigns.fetch(:form)
- group = local_assigns.fetch(:group)
.form-group.row
= form.label s_('ProjectCreationLevel|Allowed to create projects'), class: 'col-form-label col-sm-2'
.col-sm-10
= form.select :project_creation_level, options_for_select(::Gitlab::Access.project_creation_options, group.project_creation_level), {}, class: 'form-control'
- return unless group.feature_available?(:project_creation_level)
- form = local_assigns.fetch(:form)
- group = local_assigns.fetch(:group)
.form-group.col-md-9.row.prepend-top-8
= form.label :description, s_('ProjectCreationLevel|Allowed to create projects'), class: 'label-bold'
= form.select :project_creation_level, options_for_select(::Gitlab::Access.project_creation_options, group.project_creation_level), {}, class: 'form-control'
......@@ -6,10 +6,14 @@ class AddDefaultProjectCreationSetting < ActiveRecord::Migration[4.2]
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :default_project_creation, :integer, default: 2)
unless column_exists?(:application_settings, :default_project_creation)
add_column_with_default(:application_settings, :default_project_creation, :integer, default: 2)
end
end
def down
remove_column(:application_settings, :default_project_creation)
if column_exists?(:application_settings, :default_project_creation)
remove_column(:application_settings, :default_project_creation)
end
end
end
......@@ -3,7 +3,15 @@ class AddProjectCreationLevelToGroups < ActiveRecord::Migration[4.2]
DOWNTIME = false
def change
add_column :namespaces, :project_creation_level, :integer
def up
unless column_exists?(:namespaces, :project_creation_level)
add_column(:namespaces, :project_creation_level, :integer)
end
end
def down
if column_exists?(:namespaces, :project_creation_level)
remove_column(:namespaces, :project_creation_level, :integer)
end
end
end
......@@ -33,8 +33,8 @@ module EE
}
when :project_creation_level
{
from: ::Gitlab::Access.level_name(old),
to: ::Gitlab::Access.level_name(new)
from: ::Gitlab::Access.project_creation_level_name(old),
to: ::Gitlab::Access.project_creation_level_name(new)
}
when :plan_id
{
......
......@@ -9,26 +9,7 @@ module EE
module Gitlab
module Access
extend ActiveSupport::Concern
# Default project creation level
NO_ONE_PROJECT_ACCESS = 0
MAINTAINER_PROJECT_ACCESS = 1
DEVELOPER_MAINTAINER_PROJECT_ACCESS = 2
ADMIN = 60
class_methods do
def project_creation_options
{
s_('ProjectCreationLevel|No one') => NO_ONE_PROJECT_ACCESS,
s_('ProjectCreationLevel|Maintainers') => MAINTAINER_PROJECT_ACCESS,
s_('ProjectCreationLevel|Developers + Maintainers') => DEVELOPER_MAINTAINER_PROJECT_ACCESS
}
end
def level_name(name)
project_creation_options.key(name)
end
end
end
end
end
......@@ -112,14 +112,6 @@ describe Admin::ApplicationSettingsController do
it_behaves_like 'settings for licensed features'
end
it 'updates the default_project_creation for string value' do
stub_licensed_features(project_creation_level: true)
put :update, params: { application_setting: { default_project_creation: ::EE::Gitlab::Access::MAINTAINER_PROJECT_ACCESS } }
expect(response).to redirect_to(admin_application_settings_path)
expect(ApplicationSetting.current.default_project_creation).to eq(::EE::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
end
it 'updates repository_size_limit' do
put :update, params: { application_setting: { repository_size_limit: '100' } }
......
......@@ -38,26 +38,4 @@ describe Admin::GroupsController do
end
end
end
context 'PUT update' do
context 'no license' do
it 'does not update the project_creation_level successfully' do
stub_licensed_features(project_creation_level: false)
expect do
post :update, params: { id: group.to_param, group: { project_creation_level: ::EE::Gitlab::Access::NO_ONE_PROJECT_ACCESS } }
end.not_to change { group.reload.project_creation_level }
end
end
context 'licensed' do
it 'updates the project_creation_level successfully' do
stub_licensed_features(project_creation_level: true)
expect do
post :update, params: { id: group.to_param, group: { project_creation_level: ::EE::Gitlab::Access::NO_ONE_PROJECT_ACCESS } }
end.to change { group.reload.project_creation_level }.to(::EE::Gitlab::Access::NO_ONE_PROJECT_ACCESS)
end
end
end
end
# frozen_string_literal: true
FactoryBot.modify do
factory :group do
project_creation_level ::EE::Gitlab::Access::MAINTAINER_PROJECT_ACCESS
end
end
FactoryBot.define do
factory :group_with_members, parent: :group do
after(:create) do |group, evaluator|
......
......@@ -62,26 +62,6 @@ describe 'Edit group settings' do
end
end
context 'with project_creation_level feature enabled' do
it 'shows the selection menu' do
stub_licensed_features(project_creation_level: true)
visit edit_group_path(group)
expect(page).to have_content('Allowed to create projects')
end
end
context 'with project_creation_level feature disabled' do
it 'shows the selection menu' do
stub_licensed_features(project_creation_level: false)
visit edit_group_path(group)
expect(page).not_to have_content('Allowed to create projects')
end
end
describe 'Member Lock setting' do
context 'without a license key' do
before do
......
......@@ -7,25 +7,6 @@ describe 'New project' do
sign_in(user)
end
context 'Namespace selector' do
context 'with group with DEVELOPER_MAINTAINER_PROJECT_ACCESS project_creation_level' do
let(:group) { create(:group, project_creation_level: ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
before do
group.add_developer(user)
visit new_project_path(namespace_id: group.id)
end
it 'selects the group namespace' do
page.within('#blank-project-pane') do
namespace = find('#project_namespace_id option[selected]')
expect(namespace.text).to eq group.full_path
end
end
end
end
context 'repository mirrors' do
context 'when licensed' do
before do
......
# frozen_string_literal: true
require 'spec_helper'
describe 'User creates a project', :js do
let(:user) { create(:user) }
before do
sign_in(user)
end
context 'in a group with DEVELOPER_MAINTAINER_PROJECT_ACCESS project_creation_level' do
let(:group) { create(:group, project_creation_level: ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
before do
group.add_developer(user)
end
it 'creates a new project' do
visit(new_project_path)
fill_in :project_name, with: 'a-new-project'
fill_in :project_path, with: 'a-new-project'
page.find('.js-select-namespace').click
page.find("div[role='option']", text: group.full_path).click
page.within('#content-body') do
click_button('Create project')
end
expect(page).to have_content("Project 'a-new-project' was successfully created")
project = Project.find_by(name: 'a-new-project')
expect(project.namespace).to eq(group)
end
end
end
......@@ -16,70 +16,12 @@ describe EE::NamespacesHelper, :postgresql do
:private,
project_creation_level: user_project_creation_level)
end
let!(:subgroup1) do
create(:group,
:private,
parent: admin_group,
project_creation_level: nil)
end
let!(:subgroup2) do
create(:group,
:private,
parent: admin_group,
project_creation_level: ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS)
end
let!(:subgroup3) do
create(:group,
:private,
parent: admin_group,
project_creation_level: ::EE::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
end
before do
admin_group.add_owner(admin)
user_group.add_owner(user)
end
describe '#namespaces_options' do
describe 'include_groups_with_developer_maintainer_access parameter' do
context 'when DEVELOPER_MAINTAINER_PROJECT_ACCESS is set for a project' do
let!(:admin_project_creation_level) { ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS }
it 'returns groups where user is a developer' do
allow(helper).to receive(:current_user).and_return(user)
stub_application_setting(default_project_creation: ::EE::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
admin_group.add_user(user, GroupMember::DEVELOPER)
options = helper.namespaces_options_with_developer_maintainer_access
expect(options).to include(admin_group.name)
expect(options).not_to include(subgroup1.name)
expect(options).to include(subgroup2.name)
expect(options).not_to include(subgroup3.name)
expect(options).to include(user_group.name)
expect(options).to include(user.name)
end
end
context 'when DEVELOPER_MAINTAINER_PROJECT_ACCESS is set globally' do
it 'return groups where default is not overridden' do
allow(helper).to receive(:current_user).and_return(user)
stub_application_setting(default_project_creation: ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS)
admin_group.add_user(user, GroupMember::DEVELOPER)
options = helper.namespaces_options_with_developer_maintainer_access
expect(options).to include(admin_group.name)
expect(options).to include(subgroup1.name)
expect(options).to include(subgroup2.name)
expect(options).not_to include(subgroup3.name)
expect(options).to include(user_group.name)
expect(options).to include(user.name)
end
end
end
end
describe '#namespace_shared_runner_limits_quota' do
context "when it's unlimited" do
before do
......
......@@ -182,16 +182,6 @@ describe Group do
end
end
describe 'project_creation_level' do
it 'outputs the default one if it is nil' do
stub_application_setting(default_project_creation: ::EE::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
group = create(:group, project_creation_level: nil)
expect(group.project_creation_level).to eq(Gitlab::CurrentSettings.default_project_creation)
end
end
describe '#file_template_project' do
it { expect(group.private_methods).to include(:file_template_project) }
......
......@@ -146,244 +146,6 @@ describe GroupPolicy do
end
end
context "create_projects" do
context 'project_creation_level enabled' do
before do
stub_licensed_features(project_creation_level: true)
end
context 'when group has no project creation level set' do
let(:group) { create(:group, project_creation_level: nil) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_projects) }
end
end
context 'when group has project creation level set to no one' do
let(:group) { create(:group, project_creation_level: ::EE::Gitlab::Access::NO_ONE_PROJECT_ACCESS) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_disallowed(:create_projects) }
end
end
context 'when group has project creation level set to maintainer only' do
let(:group) { create(:group, project_creation_level: ::EE::Gitlab::Access::MAINTAINER_PROJECT_ACCESS) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_projects) }
end
end
context 'when group has project creation level set to developers + maintainer' do
let(:group) { create(:group, project_creation_level: ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_projects) }
end
end
end
context 'project_creation_level disabled' do
before do
stub_licensed_features(project_creation_level: false)
end
context 'when group has no project creation level set' do
let(:group) { create(:group, project_creation_level: nil) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_projects) }
end
end
context 'when group has project creation level set to no one' do
let(:group) { create(:group, project_creation_level: ::EE::Gitlab::Access::NO_ONE_PROJECT_ACCESS) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_projects) }
end
end
context 'when group has project creation level set to maintainer only' do
let(:group) { create(:group, project_creation_level: ::EE::Gitlab::Access::MAINTAINER_PROJECT_ACCESS) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_projects) }
end
end
context 'when group has project creation level set to developers + maintainer' do
let(:group) { create(:group, project_creation_level: ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_projects) }
end
end
end
end
describe 'read_group_security_dashboard' do
before do
stub_licensed_features(security_dashboard: true)
......
......@@ -40,7 +40,8 @@ module API
end
optional :container_registry_token_expire_delay, type: Integer, desc: 'Authorization token duration (minutes)'
optional :default_artifacts_expire_in, type: String, desc: "Set the default expiration time for each job's artifacts"
optional :default_branch_protection, type: Integer, values: Gitlab::Access.protection_values, desc: 'Determine if developers can push to master'
optional :default_project_creation, type: Integer, values: ::Gitlab::Access.project_creation_values, desc: 'Determine if developers can create projects in the group'
optional :default_branch_protection, type: Integer, values: ::Gitlab::Access.protection_values, desc: 'Determine if developers can push to master'
optional :default_group_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default group visibility'
optional :default_project_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default project visibility'
optional :default_projects_limit, type: Integer, desc: 'The maximum number of personal projects'
......
......@@ -24,6 +24,11 @@ module Gitlab
PROTECTION_FULL = 2
PROTECTION_DEV_CAN_MERGE = 3
# Default project creation level
NO_ONE_PROJECT_ACCESS = 0
MAINTAINER_PROJECT_ACCESS = 1
DEVELOPER_MAINTAINER_PROJECT_ACCESS = 2
class << self
delegate :values, to: :options
......@@ -85,6 +90,22 @@ module Gitlab
def human_access_with_none(access)
options_with_none.key(access)
end
def project_creation_options
{
s_('ProjectCreationLevel|No one') => NO_ONE_PROJECT_ACCESS,
s_('ProjectCreationLevel|Maintainers') => MAINTAINER_PROJECT_ACCESS,
s_('ProjectCreationLevel|Developers + Maintainers') => DEVELOPER_MAINTAINER_PROJECT_ACCESS
}
end
def project_creation_values
project_creation_options.values
end
def project_creation_level_name(name)
project_creation_options.key(name)
end
end
def human_access
......
......@@ -85,6 +85,13 @@ describe Admin::ApplicationSettingsController do
expect(response).to redirect_to(admin_application_settings_path)
expect(ApplicationSetting.current.receive_max_input_size).to eq(1024)
end
it 'updates the default_project_creation for string value' do
put :update, params: { application_setting: { default_project_creation: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS } }
expect(response).to redirect_to(admin_application_settings_path)
expect(ApplicationSetting.current.default_project_creation).to eq(::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
end
end
describe 'PUT #reset_registration_token' do
......
......@@ -60,5 +60,11 @@ describe Admin::GroupsController do
expect(response).to redirect_to(admin_group_path(group))
expect(group.users).not_to include group_user
end
it 'updates the project_creation_level successfully' do
expect do
post :update, params: { id: group.to_param, group: { project_creation_level: ::Gitlab::Access::NO_ONE_PROJECT_ACCESS } }
end.to change { group.reload.project_creation_level }.to(::Gitlab::Access::NO_ONE_PROJECT_ACCESS)
end
end
end
......@@ -374,13 +374,6 @@ describe GroupsController do
expect(controller).to set_flash[:notice]
end
it 'updates the project_creation_level successfully' do
post :update, params: { id: group.to_param, group: { project_creation_level: ::EE::Gitlab::Access::MAINTAINER_PROJECT_ACCESS } }
expect(response).to have_gitlab_http_status(302)
expect(group.reload.project_creation_level).to eq(::EE::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
end
it 'does not update the path on error' do
allow_any_instance_of(Group).to receive(:move_dir).and_raise(Gitlab::UpdatePathError)
post :update, params: { id: group.to_param, group: { path: 'new_path' } }
......@@ -388,6 +381,13 @@ describe GroupsController do
expect(assigns(:group).errors).not_to be_empty
expect(assigns(:group).path).not_to eq('new_path')
end
it 'updates the project_creation_level successfully' do
post :update, params: { id: group.to_param, group: { project_creation_level: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS } }
expect(response).to have_gitlab_http_status(302)
expect(group.reload.project_creation_level).to eq(::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
end
end
describe '#ensure_canonical_path' do
......
......@@ -4,6 +4,7 @@ FactoryBot.define do
path { name.downcase.gsub(/\s/, '_') }
type 'Group'
owner nil
project_creation_level ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS
after(:create) do |group|
if group.owner
......
......@@ -77,6 +77,14 @@ describe 'Edit group settings' do
end
end
describe 'project creation level menu' do
it 'shows the selection menu' do
visit edit_group_path(group)
expect(page).to have_content('Allowed to create projects')
end
end
describe 'edit group avatar' do
before do
visit edit_group_path(group)
......
......@@ -252,4 +252,23 @@ describe 'New project' do
end
end
end
context 'Namespace selector' do
context 'with group with DEVELOPER_MAINTAINER_PROJECT_ACCESS project_creation_level' do
let(:group) { create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
before do
group.add_developer(user)
visit new_project_path(namespace_id: group.id)
end
it 'selects the group namespace' do
page.within('#blank-project-pane') do
namespace = find('#project_namespace_id option[selected]')
expect(namespace.text).to eq group.full_path
end
end
end
end
end
......@@ -54,4 +54,31 @@ describe 'User creates a project', :js do
expect(project.namespace).to eq(subgroup)
end
end
context 'in a group with DEVELOPER_MAINTAINER_PROJECT_ACCESS project_creation_level' do
let(:group) { create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
before do
group.add_developer(user)
end
it 'creates a new project' do
visit(new_project_path)
fill_in :project_name, with: 'a-new-project'
fill_in :project_path, with: 'a-new-project'
page.find('.js-select-namespace').click
page.find("div[role='option']", text: group.full_path).click
page.within('#content-body') do
click_button('Create project')
end
expect(page).to have_content("Project 'a-new-project' was successfully created")
project = Project.find_by(name: 'a-new-project')
expect(project.namespace).to eq(group)
end
end
end
require 'spec_helper'
describe NamespacesHelper do
describe NamespacesHelper, :postgresql do
let!(:admin) { create(:admin) }
let!(:admin_group) { create(:group, :private) }
let!(:admin_project_creation_level) { nil }
let!(:admin_group) do
create(:group,
:private,
project_creation_level: admin_project_creation_level)
end
let!(:user) { create(:user) }
let!(:user_group) { create(:group, :private) }
let!(:user_project_creation_level) { nil }
let!(:user_group) do
create(:group,
:private,
project_creation_level: user_project_creation_level)
end
let!(:subgroup1) do
create(:group,
:private,
parent: admin_group,
project_creation_level: nil)
end
let!(:subgroup2) do
create(:group,
:private,
parent: admin_group,
project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS)
end
let!(:subgroup3) do
create(:group,
:private,
parent: admin_group,
project_creation_level: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
end
before do
admin_group.add_owner(admin)
......@@ -105,5 +133,43 @@ describe NamespacesHelper do
helper.namespaces_options
end
end
describe 'include_groups_with_developer_maintainer_access parameter' do
context 'when DEVELOPER_MAINTAINER_PROJECT_ACCESS is set for a project' do
let!(:admin_project_creation_level) { ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS }
it 'returns groups where user is a developer' do
allow(helper).to receive(:current_user).and_return(user)
stub_application_setting(default_project_creation: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
admin_group.add_user(user, GroupMember::DEVELOPER)
options = helper.namespaces_options_with_developer_maintainer_access
expect(options).to include(admin_group.name)
expect(options).not_to include(subgroup1.name)
expect(options).to include(subgroup2.name)
expect(options).not_to include(subgroup3.name)
expect(options).to include(user_group.name)
expect(options).to include(user.name)
end
end
context 'when DEVELOPER_MAINTAINER_PROJECT_ACCESS is set globally' do
it 'return groups where default is not overridden' do
allow(helper).to receive(:current_user).and_return(user)
stub_application_setting(default_project_creation: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS)
admin_group.add_user(user, GroupMember::DEVELOPER)
options = helper.namespaces_options_with_developer_maintainer_access
expect(options).to include(admin_group.name)
expect(options).to include(subgroup1.name)
expect(options).to include(subgroup2.name)
expect(options).not_to include(subgroup3.name)
expect(options).to include(user_group.name)
expect(options).to include(user.name)
end
end
end
end
end
......@@ -959,4 +959,12 @@ describe Group do
end
end
end
describe 'project_creation_level' do
it 'outputs the default one if it is nil' do
group = create(:group, project_creation_level: nil)
expect(group.project_creation_level).to eq(Gitlab::CurrentSettings.default_project_creation)
end
end
end
......@@ -347,6 +347,120 @@ describe GroupPolicy do
end
end
context "create_projects" do
context 'when group has no project creation level set' do
let(:group) { create(:group, project_creation_level: nil) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_projects) }
end
end
context 'when group has project creation level set to no one' do
let(:group) { create(:group, project_creation_level: ::Gitlab::Access::NO_ONE_PROJECT_ACCESS) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_disallowed(:create_projects) }
end
end
context 'when group has project creation level set to maintainer only' do
let(:group) { create(:group, project_creation_level: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_projects) }
end
end
context 'when group has project creation level set to developers + maintainer' do
let(:group) { create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
context 'reporter' do
let(:current_user) { reporter }
it { is_expected.to be_disallowed(:create_projects) }
end
context 'developer' do
let(:current_user) { developer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'maintainer' do
let(:current_user) { maintainer }
it { is_expected.to be_allowed(:create_projects) }
end
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:create_projects) }
end
end
end
it_behaves_like 'clusterable policies' do
let(:clusterable) { create(:group) }
let(:cluster) do
......
......@@ -45,6 +45,7 @@ describe API::Settings, 'Settings' do
put api("/application/settings", admin),
params: {
default_projects_limit: 3,
default_project_creation: 2,
password_authentication_enabled_for_web: false,
repository_storages: ['custom'],
plantuml_enabled: true,
......@@ -65,12 +66,13 @@ describe API::Settings, 'Settings' do
performance_bar_allowed_group_path: group.full_path,
instance_statistics_visibility_private: true,
diff_max_patch_bytes: 150_000,
default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE,
default_branch_protection: ::Gitlab::Access::PROTECTION_DEV_CAN_MERGE,
local_markdown_version: 3
}
expect(response).to have_gitlab_http_status(200)
expect(json_response['default_projects_limit']).to eq(3)
expect(json_response['default_project_creation']).to eq(::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS)
expect(json_response['password_authentication_enabled_for_web']).to be_falsey
expect(json_response['repository_storages']).to eq(['custom'])
expect(json_response['plantuml_enabled']).to be_truthy
......
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