transfer_service.rb 2.63 KB
Newer Older
1
2
3
4
5
6
7
8
# Projects::TransferService class
#
# Used for transfer project to another namespace
#
# Ex.
#   # Move projects to namespace with ID 17 by user
#   Projects::TransferService.new(project, user, namespace_id: 17).execute
#
9
module Projects
10
  class TransferService < BaseService
11
12
13
    include Gitlab::ShellAdapter
    class TransferError < StandardError; end

14
15
16
    def execute(new_namespace)
      if allowed_transfer?(current_user, project, new_namespace)
        transfer(project, new_namespace)
17
      else
18
        project.errors.add(:new_namespace, 'is invalid')
19
20
21
        false
      end
    rescue Projects::TransferService::TransferError => ex
22
      project.reload
23
      project.errors.add(:new_namespace, ex.message)
24
25
      false
    end
26
27
28
29

    def transfer(project, new_namespace)
      Project.transaction do
        old_path = project.path_with_namespace
30
        old_namespace = project.namespace
31
32
33
34
35
36
        new_path = File.join(new_namespace.try(:path) || '', project.path)

        if Project.where(path: project.path, namespace_id: new_namespace.try(:id)).present?
          raise TransferError.new("Project with same path in target namespace already exists")
        end

37
38
39
40
41
        if project.has_container_registry_tags?
          # we currently doesn't support renaming repository if it contains tags in container registry
          raise TransferError.new('Repository cannot be renamed, due to tags in container registry')
        end

42
43
        project.expire_caches_before_rename(old_path)

44
        # Apply new namespace id and visibility level
45
46
47
        project.namespace = new_namespace
        project.visibility_level = new_namespace.visibility_level unless project.visibility_level_allowed_by_group?
        project.save!
48

Valery Sizov's avatar
Valery Sizov committed
49
        # Notifications
50
        project.send_move_instructions(old_path)
Valery Sizov's avatar
Valery Sizov committed
51

52
53
54
55
56
57
58
59
60
61
62
        # Move main repository
        unless gitlab_shell.mv_repository(old_path, new_path)
          raise TransferError.new('Cannot move project')
        end

        # Move wiki repo also if present
        gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki")

        # clear project cached events
        project.reset_events_cache

63
64
65
        # Move uploads
        Gitlab::UploadsTransfer.new.move_project(project.path, old_namespace.path, new_namespace.path)

66
        project.old_path_with_namespace = old_path
67

68
        SystemHooksService.new.execute_hooks_for(project, :transfer)
69
70
71
72
73
74
75
76
77
78
        true
      end
    end

    def allowed_transfer?(current_user, project, namespace)
      namespace &&
        can?(current_user, :change_namespace, project) &&
        namespace.id != project.namespace_id &&
        current_user.can?(:create_projects, namespace)
    end
79
80
  end
end