Merge branch 'git-archive-refactor' into 'master'
Refactor 'git archive' hand-off to gitlab-workhorse We have a nicer way now to hand off HTTP responses to gitlab-workhorse. Companion MR: https://gitlab.com/gitlab-org/gitlab-workhorse/merge_requests/36 See merge request !2675
This commit is contained in:
commit
879d66b6ab
11 changed files with 77 additions and 71 deletions
|
@ -1 +1 @@
|
|||
0.6.4
|
||||
0.6.5
|
||||
|
|
|
@ -11,7 +11,9 @@ class Projects::RepositoriesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def archive
|
||||
render json: ArchiveRepositoryService.new(@project, params[:ref], params[:format]).execute
|
||||
RepositoryArchiveCacheWorker.perform_async
|
||||
headers.store(*Gitlab::Workhorse.send_git_archive(@project, params[:ref], params[:format]))
|
||||
head :ok
|
||||
rescue => ex
|
||||
logger.error("#{self.class.name}: #{ex}")
|
||||
return git_not_found!
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
class ArchiveRepositoryService
|
||||
attr_reader :project, :ref, :format
|
||||
|
||||
def initialize(project, ref, format)
|
||||
format ||= 'tar.gz'
|
||||
@project, @ref, @format = project, ref, format.downcase
|
||||
end
|
||||
|
||||
def execute(options = {})
|
||||
RepositoryArchiveCacheWorker.perform_async
|
||||
|
||||
metadata = project.repository.archive_metadata(ref, storage_path, format)
|
||||
raise "Repository or ref not found" if metadata.empty?
|
||||
|
||||
metadata
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def storage_path
|
||||
Gitlab.config.gitlab.repository_downloads_path
|
||||
end
|
||||
end
|
|
@ -353,7 +353,7 @@ GitLab Shell is an SSH access and repository management software developed speci
|
|||
cd /home/git
|
||||
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
|
||||
cd gitlab-workhorse
|
||||
sudo -u git -H git checkout 0.6.4
|
||||
sudo -u git -H git checkout 0.6.5
|
||||
sudo -u git -H make
|
||||
|
||||
### Initialize Database and Activate Advanced Features
|
||||
|
|
|
@ -98,11 +98,8 @@ module API
|
|||
authorize! :download_code, user_project
|
||||
|
||||
begin
|
||||
ArchiveRepositoryService.new(
|
||||
user_project,
|
||||
params[:sha],
|
||||
params[:format]
|
||||
).execute
|
||||
RepositoryArchiveCacheWorker.perform_async
|
||||
header *Gitlab::Workhorse.send_git_archive(user_project, params[:sha], params[:format])
|
||||
rescue
|
||||
not_found!('File')
|
||||
end
|
||||
|
|
|
@ -3,19 +3,38 @@ require 'json'
|
|||
|
||||
module Gitlab
|
||||
class Workhorse
|
||||
SEND_DATA_HEADER = 'Gitlab-Workhorse-Send-Data'
|
||||
|
||||
class << self
|
||||
def send_git_blob(repository, blob)
|
||||
params_hash = {
|
||||
params = {
|
||||
'RepoPath' => repository.path_to_repo,
|
||||
'BlobId' => blob.id,
|
||||
}
|
||||
params = Base64.urlsafe_encode64(JSON.dump(params_hash))
|
||||
|
||||
[
|
||||
'Gitlab-Workhorse-Send-Data',
|
||||
"git-blob:#{params}",
|
||||
SEND_DATA_HEADER,
|
||||
"git-blob:#{encode(params)}",
|
||||
]
|
||||
end
|
||||
|
||||
def send_git_archive(project, ref, format)
|
||||
format ||= 'tar.gz'
|
||||
format.downcase!
|
||||
params = project.repository.archive_metadata(ref, Gitlab.config.gitlab.repository_downloads_path, format)
|
||||
raise "Repository or ref not found" if params.empty?
|
||||
|
||||
[
|
||||
SEND_DATA_HEADER,
|
||||
"git-archive:#{encode(params)}",
|
||||
]
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def encode(hash)
|
||||
Base64.urlsafe_encode64(JSON.dump(hash))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,15 +8,10 @@ describe Projects::RepositoriesController do
|
|||
before do
|
||||
sign_in(user)
|
||||
project.team << [user, :developer]
|
||||
|
||||
allow(ArchiveRepositoryService).to receive(:new).and_return(service)
|
||||
end
|
||||
|
||||
let(:service) { ArchiveRepositoryService.new(project, "master", "zip") }
|
||||
|
||||
it "executes ArchiveRepositoryService" do
|
||||
expect(ArchiveRepositoryService).to receive(:new).with(project, "master", "zip")
|
||||
expect(service).to receive(:execute)
|
||||
it "uses Gitlab::Workhorse" do
|
||||
expect(Gitlab::Workhorse).to receive(:send_git_archive).with(project, "master", "zip")
|
||||
|
||||
get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
|
||||
end
|
||||
|
@ -24,7 +19,7 @@ describe Projects::RepositoriesController do
|
|||
context "when the service raises an error" do
|
||||
|
||||
before do
|
||||
allow(service).to receive(:execute).and_raise("Archive failed")
|
||||
allow(Gitlab::Workhorse).to receive(:send_git_archive).and_raise("Archive failed")
|
||||
end
|
||||
|
||||
it "renders Not Found" do
|
||||
|
|
18
spec/lib/gitlab/workhorse_spec.rb
Normal file
18
spec/lib/gitlab/workhorse_spec.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Workhorse, lib: true do
|
||||
let(:project) { create(:project) }
|
||||
let(:subject) { Gitlab::Workhorse }
|
||||
|
||||
describe "#send_git_archive" do
|
||||
context "when the repository doesn't have an archive file path" do
|
||||
before do
|
||||
allow(project.repository).to receive(:archive_metadata).and_return(Hash.new)
|
||||
end
|
||||
|
||||
it "raises an error" do
|
||||
expect { subject.send_git_archive(project, "master", "zip") }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,6 +4,7 @@ require 'mime/types'
|
|||
describe API::API, api: true do
|
||||
include ApiHelpers
|
||||
include RepoHelpers
|
||||
include WorkhorseHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:user2) { create(:user) }
|
||||
|
@ -91,21 +92,27 @@ describe API::API, api: true do
|
|||
get api("/projects/#{project.id}/repository/archive", user)
|
||||
repo_name = project.repository.name.gsub("\.git", "")
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.gz/)
|
||||
type, params = workhorse_send_data
|
||||
expect(type).to eq('git-archive')
|
||||
expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.gz/)
|
||||
end
|
||||
|
||||
it "should get the archive.zip" do
|
||||
get api("/projects/#{project.id}/repository/archive.zip", user)
|
||||
repo_name = project.repository.name.gsub("\.git", "")
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.zip/)
|
||||
type, params = workhorse_send_data
|
||||
expect(type).to eq('git-archive')
|
||||
expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.zip/)
|
||||
end
|
||||
|
||||
it "should get the archive.tar.bz2" do
|
||||
get api("/projects/#{project.id}/repository/archive.tar.bz2", user)
|
||||
repo_name = project.repository.name.gsub("\.git", "")
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.bz2/)
|
||||
type, params = workhorse_send_data
|
||||
expect(type).to eq('git-archive')
|
||||
expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.bz2/)
|
||||
end
|
||||
|
||||
it "should return 404 for invalid sha" do
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ArchiveRepositoryService, services: true do
|
||||
let(:project) { create(:project) }
|
||||
subject { ArchiveRepositoryService.new(project, "master", "zip") }
|
||||
|
||||
describe "#execute" do
|
||||
it "cleans old archives" do
|
||||
expect(RepositoryArchiveCacheWorker).to receive(:perform_async)
|
||||
|
||||
subject.execute(timeout: 0.0)
|
||||
end
|
||||
|
||||
context "when the repository doesn't have an archive file path" do
|
||||
before do
|
||||
allow(project.repository).to receive(:archive_metadata).and_return(Hash.new)
|
||||
end
|
||||
|
||||
it "raises an error" do
|
||||
expect { subject.execute(timeout: 0.0) }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
16
spec/support/workhorse_helpers.rb
Normal file
16
spec/support/workhorse_helpers.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
module WorkhorseHelpers
|
||||
extend self
|
||||
|
||||
def workhorse_send_data
|
||||
@_workhorse_send_data ||= begin
|
||||
header = response.headers[Gitlab::Workhorse::SEND_DATA_HEADER]
|
||||
split_header = header.split(':')
|
||||
type = split_header.shift
|
||||
header = split_header.join(':')
|
||||
[
|
||||
type,
|
||||
JSON.parse(Base64.urlsafe_decode64(header)),
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue