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 ...@@ -89,7 +89,8 @@ class Admin::GroupsController < Admin::ApplicationController
:request_access_enabled, :request_access_enabled,
:visibility_level, :visibility_level,
:require_two_factor_authentication, :require_two_factor_authentication,
:two_factor_grace_period :two_factor_grace_period,
:project_creation_level
] ]
end end
end end
......
...@@ -187,7 +187,8 @@ class GroupsController < Groups::ApplicationController ...@@ -187,7 +187,8 @@ class GroupsController < Groups::ApplicationController
:create_chat_team, :create_chat_team,
:chat_team_name, :chat_team_name,
:require_two_factor_authentication, :require_two_factor_authentication,
:two_factor_grace_period :two_factor_grace_period,
:project_creation_level
] ]
end end
......
...@@ -137,6 +137,7 @@ module ApplicationSettingsHelper ...@@ -137,6 +137,7 @@ module ApplicationSettingsHelper
:default_artifacts_expire_in, :default_artifacts_expire_in,
:default_branch_protection, :default_branch_protection,
:default_group_visibility, :default_group_visibility,
:default_project_creation,
:default_project_visibility, :default_project_visibility,
:default_projects_limit, :default_projects_limit,
:default_snippet_visibility, :default_snippet_visibility,
......
...@@ -49,6 +49,13 @@ module NamespacesHelper ...@@ -49,6 +49,13 @@ module NamespacesHelper
end end
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 private
# Many importers create a temporary Group, so use the real # Many importers create a temporary Group, so use the real
......
...@@ -26,6 +26,7 @@ module ApplicationSettingImplementation ...@@ -26,6 +26,7 @@ module ApplicationSettingImplementation
default_artifacts_expire_in: '30 days', default_artifacts_expire_in: '30 days',
default_branch_protection: Settings.gitlab['default_branch_protection'], default_branch_protection: Settings.gitlab['default_branch_protection'],
default_group_visibility: Settings.gitlab.default_projects_features['visibility_level'], 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_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_projects_limit: Settings.gitlab['default_projects_limit'], default_projects_limit: Settings.gitlab['default_projects_limit'],
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'], default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
......
...@@ -404,6 +404,10 @@ class Group < Namespace ...@@ -404,6 +404,10 @@ class Group < Namespace
Feature.enabled?(:group_clusters, root_ancestor, default_enabled: true) Feature.enabled?(:group_clusters, root_ancestor, default_enabled: true)
end end
def project_creation_level
super || ::Gitlab::CurrentSettings.default_project_creation
end
private private
def update_two_factor_requirement def update_two_factor_requirement
......
...@@ -105,6 +105,7 @@ class User < ApplicationRecord ...@@ -105,6 +105,7 @@ class User < ApplicationRecord
has_many :groups, through: :group_members has_many :groups, through: :group_members
has_many :owned_groups, -> { where(members: { access_level: Gitlab::Access::OWNER }) }, through: :group_members, source: :group 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 :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, has_many :owned_or_maintainers_groups,
-> { where(members: { access_level: [Gitlab::Access::MAINTAINER, Gitlab::Access::OWNER] }) }, -> { where(members: { access_level: [Gitlab::Access::MAINTAINER, Gitlab::Access::OWNER] }) },
through: :group_members, through: :group_members,
...@@ -883,7 +884,12 @@ class User < ApplicationRecord ...@@ -883,7 +884,12 @@ class User < ApplicationRecord
# rubocop: enable CodeReuse/ServiceClass # rubocop: enable CodeReuse/ServiceClass
def several_namespaces? 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 end
def namespace_id def namespace_id
...@@ -1169,12 +1175,24 @@ class User < ApplicationRecord ...@@ -1169,12 +1175,24 @@ class User < ApplicationRecord
@manageable_namespaces ||= [namespace] + manageable_groups @manageable_namespaces ||= [namespace] + manageable_groups
end end
def manageable_groups def manageable_groups(include_groups_with_developer_maintainer_access: false)
Gitlab::ObjectHierarchy.new(owned_or_maintainers_groups).base_and_descendants 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 end
def manageable_groups_with_routes def manageable_groups_with_routes(include_groups_with_developer_maintainer_access: false)
manageable_groups.eager_load(:route).order('routes.path') manageable_groups(include_groups_with_developer_maintainer_access: include_groups_with_developer_maintainer_access)
.eager_load(:route)
.order('routes.path')
end end
def namespaces def namespaces
...@@ -1573,6 +1591,18 @@ class User < ApplicationRecord ...@@ -1573,6 +1591,18 @@ class User < ApplicationRecord
ensure ensure
Gitlab::ExclusiveLease.cancel(lease_key, uuid) Gitlab::ExclusiveLease.cancel(lease_key, uuid)
end 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 end
User.prepend(EE::User) User.prepend(EE::User)
...@@ -35,6 +35,14 @@ class GroupPolicy < BasePolicy ...@@ -35,6 +35,14 @@ class GroupPolicy < BasePolicy
with_options scope: :subject, score: 0 with_options scope: :subject, score: 0
condition(:request_access_enabled) { @subject.request_access_enabled } 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 rule { public_group }.policy do
enable :read_group enable :read_group
enable :read_list enable :read_list
...@@ -115,6 +123,9 @@ class GroupPolicy < BasePolicy ...@@ -115,6 +123,9 @@ class GroupPolicy < BasePolicy
rule { ~can_have_multiple_clusters & has_clusters }.prevent :add_cluster 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 def access_level
return GroupMember::NO_ACCESS if @user.nil? return GroupMember::NO_ACCESS if @user.nil?
......
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
.form-group .form-group
= f.label :default_branch_protection, class: 'label-bold' = 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' = 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 .form-group.visibility-level-setting
= f.label :default_project_visibility, class: 'label-bold' = 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) = 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 @@ ...@@ -9,8 +9,10 @@
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
%br/ %br/
%span.descr This setting can be overridden in each project. %span.descr This setting can be overridden in each project.
.form-group.row
= render partial: 'groups/ee/old_project_creation_level', locals: { form: f, group: @group } = 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 .form-group.row
= f.label :require_two_factor_authentication, 'Two-factor authentication', class: 'col-form-label col-sm-2 pt-0' = f.label :require_two_factor_authentication, 'Two-factor authentication', class: 'col-form-label col-sm-2 pt-0'
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
%span.descr.text-muted= share_with_group_lock_help_text(@group) %span.descr.text-muted= share_with_group_lock_help_text(@group)
= render 'groups/settings/lfs', f: f = 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 'groups/settings/two_factor_auth', f: f
= render_if_exists 'groups/member_lock_setting', f: f, group: @group = 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'] ||= {} ...@@ -137,7 +137,7 @@ Settings['issues_tracker'] ||= {}
# GitLab # GitLab
# #
Settings['gitlab'] ||= Settingslogic.new({}) 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_projects_limit'] ||= 100000
Settings.gitlab['default_branch_protection'] ||= 2 Settings.gitlab['default_branch_protection'] ||= 2
Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_can_create_group'].nil? 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 ...@@ -179,7 +179,6 @@ ActiveRecord::Schema.define(version: 20190403161806) do
t.integer "gitaly_timeout_medium", default: 30, null: false t.integer "gitaly_timeout_medium", default: 30, null: false
t.integer "gitaly_timeout_fast", default: 10, null: false t.integer "gitaly_timeout_fast", default: 10, null: false
t.boolean "mirror_available", default: true, 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_web"
t.boolean "password_authentication_enabled_for_git", default: true, null: false t.boolean "password_authentication_enabled_for_git", default: true, null: false
t.string "auto_devops_domain" t.string "auto_devops_domain"
...@@ -218,6 +217,7 @@ ActiveRecord::Schema.define(version: 20190403161806) do ...@@ -218,6 +217,7 @@ ActiveRecord::Schema.define(version: 20190403161806) do
t.integer "local_markdown_version", default: 0, null: false t.integer "local_markdown_version", default: 0, null: false
t.integer "first_day_of_week", default: 0, null: false t.integer "first_day_of_week", default: 0, null: false
t.boolean "elasticsearch_limit_indexing", default: false, 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 ["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 ["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 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: ...@@ -153,20 +153,20 @@ There are two different ways to add a new project to a group:
![Select group](img/select_group_dropdown.png) ![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. > [Introduced][ee-2534] in [GitLab Premium][ee] 10.5.
> Brought to [GitLab Starter][ee] in 10.7. > 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 Group owners or administrators can allow users with the
Developer role the ability to create projects under groups. Developer role to create projects under groups.
By default, `Developers` and `Maintainers` are allowed to create projects under a 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
group, 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 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 ## Transfer projects into groups
......
...@@ -10,10 +10,6 @@ module EE ...@@ -10,10 +10,6 @@ module EE
attrs += EE::ApplicationSettingsHelper.repository_mirror_attributes attrs += EE::ApplicationSettingsHelper.repository_mirror_attributes
end end
if License.feature_available?(:project_creation_level)
attrs << :default_project_creation
end
if License.feature_available?(:external_authorization_service) if License.feature_available?(:external_authorization_service)
attrs += EE::ApplicationSettingsHelper.external_authorization_service_attributes attrs += EE::ApplicationSettingsHelper.external_authorization_service_attributes
end end
......
...@@ -22,9 +22,7 @@ module EE ...@@ -22,9 +22,7 @@ module EE
:repository_size_limit, :repository_size_limit,
:shared_runners_minutes_limit, :shared_runners_minutes_limit,
gitlab_subscription_attributes: [:hosted_plan_id] 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 end
end end
......
...@@ -26,7 +26,6 @@ module EE ...@@ -26,7 +26,6 @@ module EE
:repository_size_limit :repository_size_limit
].tap do |params_ee| ].tap do |params_ee|
params_ee << { insight_attributes: :project_id } if current_group&.insights_available? 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 << :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) params_ee << :custom_project_templates_group_id if License.feature_available?(:custom_project_templates)
end end
......
...@@ -68,16 +68,5 @@ module EE ...@@ -68,16 +68,5 @@ module EE
namespace_shared_runner_usage_progress_bar(percent) namespace_shared_runner_usage_progress_bar(percent)
end 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
end end
...@@ -102,7 +102,6 @@ module EE ...@@ -102,7 +102,6 @@ module EE
def defaults def defaults
super.merge( super.merge(
allow_group_owners_to_manage_ldap: true, allow_group_owners_to_manage_ldap: true,
default_project_creation: ::EE::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS,
elasticsearch_aws: false, elasticsearch_aws: false,
elasticsearch_aws_region: ENV['ELASTIC_REGION'] || 'us-east-1', elasticsearch_aws_region: ENV['ELASTIC_REGION'] || 'us-east-1',
elasticsearch_url: ENV['ELASTIC_URL'] || 'http://localhost:9200', elasticsearch_url: ENV['ELASTIC_URL'] || 'http://localhost:9200',
......
...@@ -153,10 +153,6 @@ module EE ...@@ -153,10 +153,6 @@ module EE
ensure_saml_discovery_token! ensure_saml_discovery_token!
end end
def project_creation_level
super || ::Gitlab::CurrentSettings.default_project_creation
end
override :multiple_issue_boards_available? override :multiple_issue_boards_available?
def multiple_issue_boards_available? def multiple_issue_boards_available?
feature_available?(:multiple_group_issue_boards) feature_available?(:multiple_group_issue_boards)
......
...@@ -167,43 +167,6 @@ module EE ...@@ -167,43 +167,6 @@ module EE
super || DEFAULT_GROUP_VIEW super || DEFAULT_GROUP_VIEW
end 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? def any_namespace_with_trial?
::Namespace ::Namespace
.from("(#{namespace_union(:trial_ends_on)}) #{::Namespace.table_name}") .from("(#{namespace_union(:trial_ends_on)}) #{::Namespace.table_name}")
......
...@@ -28,7 +28,6 @@ class License < ApplicationRecord ...@@ -28,7 +28,6 @@ class License < ApplicationRecord
multiple_issue_assignees multiple_issue_assignees
multiple_project_issue_boards multiple_project_issue_boards
push_rules push_rules
project_creation_level
protected_refs_for_users protected_refs_for_users
related_issues related_issues
repository_mirrors repository_mirrors
......
...@@ -12,16 +12,6 @@ module EE ...@@ -12,16 +12,6 @@ module EE
@subject.feature_available?(:contribution_analytics) @subject.feature_available?(:contribution_analytics)
end 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 condition(:can_owners_manage_ldap, scope: :global) do
::Gitlab::CurrentSettings.current_application_settings ::Gitlab::CurrentSettings.current_application_settings
.allow_group_owners_to_manage_ldap .allow_group_owners_to_manage_ldap
...@@ -69,9 +59,6 @@ module EE ...@@ -69,9 +59,6 @@ module EE
rule { ldap_synced & (admin | (can_owners_manage_ldap & owner)) }.enable :override_group_member 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 rule { developer }.policy do
enable :read_group_security_dashboard enable :read_group_security_dashboard
end 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] ...@@ -6,10 +6,14 @@ class AddDefaultProjectCreationSetting < ActiveRecord::Migration[4.2]
disable_ddl_transaction! disable_ddl_transaction!
def up def up
unless column_exists?(:application_settings, :default_project_creation)
add_column_with_default(:application_settings, :default_project_creation, :integer, default: 2) add_column_with_default(:application_settings, :default_project_creation, :integer, default: 2)
end end
end
def down def down
if column_exists?(:application_settings, :default_project_creation)
remove_column(:application_settings, :default_project_creation) remove_column(:application_settings, :default_project_creation)
end end
end
end end
...@@ -3,7 +3,15 @@ class AddProjectCreationLevelToGroups < ActiveRecord::Migration[4.2] ...@@ -3,7 +3,15 @@ class AddProjectCreationLevelToGroups < ActiveRecord::Migration[4.2]
DOWNTIME = false DOWNTIME = false
def change def up
add_column :namespaces, :project_creation_level, :integer 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
end end
...@@ -33,8 +33,8 @@ module EE ...@@ -33,8 +33,8 @@ module EE
} }
when :project_creation_level when :project_creation_level
{ {
from: ::Gitlab::Access.level_name(old), from: ::Gitlab::Access.project_creation_level_name(old),
to: ::Gitlab::Access.level_name(new) to: ::Gitlab::Access.project_creation_level_name(new)
} }
when :plan_id when :plan_id
{ {
......
...@@ -9,26 +9,7 @@ module EE ...@@ -9,26 +9,7 @@ module EE
module Gitlab module Gitlab
module Access module Access
extend ActiveSupport::Concern extend ActiveSupport::Concern
# Default project creation level
NO_ONE_PROJECT_ACCESS = 0
MAINTAINER_PROJECT_ACCESS = 1
DEVELOPER_MAINTAINER_PROJECT_ACCESS = 2
ADMIN = 60 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 end
end end
...@@ -112,14 +112,6 @@ describe Admin::ApplicationSettingsController do ...@@ -112,14 +112,6 @@ describe Admin::ApplicationSettingsController do
it_behaves_like 'settings for licensed features' it_behaves_like 'settings for licensed features'
end 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 it 'updates repository_size_limit' do
put :update, params: { application_setting: { repository_size_limit: '100' } } put :update, params: { application_setting: { repository_size_limit: '100' } }
......
...@@ -38,26 +38,4 @@ describe Admin::GroupsController do ...@@ -38,26 +38,4 @@ describe Admin::GroupsController do
end end
end 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 end
# frozen_string_literal: true # frozen_string_literal: true
FactoryBot.modify do
factory :group do
project_creation_level ::EE::Gitlab::Access::MAINTAINER_PROJECT_ACCESS
end
end
FactoryBot.define do FactoryBot.define do
factory :group_with_members, parent: :group do factory :group_with_members, parent: :group do
after(:create) do |group, evaluator| after(:create) do |group, evaluator|
......
...@@ -62,26 +62,6 @@ describe 'Edit group settings' do ...@@ -62,26 +62,6 @@ describe 'Edit group settings' do
end end
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 describe 'Member Lock setting' do
context 'without a license key' do context 'without a license key' do
before do before do
......
...@@ -7,25 +7,6 @@ describe 'New project' do ...@@ -7,25 +7,6 @@ describe 'New project' do
sign_in(user) sign_in(user)
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: ::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 'repository mirrors' do
context 'when licensed' do context 'when licensed' do
before 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 ...@@ -16,70 +16,12 @@ describe EE::NamespacesHelper, :postgresql do
:private, :private,
project_creation_level: user_project_creation_level) project_creation_level: user_project_creation_level)
end 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 before do
admin_group.add_owner(admin) admin_group.add_owner(admin)
user_group.add_owner(user) user_group.add_owner(user)
end 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 describe '#namespace_shared_runner_limits_quota' do
context "when it's unlimited" do context "when it's unlimited" do
before do before do
......
...@@ -182,16 +182,6 @@ describe Group do ...@@ -182,16 +182,6 @@ describe Group do
end end
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 describe '#file_template_project' do
it { expect(group.private_methods).to include(:file_template_project) } it { expect(group.private_methods).to include(:file_template_project) }
......
...@@ -146,244 +146,6 @@ describe GroupPolicy do ...@@ -146,244 +146,6 @@ describe GroupPolicy do
end end
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 describe 'read_group_security_dashboard' do
before do before do
stub_licensed_features(security_dashboard: true) stub_licensed_features(security_dashboard: true)
......
...@@ -40,7 +40,8 @@ module API ...@@ -40,7 +40,8 @@ module API
end end
optional :container_registry_token_expire_delay, type: Integer, desc: 'Authorization token duration (minutes)' 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_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_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_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' optional :default_projects_limit, type: Integer, desc: 'The maximum number of personal projects'
......
...@@ -24,6 +24,11 @@ module Gitlab ...@@ -24,6 +24,11 @@ module Gitlab
PROTECTION_FULL = 2 PROTECTION_FULL = 2
PROTECTION_DEV_CAN_MERGE = 3 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 class << self
delegate :values, to: :options delegate :values, to: :options
...@@ -85,6 +90,22 @@ module Gitlab ...@@ -85,6 +90,22 @@ module Gitlab
def human_access_with_none(access) def human_access_with_none(access)
options_with_none.key(access) options_with_none.key(access)
end 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 end
def human_access def human_access
......
...@@ -85,6 +85,13 @@ describe Admin::ApplicationSettingsController do ...@@ -85,6 +85,13 @@ describe Admin::ApplicationSettingsController do
expect(response).to redirect_to(admin_application_settings_path) expect(response).to redirect_to(admin_application_settings_path)
expect(ApplicationSetting.current.receive_max_input_size).to eq(1024) expect(ApplicationSetting.current.receive_max_input_size).to eq(1024)
end 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 end
describe 'PUT #reset_registration_token' do describe 'PUT #reset_registration_token' do
......
...@@ -60,5 +60,11 @@ describe Admin::GroupsController do ...@@ -60,5 +60,11 @@ describe Admin::GroupsController do
expect(response).to redirect_to(admin_group_path(group)) expect(response).to redirect_to(admin_group_path(group))
expect(group.users).not_to include group_user expect(group.users).not_to include group_user
end 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
end end
...@@ -374,13 +374,6 @@ describe GroupsController do ...@@ -374,13 +374,6 @@ describe GroupsController do
expect(controller).to set_flash[:notice] expect(controller).to set_flash[:notice]
end 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 it 'does not update the path on error' do
allow_any_instance_of(Group).to receive(:move_dir).and_raise(Gitlab::UpdatePathError) allow_any_instance_of(Group).to receive(:move_dir).and_raise(Gitlab::UpdatePathError)
post :update, params: { id: group.to_param, group: { path: 'new_path' } } post :update, params: { id: group.to_param, group: { path: 'new_path' } }
...@@ -388,6 +381,13 @@ describe GroupsController do ...@@ -388,6 +381,13 @@ describe GroupsController do
expect(assigns(:group).errors).not_to be_empty expect(assigns(:group).errors).not_to be_empty
expect(assigns(:group).path).not_to eq('new_path') expect(assigns(:group).path).not_to eq('new_path')
end 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 end
describe '#ensure_canonical_path' do describe '#ensure_canonical_path' do
......
...@@ -4,6 +4,7 @@ FactoryBot.define do ...@@ -4,6 +4,7 @@ FactoryBot.define do
path { name.downcase.gsub(/\s/, '_') } path { name.downcase.gsub(/\s/, '_') }
type 'Group' type 'Group'
owner nil owner nil
project_creation_level ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS
after(:create) do |group| after(:create) do |group|
if group.owner if group.owner
......
...@@ -77,6 +77,14 @@ describe 'Edit group settings' do ...@@ -77,6 +77,14 @@ describe 'Edit group settings' do
end end
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 describe 'edit group avatar' do
before do before do
visit edit_group_path(group) visit edit_group_path(group)
......
...@@ -252,4 +252,23 @@ describe 'New project' do ...@@ -252,4 +252,23 @@ describe 'New project' do
end end
end 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 end
...@@ -54,4 +54,31 @@ describe 'User creates a project', :js do ...@@ -54,4 +54,31 @@ describe 'User creates a project', :js do
expect(project.namespace).to eq(subgroup) expect(project.namespace).to eq(subgroup)
end end
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 end
require 'spec_helper' require 'spec_helper'
describe NamespacesHelper do describe NamespacesHelper, :postgresql do
let!(:admin) { create(:admin) } 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) { 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 before do
admin_group.add_owner(admin) admin_group.add_owner(admin)
...@@ -105,5 +133,43 @@ describe NamespacesHelper do ...@@ -105,5 +133,43 @@ describe NamespacesHelper do
helper.namespaces_options helper.namespaces_options
end end
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
end end
...@@ -959,4 +959,12 @@ describe Group do ...@@ -959,4 +959,12 @@ describe Group do
end end
end 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 end
...@@ -347,6 +347,120 @@ describe GroupPolicy do ...@@ -347,6 +347,120 @@ describe GroupPolicy do
end end
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 it_behaves_like 'clusterable policies' do
let(:clusterable) { create(:group) } let(:clusterable) { create(:group) }
let(:cluster) do let(:cluster) do
......
...@@ -45,6 +45,7 @@ describe API::Settings, 'Settings' do ...@@ -45,6 +45,7 @@ describe API::Settings, 'Settings' do
put api("/application/settings", admin), put api("/application/settings", admin),
params: { params: {
default_projects_limit: 3, default_projects_limit: 3,
default_project_creation: 2,
password_authentication_enabled_for_web: false, password_authentication_enabled_for_web: false,
repository_storages: ['custom'], repository_storages: ['custom'],
plantuml_enabled: true, plantuml_enabled: true,
...@@ -65,12 +66,13 @@ describe API::Settings, 'Settings' do ...@@ -65,12 +66,13 @@ describe API::Settings, 'Settings' do
performance_bar_allowed_group_path: group.full_path, performance_bar_allowed_group_path: group.full_path,
instance_statistics_visibility_private: true, instance_statistics_visibility_private: true,
diff_max_patch_bytes: 150_000, 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 local_markdown_version: 3
} }
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(json_response['default_projects_limit']).to eq(3) 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['password_authentication_enabled_for_web']).to be_falsey
expect(json_response['repository_storages']).to eq(['custom']) expect(json_response['repository_storages']).to eq(['custom'])
expect(json_response['plantuml_enabled']).to be_truthy 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