Commit e73a8fed authored by Patrick Bajao's avatar Patrick Bajao

Create LfsObjectsProject record for forks as well

Previous behavior was `LfsObjectsProject` are created on the
source project.

To fix the issue whenever the source project gets deleted or
fork was selectively synced, we also need to create the records
for forks.

This way, they'll also have access to the `LfsObject` and no
longer dependent on the source project.
parent 794e3ce7
......@@ -112,10 +112,6 @@ module LfsRequest
has_authentication_ability?(:build_download_code) && can?(user, :build_download_code, project)
end
def storage_project
@storage_project ||= project.lfs_storage_project
end
def objects
@objects ||= (params[:objects] || []).to_a
end
......
......@@ -80,12 +80,13 @@ module Repositories
LfsObject.create!(oid: oid, size: size, file: uploaded_file)
end
# rubocop: disable CodeReuse/ActiveRecord
def link_to_project!(object)
if object && !object.projects.exists?(storage_project.id)
object.lfs_objects_projects.create!(project: storage_project)
end
return unless object
LfsObjectsProject.safe_find_or_create_by!(
project: project,
lfs_object: object
)
end
# rubocop: enable CodeReuse/ActiveRecord
end
end
# frozen_string_literal: true
module LfsObjectsProjects
class BulkCreateService < BaseService
def initialize(project, params = {})
@project = project
@params = params
end
def execute
target_project = params[:target_project]
return unless target_project.present?
Gitlab::Database.bulk_insert(
LfsObjectsProject.table_name,
lfs_objects_projects_map(target_project),
on_conflict: :do_nothing
)
end
private
def lfs_objects_projects_map(target_project)
project.lfs_objects_projects.map do |objects_project|
{
lfs_object_id: objects_project.lfs_object_id,
project_id: target_project.id,
repository_type: objects_project.read_attribute_before_type_cast(:repository_type)
}
end
end
end
end
......@@ -39,9 +39,9 @@ module Projects
def download_lfs_file!
with_tmp_file do |tmp_file|
download_and_save_file!(tmp_file)
project.all_lfs_objects << LfsObject.new(oid: lfs_oid,
size: lfs_size,
file: tmp_file)
project.lfs_objects << LfsObject.new(oid: lfs_oid,
size: lfs_size,
file: tmp_file)
success
end
......
......@@ -29,7 +29,13 @@ class RepositoryForkWorker
result = gitlab_shell.fork_repository(source_project, target_project)
raise "Unable to fork project #{target_project.id} for repository #{source_project.disk_path} -> #{target_project.disk_path}" unless result
if result
LfsObjectsProjects::BulkCreateService
.new(source_project, target_project: target_project)
.execute
else
raise "Unable to fork project #{target_project.id} for repository #{source_project.disk_path} -> #{target_project.disk_path}"
end
target_project.after_import
end
......
---
title: Create LfsObjectsProject record for forks as well
merge_request: 22418
author:
type: fixed
......@@ -10,8 +10,6 @@ describe LfsRequest do
include LfsRequest
def show
storage_project
head :ok
end
......@@ -38,22 +36,6 @@ describe LfsRequest do
stub_lfs_setting(enabled: true)
end
describe '#storage_project' do
it 'assigns the project as storage project' do
get :show, params: { id: project.id }
expect(assigns(:storage_project)).to eq(project)
end
it 'assigns the source of a forked project' do
forked_project = fork_project(project)
get :show, params: { id: forked_project.id }
expect(assigns(:storage_project)).to eq(project)
end
end
context 'user is authenticated without access to lfs' do
before do
allow(controller).to receive(:authenticate_user)
......
......@@ -1193,8 +1193,8 @@ describe 'Git LFS API and storage' do
it_behaves_like 'LFS http 200 response'
it 'LFS object is linked to the source project' do
expect(lfs_object.projects.pluck(:id)).to include(upstream_project.id)
it 'LFS object is linked to the forked project' do
expect(lfs_object.projects.pluck(:id)).to include(project.id)
end
end
end
......
# frozen_string_literal: true
require 'spec_helper'
describe LfsObjectsProjects::BulkCreateService do
let(:project) { create(:project) }
let(:target_project) { create(:project) }
let(:params) { { target_project: target_project } }
subject { described_class.new(project, params).execute }
shared_examples_for 'LFS objects assigned to target project' do
it 'creates LfsObjectsProject records for the target project' do
expect { subject }.to change { target_project.lfs_objects.count }
expect(target_project.lfs_objects).to eq(project.lfs_objects)
end
end
context 'target_project is not associated with any of the LFS objects' do
before do
create(:lfs_objects_project, project: project)
create(:lfs_objects_project, project: project)
end
it_behaves_like 'LFS objects assigned to target project'
end
context 'target_project already associated with some of the LFS objects' do
before do
objects_project = create(:lfs_objects_project, project: project)
create(:lfs_objects_project, project: target_project, lfs_object: objects_project.lfs_object)
create(:lfs_objects_project, project: project)
end
it_behaves_like 'LFS objects assigned to target project'
end
context 'target_project is not passed' do
let(:params) { {} }
it 'does not create LfsObjectsProject records for the target project' do
expect { subject }.not_to change { target_project.lfs_objects.count }
expect(target_project.lfs_objects).to be_empty
end
end
end
......@@ -48,10 +48,11 @@ describe Projects::LfsPointers::LfsDownloadService do
end
shared_examples 'lfs object is created' do
it do
it 'creates and associate the LFS object to project' do
expect(subject).to receive(:download_and_save_file!).and_call_original
expect { subject.execute }.to change { LfsObject.count }.by(1)
expect(LfsObject.first.projects).to include(project)
end
it 'returns success result' do
......
......@@ -47,6 +47,15 @@ describe RepositoryForkWorker do
perform!
end
it 'calls LfsObjectsProjects::BulkCreateService#execute' do
expect_fork_repository.and_return(true)
expect_next_instance_of(LfsObjectsProjects::BulkCreateService) do |service|
expect(service).to receive(:execute)
end
perform!
end
it 'protects the default branch' do
expect_fork_repository.and_return(true)
......
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