2018-12-13 13:39:08 +05:30
|
|
|
# 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
|
2021-11-18 22:05:49 +05:30
|
|
|
include BaseServiceUtility
|
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
# @return [String] The Project being renamed.
|
|
|
|
attr_reader :project
|
2018-12-13 13:39:08 +05:30
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
# @return [String] The path slug the project was using, before the rename took place.
|
|
|
|
attr_reader :path_before
|
2018-12-13 13:39:08 +05:30
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
# @return [String] The full path of the namespace + project, before the rename took place.
|
|
|
|
attr_reader :full_path_before
|
2018-12-13 13:39:08 +05:30
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
# @return [String] The full path of the namespace + project, after the rename took place.
|
|
|
|
attr_reader :full_path_after
|
2018-12-13 13:39:08 +05:30
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
RenameFailedError = Class.new(StandardError)
|
2018-12-13 13:39:08 +05:30
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
# @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-12-13 13:39:08 +05:30
|
|
|
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?
|
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
raise RenameFailedError, "Project #{full_path_before} cannot be renamed because images are " \
|
2018-12-13 13:39:08 +05:30
|
|
|
"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-03-02 22:35:43 +05:30
|
|
|
::Projects::HashedStorage::MigrationService
|
2018-12-13 13:39:08 +05:30
|
|
|
.new(project, full_path_before)
|
|
|
|
.execute
|
|
|
|
else
|
2019-03-02 22:35:43 +05:30
|
|
|
project.storage.rename_repo(old_full_path: full_path_before, new_full_path: full_path_after)
|
2018-12-13 13:39:08 +05:30
|
|
|
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
|
2021-11-18 22:05:49 +05:30
|
|
|
system_hook_service.execute_hooks_for(project, :rename)
|
2018-12-13 13:39:08 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def update_repository_configuration
|
|
|
|
project.reload_repository!
|
2021-10-27 15:23:28 +05:30
|
|
|
project.set_full_path
|
2019-02-15 15:39:39 +05:30
|
|
|
project.track_project_repository
|
2018-12-13 13:39:08 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def rename_transferred_documents
|
|
|
|
if rename_uploads?
|
|
|
|
Gitlab::UploadsTransfer
|
|
|
|
.new
|
|
|
|
.rename_project(path_before, project_path, namespace_full_path)
|
|
|
|
end
|
|
|
|
|
2020-11-24 15:15:51 +05:30
|
|
|
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)
|
|
|
|
end
|
|
|
|
end
|
2018-12-13 13:39:08 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def log_completion
|
2021-11-18 22:05:49 +05:30
|
|
|
log_info(
|
2018-12-13 13:39:08 +05:30
|
|
|
"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-11-24 15:15:51 +05:30
|
|
|
project.storage_upgradable?
|
2018-12-13 13:39:08 +05:30
|
|
|
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}"
|
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
log_error(error)
|
2018-12-13 13:39:08 +05:30
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
raise RenameFailedError, error
|
2018-12-13 13:39:08 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-12-04 20:38:33 +05:30
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
Projects::AfterRenameService.prepend_mod_with('Projects::AfterRenameService')
|