2019-07-31 22:56:46 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
require 'spec_helper'
2023-05-27 22:25:52 +05:30
RSpec . describe Projects :: TransferService , feature_category : :projects do
2020-11-24 15:15:51 +05:30
let_it_be ( :group ) { create ( :group ) }
2022-04-04 11:22:00 +05:30
let_it_be ( :user ) { create ( :user ) }
2021-12-11 22:18:48 +05:30
let_it_be ( :group_integration ) { create ( :integrations_slack , :group , group : group , webhook : 'http://group.slack.com' ) }
2021-09-30 23:02:18 +05:30
2018-03-27 19:54:05 +05:30
let ( :project ) { create ( :project , :repository , :legacy_storage , namespace : user . namespace ) }
2022-04-04 11:22:00 +05:30
let ( :target ) { group }
2022-06-21 17:19:12 +05:30
let ( :executor ) { user }
2014-09-02 18:07:02 +05:30
2022-06-21 17:19:12 +05:30
subject ( :execute_transfer ) { described_class . new ( project , executor ) . execute ( target ) . tap { project . reload } }
2020-05-24 23:13:21 +05:30
2020-10-24 23:57:45 +05:30
context 'with npm packages' do
before do
group . add_owner ( user )
end
subject ( :transfer_service ) { described_class . new ( project , user ) }
2023-07-09 08:55:56 +05:30
let! ( :package ) { create ( :npm_package , project : project , name : " @testscope/test " ) }
2020-10-24 23:57:45 +05:30
context 'with a root namespace change' do
2023-07-09 08:55:56 +05:30
it 'allow the transfer' do
expect ( transfer_service . execute ( group ) ) . to be true
expect ( project . errors [ :new_namespace ] ) . to be_empty
end
end
context 'with pending destruction package' do
before do
package . pending_destruction!
end
it 'allow the transfer' do
expect ( transfer_service . execute ( group ) ) . to be true
expect ( project . errors [ :new_namespace ] ) . to be_empty
end
end
context 'with namespaced packages present' do
let! ( :package ) { create ( :npm_package , project : project , name : " @ #{ project . root_namespace . path } /test " ) }
2020-10-24 23:57:45 +05:30
it 'does not allow the transfer' do
expect ( transfer_service . execute ( group ) ) . to be false
2023-07-09 08:55:56 +05:30
expect ( project . errors [ :new_namespace ] ) . to include ( " Root namespace can't be updated if the project has NPM packages scoped to the current root level namespace. " )
2020-10-24 23:57:45 +05:30
end
end
context 'without a root namespace change' do
let ( :root ) { create ( :group ) }
let ( :group ) { create ( :group , parent : root ) }
let ( :other_group ) { create ( :group , parent : root ) }
let ( :project ) { create ( :project , :repository , namespace : group ) }
before do
other_group . add_owner ( user )
end
2023-07-09 08:55:56 +05:30
it 'allow the transfer' do
2020-10-24 23:57:45 +05:30
expect ( transfer_service . execute ( other_group ) ) . to be true
expect ( project . errors [ :new_namespace ] ) . to be_empty
end
end
end
2014-09-02 18:07:02 +05:30
context 'namespace -> namespace' do
before do
2020-05-24 23:13:21 +05:30
allow_next_instance_of ( Gitlab :: UploadsTransfer ) do | service |
allow ( service ) . to receive ( :move_project ) . and_return ( true )
end
2014-09-02 18:07:02 +05:30
group . add_owner ( user )
end
2020-05-24 23:13:21 +05:30
it 'updates the namespace' do
transfer_result = execute_transfer
expect ( transfer_result ) . to be_truthy
expect ( project . namespace ) . to eq ( group )
end
2021-11-18 22:05:49 +05:30
2022-08-27 11:52:29 +05:30
context 'EventStore' do
let ( :group ) do
create ( :group , :nested ) . tap { | g | g . add_owner ( user ) }
end
let ( :target ) do
create ( :group , :nested ) . tap { | g | g . add_owner ( user ) }
end
let ( :project ) { create ( :project , namespace : group ) }
it 'publishes a ProjectTransferedEvent' do
expect { execute_transfer }
. to publish_event ( Projects :: ProjectTransferedEvent )
. with (
project_id : project . id ,
old_namespace_id : group . id ,
old_root_namespace_id : group . root_ancestor . id ,
new_namespace_id : target . id ,
new_root_namespace_id : target . root_ancestor . id
)
end
end
2021-11-18 22:05:49 +05:30
context 'when project has an associated project namespace' do
it 'keeps project namespace in sync with project' do
transfer_result = execute_transfer
expect ( transfer_result ) . to be_truthy
project_namespace_in_sync ( group )
end
context 'when project is transferred to a deeper nested group' do
let ( :parent_group ) { create ( :group ) }
let ( :sub_group ) { create ( :group , parent : parent_group ) }
let ( :sub_sub_group ) { create ( :group , parent : sub_group ) }
let ( :group ) { sub_sub_group }
it 'keeps project namespace in sync with project' do
transfer_result = execute_transfer
expect ( transfer_result ) . to be_truthy
project_namespace_in_sync ( sub_sub_group )
end
end
end
2014-09-02 18:07:02 +05:30
end
2022-06-21 17:19:12 +05:30
context 'project in a group -> a personal namespace' , :enable_admin_mode do
let ( :project ) { create ( :project , :repository , :legacy_storage , group : group ) }
let ( :target ) { user . namespace }
# We need to use an admin user as the executor because
# only an admin user has required permissions to transfer projects
# under _all_ the different circumstances specified below.
let ( :executor ) { create ( :user , :admin ) }
it 'executes the transfer to personal namespace successfully' do
execute_transfer
expect ( project . namespace ) . to eq ( user . namespace )
end
2023-04-23 21:23:45 +05:30
it 'invalidates personal_project_count cache of the the owner of the personal namespace' do
expect ( user ) . to receive ( :invalidate_personal_projects_count )
execute_transfer
end
2022-06-21 17:19:12 +05:30
context 'the owner of the namespace does not have a direct membership in the project residing in the group' do
it 'creates a project membership record for the owner of the namespace, with OWNER access level, after the transfer' do
execute_transfer
expect ( project . members . owners . find_by ( user_id : user . id ) ) . to be_present
end
end
context 'the owner of the namespace has a direct membership in the project residing in the group' do
context 'that membership has an access level of OWNER' do
before do
project . add_owner ( user )
end
it 'retains the project membership record for the owner of the namespace, with OWNER access level, after the transfer' do
execute_transfer
expect ( project . members . owners . find_by ( user_id : user . id ) ) . to be_present
end
end
context 'that membership has an access level that is not OWNER' do
before do
project . add_developer ( user )
end
it 'updates the project membership record for the owner of the namespace, to OWNER access level, after the transfer' do
execute_transfer
expect ( project . members . owners . find_by ( user_id : user . id ) ) . to be_present
end
end
end
end
2023-04-23 21:23:45 +05:30
context 'personal namespace -> group' , :enable_admin_mode do
let ( :executor ) { create ( :admin ) }
it 'invalidates personal_project_count cache of the the owner of the personal namespace' \
'that previously held the project' do
expect ( user ) . to receive ( :invalidate_personal_projects_count )
execute_transfer
end
end
2017-09-10 17:25:29 +05:30
context 'when transfer succeeds' do
before do
group . add_owner ( user )
end
it 'sends notifications' do
expect_any_instance_of ( NotificationService ) . to receive ( :project_was_moved )
2020-05-24 23:13:21 +05:30
execute_transfer
2017-09-10 17:25:29 +05:30
end
2018-05-09 12:01:36 +05:30
it 'invalidates the user\'s personal_project_count cache' do
expect ( user ) . to receive ( :invalidate_personal_projects_count )
2020-05-24 23:13:21 +05:30
execute_transfer
2018-05-09 12:01:36 +05:30
end
2017-09-10 17:25:29 +05:30
it 'executes system hooks' do
2020-05-24 23:13:21 +05:30
expect_next_instance_of ( described_class ) do | service |
2017-09-10 17:25:29 +05:30
expect ( service ) . to receive ( :execute_system_hooks )
end
2020-05-24 23:13:21 +05:30
execute_transfer
2017-09-10 17:25:29 +05:30
end
2018-03-17 18:26:18 +05:30
2020-03-13 15:44:24 +05:30
it 'moves the disk path' , :aggregate_failures do
2018-03-17 18:26:18 +05:30
old_path = project . repository . disk_path
old_full_path = project . repository . full_path
2020-05-24 23:13:21 +05:30
execute_transfer
2020-03-13 15:44:24 +05:30
project . reload_repository!
2018-03-17 18:26:18 +05:30
expect ( project . repository . disk_path ) . not_to eq ( old_path )
expect ( project . repository . full_path ) . not_to eq ( old_full_path )
expect ( project . disk_path ) . not_to eq ( old_path )
expect ( project . disk_path ) . to start_with ( group . path )
end
2022-08-27 11:52:29 +05:30
it 'updates project full path in gitaly' do
2020-05-24 23:13:21 +05:30
execute_transfer
2018-03-17 18:26:18 +05:30
2022-08-27 11:52:29 +05:30
expect ( project . repository . full_path ) . to eq " #{ group . full_path } / #{ project . path } "
2018-03-17 18:26:18 +05:30
end
2019-02-15 15:39:39 +05:30
it 'updates storage location' do
2020-05-24 23:13:21 +05:30
execute_transfer
2019-02-15 15:39:39 +05:30
expect ( project . project_repository ) . to have_attributes (
disk_path : " #{ group . full_path } / #{ project . path } " ,
shard_name : project . repository_storage
)
end
2021-02-22 17:27:13 +05:30
context 'with a project integration' do
let_it_be_with_reload ( :project ) { create ( :project , namespace : user . namespace ) }
2022-06-21 17:19:12 +05:30
let_it_be ( :instance_integration ) { create ( :integrations_slack , :instance ) }
let_it_be ( :project_integration ) { create ( :integrations_slack , project : project ) }
2021-02-22 17:27:13 +05:30
2022-06-21 17:19:12 +05:30
context 'when it inherits from instance_integration' do
before do
project_integration . update! ( inherit_from_id : instance_integration . id , webhook : instance_integration . webhook )
end
2021-02-22 17:27:13 +05:30
it 'replaces inherited integrations' , :aggregate_failures do
2022-06-21 17:19:12 +05:30
expect { execute_transfer }
. to change ( Integration , :count ) . by ( 0 )
. and change { project . slack_integration . webhook } . to eq ( group_integration . webhook )
2021-02-22 17:27:13 +05:30
end
end
context 'with a custom integration' do
2022-06-21 17:19:12 +05:30
it 'does not update the integrations' do
2021-09-30 23:02:18 +05:30
expect { execute_transfer } . not_to change { project . slack_integration . webhook }
2021-02-22 17:27:13 +05:30
end
end
end
2021-11-18 22:05:49 +05:30
2022-01-26 12:08:38 +05:30
context 'when project has pending builds' , :sidekiq_inline do
2021-11-18 22:05:49 +05:30
let! ( :other_project ) { create ( :project ) }
let! ( :pending_build ) { create ( :ci_pending_build , project : project . reload ) }
let! ( :unrelated_pending_build ) { create ( :ci_pending_build , project : other_project ) }
before do
group . reload
end
it 'updates pending builds for the project' , :aggregate_failures do
execute_transfer
pending_build . reload
unrelated_pending_build . reload
expect ( pending_build . namespace_id ) . to eq ( group . id )
expect ( pending_build . namespace_traversal_ids ) . to eq ( group . traversal_ids )
expect ( unrelated_pending_build . namespace_id ) . to eq ( other_project . namespace_id )
expect ( unrelated_pending_build . namespace_traversal_ids ) . to eq ( other_project . namespace . traversal_ids )
end
end
2017-09-10 17:25:29 +05:30
end
context 'when transfer fails' do
2023-03-04 22:38:38 +05:30
let! ( :original_path ) { project . repository . relative_path }
2017-09-10 17:25:29 +05:30
def attempt_project_transfer ( & block )
expect do
2020-05-24 23:13:21 +05:30
execute_transfer
2017-09-10 17:25:29 +05:30
end . to raise_error ( ActiveRecord :: ActiveRecordError )
end
before do
group . add_owner ( user )
expect_any_instance_of ( Labels :: TransferService ) . to receive ( :execute ) . and_raise ( ActiveRecord :: StatementInvalid , " PG ERROR " )
end
it 'rolls back repo location' do
attempt_project_transfer
2020-04-08 14:13:33 +05:30
expect ( project . repository . raw . exists? ) . to be ( true )
2023-03-04 22:38:38 +05:30
expect ( original_path ) . to eq project . repository . relative_path
2017-09-10 17:25:29 +05:30
end
2022-08-27 11:52:29 +05:30
it 'rolls back project full path in gitaly' do
2018-03-17 18:26:18 +05:30
attempt_project_transfer
2022-08-27 11:52:29 +05:30
expect ( project . repository . full_path ) . to eq project . full_path
2018-03-17 18:26:18 +05:30
end
2017-09-10 17:25:29 +05:30
it " doesn't send move notifications " do
expect_any_instance_of ( NotificationService ) . not_to receive ( :project_was_moved )
attempt_project_transfer
end
it " doesn't run system hooks " do
attempt_project_transfer do | service |
expect ( service ) . not_to receive ( :execute_system_hooks )
end
end
2019-02-15 15:39:39 +05:30
it 'does not update storage location' do
attempt_project_transfer
expect ( project . project_repository ) . to have_attributes (
disk_path : project . disk_path ,
shard_name : project . repository_storage
)
end
2021-11-18 22:05:49 +05:30
2022-08-27 11:52:29 +05:30
it 'does not publish a ProjectTransferedEvent' do
expect { attempt_project_transfer }
. not_to publish_event ( Projects :: ProjectTransferedEvent )
end
2022-01-26 12:08:38 +05:30
context 'when project has pending builds' , :sidekiq_inline do
2021-11-18 22:05:49 +05:30
let! ( :other_project ) { create ( :project ) }
let! ( :pending_build ) { create ( :ci_pending_build , project : project . reload ) }
let! ( :unrelated_pending_build ) { create ( :ci_pending_build , project : other_project ) }
it 'does not update pending builds for the project' , :aggregate_failures do
attempt_project_transfer
pending_build . reload
unrelated_pending_build . reload
expect ( pending_build . namespace_id ) . to eq ( project . namespace_id )
expect ( pending_build . namespace_traversal_ids ) . to eq ( project . namespace . traversal_ids )
expect ( unrelated_pending_build . namespace_id ) . to eq ( other_project . namespace_id )
expect ( unrelated_pending_build . namespace_traversal_ids ) . to eq ( other_project . namespace . traversal_ids )
end
end
context 'when project has an associated project namespace' do
it 'keeps project namespace in sync with project' do
attempt_project_transfer
project_namespace_in_sync ( user . namespace )
end
end
2017-09-10 17:25:29 +05:30
end
2014-09-02 18:07:02 +05:30
context 'namespace -> no namespace' do
2020-05-24 23:13:21 +05:30
let ( :group ) { nil }
it 'does not allow the project transfer' do
transfer_result = execute_transfer
2014-09-02 18:07:02 +05:30
2020-05-24 23:13:21 +05:30
expect ( transfer_result ) . to eq false
expect ( project . namespace ) . to eq ( user . namespace )
expect ( project . errors . messages [ :new_namespace ] . first ) . to eq 'Please select a new namespace for your project.'
end
2021-11-18 22:05:49 +05:30
context 'when project has an associated project namespace' do
it 'keeps project namespace in sync with project' do
transfer_result = execute_transfer
expect ( transfer_result ) . to be false
project_namespace_in_sync ( user . namespace )
end
end
2014-09-02 18:07:02 +05:30
end
2018-12-13 13:39:08 +05:30
context 'disallow transferring of project with tags' do
2017-08-17 22:00:37 +05:30
let ( :container_repository ) { create ( :container_repository ) }
2016-06-02 11:05:42 +05:30
before do
stub_container_registry_config ( enabled : true )
2017-08-17 22:00:37 +05:30
stub_container_registry_tags ( repository : :any , tags : [ 'tag' ] )
project . container_repositories << container_repository
2016-06-02 11:05:42 +05:30
end
2020-05-24 23:13:21 +05:30
it 'does not allow the project transfer' do
expect ( execute_transfer ) . to eq false
end
2016-06-02 11:05:42 +05:30
end
2014-09-02 18:07:02 +05:30
context 'namespace -> not allowed namespace' do
2020-05-24 23:13:21 +05:30
it 'does not allow the project transfer' do
transfer_result = execute_transfer
2014-09-02 18:07:02 +05:30
2020-05-24 23:13:21 +05:30
expect ( transfer_result ) . to eq false
expect ( project . namespace ) . to eq ( user . namespace )
end
2015-04-26 12:48:37 +05:30
end
2017-09-10 17:25:29 +05:30
context 'namespace which contains orphan repository with same projects path name' do
2022-08-13 15:12:31 +05:30
let ( :raw_fake_repo ) { Gitlab :: Git :: Repository . new ( 'default' , File . join ( group . full_path , " #{ project . path } .git " ) , nil , nil ) }
2017-09-10 17:25:29 +05:30
before do
group . add_owner ( user )
2018-03-17 18:26:18 +05:30
2022-08-13 15:12:31 +05:30
raw_fake_repo . create_repository
2017-09-10 17:25:29 +05:30
end
after do
2022-08-13 15:12:31 +05:30
raw_fake_repo . remove
2017-09-10 17:25:29 +05:30
end
2020-05-24 23:13:21 +05:30
it 'does not allow the project transfer' do
transfer_result = execute_transfer
expect ( transfer_result ) . to eq false
expect ( project . namespace ) . to eq ( user . namespace )
expect ( project . errors [ :new_namespace ] ) . to include ( 'Cannot move project' )
end
2017-09-10 17:25:29 +05:30
end
2018-11-20 20:47:30 +05:30
context 'target namespace containing the same project name' do
before do
group . add_owner ( user )
2020-05-24 23:13:21 +05:30
create ( :project , name : project . name , group : group , path : 'other' )
end
2018-11-20 20:47:30 +05:30
2020-05-24 23:13:21 +05:30
it 'does not allow the project transfer' do
transfer_result = execute_transfer
2018-11-20 20:47:30 +05:30
2020-05-24 23:13:21 +05:30
expect ( transfer_result ) . to eq false
expect ( project . namespace ) . to eq ( user . namespace )
expect ( project . errors [ :new_namespace ] ) . to include ( 'Project with same name or path in target namespace already exists' )
2018-11-20 20:47:30 +05:30
end
end
context 'target namespace containing the same project path' do
before do
group . add_owner ( user )
create ( :project , name : 'other-name' , path : project . path , group : group )
end
2020-05-24 23:13:21 +05:30
it 'does not allow the project transfer' do
transfer_result = execute_transfer
expect ( transfer_result ) . to eq false
expect ( project . namespace ) . to eq ( user . namespace )
expect ( project . errors [ :new_namespace ] ) . to include ( 'Project with same name or path in target namespace already exists' )
end
2018-11-20 20:47:30 +05:30
end
2021-11-11 11:23:49 +05:30
context 'target namespace matches current namespace' do
let ( :group ) { user . namespace }
it 'does not allow project transfer' do
transfer_result = execute_transfer
expect ( transfer_result ) . to eq false
expect ( project . namespace ) . to eq ( user . namespace )
expect ( project . errors [ :new_namespace ] ) . to include ( 'Project is already in this namespace.' )
end
end
2023-03-04 22:38:38 +05:30
context 'target namespace belongs to bot user' , :enable_admin_mode do
let ( :bot ) { create ( :user , :project_bot ) }
let ( :target ) { bot . namespace }
let ( :executor ) { create ( :user , :admin ) }
it 'does not allow project transfer' do
namespace = project . namespace
transfer_result = execute_transfer
expect ( transfer_result ) . to eq false
expect ( project . namespace ) . to eq ( namespace )
expect ( project . errors [ :new_namespace ] ) . to include ( " You don't have permission to transfer projects into that namespace. " )
end
end
2021-11-11 11:23:49 +05:30
context 'when user does not own the project' do
let ( :project ) { create ( :project , :repository , :legacy_storage ) }
before do
project . add_developer ( user )
end
it 'does not allow project transfer to the target namespace' do
transfer_result = execute_transfer
expect ( transfer_result ) . to eq false
expect ( project . errors [ :new_namespace ] ) . to include ( " You don't have permission to transfer this project. " )
end
end
context 'when user can create projects in the target namespace' do
2019-10-31 01:37:42 +05:30
let ( :group ) { create ( :group , project_creation_level : :: Gitlab :: Access :: DEVELOPER_MAINTAINER_PROJECT_ACCESS ) }
2021-11-11 11:23:49 +05:30
context 'but has only developer permissions in the target namespace' do
2019-10-31 01:37:42 +05:30
before do
group . add_developer ( user )
end
it 'does not allow project transfer to the target namespace' do
2020-05-24 23:13:21 +05:30
transfer_result = execute_transfer
expect ( transfer_result ) . to eq false
2019-10-31 01:37:42 +05:30
expect ( project . namespace ) . to eq ( user . namespace )
2021-11-11 11:23:49 +05:30
expect ( project . errors [ :new_namespace ] ) . to include ( " You don't have permission to transfer projects into that namespace. " )
2019-10-31 01:37:42 +05:30
end
end
end
2016-06-02 11:05:42 +05:30
context 'visibility level' do
2020-05-24 23:13:21 +05:30
let ( :group ) { create ( :group , :internal ) }
2016-06-02 11:05:42 +05:30
2017-09-10 17:25:29 +05:30
before do
2020-05-24 23:13:21 +05:30
group . add_owner ( user )
2017-09-10 17:25:29 +05:30
end
2016-06-02 11:05:42 +05:30
context 'when namespace visibility level < project visibility level' do
2020-05-24 23:13:21 +05:30
let ( :project ) { create ( :project , :public , :repository , namespace : user . namespace ) }
2016-06-02 11:05:42 +05:30
2017-09-10 17:25:29 +05:30
before do
2020-05-24 23:13:21 +05:30
execute_transfer
2017-09-10 17:25:29 +05:30
end
2016-06-02 11:05:42 +05:30
2020-05-24 23:13:21 +05:30
it { expect ( project . visibility_level ) . to eq ( group . visibility_level ) }
2016-06-02 11:05:42 +05:30
end
context 'when namespace visibility level > project visibility level' do
2020-05-24 23:13:21 +05:30
let ( :project ) { create ( :project , :private , :repository , namespace : user . namespace ) }
2016-06-02 11:05:42 +05:30
2017-09-10 17:25:29 +05:30
before do
2020-05-24 23:13:21 +05:30
execute_transfer
2017-09-10 17:25:29 +05:30
end
2016-06-02 11:05:42 +05:30
2020-05-24 23:13:21 +05:30
it { expect ( project . visibility_level ) . to eq ( Gitlab :: VisibilityLevel :: PRIVATE ) }
2016-06-02 11:05:42 +05:30
end
end
2021-01-03 14:25:43 +05:30
context 'shared Runners group level configurations' do
using RSpec :: Parameterized :: TableSyntax
where ( :project_shared_runners_enabled , :shared_runners_setting , :expected_shared_runners_enabled ) do
2021-11-18 22:05:49 +05:30
true | :disabled_and_unoverridable | false
false | :disabled_and_unoverridable | false
2023-03-17 16:20:25 +05:30
true | :disabled_and_overridable | true
false | :disabled_and_overridable | false
2021-11-18 22:05:49 +05:30
true | :shared_runners_enabled | true
false | :shared_runners_enabled | false
2021-01-03 14:25:43 +05:30
end
with_them do
let ( :project ) { create ( :project , :public , :repository , namespace : user . namespace , shared_runners_enabled : project_shared_runners_enabled ) }
2021-11-18 22:05:49 +05:30
let ( :group ) { create ( :group , shared_runners_setting ) }
2021-01-03 14:25:43 +05:30
2021-11-18 22:05:49 +05:30
it 'updates shared runners based on the parent group' do
2021-01-03 14:25:43 +05:30
group . add_owner ( user )
2021-11-18 22:05:49 +05:30
expect ( execute_transfer ) . to eq ( true )
2021-01-03 14:25:43 +05:30
expect ( project . shared_runners_enabled ) . to eq ( expected_shared_runners_enabled )
end
end
end
2016-11-03 12:29:30 +05:30
context 'missing group labels applied to issues or merge requests' do
2019-12-04 20:38:33 +05:30
it 'delegates transfer to Labels::TransferService' do
2016-11-03 12:29:30 +05:30
group . add_owner ( user )
2020-05-24 23:13:21 +05:30
expect_next_instance_of ( Labels :: TransferService , user , project . group , project ) do | labels_transfer_service |
expect ( labels_transfer_service ) . to receive ( :execute ) . once . and_call_original
end
2016-11-03 12:29:30 +05:30
2020-05-24 23:13:21 +05:30
execute_transfer
2016-11-03 12:29:30 +05:30
end
end
2017-08-17 22:00:37 +05:30
2019-12-04 20:38:33 +05:30
context 'missing group milestones applied to issues or merge requests' do
it 'delegates transfer to Milestones::TransferService' do
group . add_owner ( user )
2020-05-24 23:13:21 +05:30
expect_next_instance_of ( Milestones :: TransferService , user , project . group , project ) do | milestones_transfer_service |
expect ( milestones_transfer_service ) . to receive ( :execute ) . once . and_call_original
end
2019-12-04 20:38:33 +05:30
2020-05-24 23:13:21 +05:30
execute_transfer
2019-12-04 20:38:33 +05:30
end
end
2018-03-17 18:26:18 +05:30
context 'when hashed storage in use' do
2020-05-24 23:13:21 +05:30
let! ( :project ) { create ( :project , :repository , namespace : user . namespace ) }
let! ( :old_disk_path ) { project . repository . disk_path }
2018-03-17 18:26:18 +05:30
before do
group . add_owner ( user )
end
2020-03-13 15:44:24 +05:30
it 'does not move the disk path' , :aggregate_failures do
2020-05-24 23:13:21 +05:30
new_full_path = " #{ group . full_path } / #{ project . path } "
2018-03-17 18:26:18 +05:30
2020-05-24 23:13:21 +05:30
execute_transfer
2018-03-17 18:26:18 +05:30
2020-05-24 23:13:21 +05:30
project . reload_repository!
expect ( project . repository ) . to have_attributes (
2020-03-13 15:44:24 +05:30
disk_path : old_disk_path ,
full_path : new_full_path
)
2020-05-24 23:13:21 +05:30
expect ( project . disk_path ) . to eq ( old_disk_path )
2020-03-13 15:44:24 +05:30
end
it 'does not move the disk path when the transfer fails' , :aggregate_failures do
2020-05-24 23:13:21 +05:30
old_full_path = project . full_path
2020-03-13 15:44:24 +05:30
expect_next_instance_of ( described_class ) do | service |
allow ( service ) . to receive ( :execute_system_hooks ) . and_raise ( 'foo' )
end
2020-05-24 23:13:21 +05:30
expect { execute_transfer } . to raise_error ( 'foo' )
project . reload_repository!
2020-03-13 15:44:24 +05:30
2020-05-24 23:13:21 +05:30
expect ( project . repository ) . to have_attributes (
2020-03-13 15:44:24 +05:30
disk_path : old_disk_path ,
full_path : old_full_path
)
2020-05-24 23:13:21 +05:30
expect ( project . disk_path ) . to eq ( old_disk_path )
2018-03-17 18:26:18 +05:30
end
end
2017-08-17 22:00:37 +05:30
describe 'refreshing project authorizations' do
2021-09-30 23:02:18 +05:30
let ( :old_group ) { create ( :group ) }
let! ( :project ) { create ( :project , namespace : old_group ) }
let ( :member_of_old_group ) { create ( :user ) }
2017-08-17 22:00:37 +05:30
let ( :group ) { create ( :group ) }
2021-09-30 23:02:18 +05:30
let ( :member_of_new_group ) { create ( :user ) }
2017-08-17 22:00:37 +05:30
before do
2021-09-30 23:02:18 +05:30
old_group . add_developer ( member_of_old_group )
group . add_maintainer ( member_of_new_group )
# Add the executing user as owner in both groups, so that
# transfer can be executed.
old_group . add_owner ( user )
group . add_owner ( user )
2017-08-17 22:00:37 +05:30
end
2021-11-18 22:05:49 +05:30
it 'calls AuthorizedProjectUpdate::ProjectRecalculateWorker to update project authorizations' do
expect ( AuthorizedProjectUpdate :: ProjectRecalculateWorker )
. to receive ( :perform_async ) . with ( project . id )
2021-09-30 23:02:18 +05:30
2021-11-18 22:05:49 +05:30
execute_transfer
2017-08-17 22:00:37 +05:30
end
2021-11-18 22:05:49 +05:30
it 'calls AuthorizedProjectUpdate::UserRefreshFromReplicaWorker with a delay to update project authorizations' do
2023-04-23 21:23:45 +05:30
stub_feature_flags ( do_not_run_safety_net_auth_refresh_jobs : false )
2021-11-18 22:05:49 +05:30
user_ids = [ user . id , member_of_old_group . id , member_of_new_group . id ] . map { | id | [ id ] }
2021-09-30 23:02:18 +05:30
2021-11-18 22:05:49 +05:30
expect ( AuthorizedProjectUpdate :: UserRefreshFromReplicaWorker ) . to (
2023-06-20 00:43:36 +05:30
receive ( :bulk_perform_in ) . with (
1 . hour ,
user_ids ,
batch_delay : 30 . seconds , batch_size : 100
)
2021-11-18 22:05:49 +05:30
)
2021-09-30 23:02:18 +05:30
2021-11-18 22:05:49 +05:30
subject
end
2021-09-30 23:02:18 +05:30
2021-11-18 22:05:49 +05:30
it 'refreshes the permissions of the members of the old and new namespace' , :sidekiq_inline do
expect { execute_transfer }
. to change { member_of_old_group . authorized_projects . include? ( project ) } . from ( true ) . to ( false )
. and change { member_of_new_group . authorized_projects . include? ( project ) } . from ( false ) . to ( true )
2020-05-24 23:13:21 +05:30
end
end
describe 'transferring a design repository' do
subject { described_class . new ( project , user ) }
before do
group . add_owner ( user )
end
def design_repository
project . design_repository
end
2023-07-09 08:55:56 +05:30
def clear_design_repo_memoization
project . design_management_repository . clear_memoization ( :repository )
project . clear_memoization ( :design_repository )
end
2020-05-24 23:13:21 +05:30
it 'does not create a design repository' do
expect ( subject . execute ( group ) ) . to be true
2023-07-09 08:55:56 +05:30
clear_design_repo_memoization
2020-05-24 23:13:21 +05:30
expect ( design_repository . exists? ) . to be false
end
2017-08-17 22:00:37 +05:30
2020-05-24 23:13:21 +05:30
describe 'when the project has a design repository' do
let ( :project_repo_path ) { " #{ project . path } #{ :: Gitlab :: GlRepository :: DESIGN . path_suffix } " }
let ( :old_full_path ) { " #{ user . namespace . full_path } / #{ project_repo_path } " }
let ( :new_full_path ) { " #{ group . full_path } / #{ project_repo_path } " }
context 'with legacy storage' do
let ( :project ) { create ( :project , :repository , :legacy_storage , :design_repo , namespace : user . namespace ) }
it 'moves the repository' do
expect ( subject . execute ( group ) ) . to be true
2023-07-09 08:55:56 +05:30
clear_design_repo_memoization
2020-05-24 23:13:21 +05:30
expect ( design_repository ) . to have_attributes (
disk_path : new_full_path ,
full_path : new_full_path
)
end
it 'does not move the repository when an error occurs' , :aggregate_failures do
allow ( subject ) . to receive ( :execute_system_hooks ) . and_raise ( 'foo' )
expect { subject . execute ( group ) } . to raise_error ( 'foo' )
2023-07-09 08:55:56 +05:30
clear_design_repo_memoization
2020-05-24 23:13:21 +05:30
expect ( design_repository ) . to have_attributes (
disk_path : old_full_path ,
full_path : old_full_path
)
end
end
context 'with hashed storage' do
let ( :project ) { create ( :project , :repository , namespace : user . namespace ) }
it 'does not move the repository' do
old_disk_path = design_repository . disk_path
expect ( subject . execute ( group ) ) . to be true
2023-07-09 08:55:56 +05:30
clear_design_repo_memoization
2020-05-24 23:13:21 +05:30
expect ( design_repository ) . to have_attributes (
disk_path : old_disk_path ,
full_path : new_full_path
)
end
it 'does not move the repository when an error occurs' do
old_disk_path = design_repository . disk_path
allow ( subject ) . to receive ( :execute_system_hooks ) . and_raise ( 'foo' )
expect { subject . execute ( group ) } . to raise_error ( 'foo' )
2023-07-09 08:55:56 +05:30
clear_design_repo_memoization
2020-05-24 23:13:21 +05:30
expect ( design_repository ) . to have_attributes (
disk_path : old_disk_path ,
full_path : old_full_path
)
end
end
2017-08-17 22:00:37 +05:30
end
end
2018-11-08 19:23:39 +05:30
2022-04-04 11:22:00 +05:30
context 'handling issue contacts' do
let_it_be ( :root_group ) { create ( :group ) }
let ( :project ) { create ( :project , group : root_group ) }
before do
root_group . add_owner ( user )
target . add_owner ( user )
create_list ( :issue_customer_relations_contact , 2 , :for_issue , issue : create ( :issue , project : project ) )
end
context 'with the same root_ancestor' do
let ( :target ) { create ( :group , parent : root_group ) }
it 'retains issue contacts' do
expect { execute_transfer } . not_to change { CustomerRelations :: IssueContact . count }
end
end
context 'with a different root_ancestor' do
it 'deletes issue contacts' do
expect { execute_transfer } . to change { CustomerRelations :: IssueContact . count } . by ( - 2 )
end
end
end
2021-11-18 22:05:49 +05:30
def project_namespace_in_sync ( group )
project . reload
expect ( project . namespace ) . to eq ( group )
expect ( project . project_namespace . visibility_level ) . to eq ( project . visibility_level )
expect ( project . project_namespace . path ) . to eq ( project . path )
expect ( project . project_namespace . parent ) . to eq ( project . namespace )
expect ( project . project_namespace . traversal_ids ) . to eq ( [ * project . namespace . traversal_ids , project . project_namespace . id ] )
end
2014-09-02 18:07:02 +05:30
end