Commit e35843f3 authored by Thong Kuah's avatar Thong Kuah

Merge branch '9490-store-designs-in-lfs' into 'master'

Support storing design blobs using LFS

See merge request gitlab-org/gitlab-ee!13389
parents 4a43187b 6001c02c
......@@ -50,7 +50,7 @@ module DesignManagement
{
action: new_file?(design) ? :create : :update,
file_path: design.full_path,
content: file.to_io
content: file_content(file, design.full_path)
}
end
......@@ -98,6 +98,13 @@ module DesignManagement
design.new_design? && existing_metadata.none? { |blob| blob.path == design.full_path }
end
def file_content(file, full_path)
return file.to_io if Feature.disabled?(:store_designs_in_lfs)
transformer = Lfs::FileTransformer.new(project, target_branch)
transformer.new_file(full_path, file.to_io).content
end
def existing_metadata
@existing_metadata ||= begin
paths = updated_designs.map(&:full_path)
......
---
title: Allow design blobs to be stored in Git LFS
merge_request: 13389
author:
type: added
......@@ -12,7 +12,7 @@ describe Projects::DesignsController do
end
describe 'GET #show' do
it 'serves the file using workhorse' do
subject do
get(:show,
params: {
namespace_id: project.namespace,
......@@ -20,11 +20,22 @@ describe Projects::DesignsController do
id: design.id,
ref: 'HEAD'
})
end
it 'serves the file using workhorse' do
subject
expect(response).to have_gitlab_http_status(200)
expect(response.header['Content-Disposition']).to eq('inline')
expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
end
it_behaves_like 'a controller that can serve LFS files' do
let(:design) { create(:design, :with_lfs_file, issue: issue) }
let(:lfs_oid) { project.design_repository.blob_at('HEAD', design.full_path).lfs_oid }
let(:filename) { design.filename }
let(:filepath) { design.full_path }
end
end
end
......@@ -6,6 +6,14 @@ FactoryBot.define do
project { issue.project }
sequence(:filename) { |n| "homescreen-#{n}.jpg" }
trait :with_lfs_file do
with_file
transient do
file Gitlab::Git::LfsPointerFile.new('').pointer
end
end
trait :with_file do
transient do
versions_count 1
......
......@@ -131,6 +131,36 @@ describe DesignManagement::SaveDesignsService do
end
end
context 'when LFS is enabled' do
before do
allow(project).to receive(:lfs_enabled?).and_return(true)
end
context 'and the `store_designs_in_lfs` feature is enabled' do
before do
stub_feature_flags(store_designs_in_lfs: true)
expect_next_instance_of(Lfs::FileTransformer) do |transformer|
expect(transformer).to receive(:lfs_file?).and_return(true)
end
end
it 'saves the design to LFS' do
expect { service.execute }.to change { LfsObject.count }.by(1)
end
end
context 'and the `store_designs_in_lfs` feature is not enabled' do
before do
stub_feature_flags(store_designs_in_lfs: false)
end
it 'does not save the design to LFS' do
expect { service.execute }.not_to change { LfsObject.count }
end
end
end
context 'when the user is not allowed to upload designs' do
let(:user) { create(:user) }
......
......@@ -39,7 +39,7 @@ describe Projects::AvatarsController do
end
context 'when the avatar is stored in lfs' do
it_behaves_like 'repository lfs file load' do
it_behaves_like 'a controller that can serve LFS files' do
let(:filename) { 'lfs_object.iso' }
let(:filepath) { "files/lfs/#{filename}" }
end
......
......@@ -42,7 +42,7 @@ describe Projects::RawController do
end
end
it_behaves_like 'repository lfs file load' do
it_behaves_like 'a controller that can serve LFS files' do
let(:filename) { 'lfs_object.iso' }
let(:filepath) { "be93687/files/lfs/#{filename}" }
end
......
......@@ -9,8 +9,7 @@
# - `filepath`: path of the file (contains filename)
# - `subject`: the request to be made to the controller. Example:
# subject { get :show, namespace_id: project.namespace, project_id: project }
shared_examples 'repository lfs file load' do
context 'when file is stored in lfs' do
shared_examples 'a controller that can serve LFS files' do
let(:lfs_oid) { '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897' }
let(:lfs_size) { '1575078' }
let!(:lfs_object) { create(:lfs_object, oid: lfs_oid, size: lfs_size) }
......@@ -28,11 +27,13 @@ shared_examples 'repository lfs file load' do
end
it 'serves the file' do
lfs_uploader = LfsObjectUploader.new(lfs_object)
# Notice the filename= is omitted from the disposition; this is because
# Rails 5 will append this header in send_file
expect(controller).to receive(:send_file)
.with(
"#{LfsObjectUploader.root}/91/ef/f75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897",
File.join(lfs_uploader.root, lfs_uploader.store_dir, lfs_uploader.filename),
filename: filename,
disposition: %Q(attachment; filename*=UTF-8''#{filename}))
......@@ -62,7 +63,7 @@ shared_examples 'repository lfs file load' do
file_uri = URI.parse(response.location)
params = CGI.parse(file_uri.query)
expect(params["response-content-disposition"].first).to eq(%q(attachment; filename="lfs_object.iso"; filename*=UTF-8''lfs_object.iso))
expect(params["response-content-disposition"].first).to eq(%Q(attachment; filename="#{filename}"; filename*=UTF-8''#{filename}))
end
end
end
......@@ -91,5 +92,4 @@ shared_examples 'repository lfs file load' do
expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
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