2019-07-31 22:56:46 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
require 'spec_helper'
2023-03-17 16:20:25 +05:30
RSpec . describe Projects :: CreateService , '#execute' , feature_category : :projects do
2019-07-07 11:18:12 +05:30
include ExternalAuthorizationServiceHelpers
2018-12-05 23:21:45 +05:30
2017-08-17 22:00:37 +05:30
let ( :user ) { create :user }
2022-04-04 11:22:00 +05:30
let ( :project_name ) { 'GitLab' }
2017-08-17 22:00:37 +05:30
let ( :opts ) do
{
2022-04-04 11:22:00 +05:30
name : project_name ,
2017-09-10 17:25:29 +05:30
namespace_id : user . namespace . id
2017-08-17 22:00:37 +05:30
}
end
2021-01-03 14:25:43 +05:30
context 'with labels' do
subject ( :project ) { create_project ( user , opts ) }
before_all do
Label . create! ( title : 'bug' , template : true )
end
it 'creates labels on project creation' do
2022-05-07 20:08:51 +05:30
expect ( project . labels ) . to include have_attributes (
type : eq ( 'ProjectLabel' ) ,
project_id : eq ( project . id ) ,
title : eq ( 'bug' )
)
2021-01-03 14:25:43 +05:30
end
context 'using gitlab project import' do
before do
opts [ :import_type ] = 'gitlab_project'
end
2019-03-02 22:35:43 +05:30
2021-01-03 14:25:43 +05:30
it 'does not creates labels on project creation' do
expect ( project . labels . size ) . to eq ( 0 )
end
end
2017-08-17 22:00:37 +05:30
end
2014-09-02 18:07:02 +05:30
2021-03-11 19:13:27 +05:30
describe 'setting name and path' do
subject ( :project ) { create_project ( user , opts ) }
context 'when both are set' do
let ( :opts ) { { name : 'one' , path : 'two' } }
it 'keeps them as specified' do
expect ( project . name ) . to eq ( 'one' )
expect ( project . path ) . to eq ( 'two' )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2021-03-11 19:13:27 +05:30
end
end
context 'when path is set' do
let ( :opts ) { { path : 'one.two_three-four' } }
it 'sets name == path' do
expect ( project . path ) . to eq ( 'one.two_three-four' )
expect ( project . name ) . to eq ( project . path )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2021-03-11 19:13:27 +05:30
end
end
context 'when name is a valid path' do
let ( :opts ) { { name : 'one.two_three-four' } }
it 'sets path == name' do
expect ( project . name ) . to eq ( 'one.two_three-four' )
expect ( project . path ) . to eq ( project . name )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2021-03-11 19:13:27 +05:30
end
end
context 'when name is not a valid path' do
let ( :opts ) { { name : 'one.two_three-four and five' } }
# TODO: Retained for backwards compatibility. Remove in API v5.
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52725
it 'parameterizes the name' do
expect ( project . name ) . to eq ( 'one.two_three-four and five' )
expect ( project . path ) . to eq ( 'one-two_three-four-and-five' )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2021-03-11 19:13:27 +05:30
end
end
end
2021-09-04 01:27:46 +05:30
describe 'topics' do
subject ( :project ) { create_project ( user , opts ) }
context " with 'topics' parameter " do
2021-11-11 11:23:49 +05:30
let ( :opts ) { { name : 'topic-project' , topics : 'topics' } }
2021-09-04 01:27:46 +05:30
it 'keeps them as specified' do
expect ( project . topic_list ) . to eq ( %w[ topics ] )
end
end
context " with 'topic_list' parameter " do
2021-11-11 11:23:49 +05:30
let ( :opts ) { { name : 'topic-project' , topic_list : 'topic_list' } }
2021-09-04 01:27:46 +05:30
it 'keeps them as specified' do
expect ( project . topic_list ) . to eq ( %w[ topic_list ] )
end
end
context " with 'tag_list' parameter (deprecated) " do
2021-11-11 11:23:49 +05:30
let ( :opts ) { { name : 'topic-project' , tag_list : 'tag_list' } }
2021-09-04 01:27:46 +05:30
it 'keeps them as specified' do
expect ( project . topic_list ) . to eq ( %w[ tag_list ] )
end
end
end
2017-08-17 22:00:37 +05:30
context 'user namespace' do
2021-12-11 22:18:48 +05:30
it 'creates a project in user namespace' do
2017-08-17 22:00:37 +05:30
project = create_project ( user , opts )
2015-09-11 14:41:01 +05:30
2017-08-17 22:00:37 +05:30
expect ( project ) . to be_valid
2022-03-02 08:16:31 +05:30
expect ( project . first_owner ) . to eq ( user )
2022-05-07 20:08:51 +05:30
expect ( project . team . maintainers ) . not_to include ( user )
expect ( project . team . owners ) . to contain_exactly ( user )
2017-08-17 22:00:37 +05:30
expect ( project . namespace ) . to eq ( user . namespace )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2015-09-11 14:41:01 +05:30
end
2022-10-11 01:57:18 +05:30
context 'project_authorizations record creation' do
context 'when the project_authrizations records are not created via the callback' do
it 'still creates project_authrizations record for the user' do
# stub out the callback that creates project_authorizations records on the `ProjectMember` model.
expect_next_instance_of ( ProjectMember ) do | member |
expect ( member ) . to receive ( :refresh_member_authorized_projects ) . and_return ( nil )
end
project = create_project ( user , opts )
expected_record = project . project_authorizations . where (
user : user ,
access_level : ProjectMember :: OWNER
)
expect ( expected_record ) . to exist
end
end
end
2023-03-04 22:38:38 +05:30
context 'when the passed in namespace is for a bot user' do
let ( :bot_user ) { create ( :user , :project_bot ) }
let ( :opts ) do
{ name : project_name , namespace_id : bot_user . namespace . id }
end
it 'raises an error' do
project = create_project ( bot_user , opts )
expect ( project . errors . errors . length ) . to eq 1
expect ( project . errors . messages [ :namespace ] . first ) . to eq ( ( " is not valid " ) )
end
end
2017-08-17 22:00:37 +05:30
end
2015-09-11 14:41:01 +05:30
2018-05-09 12:01:36 +05:30
describe 'after create actions' do
it 'invalidate personal_projects_count caches' do
2023-04-23 21:23:45 +05:30
expect ( Rails . cache ) . to receive ( :delete ) . with ( [ 'users' , user . id , 'personal_projects_count' ] )
2018-05-09 12:01:36 +05:30
create_project ( user , opts )
end
2020-03-13 15:44:24 +05:30
2022-06-21 17:19:12 +05:30
it 'creates associated project settings' do
2020-03-13 15:44:24 +05:30
project = create_project ( user , opts )
2022-06-21 17:19:12 +05:30
expect ( project . project_setting ) . to be_persisted
end
2020-10-24 23:57:45 +05:30
it_behaves_like 'storing arguments in the application context' do
2021-10-27 15:23:28 +05:30
let ( :expected_params ) { { project : subject . full_path } }
2020-10-24 23:57:45 +05:30
subject { create_project ( user , opts ) }
end
2022-04-04 11:22:00 +05:30
it 'logs creation' do
expect ( Gitlab :: AppLogger ) . to receive ( :info ) . with ( / #{ user . name } created a new project / )
create_project ( user , opts )
end
2022-08-13 15:12:31 +05:30
it 'publishes a ProjectCreatedEvent' do
group = create ( :group , :nested ) . tap do | group |
group . add_owner ( user )
end
expect { create_project ( user , name : 'Project' , path : 'project' , namespace_id : group . id ) }
. to publish_event ( Projects :: ProjectCreatedEvent )
. with (
project_id : kind_of ( Numeric ) ,
namespace_id : group . id ,
root_namespace_id : group . parent_id
)
end
2018-05-09 12:01:36 +05:30
end
2017-08-17 22:00:37 +05:30
context " admin creates project with other user's namespace_id " do
2021-01-29 00:20:46 +05:30
context 'when admin mode is enabled' , :enable_admin_mode do
it 'sets the correct permissions' do
admin = create ( :admin )
project = create_project ( admin , opts )
2015-09-25 12:07:36 +05:30
2021-01-29 00:20:46 +05:30
expect ( project ) . to be_persisted
expect ( project . owner ) . to eq ( user )
2022-03-02 08:16:31 +05:30
expect ( project . first_owner ) . to eq ( user )
2022-05-07 20:08:51 +05:30
expect ( project . team . owners ) . to contain_exactly ( user )
2021-01-29 00:20:46 +05:30
expect ( project . namespace ) . to eq ( user . namespace )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2021-01-29 00:20:46 +05:30
end
end
context 'when admin mode is disabled' do
it 'is not allowed' do
admin = create ( :admin )
project = create_project ( admin , opts )
expect ( project ) . not_to be_persisted
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2021-01-29 00:20:46 +05:30
end
2015-09-25 12:07:36 +05:30
end
2017-08-17 22:00:37 +05:30
end
2015-09-25 12:07:36 +05:30
2017-08-17 22:00:37 +05:30
context 'group namespace' do
let ( :group ) do
create ( :group ) . tap do | group |
group . add_owner ( user )
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
end
2014-09-02 18:07:02 +05:30
2017-08-17 22:00:37 +05:30
before do
user . refresh_authorized_projects # Ensure cache is warm
2014-09-02 18:07:02 +05:30
end
2022-04-04 11:22:00 +05:30
subject ( :project ) { create_project ( user , opts . merge! ( namespace_id : group . id ) ) }
2014-09-02 18:07:02 +05:30
2022-04-04 11:22:00 +05:30
shared_examples 'has sync-ed traversal_ids' do
specify { expect ( project . reload . project_namespace . traversal_ids ) . to eq ( [ project . namespace . traversal_ids , project . project_namespace . id ] . flatten . compact ) }
end
it 'creates the project' do
2017-08-17 22:00:37 +05:30
expect ( project ) . to be_valid
expect ( project . owner ) . to eq ( group )
expect ( project . namespace ) . to eq ( group )
2019-12-04 20:38:33 +05:30
expect ( project . team . owners ) . to include ( user )
2017-08-17 22:00:37 +05:30
expect ( user . authorized_projects ) . to include ( project )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2017-08-17 22:00:37 +05:30
end
2022-04-04 11:22:00 +05:30
2022-05-07 20:08:51 +05:30
it_behaves_like 'has sync-ed traversal_ids'
2023-05-27 22:25:52 +05:30
context 'when project is an import' do
2023-07-09 08:55:56 +05:30
before do
stub_application_setting ( import_sources : [ 'gitlab_project' ] )
end
2023-05-27 22:25:52 +05:30
context 'when user is not allowed to import projects' do
let ( :group ) do
create ( :group ) . tap do | group |
group . add_developer ( user )
end
end
it 'does not create the project' do
project = create_project ( user , opts . merge! ( namespace_id : group . id , import_type : 'gitlab_project' ) )
expect ( project ) . not_to be_persisted
expect ( project . errors . messages [ :user ] . first ) . to eq ( 'is not allowed to import projects' )
end
end
end
2017-08-17 22:00:37 +05:30
end
2014-09-02 18:07:02 +05:30
2020-06-23 00:09:42 +05:30
context 'group sharing' , :sidekiq_inline do
let_it_be ( :group ) { create ( :group ) }
let_it_be ( :shared_group ) { create ( :group ) }
let_it_be ( :shared_group_user ) { create ( :user ) }
2021-09-30 23:02:18 +05:30
2020-06-23 00:09:42 +05:30
let ( :opts ) do
{
2022-04-04 11:22:00 +05:30
name : project_name ,
2020-06-23 00:09:42 +05:30
namespace_id : shared_group . id
}
end
before do
create ( :group_group_link , shared_group : shared_group , shared_with_group : group )
shared_group . add_maintainer ( shared_group_user )
group . add_developer ( user )
end
it 'updates authorization' do
shared_group_project = create_project ( shared_group_user , opts )
expect (
Ability . allowed? ( shared_group_user , :read_project , shared_group_project )
) . to be_truthy
expect (
Ability . allowed? ( user , :read_project , shared_group_project )
) . to be_truthy
end
end
2022-08-27 11:52:29 +05:30
context 'user with project limit' do
let_it_be ( :user_with_projects_limit ) { create ( :user , projects_limit : 0 ) }
let ( :params ) { opts . merge! ( namespace_id : target_namespace . id ) }
subject ( :project ) { create_project ( user_with_projects_limit , params ) }
context 'under personal namespace' do
let ( :target_namespace ) { user_with_projects_limit . namespace }
it 'cannot create a project' do
expect ( project . errors . errors . length ) . to eq 1
expect ( project . errors . messages [ :limit_reached ] . first ) . to eq ( _ ( 'Personal project creation is not allowed. Please contact your administrator with questions' ) )
end
end
context 'under group namespace' do
let_it_be ( :group ) do
create ( :group ) . tap do | group |
group . add_owner ( user_with_projects_limit )
end
end
let ( :target_namespace ) { group }
it 'can create a project' do
expect ( project ) . to be_valid
expect ( project ) . to be_saved
expect ( project . errors . errors . length ) . to eq 0
end
end
end
2020-06-23 00:09:42 +05:30
context 'membership overrides' , :sidekiq_inline do
let_it_be ( :group ) { create ( :group , :private ) }
let_it_be ( :subgroup_for_projects ) { create ( :group , :private , parent : group ) }
let_it_be ( :subgroup_for_access ) { create ( :group , :private , parent : group ) }
let_it_be ( :group_maintainer ) { create ( :user ) }
2021-09-30 23:02:18 +05:30
2020-06-23 00:09:42 +05:30
let ( :group_access_level ) { Gitlab :: Access :: REPORTER }
let ( :subgroup_access_level ) { Gitlab :: Access :: DEVELOPER }
let ( :share_max_access_level ) { Gitlab :: Access :: MAINTAINER }
let ( :opts ) do
{
2022-04-04 11:22:00 +05:30
name : project_name ,
2020-06-23 00:09:42 +05:30
namespace_id : subgroup_for_projects . id
}
end
before do
group . add_maintainer ( group_maintainer )
2023-06-20 00:43:36 +05:30
create (
:group_group_link ,
shared_group : subgroup_for_projects ,
shared_with_group : subgroup_for_access ,
group_access : share_max_access_level
)
2020-06-23 00:09:42 +05:30
end
context 'membership is higher from group hierarchy' do
let ( :group_access_level ) { Gitlab :: Access :: MAINTAINER }
it 'updates authorization' do
create ( :group_member , access_level : subgroup_access_level , group : subgroup_for_access , user : user )
create ( :group_member , access_level : group_access_level , group : group , user : user )
subgroup_project = create_project ( group_maintainer , opts )
project_authorization = ProjectAuthorization . where (
project_id : subgroup_project . id ,
user_id : user . id ,
access_level : group_access_level )
expect ( project_authorization ) . to exist
end
end
context 'membership is higher from group share' do
let ( :subgroup_access_level ) { Gitlab :: Access :: MAINTAINER }
context 'share max access level is not limiting' do
it 'updates authorization' do
create ( :group_member , access_level : group_access_level , group : group , user : user )
create ( :group_member , access_level : subgroup_access_level , group : subgroup_for_access , user : user )
subgroup_project = create_project ( group_maintainer , opts )
project_authorization = ProjectAuthorization . where (
project_id : subgroup_project . id ,
user_id : user . id ,
access_level : subgroup_access_level )
expect ( project_authorization ) . to exist
end
end
context 'share max access level is limiting' do
let ( :share_max_access_level ) { Gitlab :: Access :: DEVELOPER }
it 'updates authorization' do
create ( :group_member , access_level : group_access_level , group : group , user : user )
create ( :group_member , access_level : subgroup_access_level , group : subgroup_for_access , user : user )
subgroup_project = create_project ( group_maintainer , opts )
project_authorization = ProjectAuthorization . where (
project_id : subgroup_project . id ,
user_id : user . id ,
access_level : share_max_access_level )
expect ( project_authorization ) . to exist
end
end
end
end
2017-08-17 22:00:37 +05:30
context 'error handling' do
it 'handles invalid options' do
2021-09-04 01:27:46 +05:30
opts [ :invalid ] = 'option'
2017-08-17 22:00:37 +05:30
expect ( create_project ( user , opts ) ) . to eq ( nil )
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
end
2014-09-02 18:07:02 +05:30
2017-08-17 22:00:37 +05:30
context 'wiki_enabled creates repository directory' do
context 'wiki_enabled true creates wiki repository directory' do
it do
project = create_project ( user , opts )
2018-03-17 18:26:18 +05:30
expect ( wiki_repo ( project ) . exists? ) . to be_truthy
2015-12-23 02:04:40 +05:30
end
end
2017-08-17 22:00:37 +05:30
context 'wiki_enabled false does not create wiki repository directory' do
it do
opts [ :wiki_enabled ] = false
project = create_project ( user , opts )
2014-09-02 18:07:02 +05:30
2018-03-17 18:26:18 +05:30
expect ( wiki_repo ( project ) . exists? ) . to be_falsey
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
end
2018-03-17 18:26:18 +05:30
def wiki_repo ( project )
relative_path = ProjectWiki . new ( project ) . disk_path + '.git'
2019-03-02 22:35:43 +05:30
Gitlab :: Git :: Repository . new ( project . repository_storage , relative_path , 'foobar' , project . full_path )
2018-03-17 18:26:18 +05:30
end
2017-08-17 22:00:37 +05:30
end
2014-09-02 18:07:02 +05:30
2018-11-18 11:00:15 +05:30
context 'import data' do
2020-07-28 23:09:34 +05:30
let ( :import_data ) { { data : { 'test' = > 'some data' } } }
let ( :imported_project ) { create_project ( user , { name : 'test' , import_url : 'http://import-url' , import_data : import_data } ) }
it 'does not write repository config' do
expect_next_instance_of ( Project ) do | project |
2021-10-27 15:23:28 +05:30
expect ( project ) . not_to receive ( :set_full_path )
2020-07-28 23:09:34 +05:30
end
2018-11-18 11:00:15 +05:30
2020-07-28 23:09:34 +05:30
imported_project
2021-12-11 22:18:48 +05:30
expect ( imported_project . project_namespace ) . to be_in_sync_with_project ( imported_project )
2020-07-28 23:09:34 +05:30
end
it 'stores import data and URL' do
expect ( imported_project . import_data ) . to be_persisted
expect ( imported_project . import_data . data ) . to eq ( import_data [ :data ] )
expect ( imported_project . import_url ) . to eq ( 'http://import-url' )
2018-11-18 11:00:15 +05:30
end
2021-11-11 11:23:49 +05:30
2022-10-11 01:57:18 +05:30
it 'tracks for imported project' do
2021-11-11 11:23:49 +05:30
imported_project
2022-10-11 01:57:18 +05:30
expect_snowplow_event ( category : described_class . name , action : 'import_project' , user : user )
2021-11-11 11:23:49 +05:30
end
2022-06-21 17:19:12 +05:30
describe 'import scheduling' do
context 'when project import type is gitlab project migration' do
it 'does not schedule project import' do
opts [ :import_type ] = 'gitlab_project_migration'
project = create_project ( user , opts )
expect ( project . import_state . status ) . to eq ( 'none' )
end
end
end
2018-11-18 11:00:15 +05:30
end
2017-08-17 22:00:37 +05:30
context 'builds_enabled global setting' do
let ( :project ) { create_project ( user , opts ) }
2014-09-02 18:07:02 +05:30
2017-08-17 22:00:37 +05:30
subject { project . builds_enabled? }
context 'global builds_enabled false does not enable CI by default' do
before do
project . project_feature . update_attribute ( :builds_access_level , ProjectFeature :: DISABLED )
2015-04-26 12:48:37 +05:30
end
2017-08-17 22:00:37 +05:30
it { is_expected . to be_falsey }
2015-04-26 12:48:37 +05:30
end
2017-08-17 22:00:37 +05:30
context 'global builds_enabled true does enable CI by default' do
it { is_expected . to be_truthy }
end
end
2015-11-26 14:37:03 +05:30
2019-09-04 21:01:54 +05:30
context 'default visibility level' do
let ( :group ) { create ( :group , :private ) }
2021-04-17 20:07:23 +05:30
using RSpec :: Parameterized :: TableSyntax
2015-11-26 14:37:03 +05:30
2021-04-17 20:07:23 +05:30
where ( :case_name , :group_level , :project_level ) do
[
[ 'in public group' , Gitlab :: VisibilityLevel :: PUBLIC , Gitlab :: VisibilityLevel :: INTERNAL ] ,
[ 'in internal group' , Gitlab :: VisibilityLevel :: INTERNAL , Gitlab :: VisibilityLevel :: INTERNAL ] ,
[ 'in private group' , Gitlab :: VisibilityLevel :: PRIVATE , Gitlab :: VisibilityLevel :: PRIVATE ]
]
2017-08-17 22:00:37 +05:30
end
2015-11-26 14:37:03 +05:30
2021-04-17 20:07:23 +05:30
with_them do
before do
stub_application_setting ( default_project_visibility : Gitlab :: VisibilityLevel :: INTERNAL )
group . add_developer ( user )
group . update! ( visibility_level : group_level )
opts . merge! (
name : 'test' ,
namespace : group ,
path : 'foo'
)
end
2015-11-26 14:37:03 +05:30
2021-04-17 20:07:23 +05:30
it 'creates project with correct visibility level' , :aggregate_failures do
project = create_project ( user , opts )
2015-11-26 14:37:03 +05:30
2021-04-17 20:07:23 +05:30
expect ( project ) . to respond_to ( :errors )
expect ( project . errors ) . to be_blank
expect ( project . visibility_level ) . to eq ( project_level )
expect ( project ) . to be_saved
expect ( project ) . to be_valid
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2021-04-17 20:07:23 +05:30
end
2019-09-04 21:01:54 +05:30
end
end
context 'restricted visibility level' do
before do
stub_application_setting ( restricted_visibility_levels : [ Gitlab :: VisibilityLevel :: PUBLIC ] )
end
shared_examples 'restricted visibility' do
it 'does not allow a restricted visibility level for non-admins' do
project = create_project ( user , opts )
expect ( project ) . to respond_to ( :errors )
expect ( project . errors . messages ) . to have_key ( :visibility_level )
expect ( project . errors . messages [ :visibility_level ] . first ) . to (
match ( 'restricted by your GitLab administrator' )
)
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2019-09-04 21:01:54 +05:30
end
2021-01-29 00:20:46 +05:30
it 'does not allow a restricted visibility level for admins when admin mode is disabled' do
admin = create ( :admin )
project = create_project ( admin , opts )
expect ( project . errors . any? ) . to be ( true )
expect ( project . saved? ) . to be_falsey
end
it 'allows a restricted visibility level for admins when admin mode is enabled' , :enable_admin_mode do
2019-09-04 21:01:54 +05:30
admin = create ( :admin )
project = create_project ( admin , opts )
expect ( project . errors . any? ) . to be ( false )
expect ( project . saved? ) . to be ( true )
end
end
context 'when visibility is project based' do
before do
opts . merge! (
visibility_level : Gitlab :: VisibilityLevel :: PUBLIC
)
end
include_examples 'restricted visibility'
end
context 'when visibility is overridden' do
let ( :visibility ) { 'public' }
before do
opts . merge! (
import_data : {
data : {
override_params : {
visibility : visibility
}
}
}
)
end
include_examples 'restricted visibility'
context 'when visibility is misspelled' do
let ( :visibility ) { 'publik' }
it 'does not restrict project creation' do
project = create_project ( user , opts )
expect ( project . errors . any? ) . to be ( false )
expect ( project . saved? ) . to be ( true )
end
end
2015-11-26 14:37:03 +05:30
end
2017-08-17 22:00:37 +05:30
end
2015-11-26 14:37:03 +05:30
2017-08-17 22:00:37 +05:30
context 'repository creation' do
it 'synchronously creates the repository' do
2020-03-13 15:44:24 +05:30
expect_next_instance_of ( Project ) do | instance |
expect ( instance ) . to receive ( :create_repository )
end
2015-04-26 12:48:37 +05:30
2017-08-17 22:00:37 +05:30
project = create_project ( user , opts )
expect ( project ) . to be_valid
expect ( project . owner ) . to eq ( user )
expect ( project . namespace ) . to eq ( user . namespace )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
context 'when another repository already exists on disk' do
let ( :opts ) do
{
2021-03-11 19:13:27 +05:30
name : 'existing' ,
2017-09-10 17:25:29 +05:30
namespace_id : user . namespace . id
}
end
2018-03-17 18:26:18 +05:30
context 'with legacy storage' do
2022-08-13 15:12:31 +05:30
let ( :raw_fake_repo ) { Gitlab :: Git :: Repository . new ( 'default' , File . join ( user . namespace . full_path , 'existing.git' ) , nil , nil ) }
2020-04-08 14:13:33 +05:30
2018-03-17 18:26:18 +05:30
before do
2019-09-04 21:01:54 +05:30
stub_application_setting ( hashed_storage_enabled : false )
2022-08-13 15:12:31 +05:30
raw_fake_repo . create_repository
2018-03-17 18:26:18 +05:30
end
2017-09-10 17:25:29 +05:30
2018-03-17 18:26:18 +05:30
after do
2022-08-13 15:12:31 +05:30
raw_fake_repo . remove
2018-03-17 18:26:18 +05:30
end
2017-09-10 17:25:29 +05:30
2018-03-17 18:26:18 +05:30
it 'does not allow to create a project when path matches existing repository on disk' do
project = create_project ( user , opts )
2017-09-10 17:25:29 +05:30
2018-03-17 18:26:18 +05:30
expect ( project ) . not_to be_persisted
expect ( project ) . to respond_to ( :errors )
expect ( project . errors . messages ) . to have_key ( :base )
expect ( project . errors . messages [ :base ] . first ) . to match ( 'There is already a repository with that name on disk' )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2018-03-17 18:26:18 +05:30
end
it 'does not allow to import project when path matches existing repository on disk' do
project = create_project ( user , opts . merge ( { import_url : 'https://gitlab.com/gitlab-org/gitlab-test.git' } ) )
2017-09-10 17:25:29 +05:30
2018-03-17 18:26:18 +05:30
expect ( project ) . not_to be_persisted
expect ( project ) . to respond_to ( :errors )
expect ( project . errors . messages ) . to have_key ( :base )
expect ( project . errors . messages [ :base ] . first ) . to match ( 'There is already a repository with that name on disk' )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2018-03-17 18:26:18 +05:30
end
2017-09-10 17:25:29 +05:30
end
2018-03-17 18:26:18 +05:30
context 'with hashed storage' do
let ( :hash ) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
let ( :hashed_path ) { '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
2022-08-13 15:12:31 +05:30
let ( :raw_fake_repo ) { Gitlab :: Git :: Repository . new ( 'default' , " #{ hashed_path } .git " , nil , nil ) }
2018-03-17 18:26:18 +05:30
before do
allow ( Digest :: SHA2 ) . to receive ( :hexdigest ) { hash }
2022-08-13 15:12:31 +05:30
raw_fake_repo . create_repository
2018-03-17 18:26:18 +05:30
end
after do
2022-08-13 15:12:31 +05:30
raw_fake_repo . remove
2018-03-17 18:26:18 +05:30
end
2017-09-10 17:25:29 +05:30
2018-03-17 18:26:18 +05:30
it 'does not allow to create a project when path matches existing repository on disk' do
project = create_project ( user , opts )
expect ( project ) . not_to be_persisted
expect ( project ) . to respond_to ( :errors )
expect ( project . errors . messages ) . to have_key ( :base )
expect ( project . errors . messages [ :base ] . first ) . to match ( 'There is already a repository with that name on disk' )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2018-03-17 18:26:18 +05:30
end
2017-09-10 17:25:29 +05:30
end
end
2017-08-17 22:00:37 +05:30
end
2015-04-26 12:48:37 +05:30
2018-11-08 19:23:39 +05:30
context 'when readme initialization is requested' do
2020-07-28 23:09:34 +05:30
let ( :project ) { create_project ( user , opts ) }
before do
2018-11-08 19:23:39 +05:30
opts [ :initialize_with_readme ] = '1'
2020-07-28 23:09:34 +05:30
end
2018-11-08 19:23:39 +05:30
2022-04-04 11:22:00 +05:30
shared_examples 'a repo with a README.md' do
2020-07-28 23:09:34 +05:30
it { expect ( project . repository . commit_count ) . to be ( 1 ) }
it { expect ( project . repository . readme . name ) . to eql ( 'README.md' ) }
2022-04-04 11:22:00 +05:30
it { expect ( project . repository . readme . data ) . to include ( expected_content ) }
2020-07-28 23:09:34 +05:30
end
2018-11-08 19:23:39 +05:30
2022-04-04 11:22:00 +05:30
it_behaves_like 'a repo with a README.md' do
let ( :expected_content ) do
<< ~ MARKDOWN
cd existing_repo
git remote add origin #{project.http_url_to_repo}
git branch - M master
git push - uf origin master
MARKDOWN
end
end
2020-07-28 23:09:34 +05:30
2022-04-04 11:22:00 +05:30
context 'and a readme_template is specified' do
2020-07-28 23:09:34 +05:30
before do
2022-04-04 11:22:00 +05:30
opts [ :readme_template ] = " # GitLab \n This is customized readme. "
2020-07-28 23:09:34 +05:30
end
2022-04-04 11:22:00 +05:30
it_behaves_like 'a repo with a README.md' do
let ( :expected_content ) { " # GitLab \n This is customized readme. " }
end
end
2023-07-09 08:55:56 +05:30
context 'and default_branch is specified' do
2022-04-04 11:22:00 +05:30
before do
2023-07-09 08:55:56 +05:30
opts [ :default_branch ] = 'example_branch'
2022-04-04 11:22:00 +05:30
end
2020-07-28 23:09:34 +05:30
2022-04-04 11:22:00 +05:30
it 'creates the correct branch' do
2023-07-09 08:55:56 +05:30
expect ( project . repository . branch_names ) . to contain_exactly ( 'example_branch' )
end
it_behaves_like 'a repo with a README.md' do
let ( :expected_content ) do
<< ~ MARKDOWN
cd existing_repo
git remote add origin #{project.http_url_to_repo}
git branch - M example_branch
git push - uf origin example_branch
MARKDOWN
end
end
end
2020-07-28 23:09:34 +05:30
2023-07-09 08:55:56 +05:30
context 'and the default branch setting is configured' do
before do
allow ( Gitlab :: CurrentSettings ) . to receive ( :default_branch_name ) . and_return ( 'example_branch' )
end
it 'creates the correct branch' do
expect ( project . repository . branch_names ) . to contain_exactly ( 'example_branch' )
2020-07-28 23:09:34 +05:30
end
2021-09-30 23:02:18 +05:30
2022-04-04 11:22:00 +05:30
it_behaves_like 'a repo with a README.md' do
let ( :expected_content ) do
<< ~ MARKDOWN
cd existing_repo
2021-09-30 23:02:18 +05:30
git remote add origin #{project.http_url_to_repo}
git branch - M example_branch
git push - uf origin example_branch
MARKDOWN
end
end
2018-11-08 19:23:39 +05:30
end
end
2021-11-18 22:05:49 +05:30
context 'when SAST initialization is requested' do
let ( :project ) { create_project ( user , opts ) }
before do
opts [ :initialize_with_sast ] = '1'
allow ( Gitlab :: CurrentSettings ) . to receive ( :default_branch_name ) . and_return ( 'main' )
end
it 'creates a commit for SAST' , :aggregate_failures do
expect ( project . repository . commit_count ) . to be ( 1 )
expect ( project . repository . commit . message ) . to eq (
'Configure SAST in `.gitlab-ci.yml`, creating this file if it does not already exist'
)
end
end
2021-09-30 23:02:18 +05:30
describe 'create integration for the project' do
2020-06-23 00:09:42 +05:30
subject ( :project ) { create_project ( user , opts ) }
2015-04-26 12:48:37 +05:30
2021-10-27 15:23:28 +05:30
context 'with an active instance-level integration' do
let! ( :instance_integration ) { create ( :prometheus_integration , :instance , api_url : 'https://prometheus.instance.com/' ) }
2017-09-10 17:25:29 +05:30
2021-10-27 15:23:28 +05:30
it 'creates an integration from the instance-level integration' do
2021-06-08 01:23:25 +05:30
expect ( project . integrations . count ) . to eq ( 1 )
2021-10-27 15:23:28 +05:30
expect ( project . integrations . first . api_url ) . to eq ( instance_integration . api_url )
expect ( project . integrations . first . inherit_from_id ) . to eq ( instance_integration . id )
2020-06-23 00:09:42 +05:30
end
2021-01-03 14:25:43 +05:30
2021-10-27 15:23:28 +05:30
context 'with an active group-level integration' do
2021-12-11 22:18:48 +05:30
let! ( :group_integration ) { create ( :prometheus_integration , :group , group : group , api_url : 'https://prometheus.group.com/' ) }
2021-10-27 15:23:28 +05:30
let! ( :group ) do
create ( :group ) . tap do | group |
group . add_owner ( user )
end
end
2021-01-03 14:25:43 +05:30
2021-10-27 15:23:28 +05:30
let ( :opts ) do
{
2022-04-04 11:22:00 +05:30
name : project_name ,
2021-10-27 15:23:28 +05:30
namespace_id : group . id
}
end
it 'creates an integration from the group-level integration' do
2021-06-08 01:23:25 +05:30
expect ( project . integrations . count ) . to eq ( 1 )
2021-10-27 15:23:28 +05:30
expect ( project . integrations . first . api_url ) . to eq ( group_integration . api_url )
expect ( project . integrations . first . inherit_from_id ) . to eq ( group_integration . id )
2021-01-03 14:25:43 +05:30
end
2021-10-27 15:23:28 +05:30
context 'with an active subgroup' do
2021-12-11 22:18:48 +05:30
let! ( :subgroup_integration ) { create ( :prometheus_integration , :group , group : subgroup , api_url : 'https://prometheus.subgroup.com/' ) }
2021-10-27 15:23:28 +05:30
let! ( :subgroup ) do
create ( :group , parent : group ) . tap do | subgroup |
subgroup . add_owner ( user )
2021-01-03 14:25:43 +05:30
end
end
let ( :opts ) do
{
2022-04-04 11:22:00 +05:30
name : project_name ,
2021-10-27 15:23:28 +05:30
namespace_id : subgroup . id
2021-01-03 14:25:43 +05:30
}
end
2021-10-27 15:23:28 +05:30
it 'creates an integration from the subgroup-level integration' do
2021-06-08 01:23:25 +05:30
expect ( project . integrations . count ) . to eq ( 1 )
2021-10-27 15:23:28 +05:30
expect ( project . integrations . first . api_url ) . to eq ( subgroup_integration . api_url )
expect ( project . integrations . first . inherit_from_id ) . to eq ( subgroup_integration . id )
2021-01-03 14:25:43 +05:30
end
end
end
2020-06-23 00:09:42 +05:30
end
2014-09-02 18:07:02 +05:30
end
2018-03-17 18:26:18 +05:30
context 'when skip_disk_validation is used' do
it 'sets the project attribute' do
opts [ :skip_disk_validation ] = true
project = create_project ( user , opts )
expect ( project . skip_disk_validation ) . to be_truthy
end
end
2018-12-13 13:39:08 +05:30
it 'calls the passed block' do
fake_block = double ( 'block' )
opts [ :relations_block ] = fake_block
expect_next_instance_of ( Project ) do | project |
expect ( fake_block ) . to receive ( :call ) . with ( project )
end
create_project ( user , opts )
end
2022-08-27 11:52:29 +05:30
it 'writes project full path to gitaly' do
2018-03-17 18:26:18 +05:30
project = create_project ( user , opts )
2022-08-27 11:52:29 +05:30
expect ( project . repository . full_path ) . to eq project . full_path
2018-03-17 18:26:18 +05:30
end
2021-04-29 21:17:54 +05:30
it 'triggers PostCreationWorker' do
expect ( Projects :: PostCreationWorker ) . to receive ( :perform_async ) . with ( a_kind_of ( Integer ) )
create_project ( user , opts )
end
2022-07-16 23:28:13 +05:30
context 'when import source is enabled' do
before do
stub_application_setting ( import_sources : [ 'github' ] )
end
it 'does not raise an error when import_source is string' do
opts [ :import_type ] = 'github'
project = create_project ( user , opts )
expect ( project ) . to be_persisted
expect ( project . errors ) . to be_blank
end
it 'does not raise an error when import_source is symbol' do
opts [ :import_type ] = :github
project = create_project ( user , opts )
expect ( project ) . to be_persisted
expect ( project . errors ) . to be_blank
end
end
context 'when import source is disabled' do
before do
stub_application_setting ( import_sources : [ ] )
opts [ :import_type ] = 'git'
end
it 'raises an error' do
project = create_project ( user , opts )
expect ( project ) . to respond_to ( :errors )
expect ( project . errors ) . to have_key ( :import_source_disabled )
expect ( project . saved? ) . to be_falsey
end
end
2019-07-07 11:18:12 +05:30
context 'with external authorization enabled' do
before do
enable_external_authorization_service_check
end
it 'does not save the project with an error if the service denies access' do
expect ( :: Gitlab :: ExternalAuthorization )
. to receive ( :access_allowed? ) . with ( user , 'new-label' , any_args ) { false }
project = create_project ( user , opts . merge ( { external_authorization_classification_label : 'new-label' } ) )
expect ( project . errors [ :external_authorization_classification_label ] ) . to be_present
expect ( project ) . not_to be_persisted
end
it 'saves the project when the user has access to the label' do
expect ( :: Gitlab :: ExternalAuthorization )
2022-07-16 23:28:13 +05:30
. to receive ( :access_allowed? ) . with ( user , 'new-label' , any_args ) { true } . at_least ( 1 ) . time
2019-07-07 11:18:12 +05:30
project = create_project ( user , opts . merge ( { external_authorization_classification_label : 'new-label' } ) )
expect ( project ) . to be_persisted
expect ( project . external_authorization_classification_label ) . to eq ( 'new-label' )
end
it 'does not save the project when the user has no access to the default label and no label is provided' do
expect ( :: Gitlab :: ExternalAuthorization )
. to receive ( :access_allowed? ) . with ( user , 'default_label' , any_args ) { false }
project = create_project ( user , opts )
expect ( project . errors [ :external_authorization_classification_label ] ) . to be_present
expect ( project ) . not_to be_persisted
end
end
2021-09-04 01:27:46 +05:30
context 'with specialized project_authorization workers' do
2020-05-24 23:13:21 +05:30
let_it_be ( :other_user ) { create ( :user ) }
let_it_be ( :group ) { create ( :group ) }
let ( :opts ) do
{
2022-04-04 11:22:00 +05:30
name : project_name ,
2020-05-24 23:13:21 +05:30
namespace_id : group . id
}
end
before do
group . add_maintainer ( user )
group . add_developer ( other_user )
end
it 'updates authorization for current_user' do
project = create_project ( user , opts )
expect (
Ability . allowed? ( user , :read_project , project )
) . to be_truthy
end
2021-12-11 22:18:48 +05:30
it 'schedules authorization update for users with access to group' , :sidekiq_inline do
2023-04-23 21:23:45 +05:30
stub_feature_flags ( do_not_run_safety_net_auth_refresh_jobs : false )
2020-05-24 23:13:21 +05:30
expect ( AuthorizedProjectsWorker ) . not_to (
receive ( :bulk_perform_async )
)
2021-12-11 22:18:48 +05:30
expect ( AuthorizedProjectUpdate :: ProjectRecalculateWorker ) . to (
2020-05-24 23:13:21 +05:30
receive ( :perform_async ) . and_call_original
)
2021-09-04 01:27:46 +05:30
expect ( AuthorizedProjectUpdate :: UserRefreshFromReplicaWorker ) . to (
2023-06-20 00:43:36 +05:30
receive ( :bulk_perform_in ) . with (
1 . hour ,
array_including ( [ user . id ] , [ other_user . id ] ) ,
batch_delay : 30 . seconds , batch_size : 100
) . and_call_original
2020-05-24 23:13:21 +05:30
)
2021-12-11 22:18:48 +05:30
project = create_project ( user , opts )
expect (
Ability . allowed? ( other_user , :developer_access , project )
) . to be_truthy
2020-05-24 23:13:21 +05:30
end
end
2014-09-02 18:07:02 +05:30
def create_project ( user , opts )
Projects :: CreateService . new ( user , opts ) . execute
end
2021-01-03 14:25:43 +05:30
context 'shared Runners config' do
using RSpec :: Parameterized :: TableSyntax
let_it_be ( :user ) { create :user }
context 'when parent group is present' do
2021-11-18 22:05:49 +05:30
let_it_be ( :group , reload : true ) do
2021-01-03 14:25:43 +05:30
create ( :group ) do | group |
group . add_owner ( user )
end
end
before do
2021-11-18 22:05:49 +05:30
group . update_shared_runners_setting! ( shared_runners_setting )
2021-01-03 14:25:43 +05:30
user . refresh_authorized_projects # Ensure cache is warm
end
context 'default value based on parent group setting' do
where ( :shared_runners_setting , :desired_config_for_new_project , :expected_result_for_project ) do
2021-11-18 22:05:49 +05:30
Namespace :: SR_ENABLED | nil | true
Namespace :: SR_DISABLED_WITH_OVERRIDE | nil | false
2023-03-17 16:20:25 +05:30
Namespace :: SR_DISABLED_AND_OVERRIDABLE | nil | false
2021-11-18 22:05:49 +05:30
Namespace :: SR_DISABLED_AND_UNOVERRIDABLE | nil | false
2021-01-03 14:25:43 +05:30
end
with_them do
it 'creates project following the parent config' do
params = opts . merge ( namespace_id : group . id )
params = params . merge ( shared_runners_enabled : desired_config_for_new_project ) unless desired_config_for_new_project . nil?
project = create_project ( user , params )
expect ( project ) . to be_valid
expect ( project . shared_runners_enabled ) . to eq ( expected_result_for_project )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2021-01-03 14:25:43 +05:30
end
end
end
context 'parent group is present and allows desired config' do
where ( :shared_runners_setting , :desired_config_for_new_project , :expected_result_for_project ) do
2021-11-18 22:05:49 +05:30
Namespace :: SR_ENABLED | true | true
Namespace :: SR_ENABLED | false | false
Namespace :: SR_DISABLED_WITH_OVERRIDE | false | false
Namespace :: SR_DISABLED_WITH_OVERRIDE | true | true
2023-03-17 16:20:25 +05:30
Namespace :: SR_DISABLED_AND_OVERRIDABLE | false | false
Namespace :: SR_DISABLED_AND_OVERRIDABLE | true | true
2021-11-18 22:05:49 +05:30
Namespace :: SR_DISABLED_AND_UNOVERRIDABLE | false | false
2021-01-03 14:25:43 +05:30
end
with_them do
it 'creates project following the parent config' do
params = opts . merge ( namespace_id : group . id , shared_runners_enabled : desired_config_for_new_project )
project = create_project ( user , params )
expect ( project ) . to be_valid
expect ( project . shared_runners_enabled ) . to eq ( expected_result_for_project )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2021-01-03 14:25:43 +05:30
end
end
end
context 'parent group is present and disallows desired config' do
where ( :shared_runners_setting , :desired_config_for_new_project ) do
2021-11-18 22:05:49 +05:30
Namespace :: SR_DISABLED_AND_UNOVERRIDABLE | true
2021-01-03 14:25:43 +05:30
end
with_them do
it 'does not create project' do
params = opts . merge ( namespace_id : group . id , shared_runners_enabled : desired_config_for_new_project )
project = create_project ( user , params )
expect ( project . persisted? ) . to eq ( false )
expect ( project ) . to be_invalid
expect ( project . errors [ :shared_runners_enabled ] ) . to include ( 'cannot be enabled because parent group does not allow it' )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2021-01-03 14:25:43 +05:30
end
end
end
end
context 'parent group is not present' do
where ( :desired_config , :expected_result ) do
true | true
false | false
nil | true
end
with_them do
it 'follows desired config' do
opts [ :shared_runners_enabled ] = desired_config unless desired_config . nil?
project = create_project ( user , opts )
expect ( project ) . to be_valid
expect ( project . shared_runners_enabled ) . to eq ( expected_result )
2021-12-11 22:18:48 +05:30
expect ( project . project_namespace ) . to be_in_sync_with_project ( project )
2021-01-03 14:25:43 +05:30
end
end
end
end
2014-09-02 18:07:02 +05:30
end