4b9c17f196
This moves the logic of Project#rename_repo and all methods _only_ used by this method into a new service class: Projects::AfterRenameService. By moving this code into a separate service class we can more easily refactor it, and we also get rid of some RuboCop "disable" statements automatically. During the refactoring of this code, I removed most of the explicit logging using Gitlab::AppLogger. The data that was logged would not be useful when debugging renaming issues, as it does not add any value on top of data provided by users. I also removed a variety of comments that either mentioned something the code does in literal form, or contained various grammatical errors. Instead we now resort to more clearly named methods, removing the need for code comments. This method was chosen based on analysis in https://gitlab.com/gitlab-org/release/framework/issues/28. In this issue we determined this method has seen a total of 293 lines being changed in it. We also noticed that RuboCop determined the ABC size (https://www.softwarerenovation.com/ABCMetric.pdf) was too great.
135 lines
3.5 KiB
Ruby
135 lines
3.5 KiB
Ruby
# 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
|
|
attr_reader :project, :full_path_before, :full_path_after, :path_before
|
|
|
|
RenameFailedError = Class.new(StandardError)
|
|
|
|
# @param [Project] project The Project of the repository to rename.
|
|
def initialize(project)
|
|
@project = project
|
|
|
|
# The full path of the namespace + project, before the rename took place.
|
|
@full_path_before = project.full_path_was
|
|
|
|
# The full path of the namespace + project, after the rename took place.
|
|
@full_path_after = project.build_full_path
|
|
|
|
# The path of just the project, before the rename took place.
|
|
@path_before = project.path_was
|
|
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?
|
|
::Projects::HashedStorageMigrationService
|
|
.new(project, full_path_before)
|
|
.execute
|
|
else
|
|
project.storage.rename_repo
|
|
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
|
|
end
|
|
|
|
def rename_transferred_documents
|
|
if rename_uploads?
|
|
Gitlab::UploadsTransfer
|
|
.new
|
|
.rename_project(path_before, project_path, namespace_full_path)
|
|
end
|
|
|
|
Gitlab::PagesTransfer
|
|
.new
|
|
.rename_project(path_before, project_path, namespace_full_path)
|
|
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? &&
|
|
project.storage_upgradable? &&
|
|
Feature.disabled?(:skip_hashed_storage_upgrade)
|
|
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
|