2018-10-17 07:33:54 -04:00
|
|
|
# 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
|
2019-01-21 22:33:32 -05:00
|
|
|
# @return [String] The Project being renamed.
|
|
|
|
attr_reader :project
|
2018-10-17 07:33:54 -04:00
|
|
|
|
2019-01-21 22:33:32 -05:00
|
|
|
# @return [String] The path slug the project was using, before the rename took place.
|
|
|
|
attr_reader :path_before
|
2018-10-17 07:33:54 -04:00
|
|
|
|
2019-01-21 22:33:32 -05:00
|
|
|
# @return [String] The full path of the namespace + project, before the rename took place.
|
|
|
|
attr_reader :full_path_before
|
2018-10-17 07:33:54 -04:00
|
|
|
|
2019-01-21 22:33:32 -05:00
|
|
|
# @return [String] The full path of the namespace + project, after the rename took place.
|
|
|
|
attr_reader :full_path_after
|
2018-10-17 07:33:54 -04:00
|
|
|
|
2019-01-21 22:33:32 -05:00
|
|
|
RenameFailedError = Class.new(StandardError)
|
2018-10-17 07:33:54 -04:00
|
|
|
|
2019-01-21 22:33:32 -05:00
|
|
|
# @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
|
2018-10-17 07:33:54 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def execute
|
|
|
|
first_ensure_no_registry_tags_are_present
|
|
|
|
expire_caches_before_rename
|
|
|
|
rename_or_migrate_repository!
|
|
|
|
send_move_instructions
|
|
|
|
execute_system_hooks
|
|
|
|
update_repository_configuration
|
|
|
|
rename_transferred_documents
|
|
|
|
log_completion
|
|
|
|
end
|
|
|
|
|
|
|
|
def first_ensure_no_registry_tags_are_present
|
|
|
|
return unless project.has_container_registry_tags?
|
|
|
|
|
|
|
|
raise RenameFailedError.new(
|
|
|
|
"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 =
|
|
|
|
if migrate_to_hashed_storage?
|
2019-01-14 22:30:55 -05:00
|
|
|
::Projects::HashedStorage::MigrationService
|
2018-10-17 07:33:54 -04:00
|
|
|
.new(project, full_path_before)
|
|
|
|
.execute
|
|
|
|
else
|
2019-01-21 22:33:32 -05:00
|
|
|
project.storage.rename_repo(old_full_path: full_path_before, new_full_path: full_path_after)
|
2018-10-17 07:33:54 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
rename_failed! unless success
|
|
|
|
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
|
|
|
|
SystemHooksService.new.execute_hooks_for(project, :rename)
|
|
|
|
end
|
|
|
|
|
|
|
|
def update_repository_configuration
|
|
|
|
project.reload_repository!
|
|
|
|
project.write_repository_config
|
2018-12-18 14:00:27 -05:00
|
|
|
project.track_project_repository
|
2018-10-17 07:33:54 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def rename_transferred_documents
|
|
|
|
if rename_uploads?
|
|
|
|
Gitlab::UploadsTransfer
|
|
|
|
.new
|
|
|
|
.rename_project(path_before, project_path, namespace_full_path)
|
|
|
|
end
|
|
|
|
|
2020-09-04 08:08:27 -04:00
|
|
|
if project.pages_deployed?
|
|
|
|
# Block will be evaluated in the context of project so we need
|
|
|
|
# to bind to a local variable to capture it, as the instance
|
|
|
|
# variable and method aren't available on Project
|
|
|
|
path_before_local = @path_before
|
|
|
|
|
|
|
|
project.run_after_commit_or_now do
|
|
|
|
Gitlab::PagesTransfer
|
|
|
|
.new
|
|
|
|
.async
|
|
|
|
.rename_project(path_before_local, path, namespace.full_path)
|
2020-08-26 08:10:53 -04:00
|
|
|
end
|
|
|
|
end
|
2018-10-17 07:33:54 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def log_completion
|
|
|
|
Gitlab::AppLogger.info(
|
|
|
|
"Project #{project.id} has been renamed from " \
|
|
|
|
"#{full_path_before} to #{full_path_after}"
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
def migrate_to_hashed_storage?
|
|
|
|
Gitlab::CurrentSettings.hashed_storage_enabled? &&
|
2020-08-31 20:10:35 -04:00
|
|
|
project.storage_upgradable?
|
2018-10-17 07:33:54 -04:00
|
|
|
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 = "Repository #{full_path_before} could not be renamed to #{full_path_after}"
|
|
|
|
|
|
|
|
Gitlab::AppLogger.error(error)
|
|
|
|
|
|
|
|
raise RenameFailedError.new(error)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-09-13 09:26:31 -04:00
|
|
|
|
|
|
|
Projects::AfterRenameService.prepend_if_ee('EE::Projects::AfterRenameService')
|