Commit 879d66b6 authored by Douwe Maan's avatar Douwe Maan

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
parents a4ffdf92 64d8a38b
...@@ -11,7 +11,9 @@ class Projects::RepositoriesController < Projects::ApplicationController ...@@ -11,7 +11,9 @@ class Projects::RepositoriesController < Projects::ApplicationController
end end
def archive 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 rescue => ex
logger.error("#{self.class.name}: #{ex}") logger.error("#{self.class.name}: #{ex}")
return git_not_found! return git_not_found!
......
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 ...@@ -353,7 +353,7 @@ GitLab Shell is an SSH access and repository management software developed speci
cd /home/git cd /home/git
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
cd gitlab-workhorse 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 sudo -u git -H make
### Initialize Database and Activate Advanced Features ### Initialize Database and Activate Advanced Features
......
...@@ -98,11 +98,8 @@ module API ...@@ -98,11 +98,8 @@ module API
authorize! :download_code, user_project authorize! :download_code, user_project
begin begin
ArchiveRepositoryService.new( RepositoryArchiveCacheWorker.perform_async
user_project, header *Gitlab::Workhorse.send_git_archive(user_project, params[:sha], params[:format])
params[:sha],
params[:format]
).execute
rescue rescue
not_found!('File') not_found!('File')
end end
......
...@@ -3,19 +3,38 @@ require 'json' ...@@ -3,19 +3,38 @@ require 'json'
module Gitlab module Gitlab
class Workhorse class Workhorse
SEND_DATA_HEADER = 'Gitlab-Workhorse-Send-Data'
class << self class << self
def send_git_blob(repository, blob) def send_git_blob(repository, blob)
params_hash = { params = {
'RepoPath' => repository.path_to_repo, 'RepoPath' => repository.path_to_repo,
'BlobId' => blob.id, 'BlobId' => blob.id,
} }
params = Base64.urlsafe_encode64(JSON.dump(params_hash))
[ [
'Gitlab-Workhorse-Send-Data', SEND_DATA_HEADER,
"git-blob:#{params}", "git-blob:#{encode(params)}",
] ]
end 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 end
end end
...@@ -8,15 +8,10 @@ describe Projects::RepositoriesController do ...@@ -8,15 +8,10 @@ describe Projects::RepositoriesController do
before do before do
sign_in(user) sign_in(user)
project.team << [user, :developer] project.team << [user, :developer]
allow(ArchiveRepositoryService).to receive(:new).and_return(service)
end end
let(:service) { ArchiveRepositoryService.new(project, "master", "zip") } it "uses Gitlab::Workhorse" do
expect(Gitlab::Workhorse).to receive(:send_git_archive).with(project, "master", "zip")
it "executes ArchiveRepositoryService" do
expect(ArchiveRepositoryService).to receive(:new).with(project, "master", "zip")
expect(service).to receive(:execute)
get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip" get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
end end
...@@ -24,7 +19,7 @@ describe Projects::RepositoriesController do ...@@ -24,7 +19,7 @@ describe Projects::RepositoriesController do
context "when the service raises an error" do context "when the service raises an error" do
before 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 end
it "renders Not Found" do it "renders Not Found" do
......
require 'spec_helper' require 'spec_helper'
describe ArchiveRepositoryService, services: true do describe Gitlab::Workhorse, lib: true do
let(:project) { create(:project) } let(:project) { create(:project) }
subject { ArchiveRepositoryService.new(project, "master", "zip") } let(:subject) { Gitlab::Workhorse }
describe "#execute" do
it "cleans old archives" do
expect(RepositoryArchiveCacheWorker).to receive(:perform_async)
subject.execute(timeout: 0.0)
end
describe "#send_git_archive" do
context "when the repository doesn't have an archive file path" do context "when the repository doesn't have an archive file path" do
before do before do
allow(project.repository).to receive(:archive_metadata).and_return(Hash.new) allow(project.repository).to receive(:archive_metadata).and_return(Hash.new)
end end
it "raises an error" do it "raises an error" do
expect { subject.execute(timeout: 0.0) }.to raise_error(RuntimeError) expect { subject.send_git_archive(project, "master", "zip") }.to raise_error(RuntimeError)
end end
end end
end end
end end
...@@ -4,6 +4,7 @@ require 'mime/types' ...@@ -4,6 +4,7 @@ require 'mime/types'
describe API::API, api: true do describe API::API, api: true do
include ApiHelpers include ApiHelpers
include RepoHelpers include RepoHelpers
include WorkhorseHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) } let(:user2) { create(:user) }
...@@ -91,21 +92,27 @@ describe API::API, api: true do ...@@ -91,21 +92,27 @@ describe API::API, api: true do
get api("/projects/#{project.id}/repository/archive", user) get api("/projects/#{project.id}/repository/archive", user)
repo_name = project.repository.name.gsub("\.git", "") repo_name = project.repository.name.gsub("\.git", "")
expect(response.status).to eq(200) 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 end
it "should get the archive.zip" do it "should get the archive.zip" do
get api("/projects/#{project.id}/repository/archive.zip", user) get api("/projects/#{project.id}/repository/archive.zip", user)
repo_name = project.repository.name.gsub("\.git", "") repo_name = project.repository.name.gsub("\.git", "")
expect(response.status).to eq(200) 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 end
it "should get the archive.tar.bz2" do it "should get the archive.tar.bz2" do
get api("/projects/#{project.id}/repository/archive.tar.bz2", user) get api("/projects/#{project.id}/repository/archive.tar.bz2", user)
repo_name = project.repository.name.gsub("\.git", "") repo_name = project.repository.name.gsub("\.git", "")
expect(response.status).to eq(200) 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 end
it "should return 404 for invalid sha" do it "should return 404 for invalid sha" do
......
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
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