Use Gitaly for CommitController#show
This commit is contained in:
parent
b716680692
commit
c0a4f527db
11 changed files with 199 additions and 7 deletions
2
Gemfile
2
Gemfile
|
@ -352,4 +352,4 @@ gem 'vmstat', '~> 2.3.0'
|
|||
gem 'sys-filesystem', '~> 1.1.6'
|
||||
|
||||
# Gitaly GRPC client
|
||||
gem 'gitaly', '~> 0.2.1'
|
||||
gem 'gitaly', '~> 0.3.0'
|
||||
|
|
|
@ -250,7 +250,7 @@ GEM
|
|||
json
|
||||
get_process_mem (0.2.0)
|
||||
gherkin-ruby (0.3.2)
|
||||
gitaly (0.2.1)
|
||||
gitaly (0.3.0)
|
||||
google-protobuf (~> 3.1)
|
||||
grpc (~> 1.0)
|
||||
github-linguist (4.7.6)
|
||||
|
@ -896,7 +896,7 @@ DEPENDENCIES
|
|||
fuubar (~> 2.0.0)
|
||||
gemnasium-gitlab-service (~> 0.2)
|
||||
gemojione (~> 3.0)
|
||||
gitaly (~> 0.2.1)
|
||||
gitaly (~> 0.3.0)
|
||||
github-linguist (~> 4.7.0)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab-markup (~> 1.5.1)
|
||||
|
|
|
@ -317,7 +317,14 @@ class Commit
|
|||
end
|
||||
|
||||
def raw_diffs(*args)
|
||||
raw.diffs(*args)
|
||||
use_gitaly = Gitlab::GitalyClient.feature_enabled?(:commit_raw_diffs)
|
||||
deltas_only = args.last.is_a?(Hash) && args.last[:deltas_only]
|
||||
|
||||
if use_gitaly && !deltas_only
|
||||
Gitlab::GitalyClient::Commit.diff_from_parent(self, *args)
|
||||
else
|
||||
raw.diffs(*args)
|
||||
end
|
||||
end
|
||||
|
||||
def diffs(diff_options = nil)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Use Gitaly for CommitController#show
|
||||
merge_request: 9629
|
||||
author:
|
|
@ -176,9 +176,13 @@ module Gitlab
|
|||
def initialize(raw_diff, collapse: false)
|
||||
case raw_diff
|
||||
when Hash
|
||||
init_from_hash(raw_diff, collapse: collapse)
|
||||
init_from_hash(raw_diff)
|
||||
prune_diff_if_eligible(collapse)
|
||||
when Rugged::Patch, Rugged::Diff::Delta
|
||||
init_from_rugged(raw_diff, collapse: collapse)
|
||||
when Gitaly::CommitDiffResponse
|
||||
init_from_gitaly(raw_diff)
|
||||
prune_diff_if_eligible(collapse)
|
||||
when nil
|
||||
raise "Nil as raw diff passed"
|
||||
else
|
||||
|
@ -266,13 +270,26 @@ module Gitlab
|
|||
@diff = encode!(strip_diff_headers(patch.to_s))
|
||||
end
|
||||
|
||||
def init_from_hash(hash, collapse: false)
|
||||
def init_from_hash(hash)
|
||||
raw_diff = hash.symbolize_keys
|
||||
|
||||
serialize_keys.each do |key|
|
||||
send(:"#{key}=", raw_diff[key.to_sym])
|
||||
end
|
||||
end
|
||||
|
||||
def init_from_gitaly(diff_msg)
|
||||
@diff = diff_msg.raw_chunks.join
|
||||
@new_path = encode!(diff_msg.to_path.dup)
|
||||
@old_path = encode!(diff_msg.from_path.dup)
|
||||
@a_mode = diff_msg.old_mode.to_s(8)
|
||||
@b_mode = diff_msg.new_mode.to_s(8)
|
||||
@new_file = diff_msg.from_id == BLANK_SHA
|
||||
@renamed_file = diff_msg.from_path != diff_msg.to_path
|
||||
@deleted_file = diff_msg.to_id == BLANK_SHA
|
||||
end
|
||||
|
||||
def prune_diff_if_eligible(collapse = false)
|
||||
prune_large_diff! if too_large?
|
||||
prune_collapsed_diff! if collapse && collapsible?
|
||||
end
|
||||
|
|
|
@ -30,7 +30,9 @@ module Gitlab
|
|||
elsif @deltas_only
|
||||
each_delta(&block)
|
||||
else
|
||||
each_patch(&block)
|
||||
Gitlab::GitalyClient.migrate(:commit_raw_diffs) do
|
||||
each_patch(&block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -25,5 +25,19 @@ module Gitlab
|
|||
def self.enabled?
|
||||
gitaly_address.present?
|
||||
end
|
||||
|
||||
def self.feature_enabled?(feature)
|
||||
enabled? && ENV["GITALY_#{feature.upcase}"] == '1'
|
||||
end
|
||||
|
||||
def self.migrate(feature)
|
||||
is_enabled = feature_enabled?(feature)
|
||||
metric_name = feature.to_s
|
||||
metric_name += "_gitaly" if is_enabled
|
||||
|
||||
Gitlab::Metrics.measure(metric_name) do
|
||||
yield is_enabled
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
25
lib/gitlab/gitaly_client/commit.rb
Normal file
25
lib/gitlab/gitaly_client/commit.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
module Gitlab
|
||||
module GitalyClient
|
||||
class Commit
|
||||
# The ID of empty tree.
|
||||
# See http://stackoverflow.com/a/40884093/1856239 and https://github.com/git/git/blob/3ad8b5bf26362ac67c9020bf8c30eee54a84f56d/cache.h#L1011-L1012
|
||||
EMPTY_TREE_ID = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'.freeze
|
||||
|
||||
class << self
|
||||
def diff_from_parent(commit, options = {})
|
||||
stub = Gitaly::Diff::Stub.new(nil, nil, channel_override: GitalyClient.channel)
|
||||
repo = Gitaly::Repository.new(path: commit.project.repository.path_to_repo)
|
||||
parent = commit.parents[0]
|
||||
parent_id = parent ? parent.id : EMPTY_TREE_ID
|
||||
request = Gitaly::CommitDiffRequest.new(
|
||||
repository: repo,
|
||||
left_commit_id: parent_id,
|
||||
right_commit_id: commit.id
|
||||
)
|
||||
|
||||
Gitlab::Git::DiffCollection.new(stub.commit_diff(request), options)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -109,6 +109,43 @@ EOT
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'using a Gitaly::CommitDiffResponse' do
|
||||
let(:diff) do
|
||||
described_class.new(
|
||||
Gitaly::CommitDiffResponse.new(
|
||||
to_path: ".gitmodules",
|
||||
from_path: ".gitmodules",
|
||||
old_mode: 0100644,
|
||||
new_mode: 0100644,
|
||||
from_id: '357406f3075a57708d0163752905cc1576fceacc',
|
||||
to_id: '8e5177d718c561d36efde08bad36b43687ee6bf0',
|
||||
raw_chunks: raw_chunks,
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
context 'with a small diff' do
|
||||
let(:raw_chunks) { [@raw_diff_hash[:diff]] }
|
||||
|
||||
it 'initializes the diff' do
|
||||
expect(diff.to_hash).to eq(@raw_diff_hash)
|
||||
end
|
||||
|
||||
it 'does not prune the diff' do
|
||||
expect(diff).not_to be_too_large
|
||||
end
|
||||
end
|
||||
|
||||
context 'using a diff that is too large' do
|
||||
let(:raw_chunks) { ['a' * 204800] }
|
||||
|
||||
it 'prunes the diff' do
|
||||
expect(diff.diff).to be_empty
|
||||
expect(diff).to be_too_large
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'straight diffs' do
|
||||
|
|
58
spec/lib/gitlab/gitaly_client/commit_spec.rb
Normal file
58
spec/lib/gitlab/gitaly_client/commit_spec.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GitalyClient::Commit do
|
||||
describe '.diff_from_parent' do
|
||||
let(:diff_stub) { double('Gitaly::Diff::Stub') }
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:repository_message) { Gitaly::Repository.new(path: project.repository.path) }
|
||||
let(:commit) { project.commit('913c66a37b4a45b9769037c55c2d238bd0942d2e') }
|
||||
|
||||
before do
|
||||
allow(Gitaly::Diff::Stub).to receive(:new).and_return(diff_stub)
|
||||
allow(diff_stub).to receive(:commit_diff).and_return([])
|
||||
end
|
||||
|
||||
context 'when a commit has a parent' do
|
||||
it 'sends an RPC request with the parent ID as left commit' do
|
||||
request = Gitaly::CommitDiffRequest.new(
|
||||
repository: repository_message,
|
||||
left_commit_id: 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
|
||||
right_commit_id: commit.id,
|
||||
)
|
||||
|
||||
expect(diff_stub).to receive(:commit_diff).with(request)
|
||||
|
||||
described_class.diff_from_parent(commit)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a commit does not have a parent' do
|
||||
it 'sends an RPC request with empty tree ref as left commit' do
|
||||
initial_commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863')
|
||||
request = Gitaly::CommitDiffRequest.new(
|
||||
repository: repository_message,
|
||||
left_commit_id: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
|
||||
right_commit_id: initial_commit.id,
|
||||
)
|
||||
|
||||
expect(diff_stub).to receive(:commit_diff).with(request)
|
||||
|
||||
described_class.diff_from_parent(initial_commit)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns a Gitlab::Git::DiffCollection' do
|
||||
ret = described_class.diff_from_parent(commit)
|
||||
|
||||
expect(ret).to be_kind_of(Gitlab::Git::DiffCollection)
|
||||
end
|
||||
|
||||
it 'passes options to Gitlab::Git::DiffCollection' do
|
||||
options = { max_files: 31, max_lines: 13 }
|
||||
|
||||
expect(Gitlab::Git::DiffCollection).to receive(:new).with([], options)
|
||||
|
||||
described_class.diff_from_parent(commit, options)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -369,4 +369,32 @@ eos
|
|||
expect(described_class.valid_hash?('a' * 41)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe '#raw_diffs' do
|
||||
context 'Gitaly commit_raw_diffs feature enabled' do
|
||||
before do
|
||||
allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:commit_raw_diffs).and_return(true)
|
||||
end
|
||||
|
||||
context 'when a truthy deltas_only is not passed to args' do
|
||||
it 'fetches diffs from Gitaly server' do
|
||||
expect(Gitlab::GitalyClient::Commit).to receive(:diff_from_parent).
|
||||
with(commit)
|
||||
|
||||
commit.raw_diffs
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a truthy deltas_only is passed to args' do
|
||||
it 'fetches diffs using Rugged' do
|
||||
opts = { deltas_only: true }
|
||||
|
||||
expect(Gitlab::GitalyClient::Commit).not_to receive(:diff_from_parent)
|
||||
expect(commit.raw).to receive(:diffs).with(opts)
|
||||
|
||||
commit.raw_diffs(opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue