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