Commit 64d10109 authored by Luke Duncalfe's avatar Luke Duncalfe

CE-specific changes to allow design repo exports

https://gitlab.com/gitlab-org/gitlab-ee/issues/11090
parent 324b2772
...@@ -1098,6 +1098,8 @@ class Repository ...@@ -1098,6 +1098,8 @@ class Repository
raw.create_repository raw.create_repository
after_create after_create
true
end end
def blobs_metadata(paths, ref = 'HEAD') def blobs_metadata(paths, ref = 'HEAD')
......
...@@ -12,6 +12,8 @@ module Projects ...@@ -12,6 +12,8 @@ module Projects
private private
attr_accessor :shared
def execute_after_export_action(after_export_strategy) def execute_after_export_action(after_export_strategy)
return unless after_export_strategy return unless after_export_strategy
...@@ -21,50 +23,54 @@ module Projects ...@@ -21,50 +23,54 @@ module Projects
end end
def save_all! def save_all!
if save_services if save_exporters
Gitlab::ImportExport::Saver.save(project: project, shared: @shared) Gitlab::ImportExport::Saver.save(project: project, shared: shared)
notify_success notify_success
else else
cleanup_and_notify_error! cleanup_and_notify_error!
end end
end end
def save_services def save_exporters
[version_saver, avatar_saver, project_tree_saver, uploads_saver, repo_saver, wiki_repo_saver, lfs_saver].all?(&:save) exporters.all?(&:save)
end
def exporters
[version_saver, avatar_saver, project_tree_saver, uploads_saver, repo_saver, wiki_repo_saver, lfs_saver]
end end
def version_saver def version_saver
Gitlab::ImportExport::VersionSaver.new(shared: @shared) Gitlab::ImportExport::VersionSaver.new(shared: shared)
end end
def avatar_saver def avatar_saver
Gitlab::ImportExport::AvatarSaver.new(project: project, shared: @shared) Gitlab::ImportExport::AvatarSaver.new(project: project, shared: shared)
end end
def project_tree_saver def project_tree_saver
Gitlab::ImportExport::ProjectTreeSaver.new(project: project, current_user: @current_user, shared: @shared, params: @params) Gitlab::ImportExport::ProjectTreeSaver.new(project: project, current_user: current_user, shared: shared, params: params)
end end
def uploads_saver def uploads_saver
Gitlab::ImportExport::UploadsSaver.new(project: project, shared: @shared) Gitlab::ImportExport::UploadsSaver.new(project: project, shared: shared)
end end
def repo_saver def repo_saver
Gitlab::ImportExport::RepoSaver.new(project: project, shared: @shared) Gitlab::ImportExport::RepoSaver.new(project: project, shared: shared)
end end
def wiki_repo_saver def wiki_repo_saver
Gitlab::ImportExport::WikiRepoSaver.new(project: project, shared: @shared) Gitlab::ImportExport::WikiRepoSaver.new(project: project, shared: shared)
end end
def lfs_saver def lfs_saver
Gitlab::ImportExport::LfsSaver.new(project: project, shared: @shared) Gitlab::ImportExport::LfsSaver.new(project: project, shared: shared)
end end
def cleanup_and_notify_error def cleanup_and_notify_error
Rails.logger.error("Import/Export - Project #{project.name} with ID: #{project.id} export error - #{@shared.errors.join(', ')}") # rubocop:disable Gitlab/RailsLogger Rails.logger.error("Import/Export - Project #{project.name} with ID: #{project.id} export error - #{shared.errors.join(', ')}") # rubocop:disable Gitlab/RailsLogger
FileUtils.rm_rf(@shared.export_path) FileUtils.rm_rf(shared.export_path)
notify_error notify_error
end end
...@@ -72,7 +78,7 @@ module Projects ...@@ -72,7 +78,7 @@ module Projects
def cleanup_and_notify_error! def cleanup_and_notify_error!
cleanup_and_notify_error cleanup_and_notify_error
raise Gitlab::ImportExport::Error.new(@shared.errors.join(', ')) raise Gitlab::ImportExport::Error.new(shared.errors.to_sentence)
end end
def notify_success def notify_success
...@@ -80,7 +86,7 @@ module Projects ...@@ -80,7 +86,7 @@ module Projects
end end
def notify_error def notify_error
notification_service.project_not_exported(@project, @current_user, @shared.errors) notification_service.project_not_exported(project, current_user, shared.errors)
end end
end end
end end
......
...@@ -38,6 +38,10 @@ module Gitlab ...@@ -38,6 +38,10 @@ module Gitlab
"lfs-objects" "lfs-objects"
end end
def wiki_repo_bundle_filename
"project.wiki.bundle"
end
def config_file def config_file
Rails.root.join('lib/gitlab/import_export/import_export.yml') Rails.root.join('lib/gitlab/import_export/import_export.yml')
end end
......
...@@ -21,7 +21,7 @@ module Gitlab ...@@ -21,7 +21,7 @@ module Gitlab
if import_file && check_version! && restorers.all?(&:restore) && overwrite_project if import_file && check_version! && restorers.all?(&:restore) && overwrite_project
project_tree.restored_project project_tree.restored_project
else else
raise Projects::ImportService::Error.new(@shared.errors.join(', ')) raise Projects::ImportService::Error.new(shared.errors.to_sentence)
end end
rescue => e rescue => e
raise Projects::ImportService::Error.new(e.message) raise Projects::ImportService::Error.new(e.message)
...@@ -31,70 +31,72 @@ module Gitlab ...@@ -31,70 +31,72 @@ module Gitlab
private private
attr_accessor :archive_file, :current_user, :project, :shared
def restorers def restorers
[repo_restorer, wiki_restorer, project_tree, avatar_restorer, [repo_restorer, wiki_restorer, project_tree, avatar_restorer,
uploads_restorer, lfs_restorer, statistics_restorer] uploads_restorer, lfs_restorer, statistics_restorer]
end end
def import_file def import_file
Gitlab::ImportExport::FileImporter.import(project: @project, Gitlab::ImportExport::FileImporter.import(project: project,
archive_file: @archive_file, archive_file: archive_file,
shared: @shared) shared: shared)
end end
def check_version! def check_version!
Gitlab::ImportExport::VersionChecker.check!(shared: @shared) Gitlab::ImportExport::VersionChecker.check!(shared: shared)
end end
def project_tree def project_tree
@project_tree ||= Gitlab::ImportExport::ProjectTreeRestorer.new(user: @current_user, @project_tree ||= Gitlab::ImportExport::ProjectTreeRestorer.new(user: current_user,
shared: @shared, shared: shared,
project: @project) project: project)
end end
def avatar_restorer def avatar_restorer
Gitlab::ImportExport::AvatarRestorer.new(project: project_tree.restored_project, shared: @shared) Gitlab::ImportExport::AvatarRestorer.new(project: project_tree.restored_project, shared: shared)
end end
def repo_restorer def repo_restorer
Gitlab::ImportExport::RepoRestorer.new(path_to_bundle: repo_path, Gitlab::ImportExport::RepoRestorer.new(path_to_bundle: repo_path,
shared: @shared, shared: shared,
project: project_tree.restored_project) project: project_tree.restored_project)
end end
def wiki_restorer def wiki_restorer
Gitlab::ImportExport::WikiRestorer.new(path_to_bundle: wiki_repo_path, Gitlab::ImportExport::WikiRestorer.new(path_to_bundle: wiki_repo_path,
shared: @shared, shared: shared,
project: ProjectWiki.new(project_tree.restored_project), project: ProjectWiki.new(project_tree.restored_project),
wiki_enabled: @project.wiki_enabled?) wiki_enabled: project.wiki_enabled?)
end end
def uploads_restorer def uploads_restorer
Gitlab::ImportExport::UploadsRestorer.new(project: project_tree.restored_project, shared: @shared) Gitlab::ImportExport::UploadsRestorer.new(project: project_tree.restored_project, shared: shared)
end end
def lfs_restorer def lfs_restorer
Gitlab::ImportExport::LfsRestorer.new(project: project_tree.restored_project, shared: @shared) Gitlab::ImportExport::LfsRestorer.new(project: project_tree.restored_project, shared: shared)
end end
def statistics_restorer def statistics_restorer
Gitlab::ImportExport::StatisticsRestorer.new(project: project_tree.restored_project, shared: @shared) Gitlab::ImportExport::StatisticsRestorer.new(project: project_tree.restored_project, shared: shared)
end end
def path_with_namespace def path_with_namespace
File.join(@project.namespace.full_path, @project.path) File.join(project.namespace.full_path, project.path)
end end
def repo_path def repo_path
File.join(@shared.export_path, 'project.bundle') File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename)
end end
def wiki_repo_path def wiki_repo_path
File.join(@shared.export_path, 'project.wiki.bundle') File.join(shared.export_path, Gitlab::ImportExport.wiki_repo_bundle_filename)
end end
def remove_import_file def remove_import_file
upload = @project.import_export_upload upload = project.import_export_upload
return unless upload&.import_file&.file return unless upload&.import_file&.file
...@@ -105,10 +107,10 @@ module Gitlab ...@@ -105,10 +107,10 @@ module Gitlab
def overwrite_project def overwrite_project
project = project_tree.restored_project project = project_tree.restored_project
return unless can?(@current_user, :admin_namespace, project.namespace) return unless can?(current_user, :admin_namespace, project.namespace)
if overwrite_project? if overwrite_project?
::Projects::OverwriteProjectService.new(project, @current_user) ::Projects::OverwriteProjectService.new(project, current_user)
.execute(project_to_overwrite) .execute(project_to_overwrite)
end end
...@@ -116,7 +118,7 @@ module Gitlab ...@@ -116,7 +118,7 @@ module Gitlab
end end
def original_path def original_path
@project.import_data&.data&.fetch('original_path', nil) project.import_data&.data&.fetch('original_path', nil)
end end
def overwrite_project? def overwrite_project?
...@@ -125,7 +127,7 @@ module Gitlab ...@@ -125,7 +127,7 @@ module Gitlab
def project_to_overwrite def project_to_overwrite
strong_memoize(:project_to_overwrite) do strong_memoize(:project_to_overwrite) do
Project.find_by_full_path("#{@project.namespace.full_path}/#{original_path}") Project.find_by_full_path("#{project.namespace.full_path}/#{original_path}")
end end
end end
end end
......
...@@ -6,19 +6,23 @@ module Gitlab ...@@ -6,19 +6,23 @@ module Gitlab
include Gitlab::ImportExport::CommandLineUtil include Gitlab::ImportExport::CommandLineUtil
def initialize(project:, shared:, path_to_bundle:) def initialize(project:, shared:, path_to_bundle:)
@project = project @repository = project.repository
@path_to_bundle = path_to_bundle @path_to_bundle = path_to_bundle
@shared = shared @shared = shared
end end
def restore def restore
return true unless File.exist?(@path_to_bundle) return true unless File.exist?(path_to_bundle)
@project.repository.create_from_bundle(@path_to_bundle) repository.create_from_bundle(path_to_bundle)
rescue => e rescue => e
@shared.error(e) shared.error(e)
false false
end end
private
attr_accessor :repository, :path_to_bundle, :shared
end end
end end
end end
...@@ -5,27 +5,35 @@ module Gitlab ...@@ -5,27 +5,35 @@ module Gitlab
class RepoSaver class RepoSaver
include Gitlab::ImportExport::CommandLineUtil include Gitlab::ImportExport::CommandLineUtil
attr_reader :full_path attr_reader :project, :repository, :shared
def initialize(project:, shared:) def initialize(project:, shared:)
@project = project @project = project
@shared = shared @shared = shared
@repository = @project.repository
end end
def save def save
return true if @project.empty_repo? # it's ok to have no repo return true unless repository_exists? # it's ok to have no repo
@full_path = File.join(@shared.export_path, ImportExport.project_bundle_filename)
bundle_to_disk bundle_to_disk
end end
private private
def repository_exists?
repository.exists? && !repository.empty?
end
def bundle_full_path
File.join(shared.export_path, ImportExport.project_bundle_filename)
end
def bundle_to_disk def bundle_to_disk
mkdir_p(@shared.export_path) mkdir_p(shared.export_path)
@project.repository.bundle_to_disk(@full_path) repository.bundle_to_disk(bundle_full_path)
rescue => e rescue => e
@shared.error(e) shared.error(e)
false false
end end
end end
......
...@@ -4,28 +4,16 @@ module Gitlab ...@@ -4,28 +4,16 @@ module Gitlab
module ImportExport module ImportExport
class WikiRepoSaver < RepoSaver class WikiRepoSaver < RepoSaver
def save def save
@wiki = ProjectWiki.new(@project) wiki = ProjectWiki.new(project)
return true unless wiki_repository_exists? # it's okay to have no Wiki @repository = wiki.repository
bundle_to_disk(File.join(@shared.export_path, project_filename)) super
end
def bundle_to_disk(full_path)
mkdir_p(@shared.export_path)
@wiki.repository.bundle_to_disk(full_path)
rescue => e
@shared.error(e)
false
end end
private private
def project_filename def bundle_full_path
"project.wiki.bundle" File.join(shared.export_path, ImportExport.wiki_repo_bundle_filename)
end
def wiki_repository_exists?
@wiki.repository.exists? && !@wiki.repository.empty?
end end
end end
end end
......
...@@ -6,19 +6,22 @@ module Gitlab ...@@ -6,19 +6,22 @@ module Gitlab
def initialize(project:, shared:, path_to_bundle:, wiki_enabled:) def initialize(project:, shared:, path_to_bundle:, wiki_enabled:)
super(project: project, shared: shared, path_to_bundle: path_to_bundle) super(project: project, shared: shared, path_to_bundle: path_to_bundle)
@project = project
@wiki_enabled = wiki_enabled @wiki_enabled = wiki_enabled
end end
def restore def restore
@project.wiki if create_empty_wiki? project.wiki if create_empty_wiki?
super super
end end
private private
attr_accessor :project, :wiki_enabled
def create_empty_wiki? def create_empty_wiki?
!File.exist?(@path_to_bundle) && @wiki_enabled !File.exist?(path_to_bundle) && wiki_enabled
end end
end end
end end
......
...@@ -2,8 +2,8 @@ require 'spec_helper' ...@@ -2,8 +2,8 @@ require 'spec_helper'
describe Gitlab::ImportExport::RepoSaver do describe Gitlab::ImportExport::RepoSaver do
describe 'bundle a project Git repo' do describe 'bundle a project Git repo' do
let(:user) { create(:user) } set(:user) { create(:user) }
let!(:project) { create(:project, :public, name: 'searchable_project') } let!(:project) { create(:project, :repository) }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:shared) { project.import_export_shared } let(:shared) { project.import_export_shared }
let(:bundler) { described_class.new(project: project, shared: shared) } let(:bundler) { described_class.new(project: project, shared: shared) }
...@@ -20,5 +20,13 @@ describe Gitlab::ImportExport::RepoSaver do ...@@ -20,5 +20,13 @@ describe Gitlab::ImportExport::RepoSaver do
it 'bundles the repo successfully' do it 'bundles the repo successfully' do
expect(bundler.save).to be true expect(bundler.save).to be true
end end
context 'when the repo is empty' do
let!(:project) { create(:project) }
it 'bundles the repo successfully' do
expect(bundler.save).to be true
end
end
end end
end end
...@@ -2,8 +2,8 @@ require 'spec_helper' ...@@ -2,8 +2,8 @@ require 'spec_helper'
describe Gitlab::ImportExport::WikiRepoSaver do describe Gitlab::ImportExport::WikiRepoSaver do
describe 'bundle a wiki Git repo' do describe 'bundle a wiki Git repo' do
let(:user) { create(:user) } set(:user) { create(:user) }
let!(:project) { create(:project, :public, :wiki_repo, name: 'searchable_project') } let!(:project) { create(:project, :wiki_repo) }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:shared) { project.import_export_shared } let(:shared) { project.import_export_shared }
let(:wiki_bundler) { described_class.new(project: project, shared: shared) } let(:wiki_bundler) { described_class.new(project: project, shared: shared) }
...@@ -23,5 +23,13 @@ describe Gitlab::ImportExport::WikiRepoSaver do ...@@ -23,5 +23,13 @@ describe Gitlab::ImportExport::WikiRepoSaver do
it 'bundles the repo successfully' do it 'bundles the repo successfully' do
expect(wiki_bundler.save).to be true expect(wiki_bundler.save).to be true
end end
context 'when the repo is empty' do
let!(:project) { create(:project) }
it 'bundles the repo successfully' do
expect(wiki_bundler.save).to be true
end
end
end end
end end
...@@ -1075,7 +1075,7 @@ describe Repository do ...@@ -1075,7 +1075,7 @@ describe Repository do
let(:ref) { 'refs/heads/master' } let(:ref) { 'refs/heads/master' }
it 'returns nil' do it 'returns nil' do
is_expected.to eq(nil) is_expected.to be_nil
end end
end end
...@@ -2002,7 +2002,7 @@ describe Repository do ...@@ -2002,7 +2002,7 @@ describe Repository do
it 'returns nil if repo does not exist' do it 'returns nil if repo does not exist' do
allow(repository).to receive(:root_ref).and_raise(Gitlab::Git::Repository::NoRepository) allow(repository).to receive(:root_ref).and_raise(Gitlab::Git::Repository::NoRepository)
expect(repository.avatar).to eq(nil) expect(repository.avatar).to be_nil
end end
it 'returns the first avatar file found in the repository' do it 'returns the first avatar file found in the repository' do
...@@ -2604,6 +2604,10 @@ describe Repository do ...@@ -2604,6 +2604,10 @@ describe Repository do
expect { repository.create_if_not_exists }.to change { repository.exists? }.from(false).to(true) expect { repository.create_if_not_exists }.to change { repository.exists? }.from(false).to(true)
end end
it 'returns true' do
expect(repository.create_if_not_exists).to eq(true)
end
it 'calls out to the repository client to create a repo' do it 'calls out to the repository client to create a repo' do
expect(repository.raw.gitaly_repository_client).to receive(:create_repository) expect(repository.raw.gitaly_repository_client).to receive(:create_repository)
...@@ -2618,6 +2622,10 @@ describe Repository do ...@@ -2618,6 +2622,10 @@ describe Repository do
repository.create_if_not_exists repository.create_if_not_exists
end end
it 'returns nil' do
expect(repository.create_if_not_exists).to be_nil
end
end end
context 'when the repository exists but the cache is not up to date' do context 'when the repository exists but the cache is not up to date' do
...@@ -2629,6 +2637,10 @@ describe Repository do ...@@ -2629,6 +2637,10 @@ describe Repository do
expect { repository.create_if_not_exists }.not_to raise_error expect { repository.create_if_not_exists }.not_to raise_error
end end
it 'returns nil' do
expect(repository.create_if_not_exists).to be_nil
end
end end
end end
......
...@@ -35,20 +35,27 @@ describe Projects::ImportExport::ExportService do ...@@ -35,20 +35,27 @@ describe Projects::ImportExport::ExportService do
end end
it 'saves the repo' do it 'saves the repo' do
# This spec errors when run against the EE codebase as there will be a third repository
# saved (the EE-specific design repository).
#
# Instead, skip this test when run within EE. There is a spec for the EE-specific design repo
# in the corresponding EE spec.
skip if Gitlab.ee?
# once for the normal repo, once for the wiki # once for the normal repo, once for the wiki
expect(Gitlab::ImportExport::RepoSaver).to receive(:new).twice.and_call_original expect(Gitlab::ImportExport::RepoSaver).to receive(:new).twice.and_call_original
service.execute service.execute
end end
it 'saves the lfs objects' do it 'saves the wiki repo' do
expect(Gitlab::ImportExport::LfsSaver).to receive(:new).and_call_original expect(Gitlab::ImportExport::WikiRepoSaver).to receive(:new).and_call_original
service.execute service.execute
end end
it 'saves the wiki repo' do it 'saves the lfs objects' do
expect(Gitlab::ImportExport::WikiRepoSaver).to receive(:new).and_call_original expect(Gitlab::ImportExport::LfsSaver).to receive(:new).and_call_original
service.execute service.execute
end end
...@@ -98,9 +105,9 @@ describe Projects::ImportExport::ExportService do ...@@ -98,9 +105,9 @@ describe Projects::ImportExport::ExportService do
end end
end end
context 'when saver services fail' do context 'when saving services fail' do
before do before do
allow(service).to receive(:save_services).and_return(false) allow(service).to receive(:save_exporters).and_return(false)
end end
after do after do
...@@ -122,7 +129,7 @@ describe Projects::ImportExport::ExportService do ...@@ -122,7 +129,7 @@ describe Projects::ImportExport::ExportService do
expect(Rails.logger).to receive(:error) expect(Rails.logger).to receive(:error)
end end
it 'the after export strategy is not called' do it 'does not call the export strategy' do
expect(service).not_to receive(:execute_after_export_action) expect(service).not_to receive(:execute_after_export_action)
end end
end end
......
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