Commit d27bc0c3 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'fj-refactor-group-importer-exporter' into 'master'

Refactor code in groups' importer and exporter

See merge request gitlab-org/gitlab!52767
parents 322d1214 684f5c3f
...@@ -12,13 +12,13 @@ module Groups ...@@ -12,13 +12,13 @@ module Groups
end end
def async_execute def async_execute
GroupExportWorker.perform_async(@current_user.id, @group.id, @params) GroupExportWorker.perform_async(current_user.id, group.id, params)
end end
def execute def execute
validate_user_permissions validate_user_permissions
remove_existing_export! if @group.export_file_exists? remove_existing_export! if group.export_file_exists?
save! save!
ensure ensure
...@@ -27,25 +27,29 @@ module Groups ...@@ -27,25 +27,29 @@ module Groups
private private
attr_reader :group, :current_user, :params
attr_accessor :shared attr_accessor :shared
def validate_user_permissions def validate_user_permissions
unless @current_user.can?(:admin_group, @group) unless current_user.can?(:admin_group, group)
@shared.error(::Gitlab::ImportExport::Error.permission_error(@current_user, @group)) shared.error(::Gitlab::ImportExport::Error.permission_error(current_user, group))
notify_error! notify_error!
end end
end end
def remove_existing_export! def remove_existing_export!
import_export_upload = @group.import_export_upload import_export_upload = group.import_export_upload
import_export_upload.remove_export_file! import_export_upload.remove_export_file!
import_export_upload.save import_export_upload.save
end end
def save! def save!
if savers.all?(&:save) # We cannot include the file_saver with the other savers because
# it removes the tmp dir. This means that if we want to add new savers
# in EE the data won't be available.
if savers.all?(&:save) && file_saver.save
notify_success notify_success
else else
notify_error! notify_error!
...@@ -53,32 +57,36 @@ module Groups ...@@ -53,32 +57,36 @@ module Groups
end end
def savers def savers
[version_saver, tree_exporter, file_saver] [version_saver, tree_exporter]
end end
def tree_exporter def tree_exporter
tree_exporter_class.new( tree_exporter_class.new(
group: @group, group: group,
current_user: @current_user, current_user: current_user,
shared: @shared, shared: shared,
params: @params params: params
) )
end end
def tree_exporter_class def tree_exporter_class
if ::Feature.enabled?(:group_export_ndjson, @group&.parent, default_enabled: true) if ndjson?
Gitlab::ImportExport::Group::TreeSaver Gitlab::ImportExport::Group::TreeSaver
else else
Gitlab::ImportExport::Group::LegacyTreeSaver Gitlab::ImportExport::Group::LegacyTreeSaver
end end
end end
def ndjson?
::Feature.enabled?(:group_export_ndjson, group&.parent, default_enabled: :yaml)
end
def version_saver def version_saver
Gitlab::ImportExport::VersionSaver.new(shared: shared) Gitlab::ImportExport::VersionSaver.new(shared: shared)
end end
def file_saver def file_saver
Gitlab::ImportExport::Saver.new(exportable: @group, shared: @shared) Gitlab::ImportExport::Saver.new(exportable: group, shared: shared)
end end
def remove_archive_tmp_dir def remove_archive_tmp_dir
...@@ -94,22 +102,22 @@ module Groups ...@@ -94,22 +102,22 @@ module Groups
def notify_success def notify_success
@logger.info( @logger.info(
message: 'Group Export succeeded', message: 'Group Export succeeded',
group_id: @group.id, group_id: group.id,
group_name: @group.name group_name: group.name
) )
notification_service.group_was_exported(@group, @current_user) notification_service.group_was_exported(group, current_user)
end end
def notify_error def notify_error
@logger.error( @logger.error(
message: 'Group Export failed', message: 'Group Export failed',
group_id: @group.id, group_id: group.id,
group_name: @group.name, group_name: group.name,
errors: @shared.errors.join(', ') errors: shared.errors.join(', ')
) )
notification_service.group_was_not_exported(@group, @current_user, @shared.errors) notification_service.group_was_not_exported(group, current_user, shared.errors)
end end
def notification_service def notification_service
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Groups module Groups
module ImportExport module ImportExport
class ImportService class ImportService
attr_reader :current_user, :group, :params attr_reader :current_user, :group, :shared
def initialize(group:, user:) def initialize(group:, user:)
@group = group @group = group
...@@ -26,10 +26,10 @@ module Groups ...@@ -26,10 +26,10 @@ module Groups
end end
def execute def execute
if valid_user_permissions? && import_file && restorer.restore if valid_user_permissions? && import_file && restorers.all?(&:restore)
notify_success notify_success
@group group
else else
notify_error! notify_error!
end end
...@@ -43,37 +43,41 @@ module Groups ...@@ -43,37 +43,41 @@ module Groups
def import_file def import_file
@import_file ||= Gitlab::ImportExport::FileImporter.import( @import_file ||= Gitlab::ImportExport::FileImporter.import(
importable: @group, importable: group,
archive_file: nil, archive_file: nil,
shared: @shared shared: shared
) )
end end
def restorer def restorers
@restorer ||= [tree_restorer]
end
def tree_restorer
@tree_restorer ||=
if ndjson? if ndjson?
Gitlab::ImportExport::Group::TreeRestorer.new( Gitlab::ImportExport::Group::TreeRestorer.new(
user: @current_user, user: current_user,
shared: @shared, shared: shared,
group: @group group: group
) )
else else
Gitlab::ImportExport::Group::LegacyTreeRestorer.new( Gitlab::ImportExport::Group::LegacyTreeRestorer.new(
user: @current_user, user: current_user,
shared: @shared, shared: shared,
group: @group, group: group,
group_hash: nil group_hash: nil
) )
end end
end end
def ndjson? def ndjson?
::Feature.enabled?(:group_import_ndjson, @group&.parent, default_enabled: true) && ::Feature.enabled?(:group_import_ndjson, group&.parent, default_enabled: true) &&
File.exist?(File.join(@shared.export_path, 'tree/groups/_all.ndjson')) File.exist?(File.join(shared.export_path, 'tree/groups/_all.ndjson'))
end end
def remove_import_file def remove_import_file
upload = @group.import_export_upload upload = group.import_export_upload
return unless upload&.import_file&.file return unless upload&.import_file&.file
...@@ -85,7 +89,7 @@ module Groups ...@@ -85,7 +89,7 @@ module Groups
if current_user.can?(:admin_group, group) if current_user.can?(:admin_group, group)
true true
else else
@shared.error(::Gitlab::ImportExport::Error.permission_error(current_user, group)) shared.error(::Gitlab::ImportExport::Error.permission_error(current_user, group))
false false
end end
...@@ -93,16 +97,16 @@ module Groups ...@@ -93,16 +97,16 @@ module Groups
def notify_success def notify_success
@logger.info( @logger.info(
group_id: @group.id, group_id: group.id,
group_name: @group.name, group_name: group.name,
message: 'Group Import/Export: Import succeeded' message: 'Group Import/Export: Import succeeded'
) )
end end
def notify_error def notify_error
@logger.error( @logger.error(
group_id: @group.id, group_id: group.id,
group_name: @group.name, group_name: group.name,
message: "Group Import/Export: Errors occurred, see '#{Gitlab::ErrorTracking::Logger.file_name}' for details" message: "Group Import/Export: Errors occurred, see '#{Gitlab::ErrorTracking::Logger.file_name}' for details"
) )
end end
...@@ -110,11 +114,11 @@ module Groups ...@@ -110,11 +114,11 @@ module Groups
def notify_error! def notify_error!
notify_error notify_error
raise Gitlab::ImportExport::Error.new(@shared.errors.to_sentence) raise Gitlab::ImportExport::Error.new(shared.errors.to_sentence)
end end
def remove_base_tmp_dir def remove_base_tmp_dir
FileUtils.rm_rf(@shared.base_path) FileUtils.rm_rf(shared.base_path)
end end
end end
end end
......
...@@ -6,7 +6,7 @@ module Gitlab ...@@ -6,7 +6,7 @@ module Gitlab
class TreeRestorer class TreeRestorer
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
attr_reader :user, :shared attr_reader :user, :shared, :groups_mapping
def initialize(user:, shared:, group:) def initialize(user:, shared:, group:)
@user = user @user = user
......
...@@ -37,7 +37,8 @@ module Gitlab ...@@ -37,7 +37,8 @@ module Gitlab
end end
def bundle_to_disk def bundle_to_disk
mkdir_p(shared.export_path) mkdir_p(File.dirname(bundle_full_path))
repository.bundle_to_disk(bundle_full_path) repository.bundle_to_disk(bundle_full_path)
rescue => e rescue => e
shared.error(e) shared.error(e)
......
...@@ -21,6 +21,7 @@ RSpec.describe Gitlab::ImportExport::Group::TreeRestorer do ...@@ -21,6 +21,7 @@ RSpec.describe Gitlab::ImportExport::Group::TreeRestorer do
group_tree_restorer = described_class.new(user: user, shared: @shared, group: @group) group_tree_restorer = described_class.new(user: user, shared: @shared, group: @group)
expect(group_tree_restorer.restore).to be_truthy expect(group_tree_restorer.restore).to be_truthy
expect(group_tree_restorer.groups_mapping).not_to be_empty
end end
end end
......
...@@ -25,6 +25,14 @@ RSpec.describe Gitlab::ImportExport::RepoSaver do ...@@ -25,6 +25,14 @@ RSpec.describe Gitlab::ImportExport::RepoSaver do
expect(bundler.save).to be true expect(bundler.save).to be true
end end
it 'creates the directory for the repository' do
allow(bundler).to receive(:bundle_full_path).and_return('/foo/bar/file.tar.gz')
expect(FileUtils).to receive(:mkdir_p).with('/foo/bar', anything)
bundler.save # rubocop:disable Rails/SaveBang
end
context 'when the repo is empty' do context 'when the repo is empty' do
let!(:project) { create(:project) } let!(:project) { create(:project) }
......
...@@ -71,6 +71,16 @@ RSpec.describe Groups::ImportExport::ExportService do ...@@ -71,6 +71,16 @@ RSpec.describe Groups::ImportExport::ExportService do
service.execute service.execute
end end
it 'compresses and removes tmp files' do
expect(group.import_export_upload).to be_nil
expect(Gitlab::ImportExport::Saver).to receive(:new).and_call_original
service.execute
expect(Dir.exist?(shared.archive_path)).to eq false
expect(File.exist?(group.import_export_upload.export_file.path)).to eq true
end
it 'notifies the user' do it 'notifies the user' do
expect_next_instance_of(NotificationService) do |instance| expect_next_instance_of(NotificationService) do |instance|
expect(instance).to receive(:group_was_exported) expect(instance).to receive(:group_was_exported)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment