2019-12-26 22:10:19 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
require 'spec_helper'
2023-04-23 21:23:45 +05:30
RSpec . shared_examples 'languages and percentages JSON response' do
2021-04-29 21:17:54 +05:30
let ( :expected_languages ) { project . repository . languages . to_h { | language | language . values_at ( :label , :value ) } }
2018-10-15 14:42:47 +05:30
2019-07-07 11:18:12 +05:30
before do
allow ( project . repository ) . to receive ( :languages ) . and_return (
[ { value : 66 . 69 , label : " Ruby " , color : " # 701516 " , highlight : " # 701516 " } ,
{ value : 22 . 98 , label : " JavaScript " , color : " # f1e05a " , highlight : " # f1e05a " } ,
{ value : 7 . 91 , label : " HTML " , color : " # e34c26 " , highlight : " # e34c26 " } ,
{ value : 2 . 42 , label : " CoffeeScript " , color : " # 244776 " , highlight : " # 244776 " } ]
)
end
context " when the languages haven't been detected yet " do
2023-06-20 00:43:36 +05:30
it 'returns expected language values' , :aggregate_failures , :sidekiq_might_not_need_inline do
2019-07-07 11:18:12 +05:30
get api ( " /projects/ #{ project . id } /languages " , user )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to eq ( { } )
get api ( " /projects/ #{ project . id } /languages " , user )
expect ( response ) . to have_gitlab_http_status ( :ok )
2020-05-24 23:13:21 +05:30
expect ( Gitlab :: Json . parse ( response . body ) ) . to eq ( expected_languages )
2019-07-07 11:18:12 +05:30
end
end
context 'when the languages were detected before' do
before do
2022-04-04 11:22:00 +05:30
Projects :: DetectRepositoryLanguagesService . new ( project , project . first_owner ) . execute
2019-07-07 11:18:12 +05:30
end
2023-06-20 00:43:36 +05:30
it 'returns the detection from the database' , :aggregate_failures do
2019-07-07 11:18:12 +05:30
# Allow this to happen once, so the expected languages can be determined
expect ( project . repository ) . to receive ( :languages ) . once
2018-10-15 14:42:47 +05:30
2019-07-07 11:18:12 +05:30
get api ( " /projects/ #{ project . id } /languages " , user )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to eq ( expected_languages )
expect ( json_response . count ) . to be > 1
end
2018-10-15 14:42:47 +05:30
end
end
2023-06-20 00:43:36 +05:30
RSpec . describe API :: Projects , :aggregate_failures , feature_category : :projects do
2019-12-04 20:38:33 +05:30
include ProjectForksHelper
2022-10-11 01:57:18 +05:30
include WorkhorseHelpers
2021-12-11 22:18:48 +05:30
include StubRequests
2019-12-04 20:38:33 +05:30
2020-11-24 15:15:51 +05:30
let_it_be ( :user ) { create ( :user ) }
let_it_be ( :user2 ) { create ( :user ) }
let_it_be ( :user3 ) { create ( :user ) }
let_it_be ( :admin ) { create ( :admin ) }
2023-06-20 00:43:36 +05:30
let_it_be ( :project , reload : true ) { create ( :project , :repository , create_branch : 'something_else' , namespace : user . namespace , updated_at : 5 . days . ago ) }
let_it_be ( :project2 , reload : true ) { create ( :project , namespace : user . namespace , updated_at : 4 . days . ago ) }
2020-11-24 15:15:51 +05:30
let_it_be ( :project_member ) { create ( :project_member , :developer , user : user3 , project : project ) }
2021-07-02 01:05:55 +05:30
let_it_be ( :user4 ) { create ( :user , username : 'user.withdot' ) }
2020-11-24 15:15:51 +05:30
let_it_be ( :project3 , reload : true ) do
2015-04-26 12:48:37 +05:30
create ( :project ,
2016-06-02 11:05:42 +05:30
:private ,
2017-08-17 22:00:37 +05:30
:repository ,
2015-04-26 12:48:37 +05:30
name : 'second_project' ,
path : 'second_project' ,
creator_id : user . id ,
namespace : user . namespace ,
merge_requests_enabled : false ,
issues_enabled : false , wiki_enabled : false ,
2017-08-17 22:00:37 +05:30
builds_enabled : false ,
2016-06-02 11:05:42 +05:30
snippets_enabled : false )
2015-04-26 12:48:37 +05:30
end
2020-10-24 23:57:45 +05:30
2020-11-24 15:15:51 +05:30
let_it_be ( :project_member2 ) do
2015-04-26 12:48:37 +05:30
create ( :project_member ,
user : user4 ,
project : project3 ,
2018-11-18 11:00:15 +05:30
access_level : ProjectMember :: MAINTAINER )
2015-04-26 12:48:37 +05:30
end
2020-10-24 23:57:45 +05:30
2020-11-24 15:15:51 +05:30
let_it_be ( :project4 , reload : true ) do
2017-09-10 17:25:29 +05:30
create ( :project ,
2015-04-26 12:48:37 +05:30
name : 'third_project' ,
path : 'third_project' ,
creator_id : user4 . id ,
namespace : user4 . namespace )
end
2014-09-02 18:07:02 +05:30
2020-11-24 15:15:51 +05:30
let ( :user_projects ) { [ public_project , project , project2 , project3 ] }
2019-03-02 22:35:43 +05:30
shared_context 'with language detection' do
let ( :ruby ) { create ( :programming_language , name : 'Ruby' ) }
let ( :javascript ) { create ( :programming_language , name : 'JavaScript' ) }
let ( :html ) { create ( :programming_language , name : 'HTML' ) }
let ( :mock_repo_languages ) do
{
project = > { ruby = > 0 . 5 , html = > 0 . 5 } ,
project3 = > { html = > 0 . 7 , javascript = > 0 . 3 }
}
end
before do
mock_repo_languages . each do | proj , lang_shares |
lang_shares . each do | lang , share |
create ( :repository_language , project : proj , programming_language : lang , share : share )
end
end
end
end
2021-09-04 01:27:46 +05:30
shared_examples_for 'create project with default branch parameter' do
let ( :params ) { { name : 'Foo Project' , initialize_with_readme : true , default_branch : default_branch } }
let ( :default_branch ) { 'main' }
it 'creates project with provided default branch name' do
expect { request } . to change { Project . count } . by ( 1 )
expect ( response ) . to have_gitlab_http_status ( :created )
project = Project . find ( json_response [ 'id' ] )
expect ( project . default_branch ) . to eq ( default_branch )
end
context 'when branch name is empty' do
let ( :default_branch ) { '' }
it 'creates project with a default project branch name' do
expect { request } . to change { Project . count } . by ( 1 )
expect ( response ) . to have_gitlab_http_status ( :created )
project = Project . find ( json_response [ 'id' ] )
expect ( project . default_branch ) . to eq ( 'master' )
end
end
context 'when initialize with readme is not set' do
let ( :params ) { super ( ) . merge ( initialize_with_readme : nil ) }
it 'creates project with a default project branch name' do
expect { request } . to change { Project . count } . by ( 1 )
expect ( response ) . to have_gitlab_http_status ( :created )
project = Project . find ( json_response [ 'id' ] )
expect ( project . default_branch ) . to be_nil
end
end
end
2015-04-26 12:48:37 +05:30
describe 'GET /projects' do
2023-06-20 00:43:36 +05:30
let ( :path ) { '/projects' }
let_it_be ( :public_project ) { create ( :project , :public , name : 'public_project' ) }
2017-08-17 22:00:37 +05:30
shared_examples_for 'projects response' do
2023-06-20 00:43:36 +05:30
let_it_be ( :admin_mode ) { false }
2017-08-17 22:00:37 +05:30
it 'returns an array of projects' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user , admin_mode : admin_mode ) , params : filter
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | p | p [ 'id' ] } ) . to contain_exactly ( * projects . map ( & :id ) )
end
2018-03-17 18:26:18 +05:30
it 'returns the proper security headers' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user , admin_mode : admin_mode ) , params : filter
2018-03-17 18:26:18 +05:30
expect ( response ) . to include_security_headers
end
2017-08-17 22:00:37 +05:30
end
2021-09-30 23:02:18 +05:30
shared_examples_for 'projects response without N + 1 queries' do | threshold |
let ( :additional_project ) { create ( :project , :public ) }
2023-01-13 00:05:48 +05:30
it 'avoids N + 1 queries' , :use_sql_query_cache do
control = ActiveRecord :: QueryRecorder . new ( skip_cached : false ) do
2023-06-20 00:43:36 +05:30
get api ( path , current_user )
2018-03-17 18:26:18 +05:30
end
2017-09-10 17:25:29 +05:30
2021-09-30 23:02:18 +05:30
additional_project
2017-09-10 17:25:29 +05:30
expect do
2023-06-20 00:43:36 +05:30
get api ( path , current_user )
2023-01-13 00:05:48 +05:30
end . not_to exceed_all_query_limit ( control ) . with_threshold ( threshold )
2017-09-10 17:25:29 +05:30
end
end
2015-04-26 12:48:37 +05:30
context 'when unauthenticated' do
2017-08-17 22:00:37 +05:30
it_behaves_like 'projects response' do
2017-09-10 17:25:29 +05:30
let ( :filter ) { { search : project . name } }
let ( :current_user ) { user }
let ( :projects ) { [ project ] }
end
2021-09-30 23:02:18 +05:30
it_behaves_like 'projects response without N + 1 queries' , 1 do
2017-08-17 22:00:37 +05:30
let ( :current_user ) { nil }
2014-09-02 18:07:02 +05:30
end
end
2017-08-17 22:00:37 +05:30
context 'when authenticated as regular user' do
it_behaves_like 'projects response' do
let ( :filter ) { { } }
let ( :current_user ) { user }
2020-11-24 15:15:51 +05:30
let ( :projects ) { user_projects }
2015-04-26 12:48:37 +05:30
end
2015-09-11 14:41:01 +05:30
2021-09-30 23:02:18 +05:30
it_behaves_like 'projects response without N + 1 queries' , 0 do
2017-09-10 17:25:29 +05:30
let ( :current_user ) { user }
end
2023-04-23 21:23:45 +05:30
shared_examples 'includes container_registry_access_level' do
2023-06-20 00:43:36 +05:30
specify do
2023-01-13 00:05:48 +05:30
project . project_feature . update! ( container_registry_access_level : ProjectFeature :: DISABLED )
2021-10-27 15:23:28 +05:30
2023-06-20 00:43:36 +05:30
get api ( path , user )
2023-01-13 00:05:48 +05:30
project_response = json_response . find { | p | p [ 'id' ] == project . id }
2021-10-27 15:23:28 +05:30
2023-01-13 00:05:48 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to be_an Array
expect ( project_response [ 'container_registry_access_level' ] ) . to eq ( 'disabled' )
expect ( project_response [ 'container_registry_enabled' ] ) . to eq ( false )
end
end
include_examples 'includes container_registry_access_level'
context 'when projects_preloader_fix is disabled' do
before do
stub_feature_flags ( projects_preloader_fix : false )
end
include_examples 'includes container_registry_access_level'
2021-10-27 15:23:28 +05:30
end
2023-06-20 00:43:36 +05:30
it 'includes various project feature fields' do
get api ( path , user )
2022-11-25 23:54:43 +05:30
project_response = json_response . find { | p | p [ 'id' ] == project . id }
expect ( response ) . to have_gitlab_http_status ( :ok )
2023-03-04 22:38:38 +05:30
expect ( project_response [ 'releases_access_level' ] ) . to eq ( 'enabled' )
expect ( project_response [ 'environments_access_level' ] ) . to eq ( 'enabled' )
expect ( project_response [ 'feature_flags_access_level' ] ) . to eq ( 'enabled' )
expect ( project_response [ 'infrastructure_access_level' ] ) . to eq ( 'enabled' )
expect ( project_response [ 'monitor_access_level' ] ) . to eq ( 'enabled' )
2022-11-25 23:54:43 +05:30
end
2017-09-10 17:25:29 +05:30
context 'when some projects are in a group' do
before do
create ( :project , :public , group : create ( :group ) )
end
2021-12-07 22:27:20 +05:30
it_behaves_like 'projects response without N + 1 queries' , 1 do
2017-09-10 17:25:29 +05:30
let ( :current_user ) { user }
let ( :additional_project ) { create ( :project , :public , group : create ( :group ) ) }
end
end
2023-06-20 00:43:36 +05:30
it 'includes correct value of container_registry_enabled' do
2021-09-04 01:27:46 +05:30
project . project_feature . update! ( container_registry_access_level : ProjectFeature :: DISABLED )
2023-06-20 00:43:36 +05:30
get api ( path , user )
2021-09-04 01:27:46 +05:30
project_response = json_response . find { | p | p [ 'id' ] == project . id }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to be_an Array
expect ( project_response [ 'container_registry_enabled' ] ) . to eq ( false )
end
it 'includes project topics' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2017-08-17 22:00:37 +05:30
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
2015-09-11 14:41:01 +05:30
expect ( json_response ) . to be_an Array
2021-09-04 01:27:46 +05:30
expect ( json_response . first . keys ) . to include ( 'tag_list' ) # deprecated in favor of 'topics'
expect ( json_response . first . keys ) . to include ( 'topics' )
2015-04-26 12:48:37 +05:30
end
2015-09-11 14:41:01 +05:30
2016-09-13 17:45:13 +05:30
it 'includes open_issues_count' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2017-08-17 22:00:37 +05:30
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
2015-12-23 02:04:40 +05:30
expect ( json_response ) . to be_an Array
expect ( json_response . first . keys ) . to include ( 'open_issues_count' )
end
2018-12-05 23:21:45 +05:30
it 'does not include projects marked for deletion' do
2020-11-24 15:15:51 +05:30
project . update! ( pending_delete : true )
2018-12-05 23:21:45 +05:30
2023-06-20 00:43:36 +05:30
get api ( path , user )
2018-12-05 23:21:45 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-12-05 23:21:45 +05:30
expect ( json_response ) . to be_an Array
expect ( json_response . map { | p | p [ 'id' ] } ) . not_to include ( project . id )
end
2017-08-17 22:00:37 +05:30
it 'does not include open_issues_count if issues are disabled' do
2016-09-29 09:46:39 +05:30
project . project_feature . update_attribute ( :issues_access_level , ProjectFeature :: DISABLED )
2015-12-23 02:04:40 +05:30
2023-06-20 00:43:36 +05:30
get api ( path , user )
2017-08-17 22:00:37 +05:30
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . find { | hash | hash [ 'id' ] == project . id } . keys ) . not_to include ( 'open_issues_count' )
end
2021-09-04 01:27:46 +05:30
context 'filter by topic (column topic_list)' do
2021-06-08 01:23:25 +05:30
before do
2021-09-04 01:27:46 +05:30
project . update! ( topic_list : %w( ruby javascript ) )
2021-06-08 01:23:25 +05:30
end
it 'returns no projects' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { topic : 'foo' }
2021-06-08 01:23:25 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_empty
end
it 'returns matching project for a single topic' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { topic : 'ruby' }
2021-06-08 01:23:25 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to contain_exactly a_hash_including ( 'id' = > project . id )
end
it 'returns matching project for multiple topics' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { topic : 'ruby, javascript' }
2021-06-08 01:23:25 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to contain_exactly a_hash_including ( 'id' = > project . id )
end
it 'returns no projects if project match only some topic' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { topic : 'ruby, foo' }
2021-06-08 01:23:25 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_empty
end
it 'ignores topic if it is empty' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { topic : '' }
2021-06-08 01:23:25 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_present
end
end
2022-08-13 15:12:31 +05:30
context 'filter by topic_id' do
let_it_be ( :topic1 ) { create ( :topic ) }
let_it_be ( :topic2 ) { create ( :topic ) }
let ( :current_user ) { user }
before do
project . topics << topic1
end
context 'with id of assigned topic' do
it_behaves_like 'projects response' do
let ( :filter ) { { topic_id : topic1 . id } }
let ( :projects ) { [ project ] }
end
end
context 'with id of unassigned topic' do
it_behaves_like 'projects response' do
let ( :filter ) { { topic_id : topic2 . id } }
let ( :projects ) { [ ] }
end
end
context 'with non-existing topic id' do
it_behaves_like 'projects response' do
let ( :filter ) { { topic_id : non_existing_record_id } }
let ( :projects ) { [ ] }
end
end
context 'with empty topic id' do
it_behaves_like 'projects response' do
let ( :filter ) { { topic_id : '' } }
let ( :projects ) { user_projects }
end
end
end
2018-03-17 18:26:18 +05:30
context 'and with_issues_enabled=true' do
it 'only returns projects with issues enabled' do
project . project_feature . update_attribute ( :issues_access_level , ProjectFeature :: DISABLED )
get api ( '/projects?with_issues_enabled=true' , user )
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-03-17 18:26:18 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | p | p [ 'id' ] } ) . not_to include ( project . id )
end
end
2017-08-17 22:00:37 +05:30
it " does not include statistics by default " do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . first ) . not_to include ( 'statistics' )
end
it " includes statistics if requested " do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { statistics : true }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
2015-12-23 02:04:40 +05:30
expect ( json_response ) . to be_an Array
2020-07-28 23:09:34 +05:30
2020-11-24 15:15:51 +05:30
statistics = json_response . find { | p | p [ 'id' ] == project . id } [ 'statistics' ]
2020-07-28 23:09:34 +05:30
expect ( statistics ) . to be_present
2021-12-11 22:18:48 +05:30
expect ( statistics ) . to include ( 'commit_count' , 'storage_size' , 'repository_size' , 'wiki_size' , 'lfs_objects_size' , 'job_artifacts_size' , 'pipeline_artifacts_size' , 'snippets_size' , 'packages_size' , 'uploads_size' )
2015-12-23 02:04:40 +05:30
end
2018-12-13 13:39:08 +05:30
it " does not include license by default " do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2018-12-13 13:39:08 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-12-13 13:39:08 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . first ) . not_to include ( 'license' , 'license_url' )
end
it " does not include license if requested " do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { license : true }
2018-12-13 13:39:08 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-12-13 13:39:08 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . first ) . not_to include ( 'license' , 'license_url' )
end
2017-09-10 17:25:29 +05:30
context 'when external issue tracker is enabled' do
2021-09-30 23:02:18 +05:30
let! ( :jira_integration ) { create ( :jira_integration , project : project ) }
2017-09-10 17:25:29 +05:30
it 'includes open_issues_count' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2017-09-10 17:25:29 +05:30
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-09-10 17:25:29 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . first . keys ) . to include ( 'open_issues_count' )
expect ( json_response . find { | hash | hash [ 'id' ] == project . id } . keys ) . to include ( 'open_issues_count' )
end
it 'does not include open_issues_count if issues are disabled' do
project . project_feature . update_attribute ( :issues_access_level , ProjectFeature :: DISABLED )
2023-06-20 00:43:36 +05:30
get api ( path , user )
2017-09-10 17:25:29 +05:30
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-09-10 17:25:29 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . find { | hash | hash [ 'id' ] == project . id } . keys ) . not_to include ( 'open_issues_count' )
end
end
2017-08-17 22:00:37 +05:30
context 'and with simple=true' do
2016-08-24 12:49:21 +05:30
it 'returns a simplified version of all the projects' do
get api ( '/projects?simple=true' , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
2021-06-08 01:23:25 +05:30
expect ( response ) . to match_response_schema ( 'public_api/v4/projects' )
2016-08-24 12:49:21 +05:30
end
end
2018-11-18 11:00:15 +05:30
context 'and using archived' do
let! ( :archived_project ) { create ( :project , creator_id : user . id , namespace : user . namespace , archived : true ) }
it 'returns archived projects' do
get api ( '/projects?archived=true' , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-11-18 11:00:15 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . length ) . to eq ( Project . public_or_visible_to_user ( user ) . where ( archived : true ) . size )
expect ( json_response . map { | project | project [ 'id' ] } ) . to include ( archived_project . id )
end
it 'returns non-archived projects' do
get api ( '/projects?archived=false' , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-11-18 11:00:15 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . length ) . to eq ( Project . public_or_visible_to_user ( user ) . where ( archived : false ) . size )
expect ( json_response . map { | project | project [ 'id' ] } ) . not_to include ( archived_project . id )
end
it 'returns every project' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2018-11-18 11:00:15 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-11-18 11:00:15 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( * Project . public_or_visible_to_user ( user ) . pluck ( :id ) )
end
end
2023-06-20 00:43:36 +05:30
context 'filter by updated_at' do
let ( :filter ) { { updated_before : 2 . days . ago . iso8601 , updated_after : 6 . days . ago , order_by : :updated_at } }
it_behaves_like 'projects response' do
let ( :current_user ) { user }
let ( :projects ) { [ project2 , project ] }
end
it 'returns projects sorted by updated_at' do
get api ( path , user ) , params : filter
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response . map { | p | p [ 'id' ] } ) . to match ( [ project2 , project ] . map ( & :id ) )
end
context 'when filtering by updated_at and sorting by a different column' do
let ( :filter ) { { updated_before : 2 . days . ago . iso8601 , updated_after : 6 . days . ago , order_by : 'id' } }
it 'returns an error' do
get api ( path , user ) , params : filter
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'message' ] ) . to eq (
'400 Bad request - `updated_at` filter and `updated_at` sorting must be paired'
)
end
end
end
2015-04-26 12:48:37 +05:30
context 'and using search' do
2017-08-17 22:00:37 +05:30
it_behaves_like 'projects response' do
let ( :filter ) { { search : project . name } }
let ( :current_user ) { user }
let ( :projects ) { [ project ] }
end
end
2020-04-22 19:07:51 +05:30
context 'and using search and search_namespaces is true' do
let ( :group ) { create ( :group ) }
let! ( :project_in_group ) { create ( :project , group : group ) }
before do
group . add_guest ( user )
end
it_behaves_like 'projects response' do
let ( :filter ) { { search : group . name , search_namespaces : true } }
let ( :current_user ) { user }
let ( :projects ) { [ project_in_group ] }
end
end
2019-12-26 22:10:19 +05:30
context 'and using id_after' do
it_behaves_like 'projects response' do
let ( :filter ) { { id_after : project2 . id } }
let ( :current_user ) { user }
2020-11-24 15:15:51 +05:30
let ( :projects ) { user_projects . select { | p | p . id > project2 . id } }
2019-12-26 22:10:19 +05:30
end
2020-10-24 23:57:45 +05:30
context 'regression: empty string is ignored' do
it_behaves_like 'projects response' do
let ( :filter ) { { id_after : '' } }
let ( :current_user ) { user }
2020-11-24 15:15:51 +05:30
let ( :projects ) { user_projects }
2020-10-24 23:57:45 +05:30
end
end
2019-12-26 22:10:19 +05:30
end
context 'and using id_before' do
it_behaves_like 'projects response' do
let ( :filter ) { { id_before : project2 . id } }
let ( :current_user ) { user }
2020-11-24 15:15:51 +05:30
let ( :projects ) { user_projects . select { | p | p . id < project2 . id } }
2019-12-26 22:10:19 +05:30
end
2020-10-24 23:57:45 +05:30
context 'regression: empty string is ignored' do
it_behaves_like 'projects response' do
let ( :filter ) { { id_before : '' } }
let ( :current_user ) { user }
2020-11-24 15:15:51 +05:30
let ( :projects ) { user_projects }
2020-10-24 23:57:45 +05:30
end
end
2019-12-26 22:10:19 +05:30
end
context 'and using both id_after and id_before' do
it_behaves_like 'projects response' do
let ( :filter ) { { id_before : project2 . id , id_after : public_project . id } }
let ( :current_user ) { user }
2020-11-24 15:15:51 +05:30
let ( :projects ) { user_projects . select { | p | p . id < project2 . id && p . id > public_project . id } }
2019-12-26 22:10:19 +05:30
end
end
2017-08-17 22:00:37 +05:30
context 'and membership=true' do
it_behaves_like 'projects response' do
let ( :filter ) { { membership : true } }
let ( :current_user ) { user }
let ( :projects ) { [ project , project2 , project3 ] }
2015-04-26 12:48:37 +05:30
end
end
2016-04-02 18:10:28 +05:30
context 'and using the visibility filter' do
2016-09-13 17:45:13 +05:30
it 'filters based on private visibility param' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { visibility : 'private' }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
2016-04-02 18:10:28 +05:30
expect ( json_response ) . to be_an Array
2017-08-17 22:00:37 +05:30
expect ( json_response . map { | p | p [ 'id' ] } ) . to contain_exactly ( project . id , project2 . id , project3 . id )
2016-04-02 18:10:28 +05:30
end
2016-09-13 17:45:13 +05:30
it 'filters based on internal visibility param' do
2017-08-17 22:00:37 +05:30
project2 . update_attribute ( :visibility_level , Gitlab :: VisibilityLevel :: INTERNAL )
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { visibility : 'internal' }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
2016-04-02 18:10:28 +05:30
expect ( json_response ) . to be_an Array
2017-08-17 22:00:37 +05:30
expect ( json_response . map { | p | p [ 'id' ] } ) . to contain_exactly ( project2 . id )
2016-04-02 18:10:28 +05:30
end
2016-09-13 17:45:13 +05:30
it 'filters based on public visibility param' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { visibility : 'public' }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
2016-04-02 18:10:28 +05:30
expect ( json_response ) . to be_an Array
2017-08-17 22:00:37 +05:30
expect ( json_response . map { | p | p [ 'id' ] } ) . to contain_exactly ( public_project . id )
2016-04-02 18:10:28 +05:30
end
end
2019-03-02 22:35:43 +05:30
context 'and using the programming language filter' do
include_context 'with language detection'
it 'filters case-insensitively by programming language' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { with_programming_language : 'javascript' }
2019-03-02 22:35:43 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-03-02 22:35:43 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | p | p [ 'id' ] } ) . to contain_exactly ( project3 . id )
end
end
2015-04-26 12:48:37 +05:30
context 'and using sorting' do
2016-09-13 17:45:13 +05:30
it 'returns the correct order when sorted by id' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { order_by : 'id' , sort : 'desc' }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
2015-04-26 12:48:37 +05:30
expect ( json_response ) . to be_an Array
2020-11-24 15:15:51 +05:30
expect ( json_response . map { | p | p [ 'id' ] } ) . to eq ( user_projects . map ( & :id ) . sort . reverse )
2015-04-26 12:48:37 +05:30
end
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
context 'and with owned=true' do
it 'returns an array of projects the user owns' do
2023-06-20 00:43:36 +05:30
get api ( path , user4 ) , params : { owned : true }
2014-09-02 18:07:02 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . first [ 'name' ] ) . to eq ( project4 . name )
expect ( json_response . first [ 'owner' ] [ 'username' ] ) . to eq ( user4 . username )
end
2020-11-24 15:15:51 +05:30
context 'when admin creates a project' do
before do
group = create ( :group )
project_create_opts = {
name : 'GitLab' ,
namespace_id : group . id
}
Projects :: CreateService . new ( admin , project_create_opts ) . execute
end
it 'does not list as owned project for admin' do
2023-06-20 00:43:36 +05:30
get api ( path , admin , admin_mode : true ) , params : { owned : true }
2020-11-24 15:15:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to be_empty
end
end
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
context 'and with starred=true' do
2017-09-10 17:25:29 +05:30
let ( :public_project ) { create ( :project , :public ) }
2014-09-02 18:07:02 +05:30
2017-08-17 22:00:37 +05:30
before do
2020-11-24 15:15:51 +05:30
user3 . update! ( starred_projects : [ project , project2 , project3 , public_project ] )
2017-08-17 22:00:37 +05:30
end
2015-04-26 12:48:37 +05:30
2017-08-17 22:00:37 +05:30
it 'returns the starred projects viewable by the user' do
2023-06-20 00:43:36 +05:30
get api ( path , user3 ) , params : { starred : true }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( project . id , public_project . id )
2015-09-11 14:41:01 +05:30
end
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
context 'and with all query parameters' do
2017-09-10 17:25:29 +05:30
let! ( :project5 ) { create ( :project , :public , path : 'gitlab5' , namespace : create ( :namespace ) ) }
2018-03-17 18:26:18 +05:30
let! ( :project6 ) { create ( :project , :public , namespace : user . namespace ) }
2017-09-10 17:25:29 +05:30
let! ( :project7 ) { create ( :project , :public , path : 'gitlab7' , namespace : user . namespace ) }
let! ( :project8 ) { create ( :project , path : 'gitlab8' , namespace : user . namespace ) }
let! ( :project9 ) { create ( :project , :public , path : 'gitlab9' ) }
2016-11-03 12:29:30 +05:30
2017-08-17 22:00:37 +05:30
before do
2020-11-24 15:15:51 +05:30
user . update! ( starred_projects : [ project5 , project7 , project8 , project9 ] )
2017-08-17 22:00:37 +05:30
end
2016-11-03 12:29:30 +05:30
2017-08-17 22:00:37 +05:30
context 'including owned filter' do
it 'returns only projects that satisfy all query parameters' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { visibility : 'public' , owned : true , starred : true , search : 'gitlab' }
2016-11-03 12:29:30 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . size ) . to eq ( 1 )
expect ( json_response . first [ 'id' ] ) . to eq ( project7 . id )
end
end
2016-11-03 12:29:30 +05:30
2017-08-17 22:00:37 +05:30
context 'including membership filter' do
before do
create ( :project_member ,
user : user ,
project : project5 ,
2018-11-18 11:00:15 +05:30
access_level : ProjectMember :: MAINTAINER )
2017-08-17 22:00:37 +05:30
end
2016-11-03 12:29:30 +05:30
2017-08-17 22:00:37 +05:30
it 'returns only projects that satisfy all query parameters' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { visibility : 'public' , membership : true , starred : true , search : 'gitlab' }
2016-11-03 12:29:30 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . size ) . to eq ( 2 )
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( project5 . id , project7 . id )
end
end
end
2018-11-18 11:00:15 +05:30
context 'and with min_access_level' do
before do
2018-11-20 20:47:30 +05:30
project2 . add_maintainer ( user2 )
2018-11-18 11:00:15 +05:30
project3 . add_developer ( user2 )
project4 . add_reporter ( user2 )
end
2019-07-07 11:18:12 +05:30
it 'returns an array of projects the user has at least developer access' do
2023-06-20 00:43:36 +05:30
get api ( path , user2 ) , params : { min_access_level : 30 }
2019-07-07 11:18:12 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-11-18 11:00:15 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( project2 . id , project3 . id )
end
end
2017-08-17 22:00:37 +05:30
end
2016-06-02 11:05:42 +05:30
2022-06-21 17:19:12 +05:30
context 'and imported=true' do
before do
other_user = create ( :user )
# imported project by other user
create ( :project , creator : other_user , import_type : 'github' , import_url : 'http://foo.com' )
# project created by current user directly instead of importing
create ( :project )
project . update_attribute ( :import_url , 'http://user:password@host/path' )
project . update_attribute ( :import_type , 'github' )
end
it 'returns only imported projects owned by current user' do
get api ( '/projects?imported=true' , user )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | p | p [ 'id' ] } ) . to eq [ project . id ]
end
it 'does not expose import credentials' do
get api ( '/projects?imported=true' , user )
expect ( json_response . first [ 'import_url' ] ) . to eq 'http://host/path'
end
end
2017-08-17 22:00:37 +05:30
context 'when authenticated as a different user' do
it_behaves_like 'projects response' do
let ( :filter ) { { } }
let ( :current_user ) { user2 }
let ( :projects ) { [ public_project ] }
end
2018-03-17 18:26:18 +05:30
context 'and with_issues_enabled=true' do
it 'does not return private issue projects' do
project . project_feature . update_attribute ( :issues_access_level , ProjectFeature :: PRIVATE )
get api ( '/projects?with_issues_enabled=true' , user2 )
2020-04-22 19:07:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-03-17 18:26:18 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | p | p [ 'id' ] } ) . not_to include ( project . id )
end
end
2015-12-23 02:04:40 +05:30
end
2017-08-17 22:00:37 +05:30
context 'when authenticated as admin' do
it_behaves_like 'projects response' do
let ( :filter ) { { } }
let ( :current_user ) { admin }
2023-06-20 00:43:36 +05:30
let ( :admin_mode ) { true }
2017-08-17 22:00:37 +05:30
let ( :projects ) { Project . all }
end
2015-12-23 02:04:40 +05:30
end
2020-03-13 15:44:24 +05:30
2022-07-16 23:28:13 +05:30
context 'with default created_at desc order' do
let_it_be ( :group_with_projects ) { create ( :group ) }
let_it_be ( :project_1 ) { create ( :project , name : 'Project 1' , created_at : 3 . days . ago , path : 'project1' , group : group_with_projects ) }
let_it_be ( :project_2 ) { create ( :project , name : 'Project 2' , created_at : 2 . days . ago , path : 'project2' , group : group_with_projects ) }
let_it_be ( :project_3 ) { create ( :project , name : 'Project 3' , created_at : 1 . day . ago , path : 'project3' , group : group_with_projects ) }
let ( :current_user ) { user }
let ( :params ) { { } }
2023-06-20 00:43:36 +05:30
subject ( :request ) { get api ( path , current_user ) , params : params }
2022-07-16 23:28:13 +05:30
before do
group_with_projects . add_owner ( current_user ) if current_user
end
it 'orders by id desc instead' do
projects_ordered_by_id_desc = / SELECT "projects".+ORDER BY "projects"."id" DESC /i
2023-06-20 00:43:36 +05:30
expect { request } . to make_queries_matching projects_ordered_by_id_desc
2022-07-16 23:28:13 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . first [ 'id' ] ) . to eq ( project_3 . id )
end
end
2021-10-27 15:23:28 +05:30
context 'sorting' do
context 'by project statistics' do
%w( repository_size storage_size wiki_size packages_size ) . each do | order_by |
context " sorting by #{ order_by } " do
before do
ProjectStatistics . update_all ( order_by = > 100 )
project4 . statistics . update_columns ( order_by = > 10 )
project . statistics . update_columns ( order_by = > 200 )
end
2020-07-28 23:09:34 +05:30
2021-10-27 15:23:28 +05:30
context 'admin user' do
let ( :current_user ) { admin }
2020-07-28 23:09:34 +05:30
2021-10-27 15:23:28 +05:30
context " when sorting by #{ order_by } ascendingly " do
it 'returns a properly sorted list of projects' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user , admin_mode : true ) , params : { order_by : order_by , sort : :asc }
2020-07-28 23:09:34 +05:30
2021-10-27 15:23:28 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . first [ 'id' ] ) . to eq ( project4 . id )
end
end
context " when sorting by #{ order_by } descendingly " do
it 'returns a properly sorted list of projects' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user , admin_mode : true ) , params : { order_by : order_by , sort : :desc }
2021-10-27 15:23:28 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . first [ 'id' ] ) . to eq ( project . id )
end
2020-07-28 23:09:34 +05:30
end
end
2021-10-27 15:23:28 +05:30
context 'non-admin user' do
let ( :current_user ) { user }
it 'returns projects ordered normally' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user ) , params : { order_by : order_by }
2020-07-28 23:09:34 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
2021-10-27 15:23:28 +05:30
expect ( json_response . map { | project | project [ 'id' ] } ) . to eq ( user_projects . map ( & :id ) . sort . reverse )
2020-07-28 23:09:34 +05:30
end
end
end
2021-10-27 15:23:28 +05:30
end
end
2020-07-28 23:09:34 +05:30
2023-06-20 00:43:36 +05:30
context 'by similarity' do
2021-10-27 15:23:28 +05:30
let_it_be ( :group_with_projects ) { create ( :group ) }
let_it_be ( :project_1 ) { create ( :project , name : 'Project' , path : 'project' , group : group_with_projects ) }
let_it_be ( :project_2 ) { create ( :project , name : 'Test Project' , path : 'test-project' , group : group_with_projects ) }
let_it_be ( :project_3 ) { create ( :project , name : 'Test' , path : 'test' , group : group_with_projects ) }
let_it_be ( :project_4 ) { create ( :project , :public , name : 'Test Public Project' ) }
2020-07-28 23:09:34 +05:30
2021-10-27 15:23:28 +05:30
let ( :current_user ) { user }
let ( :params ) { { order_by : 'similarity' , search : 'test' } }
2020-07-28 23:09:34 +05:30
2023-06-20 00:43:36 +05:30
subject ( :request ) { get api ( path , current_user ) , params : params }
2021-10-27 15:23:28 +05:30
before do
2022-06-21 17:19:12 +05:30
group_with_projects . add_owner ( current_user ) if current_user
2021-10-27 15:23:28 +05:30
end
it 'returns non-public items based ordered by similarity' do
2023-06-20 00:43:36 +05:30
request
2021-10-27 15:23:28 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response . length ) . to eq ( 2 )
project_names = json_response . map { | proj | proj [ 'name' ] }
expect ( project_names ) . to contain_exactly ( 'Test' , 'Test Project' )
end
context 'when `search` parameter is not given' do
let ( :params ) { { order_by : 'similarity' } }
it 'returns items ordered by created_at descending' do
2023-06-20 00:43:36 +05:30
request
2021-10-27 15:23:28 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response . length ) . to eq ( 8 )
project_names = json_response . map { | proj | proj [ 'name' ] }
expect ( project_names ) . to contain_exactly ( project . name , project2 . name , 'second_project' , 'public_project' , 'Project' , 'Test Project' , 'Test Public Project' , 'Test' )
end
end
context 'when called anonymously' do
let ( :current_user ) { nil }
it 'returns items ordered by created_at descending' do
2023-06-20 00:43:36 +05:30
request
2021-10-27 15:23:28 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response . length ) . to eq ( 1 )
project_names = json_response . map { | proj | proj [ 'name' ] }
expect ( project_names ) . to contain_exactly ( 'Test Public Project' )
2020-07-28 23:09:34 +05:30
end
end
end
end
context 'filtering by repository_storage' do
before do
[ project , project3 ] . each { | proj | proj . update_columns ( repository_storage : 'nfs-11' ) }
# Since we don't actually have Gitaly configured with an nfs-11 storage, an error would be raised
# when we present the projects in a response, as we ask Gitaly for stuff like default branch and Gitaly
# is not configured for a nfs-11 storage. So we trick Rails into thinking the storage for these projects
# is still default (in reality, it is).
allow_any_instance_of ( Project ) . to receive ( :repository_storage ) . and_return ( 'default' )
end
context 'admin user' do
it_behaves_like 'projects response' do
let ( :filter ) { { repository_storage : 'nfs-11' } }
let ( :current_user ) { admin }
2023-06-20 00:43:36 +05:30
let ( :admin_mode ) { true }
2020-07-28 23:09:34 +05:30
let ( :projects ) { [ project , project3 ] }
end
end
context 'non-admin user' do
it_behaves_like 'projects response' do
let ( :filter ) { { repository_storage : 'nfs-11' } }
let ( :current_user ) { user }
let ( :projects ) { [ public_project , project , project2 , project3 ] }
end
end
end
2020-03-13 15:44:24 +05:30
context 'with keyset pagination' do
let ( :current_user ) { user }
2020-11-24 15:15:51 +05:30
let ( :first_project_id ) { user_projects . map ( & :id ) . min }
let ( :last_project_id ) { user_projects . map ( & :id ) . max }
2020-03-13 15:44:24 +05:30
context 'headers and records' do
let ( :params ) { { pagination : 'keyset' , order_by : :id , sort : :asc , per_page : 1 } }
it 'includes a pagination header with link to the next page' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user ) , params : params
2020-03-13 15:44:24 +05:30
2020-06-23 00:09:42 +05:30
expect ( response . header ) . to include ( 'Link' )
expect ( response . header [ 'Link' ] ) . to include ( 'pagination=keyset' )
2020-11-24 15:15:51 +05:30
expect ( response . header [ 'Link' ] ) . to include ( " id_after= #{ first_project_id } " )
2020-03-13 15:44:24 +05:30
end
it 'contains only the first project with per_page = 1' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user ) , params : params
2020-03-13 15:44:24 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2020-03-13 15:44:24 +05:30
expect ( json_response ) . to be_an Array
2020-11-24 15:15:51 +05:30
expect ( json_response . map { | p | p [ 'id' ] } ) . to contain_exactly ( first_project_id )
2020-03-13 15:44:24 +05:30
end
it 'still includes a link if the end has reached and there is no more data after this page' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user ) , params : params . merge ( id_after : project2 . id )
2020-03-13 15:44:24 +05:30
2020-06-23 00:09:42 +05:30
expect ( response . header ) . to include ( 'Link' )
expect ( response . header [ 'Link' ] ) . to include ( 'pagination=keyset' )
expect ( response . header [ 'Link' ] ) . to include ( " id_after= #{ project3 . id } " )
2020-03-13 15:44:24 +05:30
end
it 'does not include a next link when the page does not have any records' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user ) , params : params . merge ( id_after : Project . maximum ( :id ) )
2020-03-13 15:44:24 +05:30
2020-06-23 00:09:42 +05:30
expect ( response . header ) . not_to include ( 'Link' )
2020-03-13 15:44:24 +05:30
end
it 'returns an empty array when the page does not have any records' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user ) , params : params . merge ( id_after : Project . maximum ( :id ) )
2020-03-13 15:44:24 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2020-03-13 15:44:24 +05:30
expect ( json_response ) . to eq ( [ ] )
end
it 'responds with 501 if order_by is different from id' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user ) , params : params . merge ( order_by : :created_at )
2020-03-13 15:44:24 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :method_not_allowed )
2020-03-13 15:44:24 +05:30
end
end
context 'with descending sorting' do
let ( :params ) { { pagination : 'keyset' , order_by : :id , sort : :desc , per_page : 1 } }
it 'includes a pagination header with link to the next page' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user ) , params : params
2020-03-13 15:44:24 +05:30
2020-06-23 00:09:42 +05:30
expect ( response . header ) . to include ( 'Link' )
expect ( response . header [ 'Link' ] ) . to include ( 'pagination=keyset' )
2020-11-24 15:15:51 +05:30
expect ( response . header [ 'Link' ] ) . to include ( " id_before= #{ last_project_id } " )
2020-03-13 15:44:24 +05:30
end
it 'contains only the last project with per_page = 1' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user ) , params : params
2020-03-13 15:44:24 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2020-03-13 15:44:24 +05:30
expect ( json_response ) . to be_an Array
2020-11-24 15:15:51 +05:30
expect ( json_response . map { | p | p [ 'id' ] } ) . to contain_exactly ( last_project_id )
2020-03-13 15:44:24 +05:30
end
end
context 'retrieving the full relation' do
let ( :params ) { { pagination : 'keyset' , order_by : :id , sort : :desc , per_page : 2 } }
it 'returns all projects' do
2023-06-20 00:43:36 +05:30
url = path
2020-03-13 15:44:24 +05:30
requests = 0
ids = [ ]
while url && requests < = 5 # circuit breaker
requests += 1
get api ( url , current_user ) , params : params
2020-06-23 00:09:42 +05:30
link = response . header [ 'Link' ]
2021-09-30 23:02:18 +05:30
url = link & . match ( %r{ <[^>]+(/projects \ ?[^>]+)>; rel="next" } ) do | match |
2020-06-23 00:09:42 +05:30
match [ 1 ]
end
2020-05-24 23:13:21 +05:30
ids += Gitlab :: Json . parse ( response . body ) . map { | p | p [ 'id' ] }
2020-03-13 15:44:24 +05:30
end
2020-11-24 15:15:51 +05:30
expect ( ids ) . to contain_exactly ( * user_projects . map ( & :id ) )
2020-03-13 15:44:24 +05:30
end
end
end
2021-04-29 21:17:54 +05:30
context 'with forked projects' , :use_clean_rails_memory_store_caching do
include ProjectForksHelper
let_it_be ( :admin ) { create ( :admin ) }
2023-06-20 00:43:36 +05:30
subject ( :request ) { get api ( path , admin ) }
2023-01-13 00:05:48 +05:30
it 'avoids N+1 queries' , :use_sql_query_cache do
2023-06-20 00:43:36 +05:30
request
expect ( response ) . to have_gitlab_http_status ( :ok )
2021-04-29 21:17:54 +05:30
base_project = create ( :project , :public , namespace : admin . namespace )
fork_project1 = fork_project ( base_project , admin , namespace : create ( :user ) . namespace )
fork_project2 = fork_project ( fork_project1 , admin , namespace : create ( :user ) . namespace )
2023-01-13 00:05:48 +05:30
control = ActiveRecord :: QueryRecorder . new ( skip_cached : false ) do
2023-06-20 00:43:36 +05:30
request
2021-04-29 21:17:54 +05:30
end
fork_project ( fork_project2 , admin , namespace : create ( :user ) . namespace )
expect do
2023-06-20 00:43:36 +05:30
request
end . not_to exceed_all_query_limit ( control . count )
2021-04-29 21:17:54 +05:30
end
end
context 'when service desk is enabled' , :use_clean_rails_memory_store_caching do
let_it_be ( :admin ) { create ( :admin ) }
2023-06-20 00:43:36 +05:30
subject ( :request ) { get api ( path , admin ) }
2021-04-29 21:17:54 +05:30
it 'avoids N+1 queries' do
2023-06-20 00:43:36 +05:30
allow ( Gitlab :: Email :: ServiceDeskEmail ) . to receive ( :enabled? ) . and_return ( true )
allow ( Gitlab :: Email :: IncomingEmail ) . to receive ( :enabled? ) . and_return ( true )
2021-04-29 21:17:54 +05:30
2023-06-20 00:43:36 +05:30
request
expect ( response ) . to have_gitlab_http_status ( :ok )
2021-04-29 21:17:54 +05:30
create ( :project , :public , :service_desk_enabled , namespace : admin . namespace )
control = ActiveRecord :: QueryRecorder . new do
2023-06-20 00:43:36 +05:30
request
2021-04-29 21:17:54 +05:30
end
create_list ( :project , 2 , :public , :service_desk_enabled , namespace : admin . namespace )
expect do
2023-06-20 00:43:36 +05:30
request
end . not_to exceed_all_query_limit ( control )
2021-04-29 21:17:54 +05:30
end
end
2023-05-27 22:25:52 +05:30
context 'rate limiting' do
let_it_be ( :current_user ) { create ( :user ) }
shared_examples_for 'does not log request and does not block the request' do
specify do
request
request
expect ( response ) . not_to have_gitlab_http_status ( :too_many_requests )
expect ( Gitlab :: AuthLogger ) . not_to receive ( :error )
end
end
before do
stub_application_setting ( projects_api_rate_limit_unauthenticated : 1 )
end
context 'when the user is signed in' do
it_behaves_like 'does not log request and does not block the request' do
def request
2023-06-20 00:43:36 +05:30
get api ( path , current_user )
2023-05-27 22:25:52 +05:30
end
end
end
context 'when the user is not signed in' do
let_it_be ( :current_user ) { nil }
it_behaves_like 'rate limited endpoint' , rate_limit_key : :projects_api_rate_limit_unauthenticated do
def request
2023-06-20 00:43:36 +05:30
get api ( path , current_user )
2023-05-27 22:25:52 +05:30
end
end
end
context 'when the feature flag `rate_limit_for_unauthenticated_projects_api_access` is disabled' do
before do
stub_feature_flags ( rate_limit_for_unauthenticated_projects_api_access : false )
end
context 'when the user is not signed in' do
let_it_be ( :current_user ) { nil }
it_behaves_like 'does not log request and does not block the request' do
def request
2023-06-20 00:43:36 +05:30
get api ( path , current_user )
2023-05-27 22:25:52 +05:30
end
end
end
context 'when the user is signed in' do
it_behaves_like 'does not log request and does not block the request' do
def request
2023-06-20 00:43:36 +05:30
get api ( path , current_user )
2023-05-27 22:25:52 +05:30
end
end
end
end
end
2015-12-23 02:04:40 +05:30
end
2015-04-26 12:48:37 +05:30
describe 'POST /projects' do
2023-06-20 00:43:36 +05:30
let ( :path ) { '/projects' }
2015-04-26 12:48:37 +05:30
context 'maximum number of projects reached' do
2016-09-13 17:45:13 +05:30
it 'does not create new project and respond with 403' do
2015-04-26 12:48:37 +05:30
allow_any_instance_of ( User ) . to receive ( :projects_limit_left ) . and_return ( 0 )
2023-06-20 00:43:36 +05:30
expect { post api ( path , user2 ) , params : { name : 'foo' } }
2022-08-27 11:52:29 +05:30
. to change { Project . count } . by ( 0 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2014-09-02 18:07:02 +05:30
end
end
2017-08-17 22:00:37 +05:30
it 'creates new project without path but with name and returns 201' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) , params : { name : 'Foo Project' } }
2017-09-10 17:25:29 +05:30
. to change { Project . count } . by ( 1 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
2020-11-24 15:15:51 +05:30
project = Project . last
2017-08-17 22:00:37 +05:30
expect ( project . name ) . to eq ( 'Foo Project' )
expect ( project . path ) . to eq ( 'foo-project' )
end
it 'creates new project without name but with path and returns 201' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) , params : { path : 'foo_project' } }
2017-09-10 17:25:29 +05:30
. to change { Project . count } . by ( 1 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
2020-11-24 15:15:51 +05:30
project = Project . last
2017-08-17 22:00:37 +05:30
expect ( project . name ) . to eq ( 'foo_project' )
expect ( project . path ) . to eq ( 'foo_project' )
end
2017-09-10 17:25:29 +05:30
it 'creates new project with name and path and returns 201' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) , params : { path : 'path-project-Foo' , name : 'Foo Project' } }
2017-09-10 17:25:29 +05:30
. to change { Project . count } . by ( 1 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
2020-11-24 15:15:51 +05:30
project = Project . last
2017-08-17 22:00:37 +05:30
expect ( project . name ) . to eq ( 'Foo Project' )
2017-09-10 17:25:29 +05:30
expect ( project . path ) . to eq ( 'path-project-Foo' )
2014-09-02 18:07:02 +05:30
end
2021-09-04 01:27:46 +05:30
it_behaves_like 'create project with default branch parameter' do
2023-06-20 00:43:36 +05:30
subject ( :request ) { post api ( path , user ) , params : params }
2021-09-04 01:27:46 +05:30
end
2016-09-13 17:45:13 +05:30
it 'creates last project before reaching project limit' do
2015-04-26 12:48:37 +05:30
allow_any_instance_of ( User ) . to receive ( :projects_limit_left ) . and_return ( 1 )
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { name : 'foo' }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
it 'does not create new project without name or path and returns 400' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) } . not_to change { Project . count }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2014-09-02 18:07:02 +05:30
end
2023-06-20 00:43:36 +05:30
it 'assigns attributes to project' do
2014-09-02 18:07:02 +05:30
project = attributes_for ( :project , {
2015-04-26 12:48:37 +05:30
path : 'camelCasePath' ,
2014-09-02 18:07:02 +05:30
issues_enabled : false ,
2017-08-17 22:00:37 +05:30
jobs_enabled : false ,
2014-09-02 18:07:02 +05:30
merge_requests_enabled : false ,
2020-04-22 19:07:51 +05:30
forking_access_level : 'disabled' ,
2021-02-22 17:27:13 +05:30
analytics_access_level : 'disabled' ,
2016-09-29 09:46:39 +05:30
wiki_enabled : false ,
2018-03-17 18:26:18 +05:30
resolve_outdated_diff_discussions : false ,
2019-12-26 22:10:19 +05:30
remove_source_branch_after_merge : true ,
2020-03-13 15:44:24 +05:30
autoclose_referenced_issues : true ,
2020-06-23 00:09:42 +05:30
only_allow_merge_if_pipeline_succeeds : true ,
allow_merge_on_skipped_pipeline : true ,
2017-08-17 22:00:37 +05:30
request_access_enabled : true ,
2017-09-10 17:25:29 +05:30
only_allow_merge_if_all_discussions_are_resolved : false ,
2018-05-09 12:01:36 +05:30
ci_config_path : 'a/custom/path' ,
2021-09-30 23:02:18 +05:30
merge_method : 'ff' ,
squash_option : 'always'
2021-02-22 17:27:13 +05:30
} ) . tap do | attrs |
attrs [ :operations_access_level ] = 'disabled'
attrs [ :analytics_access_level ] = 'disabled'
2021-10-27 15:23:28 +05:30
attrs [ :container_registry_access_level ] = 'private'
2022-05-07 20:08:51 +05:30
attrs [ :security_and_compliance_access_level ] = 'private'
2022-11-25 23:54:43 +05:30
attrs [ :releases_access_level ] = 'disabled'
2023-03-04 22:38:38 +05:30
attrs [ :environments_access_level ] = 'disabled'
attrs [ :feature_flags_access_level ] = 'disabled'
attrs [ :infrastructure_access_level ] = 'disabled'
attrs [ :monitor_access_level ] = 'disabled'
2023-03-17 16:20:25 +05:30
attrs [ :snippets_access_level ] = 'disabled'
attrs [ :wiki_access_level ] = 'disabled'
attrs [ :builds_access_level ] = 'disabled'
attrs [ :merge_requests_access_level ] = 'disabled'
attrs [ :issues_access_level ] = 'disabled'
2021-02-22 17:27:13 +05:30
end
2014-09-02 18:07:02 +05:30
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2014-09-02 18:07:02 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
2016-08-24 12:49:21 +05:30
project . each_pair do | k , v |
2021-10-27 15:23:28 +05:30
next if % i [
has_external_issue_tracker has_external_wiki issues_enabled merge_requests_enabled wiki_enabled storage_version
2023-03-04 22:38:38 +05:30
container_registry_access_level releases_access_level environments_access_level feature_flags_access_level
infrastructure_access_level monitor_access_level
2021-10-27 15:23:28 +05:30
] . include? ( k )
2018-03-17 18:26:18 +05:30
2015-04-26 12:48:37 +05:30
expect ( json_response [ k . to_s ] ) . to eq ( v )
2014-09-02 18:07:02 +05:30
end
2016-09-29 09:46:39 +05:30
# Check feature permissions attributes
project = Project . find_by_path ( project [ :path ] )
expect ( project . project_feature . issues_access_level ) . to eq ( ProjectFeature :: DISABLED )
expect ( project . project_feature . merge_requests_access_level ) . to eq ( ProjectFeature :: DISABLED )
expect ( project . project_feature . wiki_access_level ) . to eq ( ProjectFeature :: DISABLED )
2021-02-22 17:27:13 +05:30
expect ( project . operations_access_level ) . to eq ( ProjectFeature :: DISABLED )
expect ( project . project_feature . analytics_access_level ) . to eq ( ProjectFeature :: DISABLED )
2021-10-27 15:23:28 +05:30
expect ( project . project_feature . container_registry_access_level ) . to eq ( ProjectFeature :: PRIVATE )
2022-05-07 20:08:51 +05:30
expect ( project . project_feature . security_and_compliance_access_level ) . to eq ( ProjectFeature :: PRIVATE )
2022-11-25 23:54:43 +05:30
expect ( project . project_feature . releases_access_level ) . to eq ( ProjectFeature :: DISABLED )
2023-03-04 22:38:38 +05:30
expect ( project . project_feature . environments_access_level ) . to eq ( ProjectFeature :: DISABLED )
expect ( project . project_feature . feature_flags_access_level ) . to eq ( ProjectFeature :: DISABLED )
expect ( project . project_feature . infrastructure_access_level ) . to eq ( ProjectFeature :: DISABLED )
expect ( project . project_feature . monitor_access_level ) . to eq ( ProjectFeature :: DISABLED )
2023-03-17 16:20:25 +05:30
expect ( project . project_feature . wiki_access_level ) . to eq ( ProjectFeature :: DISABLED )
expect ( project . project_feature . builds_access_level ) . to eq ( ProjectFeature :: DISABLED )
expect ( project . project_feature . merge_requests_access_level ) . to eq ( ProjectFeature :: DISABLED )
expect ( project . project_feature . issues_access_level ) . to eq ( ProjectFeature :: DISABLED )
expect ( project . project_feature . snippets_access_level ) . to eq ( ProjectFeature :: DISABLED )
2021-10-27 15:23:28 +05:30
end
2023-06-20 00:43:36 +05:30
it 'assigns container_registry_enabled to project' do
2021-10-27 15:23:28 +05:30
project = attributes_for ( :project , { container_registry_enabled : true } )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2021-10-27 15:23:28 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
expect ( json_response [ 'container_registry_enabled' ] ) . to eq ( true )
expect ( json_response [ 'container_registry_access_level' ] ) . to eq ( 'enabled' )
expect ( Project . find_by ( path : project [ :path ] ) . container_registry_access_level ) . to eq ( ProjectFeature :: ENABLED )
end
it 'assigns container_registry_enabled to project' do
project = attributes_for ( :project , { container_registry_enabled : true } )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2021-10-27 15:23:28 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
expect ( json_response [ 'container_registry_enabled' ] ) . to eq ( true )
expect ( Project . find_by ( path : project [ :path ] ) . container_registry_access_level ) . to eq ( ProjectFeature :: ENABLED )
2014-09-02 18:07:02 +05:30
end
2019-12-04 20:38:33 +05:30
it 'creates a project using a template' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) , params : { template_name : 'rails' , name : 'rails-test' } }
2019-12-04 20:38:33 +05:30
. to change { Project . count } . by ( 1 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-12-04 20:38:33 +05:30
project = Project . find ( json_response [ 'id' ] )
expect ( project ) . to be_saved
expect ( project . import_type ) . to eq ( 'gitlab_project' )
end
it 'returns 400 for an invalid template' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) , params : { template_name : 'unknown' , name : 'rails-test' } }
2019-12-04 20:38:33 +05:30
. not_to change { Project . count }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2019-12-04 20:38:33 +05:30
expect ( json_response [ 'message' ] [ 'template_name' ] ) . to eq ( [ " 'unknown' is unknown or invalid " ] )
end
it 'disallows creating a project with an import_url and template' do
project_params = { import_url : 'http://example.com' , template_name : 'rails' , name : 'rails-test' }
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) , params : project_params }
2019-12-04 20:38:33 +05:30
. not_to change { Project . count }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2019-12-04 20:38:33 +05:30
end
2021-09-30 23:02:18 +05:30
it 'disallows creating a project with an import_url when git import source is disabled' do
2022-07-16 23:28:13 +05:30
url = 'http://example.com'
2021-09-30 23:02:18 +05:30
stub_application_setting ( import_sources : nil )
2022-07-16 23:28:13 +05:30
endpoint_url = " #{ url } /info/refs?service=git-upload-pack "
2022-10-11 01:57:18 +05:30
stub_full_request ( endpoint_url , method : :get ) . to_return (
{ status : 200 ,
body : '001e# service=git-upload-pack' ,
headers : { 'Content-Type' : 'application/x-git-upload-pack-advertisement' } } )
2022-07-16 23:28:13 +05:30
project_params = { import_url : url , path : 'path-project-Foo' , name : 'Foo Project' }
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) , params : project_params }
2021-09-30 23:02:18 +05:30
. not_to change { Project . count }
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
2023-06-20 00:43:36 +05:30
it 'allows creating a project without an import_url when git import source is disabled' do
2022-01-26 12:08:38 +05:30
stub_application_setting ( import_sources : nil )
project_params = { path : 'path-project-Foo' }
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) , params : project_params } . to change { Project . count } . by ( 1 )
2022-01-26 12:08:38 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
end
2023-06-20 00:43:36 +05:30
it 'disallows creating a project with an import_url that is not reachable' do
2021-12-11 22:18:48 +05:30
url = 'http://example.com'
endpoint_url = " #{ url } /info/refs?service=git-upload-pack "
stub_full_request ( endpoint_url , method : :get ) . to_return ( { status : 301 , body : '' , headers : nil } )
project_params = { import_url : url , path : 'path-project-Foo' , name : 'Foo Project' }
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) , params : project_params } . not_to change { Project . count }
2021-12-11 22:18:48 +05:30
expect ( response ) . to have_gitlab_http_status ( :unprocessable_entity )
expect ( json_response [ 'message' ] ) . to eq ( " #{ url } is not a valid HTTP Git repository " )
end
2023-06-20 00:43:36 +05:30
it 'creates a project with an import_url that is valid' do
2021-12-11 22:18:48 +05:30
url = 'http://example.com'
endpoint_url = " #{ url } /info/refs?service=git-upload-pack "
git_response = {
status : 200 ,
body : '001e# service=git-upload-pack' ,
headers : { 'Content-Type' : 'application/x-git-upload-pack-advertisement' }
}
stub_full_request ( endpoint_url , method : :get ) . to_return ( git_response )
project_params = { import_url : url , path : 'path-project-Foo' , name : 'Foo Project' }
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) , params : project_params } . to change { Project . count } . by ( 1 )
2021-12-11 22:18:48 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
end
2016-09-13 17:45:13 +05:30
it 'sets a project as public' do
2017-08-17 22:00:37 +05:30
project = attributes_for ( :project , visibility : 'public' )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'visibility' ] ) . to eq ( 'public' )
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
it 'sets a project as internal' do
project = attributes_for ( :project , visibility : 'internal' )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'visibility' ] ) . to eq ( 'internal' )
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
it 'sets a project as private' do
project = attributes_for ( :project , visibility : 'private' )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'visibility' ] ) . to eq ( 'private' )
2014-09-02 18:07:02 +05:30
end
2018-12-05 23:21:45 +05:30
it 'creates a new project initialized with a README.md' do
project = attributes_for ( :project , initialize_with_readme : 1 , name : 'somewhere' )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2018-12-05 23:21:45 +05:30
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'readme_url' ] ) . to eql ( " #{ Gitlab . config . gitlab . url } / #{ json_response [ 'namespace' ] [ 'full_path' ] } /somewhere/-/blob/master/README.md " )
2018-12-05 23:21:45 +05:30
end
2021-09-04 01:27:46 +05:30
it 'sets tag list to a project (deprecated)' do
2017-09-10 17:25:29 +05:30
project = attributes_for ( :project , tag_list : %w[ tagFirst tagSecond ] )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2017-09-10 17:25:29 +05:30
2021-09-04 01:27:46 +05:30
expect ( json_response [ 'topics' ] ) . to eq ( %w[ tagFirst tagSecond ] )
end
it 'sets topics to a project' do
project = attributes_for ( :project , topics : %w[ topic1 topics2 ] )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2021-09-04 01:27:46 +05:30
expect ( json_response [ 'topics' ] ) . to eq ( %w[ topic1 topics2 ] )
2017-09-10 17:25:29 +05:30
end
it 'uploads avatar for project a project' do
2018-11-08 19:23:39 +05:30
project = attributes_for ( :project , avatar : fixture_file_upload ( 'spec/fixtures/banana_sample.gif' , 'image/gif' ) )
2017-09-10 17:25:29 +05:30
2022-10-11 01:57:18 +05:30
workhorse_form_with_file (
2023-06-20 00:43:36 +05:30
api ( path , user ) ,
2022-10-11 01:57:18 +05:30
method : :post ,
file_key : :avatar ,
params : project
)
2017-09-10 17:25:29 +05:30
project_id = json_response [ 'id' ]
expect ( json_response [ 'avatar_url' ] ) . to eq ( " http://localhost/uploads/-/system/project/avatar/ #{ project_id } /banana_sample.gif " )
end
2018-11-20 20:47:30 +05:30
it 'sets a project as not allowing outdated diff discussions to automatically resolve' do
2018-03-17 18:26:18 +05:30
project = attributes_for ( :project , resolve_outdated_diff_discussions : false )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2018-03-17 18:26:18 +05:30
expect ( json_response [ 'resolve_outdated_diff_discussions' ] ) . to be_falsey
end
2018-11-20 20:47:30 +05:30
it 'sets a project as allowing outdated diff discussions to automatically resolve' do
2018-03-17 18:26:18 +05:30
project = attributes_for ( :project , resolve_outdated_diff_discussions : true )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2018-03-17 18:26:18 +05:30
expect ( json_response [ 'resolve_outdated_diff_discussions' ] ) . to be_truthy
end
2019-12-26 22:10:19 +05:30
it 'sets a project as not removing source branches' do
project = attributes_for ( :project , remove_source_branch_after_merge : false )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2019-12-26 22:10:19 +05:30
expect ( json_response [ 'remove_source_branch_after_merge' ] ) . to be_falsey
end
it 'sets a project as removing source branches' do
project = attributes_for ( :project , remove_source_branch_after_merge : true )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2019-12-26 22:10:19 +05:30
expect ( json_response [ 'remove_source_branch_after_merge' ] ) . to be_truthy
end
2017-08-17 22:00:37 +05:30
it 'sets a project as allowing merge even if build fails' do
2018-03-17 18:26:18 +05:30
project = attributes_for ( :project , only_allow_merge_if_pipeline_succeeds : false )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2018-03-17 18:26:18 +05:30
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'only_allow_merge_if_pipeline_succeeds' ] ) . to be_falsey
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
it 'sets a project as allowing merge only if merge_when_pipeline_succeeds' do
2018-03-17 18:26:18 +05:30
project = attributes_for ( :project , only_allow_merge_if_pipeline_succeeds : true )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2018-03-17 18:26:18 +05:30
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'only_allow_merge_if_pipeline_succeeds' ] ) . to be_truthy
2014-09-02 18:07:02 +05:30
end
2020-06-23 00:09:42 +05:30
it 'sets a project as not allowing merge when pipeline is skipped' do
project_params = attributes_for ( :project , allow_merge_on_skipped_pipeline : false )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project_params
2020-06-23 00:09:42 +05:30
expect ( json_response [ 'allow_merge_on_skipped_pipeline' ] ) . to be_falsey
end
it 'sets a project as allowing merge when pipeline is skipped' do
project_params = attributes_for ( :project , allow_merge_on_skipped_pipeline : true )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project_params
2020-06-23 00:09:42 +05:30
expect ( json_response [ 'allow_merge_on_skipped_pipeline' ] ) . to be_truthy
end
2017-08-17 22:00:37 +05:30
it 'sets a project as allowing merge even if discussions are unresolved' do
2018-03-17 18:26:18 +05:30
project = attributes_for ( :project , only_allow_merge_if_all_discussions_are_resolved : false )
2017-08-17 22:00:37 +05:30
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'only_allow_merge_if_all_discussions_are_resolved' ] ) . to be_falsey
2015-04-26 12:48:37 +05:30
end
2017-08-17 22:00:37 +05:30
it 'sets a project as allowing merge if only_allow_merge_if_all_discussions_are_resolved is nil' do
project = attributes_for ( :project , only_allow_merge_if_all_discussions_are_resolved : nil )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'only_allow_merge_if_all_discussions_are_resolved' ] ) . to be_falsey
2016-09-29 09:46:39 +05:30
end
2017-08-17 22:00:37 +05:30
it 'sets a project as allowing merge only if all discussions are resolved' do
2018-03-17 18:26:18 +05:30
project = attributes_for ( :project , only_allow_merge_if_all_discussions_are_resolved : true )
2017-08-17 22:00:37 +05:30
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'only_allow_merge_if_all_discussions_are_resolved' ] ) . to be_truthy
end
2020-03-13 15:44:24 +05:30
it 'sets a project as enabling auto close referenced issues' do
project = attributes_for ( :project , autoclose_referenced_issues : true )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'autoclose_referenced_issues' ] ) . to be_truthy
end
it 'sets a project as disabling auto close referenced issues' do
project = attributes_for ( :project , autoclose_referenced_issues : false )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'autoclose_referenced_issues' ] ) . to be_falsey
end
2018-05-09 12:01:36 +05:30
it 'sets the merge method of a project to rebase merge' do
project = attributes_for ( :project , merge_method : 'rebase_merge' )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2018-05-09 12:01:36 +05:30
expect ( json_response [ 'merge_method' ] ) . to eq ( 'rebase_merge' )
end
it 'rejects invalid values for merge_method' do
project = attributes_for ( :project , merge_method : 'totally_not_valid_method' )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2018-05-09 12:01:36 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2018-05-09 12:01:36 +05:30
end
2017-08-17 22:00:37 +05:30
it 'ignores import_url when it is nil' do
2018-03-17 18:26:18 +05:30
project = attributes_for ( :project , import_url : nil )
2017-08-17 22:00:37 +05:30
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2016-09-29 09:46:39 +05:30
end
2015-04-26 12:48:37 +05:30
context 'when a visibility level is restricted' do
2017-08-17 22:00:37 +05:30
let ( :project_param ) { attributes_for ( :project , visibility : 'public' ) }
2015-04-26 12:48:37 +05:30
before do
2015-09-11 14:41:01 +05:30
stub_application_setting ( restricted_visibility_levels : [ Gitlab :: VisibilityLevel :: PUBLIC ] )
2015-04-26 12:48:37 +05:30
end
2016-09-13 17:45:13 +05:30
it 'does not allow a non-admin to use a restricted visibility level' do
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : project_param
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2015-04-26 12:48:37 +05:30
expect ( json_response [ 'message' ] [ 'visibility_level' ] . first ) . to (
match ( 'restricted by your GitLab administrator' )
)
end
2016-09-13 17:45:13 +05:30
it 'allows an admin to override restricted visibility settings' do
2023-06-20 00:43:36 +05:30
post api ( path , admin ) , params : project_param
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'visibility' ] ) . to eq ( 'public' )
2015-04-26 12:48:37 +05:30
end
2014-09-02 18:07:02 +05:30
end
end
2017-09-10 17:25:29 +05:30
describe 'GET /users/:user_id/projects/' do
let! ( :public_project ) { create ( :project , :public , name : 'public_project' , creator_id : user4 . id , namespace : user4 . namespace ) }
it 'returns error when user not found' do
2021-03-11 19:13:27 +05:30
get api ( " /users/ #{ non_existing_record_id } /projects/ " )
2017-09-10 17:25:29 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-09-10 17:25:29 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '404 User Not Found' )
end
2019-03-02 22:35:43 +05:30
it 'returns projects filtered by user id' do
2017-09-10 17:25:29 +05:30
get api ( " /users/ #{ user4 . id } /projects/ " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-09-10 17:25:29 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( public_project . id )
end
2018-11-18 11:00:15 +05:30
2023-06-20 00:43:36 +05:30
it 'includes container_registry_access_level' do
2021-10-27 15:23:28 +05:30
get api ( " /users/ #{ user4 . id } /projects/ " , user )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response ) . to be_an Array
expect ( json_response . first . keys ) . to include ( 'container_registry_access_level' )
end
2023-06-20 00:43:36 +05:30
context 'filter by updated_at' do
it 'returns only projects updated on the given timeframe' do
get api ( " /users/ #{ user . id } /projects " , user ) ,
params : { updated_before : 2 . days . ago . iso8601 , updated_after : 6 . days . ago }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( project2 . id , project . id )
end
end
2019-12-26 22:10:19 +05:30
context 'and using id_after' do
let! ( :another_public_project ) { create ( :project , :public , name : 'another_public_project' , creator_id : user4 . id , namespace : user4 . namespace ) }
it 'only returns projects with id_after filter given' do
get api ( " /users/ #{ user4 . id } /projects?id_after= #{ public_project . id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-12-26 22:10:19 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( another_public_project . id )
end
it 'returns both projects without a id_after filter' do
get api ( " /users/ #{ user4 . id } /projects " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-12-26 22:10:19 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( public_project . id , another_public_project . id )
end
end
context 'and using id_before' do
let! ( :another_public_project ) { create ( :project , :public , name : 'another_public_project' , creator_id : user4 . id , namespace : user4 . namespace ) }
it 'only returns projects with id_before filter given' do
get api ( " /users/ #{ user4 . id } /projects?id_before= #{ another_public_project . id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-12-26 22:10:19 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( public_project . id )
end
it 'returns both projects without a id_before filter' do
get api ( " /users/ #{ user4 . id } /projects " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-12-26 22:10:19 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( public_project . id , another_public_project . id )
end
end
context 'and using both id_before and id_after' do
let! ( :more_projects ) { create_list ( :project , 5 , :public , creator_id : user4 . id , namespace : user4 . namespace ) }
it 'only returns projects with id matching the range' do
get api ( " /users/ #{ user4 . id } /projects?id_after= #{ more_projects . first . id } &id_before= #{ more_projects . last . id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-12-26 22:10:19 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( * more_projects [ 1 .. - 2 ] . map ( & :id ) )
end
end
2019-03-02 22:35:43 +05:30
it 'returns projects filtered by username' do
get api ( " /users/ #{ user4 . username } /projects/ " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-03-02 22:35:43 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( public_project . id )
end
2018-11-20 20:47:30 +05:30
it 'returns projects filtered by minimal access level' do
2018-11-18 11:00:15 +05:30
private_project1 = create ( :project , :private , name : 'private_project1' , creator_id : user4 . id , namespace : user4 . namespace )
private_project2 = create ( :project , :private , name : 'private_project2' , creator_id : user4 . id , namespace : user4 . namespace )
private_project1 . add_developer ( user2 )
private_project2 . add_reporter ( user2 )
2019-02-15 15:39:39 +05:30
get api ( " /users/ #{ user4 . id } /projects/ " , user2 ) , params : { min_access_level : 30 }
2018-11-18 11:00:15 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-11-18 11:00:15 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( private_project1 . id )
end
2019-03-02 22:35:43 +05:30
2023-06-20 00:43:36 +05:30
context 'and using an admin to search' , :enable_admin_mode do
2022-01-26 12:08:38 +05:30
it 'returns users projects when authenticated as admin' do
private_project1 = create ( :project , :private , name : 'private_project1' , creator_id : user4 . id , namespace : user4 . namespace )
# min_access_level does not make any difference when admins search for a user's projects
get api ( " /users/ #{ user4 . id } /projects/ " , admin ) , params : { min_access_level : 30 }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( project4 . id , private_project1 . id , public_project . id )
end
end
2019-03-02 22:35:43 +05:30
context 'and using the programming language filter' do
include_context 'with language detection'
it 'filters case-insensitively by programming language' do
get api ( '/projects' , user ) , params : { with_programming_language : 'ruby' }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-03-02 22:35:43 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | p | p [ 'id' ] } ) . to contain_exactly ( project . id )
end
end
2017-09-10 17:25:29 +05:30
end
2019-10-12 21:52:04 +05:30
describe 'GET /users/:user_id/starred_projects/' do
before do
2020-11-24 15:15:51 +05:30
user3 . update! ( starred_projects : [ project , project2 , project3 ] )
2021-06-08 01:23:25 +05:30
user3 . reload
2019-10-12 21:52:04 +05:30
end
2023-06-20 00:43:36 +05:30
let ( :path ) { " /users/ #{ user3 . id } /starred_projects/ " }
2019-10-12 21:52:04 +05:30
it 'returns error when user not found' do
2020-04-22 19:07:51 +05:30
get api ( " /users/ #{ non_existing_record_id } /starred_projects/ " )
2019-10-12 21:52:04 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2019-10-12 21:52:04 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '404 User Not Found' )
end
2020-12-08 15:28:05 +05:30
context 'with a public profile' do
it 'returns projects filtered by user' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2019-10-12 21:52:04 +05:30
2020-12-08 15:28:05 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } )
. to contain_exactly ( project . id , project2 . id , project3 . id )
end
2023-06-20 00:43:36 +05:30
context 'filter by updated_at' do
it 'returns only projects updated on the given timeframe' do
get api ( path , user ) ,
params : { updated_before : 2 . days . ago . iso8601 , updated_after : 6 . days . ago }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( project2 . id , project . id )
end
end
2020-12-08 15:28:05 +05:30
end
context 'with a private profile' do
before do
user3 . update! ( private_profile : true )
user3 . reload
end
context 'user does not have access to view the private profile' do
it 'returns no projects' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2020-12-08 15:28:05 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response ) . to be_empty
end
end
context 'user has access to view the private profile' do
it 'returns projects filtered by user' do
2023-06-20 00:43:36 +05:30
get api ( path , admin , admin_mode : true )
2020-12-08 15:28:05 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | project | project [ 'id' ] } )
. to contain_exactly ( project . id , project2 . id , project3 . id )
end
end
2019-10-12 21:52:04 +05:30
end
end
2015-04-26 12:48:37 +05:30
describe 'POST /projects/user/:id' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/user/ #{ user . id } " }
it_behaves_like 'POST request permissions for admin mode' do
let ( :params ) { { name : 'Foo Project' } }
end
2017-09-10 17:25:29 +05:30
it 'creates new project without path but with name and return 201' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , admin , admin_mode : true ) , params : { name : 'Foo Project' } } . to change { Project . count } . by ( 1 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-09-10 17:25:29 +05:30
2019-12-04 20:38:33 +05:30
project = Project . find ( json_response [ 'id' ] )
2017-09-10 17:25:29 +05:30
expect ( project . name ) . to eq ( 'Foo Project' )
expect ( project . path ) . to eq ( 'foo-project' )
end
2014-09-02 18:07:02 +05:30
2017-09-10 17:25:29 +05:30
it 'creates new project with name and path and returns 201' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , admin , admin_mode : true ) , params : { path : 'path-project-Foo' , name : 'Foo Project' } }
2017-09-10 17:25:29 +05:30
. to change { Project . count } . by ( 1 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-09-10 17:25:29 +05:30
2019-12-04 20:38:33 +05:30
project = Project . find ( json_response [ 'id' ] )
2017-09-10 17:25:29 +05:30
expect ( project . name ) . to eq ( 'Foo Project' )
expect ( project . path ) . to eq ( 'path-project-Foo' )
2014-09-02 18:07:02 +05:30
end
2021-09-04 01:27:46 +05:30
it_behaves_like 'create project with default branch parameter' do
2023-06-20 00:43:36 +05:30
subject ( :request ) { post api ( path , admin , admin_mode : true ) , params : params }
2021-09-04 01:27:46 +05:30
end
2016-09-13 17:45:13 +05:30
it 'responds with 400 on failure and not project' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , admin , admin_mode : true ) }
2017-09-10 17:25:29 +05:30
. not_to change { Project . count }
2014-09-02 18:07:02 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'error' ] ) . to eq ( 'name is missing' )
2014-09-02 18:07:02 +05:30
end
2021-10-27 15:23:28 +05:30
it 'sets container_registry_enabled' do
project = attributes_for ( :project ) . tap do | attrs |
attrs [ :container_registry_enabled ] = true
end
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2021-10-27 15:23:28 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
expect ( json_response [ 'container_registry_enabled' ] ) . to eq ( true )
expect ( Project . find_by ( path : project [ :path ] ) . container_registry_access_level ) . to eq ( ProjectFeature :: ENABLED )
end
2016-09-13 17:45:13 +05:30
it 'assigns attributes to project' do
2014-09-02 18:07:02 +05:30
project = attributes_for ( :project , {
issues_enabled : false ,
merge_requests_enabled : false ,
2016-09-29 09:46:39 +05:30
wiki_enabled : false ,
2018-10-15 14:42:47 +05:30
request_access_enabled : true ,
jobs_enabled : true
2014-09-02 18:07:02 +05:30
} )
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2014-09-02 18:07:02 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2018-03-27 19:54:05 +05:30
2016-08-24 12:49:21 +05:30
project . each_pair do | k , v |
2021-01-29 00:20:46 +05:30
next if % i [ has_external_issue_tracker has_external_wiki path storage_version ] . include? ( k )
2018-03-17 18:26:18 +05:30
2015-04-26 12:48:37 +05:30
expect ( json_response [ k . to_s ] ) . to eq ( v )
2014-09-02 18:07:02 +05:30
end
end
2016-09-13 17:45:13 +05:30
it 'sets a project as public' do
2017-08-17 22:00:37 +05:30
project = attributes_for ( :project , visibility : 'public' )
2014-09-02 18:07:02 +05:30
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'visibility' ] ) . to eq ( 'public' )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it 'sets a project as internal' do
2017-08-17 22:00:37 +05:30
project = attributes_for ( :project , visibility : 'internal' )
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'visibility' ] ) . to eq ( 'internal' )
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
it 'sets a project as private' do
project = attributes_for ( :project , visibility : 'private' )
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'visibility' ] ) . to eq ( 'private' )
2014-09-02 18:07:02 +05:30
end
2018-11-20 20:47:30 +05:30
it 'sets a project as not allowing outdated diff discussions to automatically resolve' do
2018-03-17 18:26:18 +05:30
project = attributes_for ( :project , resolve_outdated_diff_discussions : false )
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2018-03-17 18:26:18 +05:30
expect ( json_response [ 'resolve_outdated_diff_discussions' ] ) . to be_falsey
end
it 'sets a project as allowing outdated diff discussions to automatically resolve' do
project = attributes_for ( :project , resolve_outdated_diff_discussions : true )
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2018-03-17 18:26:18 +05:30
expect ( json_response [ 'resolve_outdated_diff_discussions' ] ) . to be_truthy
end
2019-12-26 22:10:19 +05:30
it 'sets a project as not removing source branches' do
project = attributes_for ( :project , remove_source_branch_after_merge : false )
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2019-12-26 22:10:19 +05:30
expect ( json_response [ 'remove_source_branch_after_merge' ] ) . to be_falsey
end
it 'sets a project as removing source branches' do
project = attributes_for ( :project , remove_source_branch_after_merge : true )
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2019-12-26 22:10:19 +05:30
expect ( json_response [ 'remove_source_branch_after_merge' ] ) . to be_truthy
end
2017-08-17 22:00:37 +05:30
it 'sets a project as allowing merge even if build fails' do
2018-03-17 18:26:18 +05:30
project = attributes_for ( :project , only_allow_merge_if_pipeline_succeeds : false )
2020-06-23 00:09:42 +05:30
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2020-06-23 00:09:42 +05:30
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'only_allow_merge_if_pipeline_succeeds' ] ) . to be_falsey
2014-09-02 18:07:02 +05:30
end
2018-03-17 18:26:18 +05:30
it 'sets a project as allowing merge only if pipeline succeeds' do
project = attributes_for ( :project , only_allow_merge_if_pipeline_succeeds : true )
2020-06-23 00:09:42 +05:30
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2020-06-23 00:09:42 +05:30
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'only_allow_merge_if_pipeline_succeeds' ] ) . to be_truthy
2014-09-02 18:07:02 +05:30
end
2016-09-29 09:46:39 +05:30
2020-06-23 00:09:42 +05:30
it 'sets a project as not allowing merge when pipeline is skipped' do
project = attributes_for ( :project , allow_merge_on_skipped_pipeline : false )
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2020-06-23 00:09:42 +05:30
expect ( json_response [ 'allow_merge_on_skipped_pipeline' ] ) . to be_falsey
end
it 'sets a project as allowing merge when pipeline is skipped' do
project = attributes_for ( :project , allow_merge_on_skipped_pipeline : true )
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2020-06-23 00:09:42 +05:30
expect ( json_response [ 'allow_merge_on_skipped_pipeline' ] ) . to be_truthy
end
2017-08-17 22:00:37 +05:30
it 'sets a project as allowing merge even if discussions are unresolved' do
2018-03-17 18:26:18 +05:30
project = attributes_for ( :project , only_allow_merge_if_all_discussions_are_resolved : false )
2017-08-17 22:00:37 +05:30
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'only_allow_merge_if_all_discussions_are_resolved' ] ) . to be_falsey
2016-09-29 09:46:39 +05:30
end
2017-08-17 22:00:37 +05:30
it 'sets a project as allowing merge only if all discussions are resolved' do
2018-03-17 18:26:18 +05:30
project = attributes_for ( :project , only_allow_merge_if_all_discussions_are_resolved : true )
2017-08-17 22:00:37 +05:30
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'only_allow_merge_if_all_discussions_are_resolved' ] ) . to be_truthy
2016-09-29 09:46:39 +05:30
end
2021-10-27 15:23:28 +05:30
context 'container_registry_enabled' do
using RSpec :: Parameterized :: TableSyntax
where ( :container_registry_enabled , :container_registry_access_level ) do
true | ProjectFeature :: ENABLED
false | ProjectFeature :: DISABLED
end
with_them do
2023-06-20 00:43:36 +05:30
it 'setting container_registry_enabled also sets container_registry_access_level' do
2021-10-27 15:23:28 +05:30
project_attributes = attributes_for ( :project ) . tap do | attrs |
attrs [ :container_registry_enabled ] = container_registry_enabled
end
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project_attributes
2021-10-27 15:23:28 +05:30
project = Project . find_by ( path : project_attributes [ :path ] )
expect ( response ) . to have_gitlab_http_status ( :created )
expect ( json_response [ 'container_registry_access_level' ] ) . to eq ( ProjectFeature . str_from_access_level ( container_registry_access_level ) )
expect ( json_response [ 'container_registry_enabled' ] ) . to eq ( container_registry_enabled )
expect ( project . container_registry_access_level ) . to eq ( container_registry_access_level )
expect ( project . container_registry_enabled ) . to eq ( container_registry_enabled )
end
end
end
context 'container_registry_access_level' do
using RSpec :: Parameterized :: TableSyntax
where ( :container_registry_access_level , :container_registry_enabled ) do
'enabled' | true
'private' | true
'disabled' | false
end
with_them do
2023-06-20 00:43:36 +05:30
it 'setting container_registry_access_level also sets container_registry_enabled' do
2021-10-27 15:23:28 +05:30
project_attributes = attributes_for ( :project ) . tap do | attrs |
attrs [ :container_registry_access_level ] = container_registry_access_level
end
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : project_attributes
2021-10-27 15:23:28 +05:30
project = Project . find_by ( path : project_attributes [ :path ] )
expect ( response ) . to have_gitlab_http_status ( :created )
expect ( json_response [ 'container_registry_access_level' ] ) . to eq ( container_registry_access_level )
expect ( json_response [ 'container_registry_enabled' ] ) . to eq ( container_registry_enabled )
expect ( project . container_registry_access_level ) . to eq ( ProjectFeature . access_level_from_str ( container_registry_access_level ) )
expect ( project . container_registry_enabled ) . to eq ( container_registry_enabled )
end
end
end
2014-09-02 18:07:02 +05:30
end
2021-04-29 21:17:54 +05:30
describe " POST /projects/:id/uploads/authorize " do
let ( :headers ) { workhorse_internal_api_request_header . merge ( { 'HTTP_GITLAB_WORKHORSE' = > 1 } ) }
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /uploads/authorize " }
2021-04-29 21:17:54 +05:30
context 'with authorized user' do
it " returns 200 " do
2023-06-20 00:43:36 +05:30
post api ( path , user ) , headers : headers
2021-04-29 21:17:54 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'MaximumSize' ] ) . to eq ( project . max_attachment_size )
end
end
context 'with unauthorized user' do
it " returns 404 " do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , headers : headers
2021-04-29 21:17:54 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
end
context 'with exempted project' do
before do
stub_env ( 'GITLAB_UPLOAD_API_ALLOWLIST' , project . id )
end
it " returns 200 " do
2023-06-20 00:43:36 +05:30
post api ( path , user ) , headers : headers
2021-04-29 21:17:54 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'MaximumSize' ] ) . to eq ( 1 . gigabyte )
end
end
context 'with no Workhorse headers' do
it " returns 403 " do
2023-06-20 00:43:36 +05:30
post api ( path , user )
2021-04-29 21:17:54 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
end
end
2016-01-14 18:37:52 +05:30
describe " POST /projects/:id/uploads " do
2021-04-29 21:17:54 +05:30
let ( :file ) { fixture_file_upload ( " spec/fixtures/dk.png " , " image/png " ) }
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /uploads " }
2021-04-29 21:17:54 +05:30
2017-09-10 17:25:29 +05:30
before do
project
end
2016-01-14 18:37:52 +05:30
it " uploads the file and returns its info " do
2021-04-29 21:17:54 +05:30
expect_next_instance_of ( UploadService ) do | instance |
expect ( instance ) . to receive ( :override_max_attachment_size = ) . with ( project . max_attachment_size ) . and_call_original
end
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { file : file }
2016-01-14 18:37:52 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2016-01-14 18:37:52 +05:30
expect ( json_response [ 'alt' ] ) . to eq ( " dk " )
expect ( json_response [ 'url' ] ) . to start_with ( " /uploads/ " )
expect ( json_response [ 'url' ] ) . to end_with ( " /dk.png " )
2020-04-08 14:13:33 +05:30
expect ( json_response [ 'full_path' ] ) . to start_with ( " / #{ project . namespace . path } / #{ project . path } /uploads " )
2016-01-14 18:37:52 +05:30
end
2021-04-29 21:17:54 +05:30
it " does not leave the temporary file in place after uploading, even when the tempfile reaper does not run " do
tempfile = Tempfile . new ( 'foo' )
path = tempfile . path
allow_any_instance_of ( Rack :: TempfileReaper ) . to receive ( :call ) do | instance , env |
instance . instance_variable_get ( :@app ) . call ( env )
end
expect ( path ) . not_to be ( nil )
expect ( Rack :: Multipart :: Parser :: TEMPFILE_FACTORY ) . to receive ( :call ) . and_return ( tempfile )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { file : fixture_file_upload ( " spec/fixtures/dk.png " , " image/png " ) }
2021-04-29 21:17:54 +05:30
expect ( tempfile . path ) . to be ( nil )
expect ( File . exist? ( path ) ) . to be ( false )
end
shared_examples 'capped upload attachments' do | upload_allowed |
it " limits the upload to 1 GB " do
expect_next_instance_of ( UploadService ) do | instance |
expect ( instance ) . to receive ( :override_max_attachment_size = ) . with ( 1 . gigabyte ) . and_call_original
end
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { file : file }
2021-04-29 21:17:54 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
end
it " logs a warning if file exceeds attachment size " do
allow ( Gitlab :: CurrentSettings ) . to receive ( :max_attachment_size ) . and_return ( 0 )
expect ( Gitlab :: AppLogger ) . to receive ( :info ) . with (
hash_including ( message : 'File exceeds maximum size' , upload_allowed : upload_allowed ) )
. and_call_original
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { file : file }
2021-04-29 21:17:54 +05:30
end
end
context 'with exempted project' do
before do
stub_env ( 'GITLAB_UPLOAD_API_ALLOWLIST' , project . id )
end
it_behaves_like 'capped upload attachments' , true
end
2016-01-14 18:37:52 +05:30
end
2021-04-17 20:07:23 +05:30
describe " GET /projects/:id/groups " do
let_it_be ( :root_group ) { create ( :group , :public , name : 'root group' ) }
let_it_be ( :project_group ) { create ( :group , :public , parent : root_group , name : 'project group' ) }
let_it_be ( :shared_group_with_dev_access ) { create ( :group , :private , parent : root_group , name : 'shared group' ) }
2021-06-08 01:23:25 +05:30
let_it_be ( :shared_group_with_reporter_access ) { create ( :group , :public ) }
2021-04-17 20:07:23 +05:30
let_it_be ( :private_project ) { create ( :project , :private , group : project_group ) }
let_it_be ( :public_project ) { create ( :project , :public , group : project_group ) }
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ private_project . id } /groups " }
2021-04-17 20:07:23 +05:30
before_all do
create ( :project_group_link , :developer , group : shared_group_with_dev_access , project : private_project )
create ( :project_group_link , :reporter , group : shared_group_with_reporter_access , project : private_project )
end
2023-06-20 00:43:36 +05:30
it_behaves_like 'GET request permissions for admin mode' do
let ( :failed_status_code ) { :not_found }
end
2021-04-17 20:07:23 +05:30
shared_examples_for 'successful groups response' do
it 'returns an array of groups' do
request
2023-06-20 00:43:36 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | g | g [ 'name' ] } ) . to match_array ( expected_groups . map ( & :name ) )
2021-04-17 20:07:23 +05:30
end
end
context 'when unauthenticated' do
it 'does not return groups for private projects' do
2023-06-20 00:43:36 +05:30
get api ( path )
2021-04-17 20:07:23 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
context 'for public projects' do
2023-06-20 00:43:36 +05:30
subject ( :request ) { get api ( " /projects/ #{ public_project . id } /groups " ) }
2021-04-17 20:07:23 +05:30
it_behaves_like 'successful groups response' do
let ( :expected_groups ) { [ root_group , project_group ] }
end
end
end
context 'when authenticated as user' do
context 'when user does not have access to the project' do
it 'does not return groups' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2021-04-17 20:07:23 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
end
context 'when user has access to the project' do
2023-06-20 00:43:36 +05:30
subject ( :request ) { get api ( path , user ) , params : params }
2021-04-17 20:07:23 +05:30
let ( :params ) { { } }
before do
private_project . add_developer ( user )
end
it_behaves_like 'successful groups response' do
let ( :expected_groups ) { [ root_group , project_group ] }
end
context 'when search by root group name' do
let ( :params ) { { search : 'root' } }
it_behaves_like 'successful groups response' do
let ( :expected_groups ) { [ root_group ] }
end
end
context 'with_shared option is on' do
let ( :params ) { { with_shared : true } }
it_behaves_like 'successful groups response' do
let ( :expected_groups ) { [ root_group , project_group , shared_group_with_dev_access , shared_group_with_reporter_access ] }
end
context 'when shared_min_access_level is set' do
let ( :params ) { super ( ) . merge ( shared_min_access_level : Gitlab :: Access :: DEVELOPER ) }
it_behaves_like 'successful groups response' do
let ( :expected_groups ) { [ root_group , project_group , shared_group_with_dev_access ] }
end
end
2021-06-08 01:23:25 +05:30
context 'when shared_visible_only is on' do
let ( :params ) { super ( ) . merge ( shared_visible_only : true ) }
it_behaves_like 'successful groups response' do
let ( :expected_groups ) { [ root_group , project_group , shared_group_with_reporter_access ] }
end
end
2021-04-17 20:07:23 +05:30
context 'when search by shared group name' do
let ( :params ) { super ( ) . merge ( search : 'shared' ) }
it_behaves_like 'successful groups response' do
let ( :expected_groups ) { [ shared_group_with_dev_access ] }
end
end
context 'when skip_groups is set' do
let ( :params ) { super ( ) . merge ( skip_groups : [ shared_group_with_dev_access . id , root_group . id ] ) }
it_behaves_like 'successful groups response' do
let ( :expected_groups ) { [ shared_group_with_reporter_access , project_group ] }
end
end
end
end
end
context 'when authenticated as admin' do
2023-06-20 00:43:36 +05:30
subject ( :request ) { get api ( path , admin , admin_mode : true ) }
2021-04-17 20:07:23 +05:30
it_behaves_like 'successful groups response' do
let ( :expected_groups ) { [ root_group , project_group ] }
end
end
end
2023-04-23 21:23:45 +05:30
describe 'GET /project/:id/share_locations' do
2023-05-27 22:25:52 +05:30
let_it_be ( :root_group ) { create ( :group , :public , name : 'root group' , path : 'root-group-path' ) }
let_it_be ( :project_group1 ) { create ( :group , :public , parent : root_group , name : 'group1' , path : 'group-1-path' ) }
let_it_be ( :project_group2 ) { create ( :group , :public , parent : root_group , name : 'group2' , path : 'group-2-path' ) }
2023-04-23 21:23:45 +05:30
let_it_be ( :project ) { create ( :project , :private , group : project_group1 ) }
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /share_locations " }
it_behaves_like 'GET request permissions for admin mode' do
let ( :failed_status_code ) { :not_found }
end
2023-04-23 21:23:45 +05:30
shared_examples_for 'successful groups response' do
it 'returns an array of groups' do
request
2023-06-20 00:43:36 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response . map { | g | g [ 'name' ] } ) . to match_array ( expected_groups . map ( & :name ) )
2023-04-23 21:23:45 +05:30
end
end
context 'when unauthenticated' do
it 'does not return the groups for the given project' do
2023-06-20 00:43:36 +05:30
get api ( path )
2023-04-23 21:23:45 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
end
context 'when authenticated' do
context 'when user is not the owner of the project' do
it 'does not return the groups' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2023-04-23 21:23:45 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
end
context 'when user is the owner of the project' do
2023-06-20 00:43:36 +05:30
subject ( :request ) { get api ( path , user ) , params : params }
2023-04-23 21:23:45 +05:30
let ( :params ) { { } }
before do
project . add_owner ( user )
project_group1 . add_developer ( user )
project_group2 . add_developer ( user )
end
context 'with default search' do
it_behaves_like 'successful groups response' do
2023-06-20 00:43:36 +05:30
let ( :expected_groups ) { [ project_group2 ] }
2023-04-23 21:23:45 +05:30
end
end
context 'when searching by group name' do
2023-05-27 22:25:52 +05:30
context 'searching by group name' do
it_behaves_like 'successful groups response' do
2023-06-20 00:43:36 +05:30
let ( :params ) { { search : 'group2' } }
let ( :expected_groups ) { [ project_group2 ] }
2023-05-27 22:25:52 +05:30
end
end
2023-04-23 21:23:45 +05:30
2023-05-27 22:25:52 +05:30
context 'searching by full group path' do
let_it_be ( :project_group2_subgroup ) do
create ( :group , :public , parent : project_group2 , name : 'subgroup' , path : 'subgroup-path' )
end
it_behaves_like 'successful groups response' do
let ( :params ) { { search : 'root-group-path/group-2-path/subgroup-path' } }
let ( :expected_groups ) { [ project_group2_subgroup ] }
end
2023-04-23 21:23:45 +05:30
end
end
end
end
context 'when authenticated as admin' do
2023-06-20 00:43:36 +05:30
subject ( :request ) { get api ( path , admin , admin_mode : true ) , params : { } }
2023-04-23 21:23:45 +05:30
context 'without share_with_group_lock' do
it_behaves_like 'successful groups response' do
2023-06-20 00:43:36 +05:30
let ( :expected_groups ) { [ project_group2 ] }
2023-04-23 21:23:45 +05:30
end
end
context 'with share_with_group_lock' do
before do
project . namespace . update! ( share_with_group_lock : true )
end
it_behaves_like 'successful groups response' do
let ( :expected_groups ) { [ ] }
end
end
end
end
2015-04-26 12:48:37 +05:30
describe 'GET /projects/:id' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } " }
it_behaves_like 'GET request permissions for admin mode' do
let ( :failed_status_code ) { :not_found }
end
2017-08-17 22:00:37 +05:30
context 'when unauthenticated' do
2019-03-13 22:55:13 +05:30
it 'does not return private projects' do
private_project = create ( :project , :private )
get api ( " /projects/ #{ private_project . id } " )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2019-03-13 22:55:13 +05:30
end
it 'returns public projects' do
public_project = create ( :project , :repository , :public )
2016-08-24 12:49:21 +05:30
2017-08-17 22:00:37 +05:30
get api ( " /projects/ #{ public_project . id } " )
2016-08-24 12:49:21 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'id' ] ) . to eq ( public_project . id )
expect ( json_response [ 'description' ] ) . to eq ( public_project . description )
2017-09-10 17:25:29 +05:30
expect ( json_response [ 'default_branch' ] ) . to eq ( public_project . default_branch )
2019-03-13 22:55:13 +05:30
expect ( json_response [ 'ci_config_path' ] ) . to eq ( public_project . ci_config_path )
2017-08-17 22:00:37 +05:30
expect ( json_response . keys ) . not_to include ( 'permissions' )
end
2019-03-13 22:55:13 +05:30
2019-12-04 20:38:33 +05:30
context 'the project is a public fork' do
it 'hides details of a public fork parent' do
public_project = create ( :project , :repository , :public )
fork = fork_project ( public_project )
get api ( " /projects/ #{ fork . id } " )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-12-04 20:38:33 +05:30
expect ( json_response [ 'forked_from_project' ] ) . to be_nil
end
end
2019-03-13 22:55:13 +05:30
context 'and the project has a private repository' do
let ( :project ) { create ( :project , :repository , :public , :repository_private ) }
let ( :protected_attributes ) { %w( default_branch ci_config_path ) }
it 'hides protected attributes of private repositories if user is not a member' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2019-03-13 22:55:13 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-03-13 22:55:13 +05:30
protected_attributes . each do | attribute |
expect ( json_response . keys ) . not_to include ( attribute )
end
end
it 'exposes protected attributes of private repositories if user is a member' do
project . add_developer ( user )
2023-06-20 00:43:36 +05:30
get api ( path , user )
2019-03-13 22:55:13 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-03-13 22:55:13 +05:30
protected_attributes . each do | attribute |
expect ( json_response . keys ) . to include ( attribute )
end
end
end
2014-09-02 18:07:02 +05:30
end
2023-03-17 16:20:25 +05:30
context 'when authenticated as an admin' , :with_license do
2021-04-17 20:07:23 +05:30
before do
stub_container_registry_config ( enabled : true , host_port : 'registry.example.org:5000' )
end
2021-03-11 19:13:27 +05:30
let ( :project_attributes_file ) { 'spec/requests/api/project_attributes.yml' }
let ( :project_attributes ) { YAML . load_file ( project_attributes_file ) }
let ( :expected_keys ) do
2023-04-23 21:23:45 +05:30
keys = project_attributes . flat_map do | relation , relation_config |
2021-03-11 19:13:27 +05:30
begin
actual_keys = project . send ( relation ) . attributes . keys
rescue NoMethodError
actual_keys = [ " #{ relation } is nil " ]
end
unexposed_attributes = relation_config [ 'unexposed_attributes' ] || [ ]
remapped_attributes = relation_config [ 'remapped_attributes' ] || { }
computed_attributes = relation_config [ 'computed_attributes' ] || [ ]
actual_keys - unexposed_attributes - remapped_attributes . keys + remapped_attributes . values + computed_attributes
2023-04-23 21:23:45 +05:30
end
2021-03-11 19:13:27 +05:30
unless Gitlab . ee?
keys -= %w[
approvals_before_merge
compliance_frameworks
mirror
2022-04-04 11:22:00 +05:30
requirements_access_level
2021-03-11 19:13:27 +05:30
requirements_enabled
security_and_compliance_enabled
2021-04-17 20:07:23 +05:30
issues_template
merge_requests_template
2021-03-11 19:13:27 +05:30
]
end
keys
end
2023-06-20 00:43:36 +05:30
it 'returns a project by id' do
2019-09-04 21:01:54 +05:30
project
project_member
group = create ( :group )
link = create ( :project_group_link , project : project , group : group )
2023-06-20 00:43:36 +05:30
get api ( path , admin , admin_mode : true )
2019-09-04 21:01:54 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-09-04 21:01:54 +05:30
expect ( json_response [ 'id' ] ) . to eq ( project . id )
expect ( json_response [ 'description' ] ) . to eq ( project . description )
expect ( json_response [ 'default_branch' ] ) . to eq ( project . default_branch )
2021-09-04 01:27:46 +05:30
expect ( json_response [ 'tag_list' ] ) . to be_an Array # deprecated in favor of 'topics'
expect ( json_response [ 'topics' ] ) . to be_an Array
2019-09-04 21:01:54 +05:30
expect ( json_response [ 'archived' ] ) . to be_falsey
expect ( json_response [ 'visibility' ] ) . to be_present
expect ( json_response [ 'ssh_url_to_repo' ] ) . to be_present
expect ( json_response [ 'http_url_to_repo' ] ) . to be_present
expect ( json_response [ 'web_url' ] ) . to be_present
2021-04-17 20:07:23 +05:30
expect ( json_response [ 'container_registry_image_prefix' ] ) . to eq ( " registry.example.org:5000/ #{ project . full_path } " )
2019-09-04 21:01:54 +05:30
expect ( json_response [ 'owner' ] ) . to be_a Hash
expect ( json_response [ 'name' ] ) . to eq ( project . name )
expect ( json_response [ 'path' ] ) . to be_present
expect ( json_response [ 'issues_enabled' ] ) . to be_present
expect ( json_response [ 'merge_requests_enabled' ] ) . to be_present
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'can_create_merge_request_in' ] ) . to be_present
2019-09-04 21:01:54 +05:30
expect ( json_response [ 'wiki_enabled' ] ) . to be_present
expect ( json_response [ 'jobs_enabled' ] ) . to be_present
expect ( json_response [ 'snippets_enabled' ] ) . to be_present
expect ( json_response [ 'container_registry_enabled' ] ) . to be_present
2021-10-27 15:23:28 +05:30
expect ( json_response [ 'container_registry_access_level' ] ) . to be_present
2019-09-04 21:01:54 +05:30
expect ( json_response [ 'created_at' ] ) . to be_present
expect ( json_response [ 'last_activity_at' ] ) . to be_present
expect ( json_response [ 'shared_runners_enabled' ] ) . to be_present
2023-04-23 21:23:45 +05:30
expect ( json_response [ 'group_runners_enabled' ] ) . to be_present
2019-09-04 21:01:54 +05:30
expect ( json_response [ 'creator_id' ] ) . to be_present
expect ( json_response [ 'namespace' ] ) . to be_present
expect ( json_response [ 'avatar_url' ] ) . to be_nil
expect ( json_response [ 'star_count' ] ) . to be_present
expect ( json_response [ 'forks_count' ] ) . to be_present
expect ( json_response [ 'public_jobs' ] ) . to be_present
expect ( json_response [ 'shared_with_groups' ] ) . to be_an Array
expect ( json_response [ 'shared_with_groups' ] . length ) . to eq ( 1 )
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'group_id' ] ) . to eq ( group . id )
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'group_name' ] ) . to eq ( group . name )
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'group_access_level' ] ) . to eq ( link . group_access )
expect ( json_response [ 'only_allow_merge_if_pipeline_succeeds' ] ) . to eq ( project . only_allow_merge_if_pipeline_succeeds )
2020-06-23 00:09:42 +05:30
expect ( json_response [ 'allow_merge_on_skipped_pipeline' ] ) . to eq ( project . allow_merge_on_skipped_pipeline )
2021-03-08 18:12:59 +05:30
expect ( json_response [ 'restrict_user_defined_variables' ] ) . to eq ( project . restrict_user_defined_variables? )
2019-09-04 21:01:54 +05:30
expect ( json_response [ 'only_allow_merge_if_all_discussions_are_resolved' ] ) . to eq ( project . only_allow_merge_if_all_discussions_are_resolved )
2021-02-22 17:27:13 +05:30
expect ( json_response [ 'operations_access_level' ] ) . to be_present
2022-05-07 20:08:51 +05:30
expect ( json_response [ 'security_and_compliance_access_level' ] ) . to be_present
2022-11-25 23:54:43 +05:30
expect ( json_response [ 'releases_access_level' ] ) . to be_present
2023-03-04 22:38:38 +05:30
expect ( json_response [ 'environments_access_level' ] ) . to be_present
expect ( json_response [ 'feature_flags_access_level' ] ) . to be_present
expect ( json_response [ 'infrastructure_access_level' ] ) . to be_present
expect ( json_response [ 'monitor_access_level' ] ) . to be_present
2019-09-04 21:01:54 +05:30
end
2021-03-11 19:13:27 +05:30
it 'exposes all necessary attributes' do
create ( :project_group_link , project : project )
2023-06-20 00:43:36 +05:30
get api ( path , admin , admin_mode : true )
2021-03-11 19:13:27 +05:30
diff = Set . new ( json_response . keys ) ^ Set . new ( expected_keys )
expect ( diff ) . to be_empty , failure_message ( diff )
end
2023-06-20 00:43:36 +05:30
def failure_message ( _diff )
2021-03-11 19:13:27 +05:30
<< ~ MSG
It looks like project ' s set of exposed attributes is different from the expected set .
The following attributes are missing or newly added :
2023-06-20 00:43:36 +05:30
{ diff . to_a . to_sentence }
2021-03-11 19:13:27 +05:30
Please update #{project_attributes_file} file"
MSG
end
2019-09-04 21:01:54 +05:30
end
context 'when authenticated as a regular user' do
2017-08-17 22:00:37 +05:30
before do
project
project_member
2021-04-17 20:07:23 +05:30
stub_container_registry_config ( enabled : true , host_port : 'registry.example.org:5000' )
2017-08-17 22:00:37 +05:30
end
2014-09-02 18:07:02 +05:30
2023-06-20 00:43:36 +05:30
it 'returns a project by id' do
2017-08-17 22:00:37 +05:30
group = create ( :group )
link = create ( :project_group_link , project : project , group : group )
2014-09-02 18:07:02 +05:30
2023-06-20 00:43:36 +05:30
get api ( path , user )
2016-01-14 18:37:52 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'id' ] ) . to eq ( project . id )
expect ( json_response [ 'description' ] ) . to eq ( project . description )
expect ( json_response [ 'default_branch' ] ) . to eq ( project . default_branch )
2021-09-04 01:27:46 +05:30
expect ( json_response [ 'tag_list' ] ) . to be_an Array # deprecated in favor of 'topics'
expect ( json_response [ 'topics' ] ) . to be_an Array
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'archived' ] ) . to be_falsey
expect ( json_response [ 'visibility' ] ) . to be_present
expect ( json_response [ 'ssh_url_to_repo' ] ) . to be_present
expect ( json_response [ 'http_url_to_repo' ] ) . to be_present
expect ( json_response [ 'web_url' ] ) . to be_present
2021-04-17 20:07:23 +05:30
expect ( json_response [ 'container_registry_image_prefix' ] ) . to eq ( " registry.example.org:5000/ #{ project . full_path } " )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'owner' ] ) . to be_a Hash
expect ( json_response [ 'name' ] ) . to eq ( project . name )
expect ( json_response [ 'path' ] ) . to be_present
expect ( json_response [ 'issues_enabled' ] ) . to be_present
expect ( json_response [ 'merge_requests_enabled' ] ) . to be_present
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'can_create_merge_request_in' ] ) . to be_present
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'wiki_enabled' ] ) . to be_present
expect ( json_response [ 'jobs_enabled' ] ) . to be_present
expect ( json_response [ 'snippets_enabled' ] ) . to be_present
2019-09-30 21:07:59 +05:30
expect ( json_response [ 'snippets_access_level' ] ) . to be_present
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'pages_access_level' ] ) . to be_present
2019-09-30 21:07:59 +05:30
expect ( json_response [ 'repository_access_level' ] ) . to be_present
expect ( json_response [ 'issues_access_level' ] ) . to be_present
expect ( json_response [ 'merge_requests_access_level' ] ) . to be_present
2020-04-22 19:07:51 +05:30
expect ( json_response [ 'forking_access_level' ] ) . to be_present
2021-02-22 17:27:13 +05:30
expect ( json_response [ 'analytics_access_level' ] ) . to be_present
2019-09-30 21:07:59 +05:30
expect ( json_response [ 'wiki_access_level' ] ) . to be_present
expect ( json_response [ 'builds_access_level' ] ) . to be_present
2021-02-22 17:27:13 +05:30
expect ( json_response [ 'operations_access_level' ] ) . to be_present
2022-05-07 20:08:51 +05:30
expect ( json_response [ 'security_and_compliance_access_level' ] ) . to be_present
2022-11-25 23:54:43 +05:30
expect ( json_response [ 'releases_access_level' ] ) . to be_present
2023-03-04 22:38:38 +05:30
expect ( json_response [ 'environments_access_level' ] ) . to be_present
expect ( json_response [ 'feature_flags_access_level' ] ) . to be_present
expect ( json_response [ 'infrastructure_access_level' ] ) . to be_present
expect ( json_response [ 'monitor_access_level' ] ) . to be_present
2020-03-13 15:44:24 +05:30
expect ( json_response ) . to have_key ( 'emails_disabled' )
2018-03-17 18:26:18 +05:30
expect ( json_response [ 'resolve_outdated_diff_discussions' ] ) . to eq ( project . resolve_outdated_diff_discussions )
2019-12-26 22:10:19 +05:30
expect ( json_response [ 'remove_source_branch_after_merge' ] ) . to be_truthy
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'container_registry_enabled' ] ) . to be_present
2021-10-27 15:23:28 +05:30
expect ( json_response [ 'container_registry_access_level' ] ) . to be_present
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'created_at' ] ) . to be_present
expect ( json_response [ 'last_activity_at' ] ) . to be_present
expect ( json_response [ 'shared_runners_enabled' ] ) . to be_present
2023-04-23 21:23:45 +05:30
expect ( json_response [ 'group_runners_enabled' ] ) . to be_present
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'creator_id' ] ) . to be_present
expect ( json_response [ 'namespace' ] ) . to be_present
2017-09-10 17:25:29 +05:30
expect ( json_response [ 'import_status' ] ) . to be_present
expect ( json_response ) . to include ( " import_error " )
2020-03-13 15:44:24 +05:30
expect ( json_response ) . to have_key ( 'avatar_url' )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'star_count' ] ) . to be_present
expect ( json_response [ 'forks_count' ] ) . to be_present
expect ( json_response [ 'public_jobs' ] ) . to be_present
2020-03-13 15:44:24 +05:30
expect ( json_response ) . to have_key ( 'ci_config_path' )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'shared_with_groups' ] ) . to be_an Array
expect ( json_response [ 'shared_with_groups' ] . length ) . to eq ( 1 )
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'group_id' ] ) . to eq ( group . id )
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'group_name' ] ) . to eq ( group . name )
2019-03-02 22:35:43 +05:30
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'group_full_path' ] ) . to eq ( group . full_path )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'group_access_level' ] ) . to eq ( link . group_access )
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'shared_with_groups' ] [ 0 ] ) . to have_key ( 'expires_at' )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'only_allow_merge_if_pipeline_succeeds' ] ) . to eq ( project . only_allow_merge_if_pipeline_succeeds )
2020-06-23 00:09:42 +05:30
expect ( json_response [ 'allow_merge_on_skipped_pipeline' ] ) . to eq ( project . allow_merge_on_skipped_pipeline )
2021-03-08 18:12:59 +05:30
expect ( json_response [ 'restrict_user_defined_variables' ] ) . to eq ( project . restrict_user_defined_variables? )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'only_allow_merge_if_all_discussions_are_resolved' ] ) . to eq ( project . only_allow_merge_if_all_discussions_are_resolved )
2019-09-04 21:01:54 +05:30
expect ( json_response [ 'ci_default_git_depth' ] ) . to eq ( project . ci_default_git_depth )
2021-01-03 14:25:43 +05:30
expect ( json_response [ 'ci_forward_deployment_enabled' ] ) . to eq ( project . ci_forward_deployment_enabled )
2022-08-27 11:52:29 +05:30
expect ( json_response [ 'ci_allow_fork_pipelines_to_run_in_parent_project' ] ) . to eq ( project . ci_allow_fork_pipelines_to_run_in_parent_project )
2022-08-13 15:12:31 +05:30
expect ( json_response [ 'ci_separated_caches' ] ) . to eq ( project . ci_separated_caches )
2018-05-09 12:01:36 +05:30
expect ( json_response [ 'merge_method' ] ) . to eq ( project . merge_method . to_s )
2021-09-04 01:27:46 +05:30
expect ( json_response [ 'squash_option' ] ) . to eq ( project . squash_option . to_s )
2018-11-08 19:23:39 +05:30
expect ( json_response [ 'readme_url' ] ) . to eq ( project . readme_url )
2020-10-24 23:57:45 +05:30
expect ( json_response ) . to have_key 'packages_enabled'
2021-09-04 01:27:46 +05:30
expect ( json_response [ 'keep_latest_artifact' ] ) . to be_present
2017-08-17 22:00:37 +05:30
end
2018-11-20 20:47:30 +05:30
it 'returns a group link with expiration date' do
group = create ( :group )
expires_at = 5 . days . from_now . to_date
link = create ( :project_group_link , project : project , group : group , expires_at : expires_at )
2023-06-20 00:43:36 +05:30
get api ( path , user )
2018-11-20 20:47:30 +05:30
expect ( json_response [ 'shared_with_groups' ] ) . to be_an Array
expect ( json_response [ 'shared_with_groups' ] . length ) . to eq ( 1 )
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'group_id' ] ) . to eq ( group . id )
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'group_name' ] ) . to eq ( group . name )
2019-03-02 22:35:43 +05:30
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'group_full_path' ] ) . to eq ( group . full_path )
2018-11-20 20:47:30 +05:30
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'group_access_level' ] ) . to eq ( link . group_access )
expect ( json_response [ 'shared_with_groups' ] [ 0 ] [ 'expires_at' ] ) . to eq ( expires_at . to_s )
end
2017-08-17 22:00:37 +05:30
it 'returns a project by path name' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'name' ] ) . to eq ( project . name )
end
2016-01-14 18:37:52 +05:30
2017-08-17 22:00:37 +05:30
it 'returns a 404 error if not found' do
2021-02-22 17:27:13 +05:30
get api ( " /projects/ #{ non_existing_record_id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '404 Project Not Found' )
end
2016-06-22 15:30:34 +05:30
2017-08-17 22:00:37 +05:30
it 'returns a 404 error if user is not a member' do
other_user = create ( :user )
2023-06-20 00:43:36 +05:30
get api ( path , other_user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
2016-01-14 18:37:52 +05:30
2017-08-17 22:00:37 +05:30
it 'handles users with dots' do
dot_user = create ( :user , username : 'dot.user' )
2017-09-10 17:25:29 +05:30
project = create ( :project , creator_id : dot_user . id , namespace : dot_user . namespace )
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
get api ( " /projects/ #{ CGI . escape ( project . full_path ) } " , dot_user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'name' ] ) . to eq ( project . name )
2016-01-14 18:37:52 +05:30
end
2017-08-17 22:00:37 +05:30
it 'exposes namespace fields' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2015-04-26 12:48:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'namespace' ] ) . to eq ( {
'id' = > user . namespace . id ,
'name' = > user . namespace . name ,
'path' = > user . namespace . path ,
'kind' = > user . namespace . kind ,
'full_path' = > user . namespace . full_path ,
2019-07-31 22:56:46 +05:30
'parent_id' = > nil ,
'avatar_url' = > user . avatar_url ,
'web_url' = > Gitlab :: Routing . url_helpers . user_url ( user )
2017-08-17 22:00:37 +05:30
} )
end
2018-12-13 13:39:08 +05:30
it " does not include license fields by default " do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2018-12-13 13:39:08 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-12-13 13:39:08 +05:30
expect ( json_response ) . not_to include ( 'license' , 'license_url' )
end
it 'includes license fields when requested' do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { license : true }
2018-12-13 13:39:08 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-12-13 13:39:08 +05:30
expect ( json_response [ 'license' ] ) . to eq ( {
'key' = > project . repository . license . key ,
'name' = > project . repository . license . name ,
'nickname' = > project . repository . license . nickname ,
'html_url' = > project . repository . license . url ,
2022-11-25 23:54:43 +05:30
'source_url' = > nil
2018-12-13 13:39:08 +05:30
} )
end
2017-08-17 22:00:37 +05:30
it " does not include statistics by default " do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( json_response ) . not_to include 'statistics'
end
it " includes statistics if requested " do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { statistics : true }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( json_response ) . to include 'statistics'
end
2019-03-13 22:55:13 +05:30
context " and the project has a private repository " do
let ( :project ) { create ( :project , :public , :repository , :repository_private ) }
it " does not include statistics if user is not a member " do
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { statistics : true }
2019-03-13 22:55:13 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-03-13 22:55:13 +05:30
expect ( json_response ) . not_to include 'statistics'
end
it " includes statistics if user is a member " do
project . add_developer ( user )
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { statistics : true }
2019-03-13 22:55:13 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-03-13 22:55:13 +05:30
expect ( json_response ) . to include 'statistics'
end
2019-07-07 11:18:12 +05:30
it " includes statistics also when repository is disabled " do
project . add_developer ( user )
project . project_feature . update_attribute ( :repository_access_level , ProjectFeature :: DISABLED )
2023-06-20 00:43:36 +05:30
get api ( path , user ) , params : { statistics : true }
2019-07-07 11:18:12 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-07 11:18:12 +05:30
expect ( json_response ) . to include 'statistics'
end
2019-03-13 22:55:13 +05:30
end
2017-09-10 17:25:29 +05:30
it " includes import_error if user can admin project " do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2017-09-10 17:25:29 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-09-10 17:25:29 +05:30
expect ( json_response ) . to include ( " import_error " )
end
it " does not include import_error if user cannot admin project " do
2023-06-20 00:43:36 +05:30
get api ( path , user3 )
2017-09-10 17:25:29 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-09-10 17:25:29 +05:30
expect ( json_response ) . not_to include ( " import_error " )
end
2018-12-05 23:21:45 +05:30
it 'returns 404 when project is marked for deletion' do
2020-11-24 15:15:51 +05:30
project . update! ( pending_delete : true )
2018-12-05 23:21:45 +05:30
2023-06-20 00:43:36 +05:30
get api ( path , user )
2018-12-05 23:21:45 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2018-12-05 23:21:45 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '404 Project Not Found' )
end
2017-09-10 17:25:29 +05:30
context 'links exposure' do
it 'exposes related resources full URIs' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2017-09-10 17:25:29 +05:30
links = json_response [ '_links' ]
expect ( links [ 'self' ] ) . to end_with ( " /api/v4/projects/ #{ project . id } " )
expect ( links [ 'issues' ] ) . to end_with ( " /api/v4/projects/ #{ project . id } /issues " )
expect ( links [ 'merge_requests' ] ) . to end_with ( " /api/v4/projects/ #{ project . id } /merge_requests " )
expect ( links [ 'repo_branches' ] ) . to end_with ( " /api/v4/projects/ #{ project . id } /repository/branches " )
expect ( links [ 'labels' ] ) . to end_with ( " /api/v4/projects/ #{ project . id } /labels " )
expect ( links [ 'events' ] ) . to end_with ( " /api/v4/projects/ #{ project . id } /events " )
expect ( links [ 'members' ] ) . to end_with ( " /api/v4/projects/ #{ project . id } /members " )
2022-07-16 23:28:13 +05:30
expect ( links [ 'cluster_agents' ] ) . to end_with ( " /api/v4/projects/ #{ project . id } /cluster_agents " )
2017-09-10 17:25:29 +05:30
end
it 'filters related URIs when their feature is not enabled' do
project = create ( :project , :public ,
:merge_requests_disabled ,
:issues_disabled ,
creator_id : user . id ,
namespace : user . namespace )
get api ( " /projects/ #{ project . id } " , user )
links = json_response [ '_links' ]
expect ( links . has_key? ( 'merge_requests' ) ) . to be_falsy
expect ( links . has_key? ( 'issues' ) ) . to be_falsy
expect ( links [ 'self' ] ) . to end_with ( " /api/v4/projects/ #{ project . id } " )
end
end
2019-12-04 20:38:33 +05:30
context 'the project is a fork' do
it 'shows details of a visible fork parent' do
fork = fork_project ( project , user )
get api ( " /projects/ #{ fork . id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-12-04 20:38:33 +05:30
expect ( json_response [ 'forked_from_project' ] ) . to include ( 'id' = > project . id )
end
it 'hides details of a hidden fork parent' do
fork = fork_project ( project , user )
fork_user = create ( :user )
fork . team . add_developer ( fork_user )
get api ( " /projects/ #{ fork . id } " , fork_user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-12-04 20:38:33 +05:30
expect ( json_response [ 'forked_from_project' ] ) . to be_nil
end
end
2017-08-17 22:00:37 +05:30
describe 'permissions' do
context 'all projects' do
2017-09-10 17:25:29 +05:30
before do
2018-11-18 11:00:15 +05:30
project . add_maintainer ( user )
2017-09-10 17:25:29 +05:30
end
2017-08-17 22:00:37 +05:30
it 'contains permission information' do
get api ( " /projects " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2022-05-07 20:08:51 +05:30
detail_of_project = json_response . find { | detail | detail [ 'id' ] == project . id }
expect ( detail_of_project . dig ( 'permissions' , 'project_access' , 'access_level' ) )
2018-11-18 11:00:15 +05:30
. to eq ( Gitlab :: Access :: MAINTAINER )
2022-05-07 20:08:51 +05:30
expect ( detail_of_project . dig ( 'permissions' , 'group_access' ) ) . to be_nil
2017-08-17 22:00:37 +05:30
end
2015-04-26 12:48:37 +05:30
end
2014-09-02 18:07:02 +05:30
2017-08-17 22:00:37 +05:30
context 'personal project' do
it 'sets project access and returns 200' do
2018-11-18 11:00:15 +05:30
project . add_maintainer ( user )
2023-06-20 00:43:36 +05:30
get api ( path , user )
2016-06-22 15:30:34 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-09-10 17:25:29 +05:30
expect ( json_response [ 'permissions' ] [ 'project_access' ] [ 'access_level' ] )
2018-11-18 11:00:15 +05:30
. to eq ( Gitlab :: Access :: MAINTAINER )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'permissions' ] [ 'group_access' ] ) . to be_nil
end
end
2016-06-22 15:30:34 +05:30
2017-08-17 22:00:37 +05:30
context 'group project' do
2017-09-10 17:25:29 +05:30
let ( :project2 ) { create ( :project , group : create ( :group ) ) }
2014-09-02 18:07:02 +05:30
2017-09-10 17:25:29 +05:30
before do
project2 . group . add_owner ( user )
end
2017-08-17 22:00:37 +05:30
it 'sets the owner and return 200' do
get api ( " /projects/ #{ project2 . id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'permissions' ] [ 'project_access' ] ) . to be_nil
2017-09-10 17:25:29 +05:30
expect ( json_response [ 'permissions' ] [ 'group_access' ] [ 'access_level' ] )
. to eq ( Gitlab :: Access :: OWNER )
2017-08-17 22:00:37 +05:30
end
2015-04-26 12:48:37 +05:30
end
2019-03-02 22:35:43 +05:30
2019-10-12 21:52:04 +05:30
context 'nested group project' do
2019-03-02 22:35:43 +05:30
let ( :group ) { create ( :group ) }
let ( :nested_group ) { create ( :group , parent : group ) }
let ( :project2 ) { create ( :project , group : nested_group ) }
before do
project2 . group . parent . add_owner ( user )
end
it 'sets group access and return 200' do
get api ( " /projects/ #{ project2 . id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-03-02 22:35:43 +05:30
expect ( json_response [ 'permissions' ] [ 'project_access' ] ) . to be_nil
expect ( json_response [ 'permissions' ] [ 'group_access' ] [ 'access_level' ] )
. to eq ( Gitlab :: Access :: OWNER )
end
context 'with various access levels across nested groups' do
before do
project2 . group . add_maintainer ( user )
end
it 'sets the maximum group access and return 200' do
get api ( " /projects/ #{ project2 . id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-03-02 22:35:43 +05:30
expect ( json_response [ 'permissions' ] [ 'project_access' ] ) . to be_nil
expect ( json_response [ 'permissions' ] [ 'group_access' ] [ 'access_level' ] )
. to eq ( Gitlab :: Access :: OWNER )
end
end
end
2014-09-02 18:07:02 +05:30
end
2019-07-31 22:56:46 +05:30
context 'when project belongs to a group namespace' do
let ( :group ) { create ( :group , :with_avatar ) }
let ( :project ) { create ( :project , namespace : group ) }
let! ( :project_member ) { create ( :project_member , :developer , user : user , project : project ) }
it 'returns group web_url and avatar_url' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2019-07-31 22:56:46 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-31 22:56:46 +05:30
group_data = json_response [ 'namespace' ]
expect ( group_data [ 'web_url' ] ) . to eq ( group . web_url )
expect ( group_data [ 'avatar_url' ] ) . to eq ( group . avatar_url )
end
end
context 'when project belongs to a user namespace' do
let ( :user ) { create ( :user ) }
let ( :project ) { create ( :project , namespace : user . namespace ) }
it 'returns user web_url and avatar_url' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2019-07-31 22:56:46 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-07-31 22:56:46 +05:30
user_data = json_response [ 'namespace' ]
expect ( user_data [ 'web_url' ] ) . to eq ( " http://localhost/ #{ user . username } " )
expect ( user_data [ 'avatar_url' ] ) . to eq ( user . avatar_url )
end
end
2014-09-02 18:07:02 +05:30
end
2020-03-13 15:44:24 +05:30
2021-11-18 22:05:49 +05:30
it_behaves_like 'storing arguments in the application context for the API' do
2020-03-13 15:44:24 +05:30
let_it_be ( :user ) { create ( :user ) }
let_it_be ( :project ) { create ( :project , :public ) }
let ( :expected_params ) { { user : user . username , project : project . full_path } }
2023-06-20 00:43:36 +05:30
subject { get api ( path , user ) }
2020-03-13 15:44:24 +05:30
end
2020-04-08 14:13:33 +05:30
describe 'repository_storage attribute' do
2023-06-20 00:43:36 +05:30
let_it_be ( :admin_mode ) { false }
2020-04-08 14:13:33 +05:30
before do
2023-06-20 00:43:36 +05:30
get api ( path , user , admin_mode : admin_mode )
2020-04-08 14:13:33 +05:30
end
context 'when authenticated as an admin' do
let ( :user ) { create ( :admin ) }
2023-06-20 00:43:36 +05:30
let_it_be ( :admin_mode ) { true }
2020-04-08 14:13:33 +05:30
it 'returns repository_storage attribute' do
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'repository_storage' ] ) . to eq ( project . repository_storage )
end
end
context 'when authenticated as a regular user' do
it 'does not return repository_storage attribute' do
expect ( json_response ) . not_to have_key ( 'repository_storage' )
end
end
end
2020-07-28 23:09:34 +05:30
it 'exposes service desk attributes' do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2020-07-28 23:09:34 +05:30
expect ( json_response ) . to have_key 'service_desk_enabled'
expect ( json_response ) . to have_key 'service_desk_address'
end
2021-11-11 11:23:49 +05:30
context 'when project is shared to multiple groups' do
2023-06-20 00:43:36 +05:30
it 'avoids N+1 queries' , :use_sql_query_cache do
2021-11-11 11:23:49 +05:30
create ( :project_group_link , project : project )
2023-06-20 00:43:36 +05:30
get api ( path , user )
expect ( response ) . to have_gitlab_http_status ( :ok )
2021-11-11 11:23:49 +05:30
control = ActiveRecord :: QueryRecorder . new do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2021-11-11 11:23:49 +05:30
end
create ( :project_group_link , project : project )
expect do
2023-06-20 00:43:36 +05:30
get api ( path , user )
2021-11-11 11:23:49 +05:30
end . not_to exceed_query_limit ( control )
end
end
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
describe 'GET /projects/:id/users' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /users " }
2017-08-17 22:00:37 +05:30
shared_examples_for 'project users response' do
2021-09-30 23:02:18 +05:30
let ( :reporter_1 ) { create ( :user ) }
let ( :reporter_2 ) { create ( :user ) }
before do
project . add_reporter ( reporter_1 )
project . add_reporter ( reporter_2 )
end
2017-08-17 22:00:37 +05:30
it 'returns the project users' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user )
2016-11-03 12:29:30 +05:30
2022-04-04 11:22:00 +05:30
user = project . namespace . first_owner
2017-09-10 17:25:29 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
2021-09-30 23:02:18 +05:30
expect ( json_response . size ) . to eq ( 3 )
2017-08-17 22:00:37 +05:30
first_user = json_response . first
2017-09-10 17:25:29 +05:30
expect ( first_user [ 'username' ] ) . to eq ( user . username )
expect ( first_user [ 'name' ] ) . to eq ( user . name )
2020-05-24 23:13:21 +05:30
expect ( first_user . keys ) . to include ( * %w[ name username id state avatar_url web_url ] )
2021-09-30 23:02:18 +05:30
ids = json_response . map { | raw_user | raw_user [ 'id' ] }
expect ( ids ) . to eq ( [ user . id , reporter_1 . id , reporter_2 . id ] )
2017-08-17 22:00:37 +05:30
end
end
2023-06-20 00:43:36 +05:30
it_behaves_like 'GET request permissions for admin mode' do
let ( :failed_status_code ) { :not_found }
end
2017-08-17 22:00:37 +05:30
context 'when unauthenticated' do
it_behaves_like 'project users response' do
2017-09-10 17:25:29 +05:30
let ( :project ) { create ( :project , :public ) }
2017-08-17 22:00:37 +05:30
let ( :current_user ) { nil }
end
end
context 'when authenticated' do
context 'valid request' do
2021-11-18 22:05:49 +05:30
it_behaves_like 'project users response' do
let ( :project ) { project4 }
let ( :current_user ) { user4 }
2017-08-17 22:00:37 +05:30
end
end
it 'returns a 404 error if not found' do
2021-02-22 17:27:13 +05:30
get api ( " /projects/ #{ non_existing_record_id } /users " , user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '404 Project Not Found' )
end
it 'returns a 404 error if user is not a member' do
other_user = create ( :user )
2023-06-20 00:43:36 +05:30
get api ( path , other_user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
2019-12-04 20:38:33 +05:30
it 'filters out users listed in skip_users' do
other_user = create ( :user )
project . team . add_developer ( other_user )
get api ( " /projects/ #{ project . id } /users?skip_users= #{ user . id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2020-11-24 15:15:51 +05:30
expect ( json_response . size ) . to eq ( 2 )
expect ( json_response . map { | m | m [ 'id' ] } ) . not_to include ( user . id )
2019-12-04 20:38:33 +05:30
end
2014-09-02 18:07:02 +05:30
end
end
2018-11-20 20:47:30 +05:30
describe 'fork management' do
2023-06-20 00:43:36 +05:30
let_it_be_with_refind ( :project_fork_target ) { create ( :project ) }
let_it_be_with_refind ( :project_fork_source ) { create ( :project , :public ) }
let_it_be_with_refind ( :private_project_fork_source ) { create ( :project , :private ) }
2014-09-02 18:07:02 +05:30
2018-11-20 20:47:30 +05:30
describe 'POST /projects/:id/fork/:forked_from_id' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project_fork_target . id } /fork/ #{ project_fork_source . id } " }
it_behaves_like 'POST request permissions for admin mode' do
let ( :params ) { { } }
let ( :failed_status_code ) { :not_found }
end
2018-11-20 20:47:30 +05:30
context 'user is a developer' do
before do
project_fork_target . add_developer ( user )
end
2014-09-02 18:07:02 +05:30
2018-11-20 20:47:30 +05:30
it 'denies project to be forked from an existing project' do
2023-06-20 00:43:36 +05:30
post api ( path , user )
2014-09-02 18:07:02 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2018-11-20 20:47:30 +05:30
end
end
2014-09-02 18:07:02 +05:30
2018-11-20 20:47:30 +05:30
it 'refreshes the forks count cache' do
expect ( project_fork_source . forks_count ) . to be_zero
end
2014-09-02 18:07:02 +05:30
2018-11-20 20:47:30 +05:30
context 'user is maintainer' do
before do
project_fork_target . add_maintainer ( user )
end
2014-09-02 18:07:02 +05:30
2018-11-20 20:47:30 +05:30
it 'allows project to be forked from an existing project' do
expect ( project_fork_target ) . not_to be_forked
2014-09-02 18:07:02 +05:30
2023-06-20 00:43:36 +05:30
post api ( path , user )
2018-11-20 20:47:30 +05:30
project_fork_target . reload
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2018-11-20 20:47:30 +05:30
expect ( project_fork_target . forked_from_project . id ) . to eq ( project_fork_source . id )
2018-12-13 13:39:08 +05:30
expect ( project_fork_target . fork_network_member ) . to be_present
2018-11-20 20:47:30 +05:30
expect ( project_fork_target ) . to be_forked
end
2014-09-02 18:07:02 +05:30
2020-05-30 21:06:31 +05:30
it 'fails without permission from forked_from project' do
project_fork_source . project_feature . update_attribute ( :forking_access_level , ProjectFeature :: PRIVATE )
2023-06-20 00:43:36 +05:30
post api ( path , user )
2020-05-30 21:06:31 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
expect ( project_fork_target . forked_from_project ) . to be_nil
expect ( project_fork_target . fork_network_member ) . not_to be_present
expect ( project_fork_target ) . not_to be_forked
end
2018-11-20 20:47:30 +05:30
it 'denies project to be forked from a private project' do
post api ( " /projects/ #{ project_fork_target . id } /fork/ #{ private_project_fork_source . id } " , user )
2018-03-17 18:26:18 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2018-11-20 20:47:30 +05:30
end
end
2014-09-02 18:07:02 +05:30
2018-11-20 20:47:30 +05:30
context 'user is admin' do
it 'allows project to be forked from an existing project' do
expect ( project_fork_target ) . not_to be_forked
2014-09-02 18:07:02 +05:30
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true )
2014-09-02 18:07:02 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2018-11-20 20:47:30 +05:30
end
2014-09-02 18:07:02 +05:30
2018-11-20 20:47:30 +05:30
it 'allows project to be forked from a private project' do
2023-06-20 00:43:36 +05:30
post api ( " /projects/ #{ project_fork_target . id } /fork/ #{ private_project_fork_source . id } " , admin , admin_mode : true )
2014-09-02 18:07:02 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2018-11-20 20:47:30 +05:30
end
2014-09-02 18:07:02 +05:30
2018-11-20 20:47:30 +05:30
it 'refreshes the forks count cachce' do
expect do
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true )
2018-11-20 20:47:30 +05:30
end . to change ( project_fork_source , :forks_count ) . by ( 1 )
end
2014-09-02 18:07:02 +05:30
2018-11-20 20:47:30 +05:30
it 'fails if forked_from project which does not exist' do
2023-06-20 00:43:36 +05:30
post api ( " /projects/ #{ project_fork_target . id } /fork/ #{ non_existing_record_id } " , admin , admin_mode : true )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2018-11-20 20:47:30 +05:30
end
2017-09-10 17:25:29 +05:30
2018-11-20 20:47:30 +05:30
it 'fails with 409 if already forked' do
other_project_fork_source = create ( :project , :public )
2017-09-10 17:25:29 +05:30
2018-11-20 20:47:30 +05:30
Projects :: ForkService . new ( project_fork_source , admin ) . execute ( project_fork_target )
2017-09-10 17:25:29 +05:30
2023-06-20 00:43:36 +05:30
post api ( " /projects/ #{ project_fork_target . id } /fork/ #{ other_project_fork_source . id } " , admin , admin_mode : true )
2018-11-20 20:47:30 +05:30
project_fork_target . reload
2014-09-02 18:07:02 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :conflict )
2018-11-20 20:47:30 +05:30
expect ( project_fork_target . forked_from_project . id ) . to eq ( project_fork_source . id )
expect ( project_fork_target ) . to be_forked
end
2014-09-02 18:07:02 +05:30
end
end
2015-04-26 12:48:37 +05:30
describe 'DELETE /projects/:id/fork' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project_fork_target . id } /fork " }
2016-09-13 17:45:13 +05:30
it " is not visible to users outside group " do
2023-06-20 00:43:36 +05:30
delete api ( path , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2014-09-02 18:07:02 +05:30
end
2015-11-26 14:37:03 +05:30
context 'when users belong to project group' do
2017-09-10 17:25:29 +05:30
let ( :project_fork_target ) { create ( :project , group : create ( :group ) ) }
2014-09-02 18:07:02 +05:30
2015-11-26 14:37:03 +05:30
before do
project_fork_target . group . add_owner user
project_fork_target . group . add_developer user2
end
2018-03-17 18:26:18 +05:30
context 'for a forked project' do
before do
2023-06-20 00:43:36 +05:30
post api ( " /projects/ #{ project_fork_target . id } /fork/ #{ project_fork_source . id } " , admin , admin_mode : true )
2018-03-17 18:26:18 +05:30
project_fork_target . reload
2018-11-20 20:47:30 +05:30
expect ( project_fork_target . forked_from_project ) . to be_present
expect ( project_fork_target ) . to be_forked
2018-03-17 18:26:18 +05:30
end
2015-11-26 14:37:03 +05:30
2023-06-20 00:43:36 +05:30
it_behaves_like 'DELETE request permissions for admin mode' do
let ( :success_status_code ) { :no_content }
let ( :failed_status_code ) { :not_found }
end
2018-03-17 18:26:18 +05:30
it 'makes forked project unforked' do
2023-06-20 00:43:36 +05:30
delete api ( path , admin , admin_mode : true )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :no_content )
2018-03-17 18:26:18 +05:30
project_fork_target . reload
expect ( project_fork_target . forked_from_project ) . to be_nil
2018-11-20 20:47:30 +05:30
expect ( project_fork_target ) . not_to be_forked
2018-03-17 18:26:18 +05:30
end
2017-08-17 22:00:37 +05:30
2018-03-17 18:26:18 +05:30
it_behaves_like '412 response' do
2023-06-20 00:43:36 +05:30
subject ( :request ) { api ( path , admin , admin_mode : true ) }
2018-03-17 18:26:18 +05:30
end
end
it 'is forbidden to non-owner users' do
2023-06-20 00:43:36 +05:30
delete api ( path , user2 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2015-11-26 14:37:03 +05:30
end
2016-09-13 17:45:13 +05:30
it 'is idempotent if not forked' do
2015-11-26 14:37:03 +05:30
expect ( project_fork_target . forked_from_project ) . to be_nil
2023-06-20 00:43:36 +05:30
delete api ( path , admin , admin_mode : true )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_modified )
2015-11-26 14:37:03 +05:30
expect ( project_fork_target . reload . forked_from_project ) . to be_nil
end
2014-09-02 18:07:02 +05:30
end
end
2018-03-17 18:26:18 +05:30
describe 'GET /projects/:id/forks' do
2023-06-20 00:43:36 +05:30
let_it_be_with_refind ( :private_fork ) { create ( :project , :private , :empty_repo ) }
let_it_be ( :member ) { create ( :user ) }
let_it_be ( :non_member ) { create ( :user ) }
2018-03-17 18:26:18 +05:30
2023-06-20 00:43:36 +05:30
before_all do
2018-03-17 18:26:18 +05:30
private_fork . add_developer ( member )
end
context 'for a forked project' do
before do
2023-06-20 00:43:36 +05:30
post api ( " /projects/ #{ private_fork . id } /fork/ #{ project_fork_source . id } " , admin , admin_mode : true )
2018-03-17 18:26:18 +05:30
private_fork . reload
2018-11-20 20:47:30 +05:30
expect ( private_fork . forked_from_project ) . to be_present
expect ( private_fork ) . to be_forked
2018-03-17 18:26:18 +05:30
project_fork_source . reload
expect ( project_fork_source . forks . length ) . to eq ( 1 )
expect ( project_fork_source . forks ) . to include ( private_fork )
end
context 'for a user that can access the forks' do
it 'returns the forks' do
get api ( " /projects/ #{ project_fork_source . id } /forks " , member )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-03-17 18:26:18 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response . length ) . to eq ( 1 )
expect ( json_response [ 0 ] [ 'name' ] ) . to eq ( private_fork . name )
end
2023-06-20 00:43:36 +05:30
context 'filter by updated_at' do
before do
private_fork . update! ( updated_at : 4 . days . ago )
end
it 'returns only forks updated on the given timeframe' do
get api ( " /projects/ #{ project_fork_source . id } /forks " , member ) ,
params : { updated_before : 2 . days . ago . iso8601 , updated_after : 6 . days . ago }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response . map { | project | project [ 'id' ] } ) . to contain_exactly ( private_fork . id )
end
end
2018-03-17 18:26:18 +05:30
end
context 'for a user that cannot access the forks' do
it 'returns an empty array' do
get api ( " /projects/ #{ project_fork_source . id } /forks " , non_member )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-03-17 18:26:18 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response . length ) . to eq ( 0 )
end
end
end
context 'for a non-forked project' do
it 'returns an empty array' do
get api ( " /projects/ #{ project_fork_source . id } /forks " )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-03-17 18:26:18 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response . length ) . to eq ( 0 )
end
end
end
2014-09-02 18:07:02 +05:30
end
2016-06-02 11:05:42 +05:30
describe " POST /projects/:id/share " do
2020-06-23 00:09:42 +05:30
let_it_be ( :group ) { create ( :group , :private ) }
let_it_be ( :group_user ) { create ( :user ) }
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /share " }
2020-01-01 13:55:28 +05:30
2019-03-13 22:55:13 +05:30
before do
group . add_developer ( user )
2020-06-23 00:09:42 +05:30
group . add_developer ( group_user )
2019-03-13 22:55:13 +05:30
end
2016-06-02 11:05:42 +05:30
2016-09-13 17:45:13 +05:30
it " shares project with group " do
2016-11-03 12:29:30 +05:30
expires_at = 10 . days . from_now . to_date
2016-06-02 11:05:42 +05:30
expect do
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { group_id : group . id , group_access : Gitlab :: Access :: DEVELOPER , expires_at : expires_at }
2016-06-02 11:05:42 +05:30
end . to change { ProjectGroupLink . count } . by ( 1 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2016-11-03 12:29:30 +05:30
expect ( json_response [ 'group_id' ] ) . to eq ( group . id )
expect ( json_response [ 'group_access' ] ) . to eq ( Gitlab :: Access :: DEVELOPER )
expect ( json_response [ 'expires_at' ] ) . to eq ( expires_at . to_s )
2016-06-02 11:05:42 +05:30
end
2020-07-28 23:09:34 +05:30
it 'updates project authorization' , :sidekiq_inline do
2020-06-23 00:09:42 +05:30
expect do
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { group_id : group . id , group_access : Gitlab :: Access :: DEVELOPER }
2020-06-23 00:09:42 +05:30
end . to (
change { group_user . can? ( :read_project , project ) } . from ( false ) . to ( true )
)
end
2016-09-13 17:45:13 +05:30
it " returns a 400 error when group id is not given " do
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { group_access : Gitlab :: Access :: DEVELOPER }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2016-06-02 11:05:42 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns a 400 error when access level is not given " do
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { group_id : group . id }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2016-06-02 11:05:42 +05:30
end
2016-09-13 17:45:13 +05:30
it " returns a 400 error when sharing is disabled " do
2020-11-24 15:15:51 +05:30
project . namespace . update! ( share_with_group_lock : true )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { group_id : group . id , group_access : Gitlab :: Access :: DEVELOPER }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2016-06-02 11:05:42 +05:30
end
2016-11-03 12:29:30 +05:30
it 'returns a 404 error when user cannot read group' do
private_group = create ( :group , :private )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { group_id : private_group . id , group_access : Gitlab :: Access :: DEVELOPER }
2016-11-03 12:29:30 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2016-11-03 12:29:30 +05:30
end
it 'returns a 404 error when group does not exist' do
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { group_id : non_existing_record_id , group_access : Gitlab :: Access :: DEVELOPER }
2016-11-03 12:29:30 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2016-11-03 12:29:30 +05:30
end
2017-08-17 22:00:37 +05:30
it " returns a 400 error when wrong params passed " do
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { group_id : group . id , group_access : non_existing_record_access_level }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'error' ] ) . to eq 'group_access does not have a valid value'
2016-06-02 11:05:42 +05:30
end
2019-03-13 22:55:13 +05:30
2022-07-23 23:45:48 +05:30
it " returns a 400 error when the project-group share is created with an OWNER access level " do
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { group_id : group . id , group_access : Gitlab :: Access :: OWNER }
2022-07-23 23:45:48 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'error' ] ) . to eq 'group_access does not have a valid value'
end
2019-03-13 22:55:13 +05:30
it " returns a 409 error when link is not saved " do
allow ( :: Projects :: GroupLinks :: CreateService ) . to receive_message_chain ( :new , :execute )
. and_return ( { status : :error , http_status : 409 , message : 'error' } )
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { group_id : group . id , group_access : Gitlab :: Access :: DEVELOPER }
2019-03-13 22:55:13 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :conflict )
2019-03-13 22:55:13 +05:30
end
2016-06-02 11:05:42 +05:30
end
2017-08-17 22:00:37 +05:30
describe 'DELETE /projects/:id/share/:group_id' do
2018-03-17 18:26:18 +05:30
context 'for a valid group' do
2020-06-23 00:09:42 +05:30
let_it_be ( :group ) { create ( :group , :private ) }
let_it_be ( :group_user ) { create ( :user ) }
2014-09-02 18:07:02 +05:30
2018-03-17 18:26:18 +05:30
before do
2020-06-23 00:09:42 +05:30
group . add_developer ( group_user )
2018-03-17 18:26:18 +05:30
create ( :project_group_link , group : group , project : project )
end
it 'returns 204 when deleting a group share' do
delete api ( " /projects/ #{ project . id } /share/ #{ group . id } " , user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :no_content )
2018-03-17 18:26:18 +05:30
expect ( project . project_group_links ) . to be_empty
end
2021-09-04 01:27:46 +05:30
it 'updates project authorization' , :sidekiq_inline do
2020-06-23 00:09:42 +05:30
expect do
delete api ( " /projects/ #{ project . id } /share/ #{ group . id } " , user )
end . to (
change { group_user . can? ( :read_project , project ) } . from ( true ) . to ( false )
)
end
2018-03-17 18:26:18 +05:30
it_behaves_like '412 response' do
2023-06-20 00:43:36 +05:30
subject ( :request ) { api ( " /projects/ #{ project . id } /share/ #{ group . id } " , user ) }
2018-03-17 18:26:18 +05:30
end
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
it 'returns a 400 when group id is not an integer' do
delete api ( " /projects/ #{ project . id } /share/foo " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2014-09-02 18:07:02 +05:30
end
2017-08-17 22:00:37 +05:30
it 'returns a 404 error when group link does not exist' do
2020-04-22 19:07:51 +05:30
delete api ( " /projects/ #{ project . id } /share/ #{ non_existing_record_id } " , user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
it 'returns a 404 error when project does not exist' do
2021-03-11 19:13:27 +05:30
delete api ( " /projects/ #{ non_existing_record_id } /share/ #{ non_existing_record_id } " , user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2014-09-02 18:07:02 +05:30
end
end
2021-10-27 15:23:28 +05:30
describe 'POST /projects/:id/import_project_members/:project_id' do
let_it_be ( :project2 ) { create ( :project ) }
let_it_be ( :project2_user ) { create ( :user ) }
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /import_project_members/ #{ project2 . id } " }
2021-10-27 15:23:28 +05:30
before_all do
project . add_maintainer ( user )
project2 . add_maintainer ( user )
project2 . add_developer ( project2_user )
end
2022-06-21 17:19:12 +05:30
it 'records the query' , :request_store , :use_sql_query_cache do
2023-06-20 00:43:36 +05:30
post api ( path , user )
expect ( response ) . to have_gitlab_http_status ( :created )
2022-06-21 17:19:12 +05:30
control_project = create ( :project )
control_project . add_maintainer ( user )
control_project . add_developer ( create ( :user ) )
control = ActiveRecord :: QueryRecorder . new ( skip_cached : false ) do
post api ( " /projects/ #{ project . id } /import_project_members/ #{ control_project . id } " , user )
end
measure_project = create ( :project )
measure_project . add_maintainer ( user )
measure_project . add_developer ( create ( :user ) )
measure_project . add_developer ( create ( :user ) ) # make this 2nd one to find any n+1
2022-08-13 15:12:31 +05:30
unresolved_n_plus_ones = 27 # 27 queries added per member
2022-06-21 17:19:12 +05:30
expect do
post api ( " /projects/ #{ project . id } /import_project_members/ #{ measure_project . id } " , user )
end . not_to exceed_all_query_limit ( control . count ) . with_threshold ( unresolved_n_plus_ones )
end
2021-10-27 15:23:28 +05:30
it 'returns 200 when it successfully imports members from another project' do
expect do
2023-06-20 00:43:36 +05:30
post api ( path , user )
2021-10-27 15:23:28 +05:30
end . to change { project . members . count } . by ( 2 )
expect ( response ) . to have_gitlab_http_status ( :created )
expect ( json_response [ 'message' ] ) . to eq ( 'Successfully imported' )
end
it 'returns 404 if the source project does not exist' do
expect do
post api ( " /projects/ #{ project . id } /import_project_members/ #{ non_existing_record_id } " , user )
end . not_to change { project . members . count }
expect ( response ) . to have_gitlab_http_status ( :not_found )
expect ( json_response [ 'message' ] ) . to eq ( '404 Project Not Found' )
end
it 'returns 404 if the target project members cannot be administered by the requester' do
private_project = create ( :project , :private )
expect do
post api ( " /projects/ #{ private_project . id } /import_project_members/ #{ project2 . id } " , user )
end . not_to change { project . members . count }
expect ( response ) . to have_gitlab_http_status ( :not_found )
expect ( json_response [ 'message' ] ) . to eq ( '404 Project Not Found' )
end
2022-01-12 12:59:36 +05:30
it 'returns 404 if the source project members cannot be viewed by the requester' do
private_project = create ( :project , :private )
expect do
post api ( " /projects/ #{ project . id } /import_project_members/ #{ private_project . id } " , user )
end . not_to change { project . members . count }
expect ( response ) . to have_gitlab_http_status ( :not_found )
expect ( json_response [ 'message' ] ) . to eq ( '404 Project Not Found' )
end
it 'returns 403 if the source project members cannot be administered by the requester' do
project . add_maintainer ( user2 )
project2 . add_developer ( user2 )
expect do
2023-06-20 00:43:36 +05:30
post api ( path , user2 )
2022-01-12 12:59:36 +05:30
end . not_to change { project . members . count }
expect ( response ) . to have_gitlab_http_status ( :forbidden )
expect ( json_response [ 'message' ] ) . to eq ( '403 Forbidden - Project' )
end
2021-10-27 15:23:28 +05:30
it 'returns 422 if the import failed for valid projects' do
allow_next_instance_of ( :: ProjectTeam ) do | project_team |
allow ( project_team ) . to receive ( :import ) . and_return ( false )
end
expect do
2023-06-20 00:43:36 +05:30
post api ( path , user )
2021-10-27 15:23:28 +05:30
end . not_to change { project . members . count }
expect ( response ) . to have_gitlab_http_status ( :unprocessable_entity )
expect ( json_response [ 'message' ] ) . to eq ( 'Import failed' )
end
end
2017-08-17 22:00:37 +05:30
describe 'PUT /projects/:id' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } " }
2017-09-10 17:25:29 +05:30
before do
expect ( project ) . to be_persisted
expect ( user ) . to be_persisted
expect ( user3 ) . to be_persisted
expect ( user4 ) . to be_persisted
expect ( project3 ) . to be_persisted
expect ( project4 ) . to be_persisted
expect ( project_member2 ) . to be_persisted
expect ( project_member ) . to be_persisted
end
2015-04-26 12:48:37 +05:30
2023-06-20 00:43:36 +05:30
it_behaves_like 'PUT request permissions for admin mode' do
let ( :params ) { { visibility : 'internal' } }
let ( :failed_status_code ) { :not_found }
end
2020-10-24 23:57:45 +05:30
describe 'updating packages_enabled attribute' do
it 'is enabled by default' do
expect ( project . packages_enabled ) . to be true
end
it 'disables project packages feature' do
2023-06-20 00:43:36 +05:30
put ( api ( path , user ) , params : { packages_enabled : false } )
2020-10-24 23:57:45 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( project . reload . packages_enabled ) . to be false
expect ( json_response [ 'packages_enabled' ] ) . to eq ( false )
end
end
2023-06-20 00:43:36 +05:30
it 'sets container_registry_access_level' do
put api ( path , user ) , params : { container_registry_access_level : 'private' }
2021-10-27 15:23:28 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'container_registry_access_level' ] ) . to eq ( 'private' )
expect ( Project . find_by ( path : project [ :path ] ) . container_registry_access_level ) . to eq ( ProjectFeature :: PRIVATE )
end
it 'sets container_registry_enabled' do
project . project_feature . update! ( container_registry_access_level : ProjectFeature :: DISABLED )
2023-06-20 00:43:36 +05:30
put ( api ( path , user ) , params : { container_registry_enabled : true } )
2021-10-27 15:23:28 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'container_registry_enabled' ] ) . to eq ( true )
expect ( project . reload . container_registry_access_level ) . to eq ( ProjectFeature :: ENABLED )
end
2023-06-20 00:43:36 +05:30
it 'sets security_and_compliance_access_level' do
put api ( path , user ) , params : { security_and_compliance_access_level : 'private' }
2022-05-07 20:08:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'security_and_compliance_access_level' ] ) . to eq ( 'private' )
expect ( Project . find_by ( path : project [ :path ] ) . security_and_compliance_access_level ) . to eq ( ProjectFeature :: PRIVATE )
end
2023-06-20 00:43:36 +05:30
it 'sets operations_access_level' do
put api ( path , user ) , params : { operations_access_level : 'private' }
2022-05-07 20:08:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'operations_access_level' ] ) . to eq ( 'private' )
expect ( Project . find_by ( path : project [ :path ] ) . operations_access_level ) . to eq ( ProjectFeature :: PRIVATE )
end
2023-06-20 00:43:36 +05:30
it 'sets analytics_access_level' do
put api ( path , user ) , params : { analytics_access_level : 'private' }
2022-05-07 20:08:51 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'analytics_access_level' ] ) . to eq ( 'private' )
expect ( Project . find_by ( path : project [ :path ] ) . analytics_access_level ) . to eq ( ProjectFeature :: PRIVATE )
end
2023-03-04 22:38:38 +05:30
% i ( releases_access_level environments_access_level feature_flags_access_level infrastructure_access_level monitor_access_level ) . each do | field |
2023-06-20 00:43:36 +05:30
it " sets #{ field } " do
put api ( path , user ) , params : { field = > 'private' }
2022-11-25 23:54:43 +05:30
2023-03-04 22:38:38 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ field . to_s ] ) . to eq ( 'private' )
expect ( Project . find_by ( path : project [ :path ] ) . public_send ( field ) ) . to eq ( ProjectFeature :: PRIVATE )
end
2022-11-25 23:54:43 +05:30
end
2017-08-17 22:00:37 +05:30
it 'returns 400 when nothing sent' do
project_param = { }
2023-06-20 00:43:36 +05:30
put api ( path , user ) , params : project_param
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'error' ] ) . to match ( 'at least one parameter must be provided' )
end
2015-04-26 12:48:37 +05:30
context 'when unauthenticated' do
2016-09-13 17:45:13 +05:30
it 'returns authentication error' do
2015-04-26 12:48:37 +05:30
project_param = { name : 'bar' }
2017-08-17 22:00:37 +05:30
2023-06-20 00:43:36 +05:30
put api ( path ) , params : project_param
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2015-04-26 12:48:37 +05:30
end
end
context 'when authenticated as project owner' do
2016-09-13 17:45:13 +05:30
it 'updates visibility_level' do
2017-08-17 22:00:37 +05:30
project_param = { visibility : 'public' }
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
2015-04-26 12:48:37 +05:30
project_param . each_pair do | k , v |
expect ( json_response [ k . to_s ] ) . to eq ( v )
end
end
2016-09-13 17:45:13 +05:30
it 'updates visibility_level from public to private' do
2020-11-24 15:15:51 +05:30
project3 . update! ( { visibility_level : Gitlab :: VisibilityLevel :: PUBLIC } )
2017-08-17 22:00:37 +05:30
project_param = { visibility : 'private' }
2015-12-23 02:04:40 +05:30
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
2015-12-23 02:04:40 +05:30
project_param . each_pair do | k , v |
expect ( json_response [ k . to_s ] ) . to eq ( v )
end
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'visibility' ] ) . to eq ( 'private' )
2015-12-23 02:04:40 +05:30
end
2021-10-29 20:43:33 +05:30
it 'does not update visibility_level if it is restricted' do
stub_application_setting ( restricted_visibility_levels : [ Gitlab :: VisibilityLevel :: INTERNAL ] )
put api ( " /projects/ #{ project3 . id } " , user ) , params : { visibility : 'internal' }
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'message' ] [ 'visibility_level' ] ) . to include ( 'internal has been restricted by your GitLab administrator' )
end
2016-09-13 17:45:13 +05:30
it 'does not update name to existing name' do
2015-04-26 12:48:37 +05:30
project_param = { name : project3 . name }
2017-08-17 22:00:37 +05:30
2023-06-20 00:43:36 +05:30
put api ( path , user ) , params : project_param
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2015-04-26 12:48:37 +05:30
expect ( json_response [ 'message' ] [ 'name' ] ) . to eq ( [ 'has already been taken' ] )
end
2016-09-29 09:46:39 +05:30
it 'updates request_access_enabled' do
project_param = { request_access_enabled : false }
2023-06-20 00:43:36 +05:30
put api ( path , user ) , params : project_param
2016-09-29 09:46:39 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2016-09-29 09:46:39 +05:30
expect ( json_response [ 'request_access_enabled' ] ) . to eq ( false )
end
2016-09-13 17:45:13 +05:30
it 'updates path & name to existing path & name in different namespace' do
2015-04-26 12:48:37 +05:30
project_param = { path : project4 . path , name : project4 . name }
2017-08-17 22:00:37 +05:30
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
project_param . each_pair do | k , v |
expect ( json_response [ k . to_s ] ) . to eq ( v )
end
end
2021-09-04 01:27:46 +05:30
it 'updates default_branch' do
project_param = { default_branch : 'something_else' }
2023-06-20 00:43:36 +05:30
put api ( path , user ) , params : project_param
2021-09-04 01:27:46 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
project_param . each_pair do | k , v |
expect ( json_response [ k . to_s ] ) . to eq ( v )
end
end
2017-08-17 22:00:37 +05:30
it 'updates jobs_enabled' do
project_param = { jobs_enabled : true }
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2017-08-17 22:00:37 +05:30
2015-04-26 12:48:37 +05:30
project_param . each_pair do | k , v |
expect ( json_response [ k . to_s ] ) . to eq ( v )
end
end
2018-05-09 12:01:36 +05:30
2019-09-30 21:07:59 +05:30
it 'updates builds_access_level' do
project_param = { builds_access_level : 'private' }
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-09-30 21:07:59 +05:30
expect ( json_response [ 'builds_access_level' ] ) . to eq ( 'private' )
end
2020-03-13 15:44:24 +05:30
it 'updates pages_access_level' do
project_param = { pages_access_level : 'private' }
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'pages_access_level' ] ) . to eq ( 'private' )
end
it 'updates emails_disabled' do
project_param = { emails_disabled : true }
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'emails_disabled' ] ) . to eq ( true )
end
2019-09-30 21:07:59 +05:30
it 'updates build_git_strategy' do
project_param = { build_git_strategy : 'clone' }
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-09-30 21:07:59 +05:30
expect ( json_response [ 'build_git_strategy' ] ) . to eq ( 'clone' )
end
it 'rejects to update build_git_strategy when build_git_strategy is invalid' do
project_param = { build_git_strategy : 'invalid' }
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2019-09-30 21:07:59 +05:30
end
2018-05-09 12:01:36 +05:30
it 'updates merge_method' do
project_param = { merge_method : 'ff' }
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2018-05-09 12:01:36 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-05-09 12:01:36 +05:30
project_param . each_pair do | k , v |
expect ( json_response [ k . to_s ] ) . to eq ( v )
end
end
it 'rejects to update merge_method when merge_method is invalid' do
project_param = { merge_method : 'invalid' }
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2018-05-09 12:01:36 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2018-05-09 12:01:36 +05:30
end
2018-11-18 11:00:15 +05:30
2023-06-20 00:43:36 +05:30
it 'updates restrict_user_defined_variables' do
2021-03-08 18:12:59 +05:30
project_param = { restrict_user_defined_variables : true }
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
expect ( response ) . to have_gitlab_http_status ( :ok )
project_param . each_pair do | k , v |
expect ( json_response [ k . to_s ] ) . to eq ( v )
end
end
2022-10-11 01:57:18 +05:30
context 'with changes to the avatar' do
let_it_be ( :avatar_file ) { fixture_file_upload ( 'spec/fixtures/banana_sample.gif' , 'image/gif' ) }
let_it_be ( :alternate_avatar_file ) { fixture_file_upload ( 'spec/fixtures/rails_sample.png' , 'image/png' ) }
let_it_be ( :project_with_avatar , reload : true ) do
create ( :project ,
:private ,
:repository ,
name : 'project-with-avatar' ,
creator_id : user . id ,
namespace : user . namespace ,
avatar : avatar_file )
end
2018-11-18 11:00:15 +05:30
2022-10-11 01:57:18 +05:30
it 'uploads avatar to project without an avatar' do
workhorse_form_with_file (
api ( " /projects/ #{ project3 . id } " , user ) ,
method : :put ,
file_key : :avatar ,
params : { avatar : avatar_file }
)
2018-11-18 11:00:15 +05:30
2022-10-11 01:57:18 +05:30
aggregate_failures " testing response " do
expect ( response ) . to have_gitlab_http_status ( :ok )
2023-04-23 21:23:45 +05:30
expect ( json_response [ 'avatar_url' ] ) . to eq ( 'http://localhost/uploads/' \
'-/system/project/avatar/' \
2022-10-11 01:57:18 +05:30
" #{ project3 . id } /banana_sample.gif " )
end
end
it 'uploads and changes avatar to project with an avatar' do
workhorse_form_with_file (
api ( " /projects/ #{ project_with_avatar . id } " , user ) ,
method : :put ,
file_key : :avatar ,
params : { avatar : alternate_avatar_file }
)
aggregate_failures " testing response " do
expect ( response ) . to have_gitlab_http_status ( :ok )
2023-04-23 21:23:45 +05:30
expect ( json_response [ 'avatar_url' ] ) . to eq ( 'http://localhost/uploads/' \
'-/system/project/avatar/' \
2022-10-11 01:57:18 +05:30
" #{ project_with_avatar . id } /rails_sample.png " )
end
end
it 'uploads and changes avatar to project among other changes' do
workhorse_form_with_file (
api ( " /projects/ #{ project_with_avatar . id } " , user ) ,
method : :put ,
file_key : :avatar ,
params : { description : 'changed description' , avatar : avatar_file }
)
aggregate_failures " testing response " do
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'description' ] ) . to eq ( 'changed description' )
2023-04-23 21:23:45 +05:30
expect ( json_response [ 'avatar_url' ] ) . to eq ( 'http://localhost/uploads/' \
'-/system/project/avatar/' \
2022-10-11 01:57:18 +05:30
" #{ project_with_avatar . id } /banana_sample.gif " )
end
end
it 'removes avatar from project with an avatar' do
put api ( " /projects/ #{ project_with_avatar . id } " , user ) , params : { avatar : '' }
aggregate_failures " testing response " do
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'avatar_url' ] ) . to be_nil
expect ( project_with_avatar . reload . avatar_url ) . to be_nil
end
end
2018-11-18 11:00:15 +05:30
end
2019-09-30 21:07:59 +05:30
it 'updates auto_devops_deploy_strategy' do
project_param = { auto_devops_deploy_strategy : 'timed_incremental' }
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-09-30 21:07:59 +05:30
expect ( json_response [ 'auto_devops_deploy_strategy' ] ) . to eq ( 'timed_incremental' )
end
it 'updates auto_devops_enabled' do
project_param = { auto_devops_enabled : false }
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-09-30 21:07:59 +05:30
expect ( json_response [ 'auto_devops_enabled' ] ) . to eq ( false )
end
2021-09-04 01:27:46 +05:30
it 'updates topics using tag_list (deprecated)' do
project_param = { tag_list : 'topic1' }
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'topics' ] ) . to eq ( %w[ topic1 ] )
end
it 'updates topics' do
project_param = { topics : 'topic2' }
put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'topics' ] ) . to eq ( %w[ topic2 ] )
end
2021-09-30 23:02:18 +05:30
2022-07-16 23:28:13 +05:30
it 'updates enforce_auth_checks_on_uploads' do
project3 . update! ( enforce_auth_checks_on_uploads : false )
project_param = { enforce_auth_checks_on_uploads : true }
expect { put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param }
. to change { project3 . reload . enforce_auth_checks_on_uploads }
. from ( false )
. to ( true )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'enforce_auth_checks_on_uploads' ] ) . to eq ( true )
end
2021-09-30 23:02:18 +05:30
it 'updates squash_option' do
project3 . update! ( squash_option : 'always' )
project_param = { squash_option : " default_on " }
expect { put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param }
. to change { project3 . reload . squash_option }
. from ( 'always' )
. to ( 'default_on' )
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'squash_option' ] ) . to eq ( " default_on " )
end
it 'does not update an invalid squash_option' do
project_param = { squash_option : " jawn " }
expect { put api ( " /projects/ #{ project3 . id } " , user ) , params : project_param }
. not_to change { project3 . reload . squash_option }
expect ( response ) . to have_gitlab_http_status ( :bad_request )
end
2015-04-26 12:48:37 +05:30
end
2018-11-18 11:00:15 +05:30
context 'when authenticated as project maintainer' do
2016-09-13 17:45:13 +05:30
it 'updates path' do
2015-04-26 12:48:37 +05:30
project_param = { path : 'bar' }
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project3 . id } " , user4 ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2015-04-26 12:48:37 +05:30
project_param . each_pair do | k , v |
expect ( json_response [ k . to_s ] ) . to eq ( v )
end
end
2016-09-13 17:45:13 +05:30
it 'updates other attributes' do
2015-04-26 12:48:37 +05:30
project_param = { issues_enabled : true ,
wiki_enabled : true ,
snippets_enabled : true ,
merge_requests_enabled : true ,
2018-05-09 12:01:36 +05:30
merge_method : 'ff' ,
2019-09-04 21:01:54 +05:30
ci_default_git_depth : 20 ,
2021-01-03 14:25:43 +05:30
ci_forward_deployment_enabled : false ,
2022-08-27 11:52:29 +05:30
ci_allow_fork_pipelines_to_run_in_parent_project : false ,
2022-08-13 15:12:31 +05:30
ci_separated_caches : false ,
2015-04-26 12:48:37 +05:30
description : 'new description' }
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project3 . id } " , user4 ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2015-04-26 12:48:37 +05:30
project_param . each_pair do | k , v |
expect ( json_response [ k . to_s ] ) . to eq ( v )
end
end
2016-09-13 17:45:13 +05:30
it 'does not update path to existing path' do
2015-04-26 12:48:37 +05:30
project_param = { path : project . path }
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project3 . id } " , user4 ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2015-04-26 12:48:37 +05:30
expect ( json_response [ 'message' ] [ 'path' ] ) . to eq ( [ 'has already been taken' ] )
end
2023-01-13 00:05:48 +05:30
it 'updates name' do
2015-04-26 12:48:37 +05:30
project_param = { name : 'bar' }
2023-01-13 00:05:48 +05:30
2023-06-20 00:43:36 +05:30
put api ( path , user ) , params : project_param
2023-01-13 00:05:48 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
project_param . each_pair do | k , v |
expect ( json_response [ k . to_s ] ) . to eq ( v )
end
2015-04-26 12:48:37 +05:30
end
2016-09-13 17:45:13 +05:30
it 'does not update visibility_level' do
2017-08-17 22:00:37 +05:30
project_param = { visibility : 'public' }
2019-02-15 15:39:39 +05:30
put api ( " /projects/ #{ project3 . id } " , user4 ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2015-04-26 12:48:37 +05:30
end
2020-03-13 15:44:24 +05:30
it 'updates container_expiration_policy' do
project_param = {
container_expiration_policy_attributes : {
cadence : '1month' ,
2020-04-22 19:07:51 +05:30
keep_n : 1 ,
name_regex_keep : 'foo.*'
2020-03-13 15:44:24 +05:30
}
}
put api ( " /projects/ #{ project3 . id } " , user4 ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2020-03-13 15:44:24 +05:30
expect ( json_response [ 'container_expiration_policy' ] [ 'cadence' ] ) . to eq ( '1month' )
expect ( json_response [ 'container_expiration_policy' ] [ 'keep_n' ] ) . to eq ( 1 )
2020-04-22 19:07:51 +05:30
expect ( json_response [ 'container_expiration_policy' ] [ 'name_regex_keep' ] ) . to eq ( 'foo.*' )
2020-03-13 15:44:24 +05:30
end
2020-06-23 00:09:42 +05:30
it " doesn't update container_expiration_policy with invalid regex " do
project_param = {
container_expiration_policy_attributes : {
cadence : '1month' ,
2021-01-29 00:20:46 +05:30
enabled : true ,
2020-06-23 00:09:42 +05:30
keep_n : 1 ,
name_regex_keep : '['
}
}
put api ( " /projects/ #{ project3 . id } " , user4 ) , params : project_param
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'message' ] [ 'container_expiration_policy.name_regex_keep' ] ) . to contain_exactly ( 'not valid RE2 syntax: missing ]: [' )
end
2021-03-08 18:12:59 +05:30
it " doesn't update container_expiration_policy with invalid keep_n " do
project_param = {
container_expiration_policy_attributes : {
cadence : '1month' ,
enabled : true ,
keep_n : 'not_int' ,
name_regex_keep : 'foo.*'
}
}
put api ( " /projects/ #{ project3 . id } " , user4 ) , params : project_param
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'error' ] ) . to eq ( 'container_expiration_policy_attributes[keep_n] is invalid' )
end
2015-04-26 12:48:37 +05:30
end
context 'when authenticated as project developer' do
2016-09-13 17:45:13 +05:30
it 'does not update other attributes' do
2015-04-26 12:48:37 +05:30
project_param = { path : 'bar' ,
issues_enabled : true ,
wiki_enabled : true ,
snippets_enabled : true ,
merge_requests_enabled : true ,
2016-09-29 09:46:39 +05:30
description : 'new description' ,
request_access_enabled : true }
2023-06-20 00:43:36 +05:30
put api ( path , user3 ) , params : project_param
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
end
2021-10-29 20:43:33 +05:30
context 'when authenticated as the admin' do
let_it_be ( :admin ) { create ( :admin ) }
it 'ignores visibility level restrictions' do
stub_application_setting ( restricted_visibility_levels : [ Gitlab :: VisibilityLevel :: INTERNAL ] )
2023-06-20 00:43:36 +05:30
put api ( " /projects/ #{ project3 . id } " , admin , admin_mode : true ) , params : { visibility : 'internal' }
2021-10-29 20:43:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'visibility' ] ) . to eq ( 'internal' )
end
end
2020-04-08 14:13:33 +05:30
context 'when updating repository storage' do
let ( :unknown_storage ) { 'new-storage' }
let ( :new_project ) { create ( :project , :repository , namespace : user . namespace ) }
context 'as a user' do
it 'returns 200 but does not change repository_storage' do
expect do
Sidekiq :: Testing . fake! do
put ( api ( " /projects/ #{ new_project . id } " , user ) , params : { repository_storage : unknown_storage , issues_enabled : false } )
end
2021-04-17 20:07:23 +05:30
end . not_to change ( Projects :: UpdateRepositoryStorageWorker . jobs , :size )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'issues_enabled' ] ) . to eq ( false )
expect ( new_project . reload . repository . storage ) . to eq ( 'default' )
end
end
context 'as an admin' do
include_context 'custom session'
let ( :admin ) { create ( :admin ) }
2020-06-23 00:09:42 +05:30
it 'returns 400 when repository storage is unknown' do
2023-06-20 00:43:36 +05:30
put ( api ( " /projects/ #{ new_project . id } " , admin , admin_mode : true ) , params : { repository_storage : unknown_storage } )
2020-04-08 14:13:33 +05:30
2020-06-23 00:09:42 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'message' ] [ 'repository_storage_moves' ] ) . to eq ( [ 'is invalid' ] )
2020-04-08 14:13:33 +05:30
end
it 'returns 200 when repository storage has changed' do
stub_storage_settings ( 'test_second_storage' = > { 'path' = > TestEnv :: SECOND_STORAGE_PATH } )
expect do
Sidekiq :: Testing . fake! do
2023-06-20 00:43:36 +05:30
put ( api ( " /projects/ #{ new_project . id } " , admin , admin_mode : true ) , params : { repository_storage : 'test_second_storage' } )
2020-04-08 14:13:33 +05:30
end
2021-04-17 20:07:23 +05:30
end . to change ( Projects :: UpdateRepositoryStorageWorker . jobs , :size ) . by ( 1 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
end
2015-04-26 12:48:37 +05:30
end
end
2020-07-28 23:09:34 +05:30
context 'when updating service desk' do
2023-06-20 00:43:36 +05:30
let ( :params ) { { service_desk_enabled : true } }
subject ( :request ) { put ( api ( path , user ) , params : params ) }
2020-07-28 23:09:34 +05:30
before do
project . update! ( service_desk_enabled : false )
2023-06-20 00:43:36 +05:30
allow ( :: Gitlab :: Email :: IncomingEmail ) . to receive ( :enabled? ) . and_return ( true )
2020-07-28 23:09:34 +05:30
end
it 'returns 200' do
2023-06-20 00:43:36 +05:30
request
2020-07-28 23:09:34 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
end
it 'enables the service_desk' do
2023-06-20 00:43:36 +05:30
expect { request } . to change { project . reload . service_desk_enabled } . to ( true )
2020-07-28 23:09:34 +05:30
end
end
2021-09-04 01:27:46 +05:30
context 'when updating keep latest artifact' do
2023-06-20 00:43:36 +05:30
subject ( :request ) { put ( api ( path , user ) , params : { keep_latest_artifact : true } ) }
2021-09-04 01:27:46 +05:30
before do
project . update! ( keep_latest_artifact : false )
end
it 'returns 200' do
2023-06-20 00:43:36 +05:30
request
2021-09-04 01:27:46 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
end
it 'enables keep_latest_artifact' do
2023-06-20 00:43:36 +05:30
expect { request } . to change { project . reload . keep_latest_artifact } . to ( true )
2021-09-04 01:27:46 +05:30
end
end
2022-03-02 08:16:31 +05:30
context 'attribute mr_default_target_self' do
let_it_be ( :source_project ) { create ( :project , :public ) }
let ( :forked_project ) { fork_project ( source_project , user ) }
it 'is by default set to false' do
expect ( source_project . mr_default_target_self ) . to be false
expect ( forked_project . mr_default_target_self ) . to be false
end
describe 'for a non-forked project' do
before_all do
source_project . add_maintainer ( user )
end
it 'is not exposed' do
get api ( " /projects/ #{ source_project . id } " , user )
expect ( json_response ) . not_to include ( 'mr_default_target_self' )
end
it 'is not possible to update' do
put api ( " /projects/ #{ source_project . id } " , user ) , params : { mr_default_target_self : true }
source_project . reload
expect ( source_project . mr_default_target_self ) . to be false
expect ( response ) . to have_gitlab_http_status ( :bad_request )
end
end
describe 'for a forked project' do
it 'updates to true' do
put api ( " /projects/ #{ forked_project . id } " , user ) , params : { mr_default_target_self : true }
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'mr_default_target_self' ] ) . to eq ( true )
end
end
end
2015-04-26 12:48:37 +05:30
end
2016-06-02 11:05:42 +05:30
describe 'POST /projects/:id/archive' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /archive " }
2016-06-02 11:05:42 +05:30
context 'on an unarchived project' do
it 'archives the project' do
2023-06-20 00:43:36 +05:30
post api ( path , user )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'archived' ] ) . to be_truthy
end
end
context 'on an archived project' do
before do
2018-11-18 11:00:15 +05:30
:: Projects :: UpdateService . new ( project , user , archived : true ) . execute
2016-06-02 11:05:42 +05:30
end
it 'remains archived' do
2023-06-20 00:43:36 +05:30
post api ( path , user )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'archived' ] ) . to be_truthy
end
end
context 'user without archiving rights to the project' do
before do
2018-03-17 18:26:18 +05:30
project . add_developer ( user3 )
2016-06-02 11:05:42 +05:30
end
it 'rejects the action' do
2023-06-20 00:43:36 +05:30
post api ( path , user3 )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2016-06-02 11:05:42 +05:30
end
end
end
describe 'POST /projects/:id/unarchive' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /unarchive " }
2016-06-02 11:05:42 +05:30
context 'on an unarchived project' do
it 'remains unarchived' do
2023-06-20 00:43:36 +05:30
post api ( path , user )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'archived' ] ) . to be_falsey
end
end
context 'on an archived project' do
before do
2018-11-18 11:00:15 +05:30
:: Projects :: UpdateService . new ( project , user , archived : true ) . execute
2016-06-02 11:05:42 +05:30
end
it 'unarchives the project' do
2023-06-20 00:43:36 +05:30
post api ( path , user )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'archived' ] ) . to be_falsey
end
end
context 'user without archiving rights to the project' do
before do
2018-03-17 18:26:18 +05:30
project . add_developer ( user3 )
2016-06-02 11:05:42 +05:30
end
it 'rejects the action' do
2023-06-20 00:43:36 +05:30
post api ( path , user3 )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2016-06-02 11:05:42 +05:30
end
end
end
describe 'POST /projects/:id/star' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /star " }
2016-06-02 11:05:42 +05:30
context 'on an unstarred project' do
it 'stars the project' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) } . to change { project . reload . star_count } . by ( 1 )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'star_count' ] ) . to eq ( 1 )
end
end
context 'on a starred project' do
before do
user . toggle_star ( project )
project . reload
end
it 'does not modify the star count' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) } . not_to change { project . reload . star_count }
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_modified )
2016-06-02 11:05:42 +05:30
end
end
end
2017-08-17 22:00:37 +05:30
describe 'POST /projects/:id/unstar' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /unstar " }
2016-06-02 11:05:42 +05:30
context 'on a starred project' do
before do
user . toggle_star ( project )
project . reload
end
it 'unstars the project' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) } . to change { project . reload . star_count } . by ( - 1 )
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2016-06-02 11:05:42 +05:30
expect ( json_response [ 'star_count' ] ) . to eq ( 0 )
end
end
context 'on an unstarred project' do
it 'does not modify the star count' do
2023-06-20 00:43:36 +05:30
expect { post api ( path , user ) } . not_to change { project . reload . star_count }
2016-06-02 11:05:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_modified )
2016-06-02 11:05:42 +05:30
end
end
end
2019-10-12 21:52:04 +05:30
describe 'GET /projects/:id/starrers' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ public_project . id } /starrers " }
let ( :public_project ) { create ( :project , :public ) }
let ( :private_user ) { create ( :user , private_profile : true ) }
2019-10-12 21:52:04 +05:30
shared_examples_for 'project starrers response' do
it 'returns an array of starrers' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user )
2019-10-12 21:52:04 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2019-10-12 21:52:04 +05:30
expect ( response ) . to include_pagination_headers
expect ( json_response ) . to be_an Array
expect ( json_response [ 0 ] [ 'starred_since' ] ) . to be_present
expect ( json_response [ 0 ] [ 'user' ] ) . to be_present
end
it 'returns the proper security headers' do
2023-06-20 00:43:36 +05:30
get api ( path , current_user )
2019-10-12 21:52:04 +05:30
expect ( response ) . to include_security_headers
end
end
before do
2020-11-24 15:15:51 +05:30
user . update! ( starred_projects : [ public_project ] )
private_user . update! ( starred_projects : [ public_project ] )
2019-10-12 21:52:04 +05:30
end
it 'returns not_found(404) for not existing project' do
2020-04-22 19:07:51 +05:30
get api ( " /projects/ #{ non_existing_record_id } /starrers " , user )
2019-10-12 21:52:04 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
context 'public project without user' do
it_behaves_like 'project starrers response' do
let ( :current_user ) { nil }
end
it 'returns only starrers with a public profile' do
2023-06-20 00:43:36 +05:30
get api ( path , nil )
2019-10-12 21:52:04 +05:30
user_ids = json_response . map { | s | s [ 'user' ] [ 'id' ] }
expect ( user_ids ) . to include ( user . id )
expect ( user_ids ) . not_to include ( private_user . id )
end
end
context 'public project with user with private profile' do
it_behaves_like 'project starrers response' do
let ( :current_user ) { private_user }
end
it 'returns current user with a private profile' do
2023-06-20 00:43:36 +05:30
get api ( path , private_user )
2019-10-12 21:52:04 +05:30
user_ids = json_response . map { | s | s [ 'user' ] [ 'id' ] }
expect ( user_ids ) . to include ( user . id , private_user . id )
end
end
context 'private project' do
context 'with unauthorized user' do
it 'returns not_found for existing but unauthorized project' do
get api ( " /projects/ #{ project3 . id } /starrers " , user3 )
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
end
context 'without user' do
it 'returns not_found for existing but unauthorized project' do
get api ( " /projects/ #{ project3 . id } /starrers " , nil )
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
end
end
end
2018-10-15 14:42:47 +05:30
describe 'GET /projects/:id/languages' do
context 'with an authorized user' do
it_behaves_like 'languages and percentages JSON response' do
let ( :project ) { project3 }
end
it 'returns not_found(404) for not existing project' do
2021-03-11 19:13:27 +05:30
get api ( " /projects/ #{ non_existing_record_id } /languages " , user )
2018-10-15 14:42:47 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
end
context 'with not authorized user' do
it 'returns not_found for existing but unauthorized project' do
get api ( " /projects/ #{ project3 . id } /languages " , user3 )
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
end
context 'without user' do
let ( :project_public ) { create ( :project , :public , :repository ) }
it_behaves_like 'languages and percentages JSON response' do
let ( :project ) { project_public }
end
it 'returns not_found for existing but unauthorized project' do
get api ( " /projects/ #{ project3 . id } /languages " , nil )
expect ( response ) . to have_gitlab_http_status ( :not_found )
end
end
end
2015-04-26 12:48:37 +05:30
describe 'DELETE /projects/:id' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } " }
it_behaves_like 'DELETE request permissions for admin mode' do
let ( :success_status_code ) { :accepted }
let ( :failed_status_code ) { :not_found }
end
2015-04-26 12:48:37 +05:30
context 'when authenticated as user' do
2016-09-13 17:45:13 +05:30
it 'removes project' do
2023-06-20 00:43:36 +05:30
delete api ( path , user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :accepted )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'message' ] ) . to eql ( '202 Accepted' )
2014-09-02 18:07:02 +05:30
end
2018-03-17 18:26:18 +05:30
it_behaves_like '412 response' do
let ( :success_status ) { 202 }
2023-06-20 00:43:36 +05:30
subject ( :request ) { api ( path , user ) }
2018-03-17 18:26:18 +05:30
end
2016-09-13 17:45:13 +05:30
it 'does not remove a project if not an owner' do
2014-09-02 18:07:02 +05:30
user3 = create ( :user )
2018-03-17 18:26:18 +05:30
project . add_developer ( user3 )
2023-06-20 00:43:36 +05:30
delete api ( path , user3 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it 'does not remove a non existing project' do
2021-03-11 19:13:27 +05:30
delete api ( " /projects/ #{ non_existing_record_id } " , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it 'does not remove a project not attached to user' do
2023-06-20 00:43:36 +05:30
delete api ( path , user2 )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2014-09-02 18:07:02 +05:30
end
end
2015-04-26 12:48:37 +05:30
context 'when authenticated as admin' do
2016-09-13 17:45:13 +05:30
it 'removes any existing project' do
2023-06-20 00:43:36 +05:30
delete api ( " /projects/ #{ project . id } " , admin , admin_mode : true )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :accepted )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'message' ] ) . to eql ( '202 Accepted' )
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it 'does not remove a non existing project' do
2023-06-20 00:43:36 +05:30
delete api ( " /projects/ #{ non_existing_record_id } " , admin , admin_mode : true )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2018-03-17 18:26:18 +05:30
end
it_behaves_like '412 response' do
let ( :success_status ) { 202 }
2023-06-20 00:43:36 +05:30
subject ( :request ) { api ( " /projects/ #{ project . id } " , admin , admin_mode : true ) }
2014-09-02 18:07:02 +05:30
end
end
end
2017-08-17 22:00:37 +05:30
describe 'POST /projects/:id/fork' do
let ( :project ) do
create ( :project , :repository , creator : user , namespace : user . namespace )
end
2019-07-07 11:18:12 +05:30
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /fork " }
2019-07-07 11:18:12 +05:30
let ( :project2 ) do
create ( :project , :repository , creator : user , namespace : user . namespace )
end
2020-04-08 14:13:33 +05:30
let ( :group ) { create ( :group , :public ) }
let ( :group2 ) { create ( :group , name : 'group2_name' ) }
let ( :group3 ) { create ( :group , name : 'group3_name' , parent : group2 ) }
2018-05-09 12:01:36 +05:30
2017-08-17 22:00:37 +05:30
before do
2020-04-08 14:13:33 +05:30
group . add_guest ( user2 )
group2 . add_maintainer ( user2 )
group3 . add_owner ( user2 )
2017-08-17 22:00:37 +05:30
project . add_reporter ( user2 )
2019-07-07 11:18:12 +05:30
project2 . add_reporter ( user2 )
2017-08-17 22:00:37 +05:30
end
2023-06-20 00:43:36 +05:30
it_behaves_like 'POST request permissions for admin mode' do
let ( :params ) { { } }
let ( :failed_status_code ) { :not_found }
end
2017-08-17 22:00:37 +05:30
context 'when authenticated' do
it 'forks if user has sufficient access to project' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'name' ] ) . to eq ( project . name )
expect ( json_response [ 'path' ] ) . to eq ( project . path )
expect ( json_response [ 'owner' ] [ 'id' ] ) . to eq ( user2 . id )
expect ( json_response [ 'namespace' ] [ 'id' ] ) . to eq ( user2 . namespace . id )
expect ( json_response [ 'forked_from_project' ] [ 'id' ] ) . to eq ( project . id )
2017-09-10 17:25:29 +05:30
expect ( json_response [ 'import_status' ] ) . to eq ( 'scheduled' )
expect ( json_response ) . to include ( " import_error " )
2017-08-17 22:00:37 +05:30
end
it 'forks if user is admin' do
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'name' ] ) . to eq ( project . name )
expect ( json_response [ 'path' ] ) . to eq ( project . path )
expect ( json_response [ 'owner' ] [ 'id' ] ) . to eq ( admin . id )
expect ( json_response [ 'namespace' ] [ 'id' ] ) . to eq ( admin . namespace . id )
expect ( json_response [ 'forked_from_project' ] [ 'id' ] ) . to eq ( project . id )
2017-09-10 17:25:29 +05:30
expect ( json_response [ 'import_status' ] ) . to eq ( 'scheduled' )
expect ( json_response ) . to include ( " import_error " )
2017-08-17 22:00:37 +05:30
end
it 'fails on missing project access for the project to fork' do
new_user = create ( :user )
2023-06-20 00:43:36 +05:30
post api ( path , new_user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '404 Project Not Found' )
end
it 'fails if forked project exists in the user namespace' do
2020-04-08 14:13:33 +05:30
new_project = create ( :project , name : project . name , path : project . path )
new_project . add_reporter ( user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
post api ( " /projects/ #{ new_project . id } /fork " , user )
expect ( response ) . to have_gitlab_http_status ( :conflict )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'message' ] [ 'name' ] ) . to eq ( [ 'has already been taken' ] )
expect ( json_response [ 'message' ] [ 'path' ] ) . to eq ( [ 'has already been taken' ] )
end
it 'fails if project to fork from does not exist' do
2021-02-22 17:27:13 +05:30
post api ( " /projects/ #{ non_existing_record_id } /fork " , user )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '404 Project Not Found' )
end
it 'forks with explicit own user namespace id' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace : user2 . namespace . id }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'owner' ] [ 'id' ] ) . to eq ( user2 . id )
end
it 'forks with explicit own user name as namespace' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace : user2 . username }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'owner' ] [ 'id' ] ) . to eq ( user2 . id )
end
it 'forks to another user when admin' do
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : { namespace : user2 . username }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'owner' ] [ 'id' ] ) . to eq ( user2 . id )
end
it 'fails if trying to fork to another user when not admin' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace : admin . namespace . id }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2017-08-17 22:00:37 +05:30
end
it 'fails if trying to fork to non-existent namespace' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace : non_existing_record_id }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
expect ( json_response [ 'message' ] ) . to eq ( '404 Namespace Not Found' )
2017-08-17 22:00:37 +05:30
end
it 'forks to owned group' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace : group2 . name }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'namespace' ] [ 'name' ] ) . to eq ( group2 . name )
end
2020-04-08 14:13:33 +05:30
context 'when namespace_id is specified' do
shared_examples_for 'forking to specified namespace_id' do
it 'forks to specified namespace_id' do
expect ( response ) . to have_gitlab_http_status ( :created )
expect ( json_response [ 'owner' ] [ 'id' ] ) . to eq ( user2 . id )
expect ( json_response [ 'namespace' ] [ 'id' ] ) . to eq ( user2 . namespace . id )
end
end
context 'and namespace_id is specified alone' do
before do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace_id : user2 . namespace . id }
2020-04-08 14:13:33 +05:30
end
it_behaves_like 'forking to specified namespace_id'
end
context 'and namespace_id and namespace are both specified' do
before do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace_id : user2 . namespace . id , namespace : admin . namespace . id }
2020-04-08 14:13:33 +05:30
end
it_behaves_like 'forking to specified namespace_id'
end
context 'and namespace_id and namespace_path are both specified' do
before do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace_id : user2 . namespace . id , namespace_path : admin . namespace . path }
2020-04-08 14:13:33 +05:30
end
it_behaves_like 'forking to specified namespace_id'
end
end
context 'when namespace_path is specified' do
shared_examples_for 'forking to specified namespace_path' do
it 'forks to specified namespace_path' do
expect ( response ) . to have_gitlab_http_status ( :created )
expect ( json_response [ 'owner' ] [ 'id' ] ) . to eq ( user2 . id )
expect ( json_response [ 'namespace' ] [ 'path' ] ) . to eq ( user2 . namespace . path )
end
end
context 'and namespace_path is specified alone' do
before do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace_path : user2 . namespace . path }
2020-04-08 14:13:33 +05:30
end
it_behaves_like 'forking to specified namespace_path'
end
context 'and namespace_path and namespace are both specified' do
before do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace_path : user2 . namespace . path , namespace : admin . namespace . path }
2020-04-08 14:13:33 +05:30
end
it_behaves_like 'forking to specified namespace_path'
end
end
2018-05-09 12:01:36 +05:30
it 'forks to owned subgroup' do
full_path = " #{ group2 . path } / #{ group3 . path } "
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace : full_path }
2018-05-09 12:01:36 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2018-05-09 12:01:36 +05:30
expect ( json_response [ 'namespace' ] [ 'name' ] ) . to eq ( group3 . name )
expect ( json_response [ 'namespace' ] [ 'full_path' ] ) . to eq ( full_path )
end
2017-08-17 22:00:37 +05:30
it 'fails to fork to not owned group' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { namespace : group . name }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
expect ( json_response [ 'message' ] ) . to eq ( " 404 Target Namespace Not Found " )
2017-08-17 22:00:37 +05:30
end
it 'forks to not owned group when admin' do
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true ) , params : { namespace : group . name }
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'namespace' ] [ 'name' ] ) . to eq ( group . name )
end
2019-07-07 11:18:12 +05:30
it 'accepts a path for the target project' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { path : 'foobar' }
2019-07-07 11:18:12 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'name' ] ) . to eq ( project . name )
expect ( json_response [ 'path' ] ) . to eq ( 'foobar' )
expect ( json_response [ 'owner' ] [ 'id' ] ) . to eq ( user2 . id )
expect ( json_response [ 'namespace' ] [ 'id' ] ) . to eq ( user2 . namespace . id )
expect ( json_response [ 'forked_from_project' ] [ 'id' ] ) . to eq ( project . id )
expect ( json_response [ 'import_status' ] ) . to eq ( 'scheduled' )
expect ( json_response ) . to include ( " import_error " )
end
it 'fails to fork if path is already taken' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { path : 'foobar' }
2019-07-07 11:18:12 +05:30
post api ( " /projects/ #{ project2 . id } /fork " , user2 ) , params : { path : 'foobar' }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :conflict )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'message' ] [ 'path' ] ) . to eq ( [ 'has already been taken' ] )
end
2021-03-11 19:13:27 +05:30
it 'accepts custom parameters for the target project' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) ,
2022-03-02 08:16:31 +05:30
params : {
name : 'My Random Project' ,
description : 'A description' ,
visibility : 'private' ,
mr_default_target_self : true
}
2019-07-07 11:18:12 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'name' ] ) . to eq ( 'My Random Project' )
expect ( json_response [ 'path' ] ) . to eq ( project . path )
expect ( json_response [ 'owner' ] [ 'id' ] ) . to eq ( user2 . id )
expect ( json_response [ 'namespace' ] [ 'id' ] ) . to eq ( user2 . namespace . id )
expect ( json_response [ 'forked_from_project' ] [ 'id' ] ) . to eq ( project . id )
2021-03-11 19:13:27 +05:30
expect ( json_response [ 'description' ] ) . to eq ( 'A description' )
expect ( json_response [ 'visibility' ] ) . to eq ( 'private' )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'import_status' ] ) . to eq ( 'scheduled' )
2022-03-02 08:16:31 +05:30
expect ( json_response [ 'mr_default_target_self' ] ) . to eq ( true )
2019-07-07 11:18:12 +05:30
expect ( json_response ) . to include ( " import_error " )
end
it 'fails to fork if name is already taken' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { name : 'My Random Project' }
2019-07-07 11:18:12 +05:30
post api ( " /projects/ #{ project2 . id } /fork " , user2 ) , params : { name : 'My Random Project' }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :conflict )
expect ( json_response [ 'message' ] [ 'name' ] ) . to eq ( [ 'has already been taken' ] )
end
it 'forks to the same namespace with alternative path and name' do
2023-06-20 00:43:36 +05:30
post api ( path , user ) , params : { path : 'path_2' , name : 'name_2' }
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
expect ( json_response [ 'name' ] ) . to eq ( 'name_2' )
expect ( json_response [ 'path' ] ) . to eq ( 'path_2' )
expect ( json_response [ 'owner' ] [ 'id' ] ) . to eq ( user . id )
expect ( json_response [ 'namespace' ] [ 'id' ] ) . to eq ( user . namespace . id )
expect ( json_response [ 'forked_from_project' ] [ 'id' ] ) . to eq ( project . id )
expect ( json_response [ 'import_status' ] ) . to eq ( 'scheduled' )
end
it 'fails to fork to the same namespace without alternative path and name' do
2023-06-20 00:43:36 +05:30
post api ( path , user )
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :conflict )
expect ( json_response [ 'message' ] [ 'path' ] ) . to eq ( [ 'has already been taken' ] )
2019-07-07 11:18:12 +05:30
expect ( json_response [ 'message' ] [ 'name' ] ) . to eq ( [ 'has already been taken' ] )
end
2021-03-11 19:13:27 +05:30
it 'fails to fork with an unknown visibility level' do
2023-06-20 00:43:36 +05:30
post api ( path , user2 ) , params : { visibility : 'something' }
2021-03-11 19:13:27 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
expect ( json_response [ 'error' ] ) . to eq ( 'visibility does not have a valid value' )
end
2017-08-17 22:00:37 +05:30
end
context 'when unauthenticated' do
it 'returns authentication error' do
2023-06-20 00:43:36 +05:30
post api ( path )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2017-08-17 22:00:37 +05:30
expect ( json_response [ 'message' ] ) . to eq ( '401 Unauthorized' )
end
end
2020-03-13 15:44:24 +05:30
context 'forking disabled' do
before do
project . project_feature . update_attribute (
:forking_access_level , ProjectFeature :: DISABLED )
end
it 'denies project to be forked' do
2023-06-20 00:43:36 +05:30
post api ( path , admin , admin_mode : true )
2020-03-13 15:44:24 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2020-03-13 15:44:24 +05:30
end
end
2017-08-17 22:00:37 +05:30
end
describe 'POST /projects/:id/housekeeping' do
2021-03-08 18:12:59 +05:30
let ( :housekeeping ) { Repositories :: HousekeepingService . new ( project ) }
2023-04-23 21:23:45 +05:30
let ( :params ) { { } }
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /housekeeping " }
2023-04-23 21:23:45 +05:30
2023-06-20 00:43:36 +05:30
subject ( :request ) { post api ( path , user ) , params : params }
2017-08-17 22:00:37 +05:30
before do
2023-04-23 21:23:45 +05:30
allow ( Repositories :: HousekeepingService ) . to receive ( :new ) . with ( project , :eager ) . and_return ( housekeeping )
2017-08-17 22:00:37 +05:30
end
context 'when authenticated as owner' do
it 'starts the housekeeping process' do
expect ( housekeeping ) . to receive ( :execute ) . once
2023-06-20 00:43:36 +05:30
request
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
2017-08-17 22:00:37 +05:30
end
2023-04-23 21:23:45 +05:30
it 'logs an audit event' do
expect ( housekeeping ) . to receive ( :execute ) . once . and_yield
expect ( :: Gitlab :: Audit :: Auditor ) . to receive ( :audit ) . with ( a_hash_including (
name : 'manually_trigger_housekeeping' ,
author : user ,
scope : project ,
target : project ,
message : " Housekeeping task: eager "
) )
2023-06-20 00:43:36 +05:30
request
2023-04-23 21:23:45 +05:30
end
context 'when requesting prune' do
let ( :params ) { { task : :prune } }
it 'triggers a prune' do
expect ( Repositories :: HousekeepingService ) . to receive ( :new ) . with ( project , :prune ) . and_return ( housekeeping )
expect ( housekeeping ) . to receive ( :execute ) . once
2023-06-20 00:43:36 +05:30
request
2023-04-23 21:23:45 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
end
end
context 'when requesting an unsupported task' do
let ( :params ) { { task : :unsupported_task } }
it 'responds with bad_request' do
expect ( Repositories :: HousekeepingService ) . not_to receive ( :new )
2023-06-20 00:43:36 +05:30
request
2023-04-23 21:23:45 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
end
end
2017-08-17 22:00:37 +05:30
context 'when housekeeping lease is taken' do
it 'returns conflict' do
2021-03-08 18:12:59 +05:30
expect ( housekeeping ) . to receive ( :execute ) . once . and_raise ( Repositories :: HousekeepingService :: LeaseTaken )
2017-08-17 22:00:37 +05:30
2023-06-20 00:43:36 +05:30
request
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :conflict )
2021-03-08 18:12:59 +05:30
expect ( json_response [ 'message' ] ) . to match ( / Somebody already triggered housekeeping for this resource / )
2017-08-17 22:00:37 +05:30
end
end
end
context 'when authenticated as developer' do
before do
2017-09-10 17:25:29 +05:30
project_member
2017-08-17 22:00:37 +05:30
end
it 'returns forbidden error' do
2023-06-20 00:43:36 +05:30
post api ( path , user3 )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
2017-08-17 22:00:37 +05:30
end
end
context 'when unauthenticated' do
it 'returns authentication error' do
2023-06-20 00:43:36 +05:30
post api ( path )
2017-08-17 22:00:37 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
2017-08-17 22:00:37 +05:30
end
end
end
2018-03-17 18:26:18 +05:30
2022-07-16 23:28:13 +05:30
describe 'POST /projects/:id/repository_size' do
let ( :update_statistics_service ) { Projects :: UpdateStatisticsService . new ( project , nil , statistics : [ :repository_size , :lfs_objects_size ] ) }
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /repository_size " }
2022-07-16 23:28:13 +05:30
before do
allow ( Projects :: UpdateStatisticsService ) . to receive ( :new ) . with ( project , nil , statistics : [ :repository_size , :lfs_objects_size ] ) . and_return ( update_statistics_service )
end
context 'when authenticated as owner' do
it 'starts the housekeeping process' do
expect ( update_statistics_service ) . to receive ( :execute ) . once
2023-06-20 00:43:36 +05:30
post api ( path , user )
2022-07-16 23:28:13 +05:30
expect ( response ) . to have_gitlab_http_status ( :created )
end
end
context 'when authenticated as developer' do
before do
project_member
end
it 'returns forbidden error' do
2023-06-20 00:43:36 +05:30
post api ( path , user3 )
2022-07-16 23:28:13 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
end
context 'when unauthenticated' do
it 'returns authentication error' do
2023-06-20 00:43:36 +05:30
post api ( path )
2022-07-16 23:28:13 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
end
end
end
2023-03-04 22:38:38 +05:30
2018-11-08 19:23:39 +05:30
describe 'PUT /projects/:id/transfer' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /transfer " }
2018-11-08 19:23:39 +05:30
context 'when authenticated as owner' do
let ( :group ) { create :group }
it 'transfers the project to the new namespace' do
group . add_owner ( user )
2023-06-20 00:43:36 +05:30
put api ( path , user ) , params : { namespace : group . id }
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
2018-11-08 19:23:39 +05:30
end
it 'fails when transferring to a non owned namespace' do
2023-06-20 00:43:36 +05:30
put api ( path , user ) , params : { namespace : group . id }
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2018-11-08 19:23:39 +05:30
end
it 'fails when transferring to an unknown namespace' do
2023-06-20 00:43:36 +05:30
put api ( path , user ) , params : { namespace : 'unknown' }
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :not_found )
2018-11-08 19:23:39 +05:30
end
it 'fails on missing namespace' do
2023-06-20 00:43:36 +05:30
put api ( path , user )
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2018-11-08 19:23:39 +05:30
end
end
2019-10-31 01:37:42 +05:30
context 'when authenticated as developer' do
before do
group . add_developer ( user )
end
context 'target namespace allows developers to create projects' do
let ( :group ) { create ( :group , project_creation_level : :: Gitlab :: Access :: DEVELOPER_MAINTAINER_PROJECT_ACCESS ) }
it 'fails transferring the project to the target namespace' do
2023-06-20 00:43:36 +05:30
put api ( path , user ) , params : { namespace : group . id }
2019-10-31 01:37:42 +05:30
2020-04-08 14:13:33 +05:30
expect ( response ) . to have_gitlab_http_status ( :bad_request )
2019-10-31 01:37:42 +05:30
end
end
end
2018-11-08 19:23:39 +05:30
end
2022-10-11 01:57:18 +05:30
describe 'GET /projects/:id/transfer_locations' do
let_it_be ( :user ) { create ( :user ) }
let_it_be ( :source_group ) { create ( :group ) }
let_it_be ( :project ) { create ( :project , group : source_group ) }
let ( :params ) { { } }
subject ( :request ) do
get api ( " /projects/ #{ project . id } /transfer_locations " , user ) , params : params
end
context 'when the user has rights to transfer the project' do
let_it_be ( :guest_group ) { create ( :group ) }
let_it_be ( :maintainer_group ) { create ( :group , name : 'maintainer group' , path : 'maintainer-group' ) }
let_it_be ( :owner_group ) { create ( :group , name : 'owner group' , path : 'owner-group' ) }
before do
source_group . add_owner ( user )
guest_group . add_guest ( user )
maintainer_group . add_maintainer ( user )
owner_group . add_owner ( user )
end
it 'returns 200' do
request
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( response ) . to include_pagination_headers
end
it 'includes groups where the user has permissions to transfer a project to' do
request
expect ( project_ids_from_response ) . to include ( maintainer_group . id , owner_group . id )
end
it 'does not include groups where the user doesn not have permissions to transfer a project' do
request
expect ( project_ids_from_response ) . not_to include ( guest_group . id )
end
context 'with search' do
let ( :params ) { { search : 'maintainer' } }
it 'includes groups where the user has permissions to transfer a project to' do
request
expect ( project_ids_from_response ) . to contain_exactly ( maintainer_group . id )
end
end
context 'group shares' do
let_it_be ( :shared_to_owner_group ) { create ( :group ) }
let_it_be ( :shared_to_guest_group ) { create ( :group ) }
before do
create ( :group_group_link , :owner ,
shared_with_group : owner_group ,
shared_group : shared_to_owner_group
)
create ( :group_group_link , :guest ,
shared_with_group : guest_group ,
shared_group : shared_to_guest_group
)
end
it 'only includes groups arising from group shares where the user has permission to transfer a project to' do
request
expect ( project_ids_from_response ) . to include ( shared_to_owner_group . id )
expect ( project_ids_from_response ) . not_to include ( shared_to_guest_group . id )
end
end
def project_ids_from_response
json_response . map { | project | project [ 'id' ] }
end
end
context 'when the user does not have permissions to transfer the project' do
before do
source_group . add_developer ( user )
end
it 'returns 403' do
request
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
end
end
2021-09-04 01:27:46 +05:30
describe 'GET /projects/:id/storage' do
2023-06-20 00:43:36 +05:30
let ( :path ) { " /projects/ #{ project . id } /storage " }
it_behaves_like 'GET request permissions for admin mode'
2021-09-04 01:27:46 +05:30
context 'when unauthenticated' do
it 'does not return project storage data' do
2023-06-20 00:43:36 +05:30
get api ( path )
2021-09-04 01:27:46 +05:30
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
end
end
it 'returns project storage data when user is admin' do
2023-06-20 00:43:36 +05:30
get api ( path , create ( :admin ) , admin_mode : true )
2021-09-04 01:27:46 +05:30
expect ( response ) . to have_gitlab_http_status ( :ok )
expect ( json_response [ 'project_id' ] ) . to eq ( project . id )
expect ( json_response [ 'disk_path' ] ) . to eq ( project . repository . disk_path )
expect ( json_response [ 'created_at' ] ) . to be_present
expect ( json_response [ 'repository_storage' ] ) . to eq ( project . repository_storage )
end
it 'does not return project storage data when user is not admin' do
2023-06-20 00:43:36 +05:30
get api ( path , user3 )
2021-09-04 01:27:46 +05:30
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
it 'responds with a 401 for unauthenticated users trying to access a non-existent project id' do
expect ( Project . find_by ( id : non_existing_record_id ) ) . to be_nil
get api ( " /projects/ #{ non_existing_record_id } /storage " )
expect ( response ) . to have_gitlab_http_status ( :unauthorized )
end
it 'responds with a 403 for non-admin users trying to access a non-existent project id' do
expect ( Project . find_by ( id : non_existing_record_id ) ) . to be_nil
get api ( " /projects/ #{ non_existing_record_id } /storage " , user3 )
expect ( response ) . to have_gitlab_http_status ( :forbidden )
end
end
2018-03-17 18:26:18 +05:30
it_behaves_like 'custom attributes endpoints' , 'projects' do
let ( :attributable ) { project }
let ( :other_attributable ) { project2 }
end
2014-09-02 18:07:02 +05:30
end