1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
# frozen_string_literal: true
module Projects
# Service class for performing operations that should take place after a
# project has been renamed.
#
# Example usage:
#
# project = Project.find(42)
#
# project.update(...)
#
# Projects::AfterRenameService.new(project).execute
class AfterRenameService
include BaseServiceUtility
# @return [String] The Project being renamed.
attr_reader :project
# @return [String] The path slug the project was using, before the rename took place.
attr_reader :path_before
# @return [String] The full path of the namespace + project, before the rename took place.
attr_reader :full_path_before
# @return [String] The full path of the namespace + project, after the rename took place.
attr_reader :full_path_after
RenameFailedError = Class.new(StandardError)
# @param [Project] project The Project being renamed.
# @param [String] path_before The path slug the project was using, before the rename took place.
def initialize(project, path_before:, full_path_before:)
@project = project
@path_before = path_before
@full_path_before = full_path_before
@full_path_after = project.full_path
end
def execute
rename_base_repository_in_registry!
expire_caches_before_rename
rename_or_migrate_repository!
send_move_instructions
execute_system_hooks
update_repository_configuration
rename_transferred_documents
log_completion
publish_event
end
def rename_base_repository_in_registry!
return unless project.has_container_registry_tags?
ensure_registry_tags_can_be_handled
result = ContainerRegistry::GitlabApiClient.rename_base_repository_path(
full_path_before, name: project_path)
return if result == :ok
rename_failed!("Renaming the base repository in the registry failed with error #{result}.")
end
def ensure_registry_tags_can_be_handled
return if ContainerRegistry::GitlabApiClient.supports_gitlab_api?
rename_failed!("Project #{full_path_before} cannot be renamed because images are " \
"present in its container registry")
end
def expire_caches_before_rename
project.expire_caches_before_rename(full_path_before)
end
def rename_or_migrate_repository!
success =
::Projects::HashedStorage::MigrationService
.new(project, full_path_before)
.execute
return if success
rename_failed!("Repository #{full_path_before} could not be renamed to #{full_path_after}")
end
def send_move_instructions
return unless send_move_instructions?
project.send_move_instructions(full_path_before)
end
def execute_system_hooks
project.old_path_with_namespace = full_path_before
system_hook_service.execute_hooks_for(project, :rename)
end
def update_repository_configuration
project.reload_repository!
project.set_full_path
project.track_project_repository
end
def rename_transferred_documents
if rename_uploads?
Gitlab::UploadsTransfer
.new
.rename_project(path_before, project_path, namespace_full_path)
end
end
def log_completion
log_info(
"Project #{project.id} has been renamed from " \
"#{full_path_before} to #{full_path_after}"
)
end
def send_move_instructions?
!project.import_started?
end
def rename_uploads?
!project.hashed_storage?(:attachments)
end
def project_path
project.path
end
def namespace_full_path
project.namespace.full_path
end
def rename_failed!(error)
log_error(error)
raise RenameFailedError, error
end
def publish_event
event = Projects::ProjectPathChangedEvent.new(data: {
project_id: project.id,
namespace_id: project.namespace_id,
root_namespace_id: project.root_namespace.id,
old_path: full_path_before,
new_path: full_path_after
})
Gitlab::EventStore.publish(event)
end
end
end
|