Commit 1dcfb1d3 authored by Alejandro Rodríguez's avatar Alejandro Rodríguez

Fix a bug where forking a project from a repository storage to another would fail

parent 0c799be6
......@@ -21,6 +21,7 @@ v 8.10.2 (unreleased)
- Fix backup restore. !5459
- Rescue Rugged::OSError (lock exists) when creating references. !5497
- Disable MySQL foreign key checks before dropping all tables. !5472
- Fix a bug where forking a project from a repository storage to another would fail
- Show release notes in tags list
- Use project ID in repository cache to prevent stale data from persisting across projects. !5460
- Ensure relative paths for video are rewritten as we do for images. !5474
......
......@@ -451,7 +451,9 @@ class Project < ActiveRecord::Base
def add_import_job
if forked?
job_id = RepositoryForkWorker.perform_async(self.id, forked_from_project.path_with_namespace, self.namespace.path)
job_id = RepositoryForkWorker.perform_async(id, forked_from_project.repository_storage_path,
forked_from_project.path_with_namespace,
self.namespace.path)
else
job_id = RepositoryImportWorker.perform_async(self.id)
end
......
......@@ -4,7 +4,7 @@ class RepositoryForkWorker
sidekiq_options queue: :gitlab_shell
def perform(project_id, source_path, target_path)
def perform(project_id, forked_from_repository_storage_path, source_path, target_path)
project = Project.find_by_id(project_id)
unless project.present?
......@@ -12,7 +12,8 @@ class RepositoryForkWorker
return
end
result = gitlab_shell.fork_repository(project.repository_storage_path, source_path, target_path)
result = gitlab_shell.fork_repository(forked_from_repository_storage_path, source_path,
project.repository_storage_path, target_path)
unless result
logger.error("Unable to fork project #{project_id} for repository #{source_path} -> #{target_path}")
project.mark_import_as_failed('The project could not be forked.')
......
......@@ -60,16 +60,18 @@ module Gitlab
end
# Fork repository to new namespace
# storage - project's storage path
# forked_from_storage - forked-from project's storage path
# path - project path with namespace
# forked_to_storage - forked-to project's storage path
# fork_namespace - namespace for forked project
#
# Ex.
# fork_repository("/path/to/storage", "gitlab/gitlab-ci", "randx")
# fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "randx")
#
def fork_repository(storage, path, fork_namespace)
def fork_repository(forked_from_storage, path, forked_to_storage, fork_namespace)
Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'fork-project',
storage, "#{path}.git", fork_namespace])
forked_from_storage, "#{path}.git", forked_to_storage,
fork_namespace])
end
# Remove repository from file system
......
......@@ -1244,6 +1244,32 @@ describe Project, models: true do
end
end
describe '#add_import_job' do
context 'forked' do
let(:forked_project_link) { create(:forked_project_link) }
let(:forked_from_project) { forked_project_link.forked_from_project }
let(:project) { forked_project_link.forked_to_project }
it 'schedules a RepositoryForkWorker job' do
expect(RepositoryForkWorker).to receive(:perform_async).
with(project.id, forked_from_project.repository_storage_path,
forked_from_project.path_with_namespace, project.namespace.path)
project.add_import_job
end
end
context 'not forked' do
let(:project) { create(:project) }
it 'schedules a RepositoryImportWorker job' do
expect(RepositoryImportWorker).to receive(:perform_async).with(project.id)
project.add_import_job
end
end
end
describe '.where_paths_in' do
context 'without any paths' do
it 'returns an empty relation' do
......
......@@ -14,21 +14,24 @@ describe RepositoryForkWorker do
describe "#perform" do
it "creates a new repository from a fork" do
expect(shell).to receive(:fork_repository).with(
project.repository_storage_path,
'/test/path',
project.path_with_namespace,
project.repository_storage_path,
fork_project.namespace.path
).and_return(true)
subject.perform(
project.id,
'/test/path',
project.path_with_namespace,
fork_project.namespace.path)
end
it 'flushes various caches' do
expect(shell).to receive(:fork_repository).with(
project.repository_storage_path,
'/test/path',
project.path_with_namespace,
project.repository_storage_path,
fork_project.namespace.path
).and_return(true)
......@@ -38,7 +41,7 @@ describe RepositoryForkWorker do
expect_any_instance_of(Repository).to receive(:expire_exists_cache).
and_call_original
subject.perform(project.id, project.path_with_namespace,
subject.perform(project.id, '/test/path', project.path_with_namespace,
fork_project.namespace.path)
end
......@@ -49,6 +52,7 @@ describe RepositoryForkWorker do
subject.perform(
project.id,
'/test/path',
project.path_with_namespace,
fork_project.namespace.path)
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