Commit 99feed6e authored by Ahmad Sherif's avatar Ahmad Sherif

Add support for deltas_only under Gitaly

Closes gitaly#199
parent aa6f4432
...@@ -367,6 +367,6 @@ gem 'vmstat', '~> 2.3.0' ...@@ -367,6 +367,6 @@ gem 'vmstat', '~> 2.3.0'
gem 'sys-filesystem', '~> 1.1.6' gem 'sys-filesystem', '~> 1.1.6'
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly', '~> 0.6.0' gem 'gitaly', '~> 0.7.0'
gem 'toml-rb', '~> 0.3.15', require: false gem 'toml-rb', '~> 0.3.15', require: false
...@@ -265,7 +265,7 @@ GEM ...@@ -265,7 +265,7 @@ GEM
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gherkin-ruby (0.3.2) gherkin-ruby (0.3.2)
gitaly (0.6.0) gitaly (0.7.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
grpc (~> 1.0) grpc (~> 1.0)
github-linguist (4.7.6) github-linguist (4.7.6)
...@@ -924,7 +924,7 @@ DEPENDENCIES ...@@ -924,7 +924,7 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0) gettext_i18n_rails_js (~> 1.2.0)
gitaly (~> 0.6.0) gitaly (~> 0.7.0)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.5.1) gitlab-markup (~> 1.5.1)
......
...@@ -327,13 +327,21 @@ class Commit ...@@ -327,13 +327,21 @@ class Commit
def raw_diffs(*args) def raw_diffs(*args)
if Gitlab::GitalyClient.feature_enabled?(:commit_raw_diffs) if Gitlab::GitalyClient.feature_enabled?(:commit_raw_diffs)
Gitlab::GitalyClient::Commit.diff_from_parent(self, *args) Gitlab::GitalyClient::Commit.new(project.repository).diff_from_parent(self, *args)
else else
raw.diffs(*args) raw.diffs(*args)
end end
end end
delegate :deltas, to: :raw, prefix: :raw def raw_deltas
@deltas ||= Gitlab::GitalyClient.migrate(:commit_deltas) do |is_enabled|
if is_enabled
Gitlab::GitalyClient::Commit.new(project.repository).commit_deltas(self)
else
raw.deltas
end
end
end
def diffs(diff_options = nil) def diffs(diff_options = nil)
Gitlab::Diff::FileCollection::Commit.new(self, diff_options: diff_options) Gitlab::Diff::FileCollection::Commit.new(self, diff_options: diff_options)
......
...@@ -183,6 +183,8 @@ module Gitlab ...@@ -183,6 +183,8 @@ module Gitlab
when Gitaly::CommitDiffResponse when Gitaly::CommitDiffResponse
init_from_gitaly(raw_diff) init_from_gitaly(raw_diff)
prune_diff_if_eligible(collapse) prune_diff_if_eligible(collapse)
when Gitaly::CommitDelta
init_from_gitaly(raw_diff)
when nil when nil
raise "Nil as raw diff passed" raise "Nil as raw diff passed"
else else
...@@ -278,15 +280,15 @@ module Gitlab ...@@ -278,15 +280,15 @@ module Gitlab
end end
end end
def init_from_gitaly(diff_msg) def init_from_gitaly(msg)
@diff = diff_msg.raw_chunks.join @diff = msg.raw_chunks.join if msg.respond_to?(:raw_chunks)
@new_path = encode!(diff_msg.to_path.dup) @new_path = encode!(msg.to_path.dup)
@old_path = encode!(diff_msg.from_path.dup) @old_path = encode!(msg.from_path.dup)
@a_mode = diff_msg.old_mode.to_s(8) @a_mode = msg.old_mode.to_s(8)
@b_mode = diff_msg.new_mode.to_s(8) @b_mode = msg.new_mode.to_s(8)
@new_file = diff_msg.from_id == BLANK_SHA @new_file = msg.from_id == BLANK_SHA
@renamed_file = diff_msg.from_path != diff_msg.to_path @renamed_file = msg.from_path != msg.to_path
@deleted_file = diff_msg.to_id == BLANK_SHA @deleted_file = msg.to_id == BLANK_SHA
end end
def prune_diff_if_eligible(collapse = false) def prune_diff_if_eligible(collapse = false)
......
...@@ -5,40 +5,54 @@ module Gitlab ...@@ -5,40 +5,54 @@ module Gitlab
# See http://stackoverflow.com/a/40884093/1856239 and https://github.com/git/git/blob/3ad8b5bf26362ac67c9020bf8c30eee54a84f56d/cache.h#L1011-L1012 # See http://stackoverflow.com/a/40884093/1856239 and https://github.com/git/git/blob/3ad8b5bf26362ac67c9020bf8c30eee54a84f56d/cache.h#L1011-L1012
EMPTY_TREE_ID = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'.freeze EMPTY_TREE_ID = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'.freeze
attr_accessor :stub
def initialize(repository) def initialize(repository)
@gitaly_repo = repository.gitaly_repository @gitaly_repo = repository.gitaly_repository
@stub = Gitaly::Commit::Stub.new(nil, nil, channel_override: repository.gitaly_channel) @repository = repository
end end
def is_ancestor(ancestor_id, child_id) def is_ancestor(ancestor_id, child_id)
stub = Gitaly::Commit::Stub.new(nil, nil, channel_override: @repository.gitaly_channel)
request = Gitaly::CommitIsAncestorRequest.new( request = Gitaly::CommitIsAncestorRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
ancestor_id: ancestor_id, ancestor_id: ancestor_id,
child_id: child_id child_id: child_id
) )
@stub.commit_is_ancestor(request).value stub.commit_is_ancestor(request).value
end end
class << self
def diff_from_parent(commit, options = {}) def diff_from_parent(commit, options = {})
repository = commit.project.repository request_params = commit_diff_request_params(commit, options)
gitaly_repo = repository.gitaly_repository request_params[:ignore_whitespace_change] = options.fetch(:ignore_whitespace_change, false)
stub = Gitaly::Diff::Stub.new(nil, nil, channel_override: repository.gitaly_channel)
parent = commit.parents[0] response = diff_service_stub.commit_diff(Gitaly::CommitDiffRequest.new(request_params))
parent_id = parent ? parent.id : EMPTY_TREE_ID Gitlab::Git::DiffCollection.new(response, options)
request = Gitaly::CommitDiffRequest.new( end
repository: gitaly_repo,
def commit_deltas(commit)
request_params = commit_diff_request_params(commit)
response = diff_service_stub.commit_delta(Gitaly::CommitDeltaRequest.new(request_params))
response.flat_map do |msg|
msg.deltas.map { |d| Gitlab::Git::Diff.new(d) }
end
end
private
def commit_diff_request_params(commit, options = {})
parent_id = commit.parents[0]&.id || EMPTY_TREE_ID
{
repository: @gitaly_repo,
left_commit_id: parent_id, left_commit_id: parent_id,
right_commit_id: commit.id, right_commit_id: commit.id,
ignore_whitespace_change: options.fetch(:ignore_whitespace_change, false),
paths: options.fetch(:paths, []) paths: options.fetch(:paths, [])
) }
Gitlab::Git::DiffCollection.new(stub.commit_diff(request), options)
end end
def diff_service_stub
Gitaly::Diff::Stub.new(nil, nil, channel_override: @repository.gitaly_channel)
end end
end end
end end
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::GitalyClient::Commit do describe Gitlab::GitalyClient::Commit do
describe '.diff_from_parent' do
let(:diff_stub) { double('Gitaly::Diff::Stub') } let(:diff_stub) { double('Gitaly::Diff::Stub') }
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:repository_message) { project.repository.gitaly_repository } let(:repository) { project.repository }
let(:repository_message) { repository.gitaly_repository }
let(:commit) { project.commit('913c66a37b4a45b9769037c55c2d238bd0942d2e') } let(:commit) { project.commit('913c66a37b4a45b9769037c55c2d238bd0942d2e') }
describe '#diff_from_parent' do
context 'when a commit has a parent' do context 'when a commit has a parent' do
it 'sends an RPC request with the parent ID as left commit' do it 'sends an RPC request with the parent ID as left commit' do
request = Gitaly::CommitDiffRequest.new( request = Gitaly::CommitDiffRequest.new(
...@@ -17,7 +18,7 @@ describe Gitlab::GitalyClient::Commit do ...@@ -17,7 +18,7 @@ describe Gitlab::GitalyClient::Commit do
expect_any_instance_of(Gitaly::Diff::Stub).to receive(:commit_diff).with(request) expect_any_instance_of(Gitaly::Diff::Stub).to receive(:commit_diff).with(request)
described_class.diff_from_parent(commit) described_class.new(repository).diff_from_parent(commit)
end end
end end
...@@ -32,12 +33,12 @@ describe Gitlab::GitalyClient::Commit do ...@@ -32,12 +33,12 @@ describe Gitlab::GitalyClient::Commit do
expect_any_instance_of(Gitaly::Diff::Stub).to receive(:commit_diff).with(request) expect_any_instance_of(Gitaly::Diff::Stub).to receive(:commit_diff).with(request)
described_class.diff_from_parent(initial_commit) described_class.new(repository).diff_from_parent(initial_commit)
end end
end end
it 'returns a Gitlab::Git::DiffCollection' do it 'returns a Gitlab::Git::DiffCollection' do
ret = described_class.diff_from_parent(commit) ret = described_class.new(repository).diff_from_parent(commit)
expect(ret).to be_kind_of(Gitlab::Git::DiffCollection) expect(ret).to be_kind_of(Gitlab::Git::DiffCollection)
end end
...@@ -47,7 +48,38 @@ describe Gitlab::GitalyClient::Commit do ...@@ -47,7 +48,38 @@ describe Gitlab::GitalyClient::Commit do
expect(Gitlab::Git::DiffCollection).to receive(:new).with(kind_of(Enumerable), options) expect(Gitlab::Git::DiffCollection).to receive(:new).with(kind_of(Enumerable), options)
described_class.diff_from_parent(commit, options) described_class.new(repository).diff_from_parent(commit, options)
end
end
describe '#commit_deltas' do
context 'when a commit has a parent' do
it 'sends an RPC request with the parent ID as left commit' do
request = Gitaly::CommitDeltaRequest.new(
repository: repository_message,
left_commit_id: 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
right_commit_id: commit.id
)
expect_any_instance_of(Gitaly::Diff::Stub).to receive(:commit_delta).with(request).and_return([])
described_class.new(repository).commit_deltas(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::CommitDeltaRequest.new(
repository: repository_message,
left_commit_id: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
right_commit_id: initial_commit.id
)
expect_any_instance_of(Gitaly::Diff::Stub).to receive(:commit_delta).with(request).and_return([])
described_class.new(repository).commit_deltas(initial_commit)
end
end end
end end
end end
...@@ -388,19 +388,4 @@ eos ...@@ -388,19 +388,4 @@ eos
expect(described_class.valid_hash?('a' * 41)).to be false expect(described_class.valid_hash?('a' * 41)).to be false
end end
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
it 'fetches diffs from Gitaly server' do
expect(Gitlab::GitalyClient::Commit).to receive(:diff_from_parent).
with(commit)
commit.raw_diffs
end
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