Commit 7848d54f authored by Douwe Maan's avatar Douwe Maan

Clean up LegacyDiffNote somewhat

parent 9a3ed265
...@@ -23,42 +23,65 @@ class LegacyDiffNote < Note ...@@ -23,42 +23,65 @@ class LegacyDiffNote < Note
@discussion_id ||= self.class.build_discussion_id(noteable_type, noteable_id || commit_id, line_code, active?) @discussion_id ||= self.class.build_discussion_id(noteable_type, noteable_id || commit_id, line_code, active?)
end end
def find_diff def diff_file_hash
return nil unless noteable line_code.split('_')[0] if line_code
return @diff if defined?(@diff)
# Don't use ||= because nil is a valid value for @diff
@diff = noteable.diffs(Commit.max_diff_options).find do |d|
Digest::SHA1.hexdigest(d.new_path) == diff_file_index if d.new_path
end
end end
def set_diff def diff_old_line
# First lets find notes with same diff line_code.split('_')[1].to_i if line_code
# before iterating over all mr diffs end
diff = diff_for_line_code unless for_merge_request?
diff ||= find_diff
self.st_diff = diff.to_hash if diff def diff_new_line
line_code.split('_')[2].to_i if line_code
end end
def diff def diff
@diff ||= Gitlab::Git::Diff.new(st_diff) if st_diff.respond_to?(:map) @diff ||= Gitlab::Git::Diff.new(st_diff) if st_diff.respond_to?(:map)
end end
def diff_for_line_code def diff_file_path
attributes = { diff.new_path.presence || diff.old_path
noteable_type: noteable_type, end
line_code: line_code
}
if for_commit? def diff_lines
attributes[:commit_id] = commit_id @diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.each_line)
else end
attributes[:noteable_id] = noteable_id
def diff_line
@diff_line ||= diff_lines.find { |line| generate_line_code(line) == self.line_code }
end
def diff_line_text
diff_line.try(:text)
end
def diff_line_type
diff_line.try(:type)
end
def highlighted_diff_lines
Gitlab::Diff::Highlight.new(diff_lines).highlight
end
def truncated_diff_lines
max_number_of_lines = 16
prev_match_line = nil
prev_lines = []
highlighted_diff_lines.each do |line|
if line.type == "match"
prev_lines.clear
prev_match_line = line
else
prev_lines << line
break if generate_line_code(line) == self.line_code
prev_lines.shift if prev_lines.length >= max_number_of_lines
end
end end
self.class.where(attributes).last.try(:diff) prev_lines
end end
# Check if this note is part of an "active" discussion # Check if this note is part of an "active" discussion
...@@ -69,17 +92,17 @@ class LegacyDiffNote < Note ...@@ -69,17 +92,17 @@ class LegacyDiffNote < Note
# If the note's current diff cannot be matched in the MergeRequest's current # If the note's current diff cannot be matched in the MergeRequest's current
# diff, it's considered inactive. # diff, it's considered inactive.
def active? def active?
return @active if defined?(@active)
return true if for_commit? return true if for_commit?
return true unless self.diff return true unless self.diff
return false unless noteable return false unless noteable
return @active if defined?(@active)
noteable_diff = find_noteable_diff noteable_diff = find_noteable_diff
if noteable_diff if noteable_diff
parsed_lines = Gitlab::Diff::Parser.new.parse(noteable_diff.diff.each_line) parsed_lines = Gitlab::Diff::Parser.new.parse(noteable_diff.diff.each_line)
@active = parsed_lines.any? { |line_obj| line_obj.text == diff_line } @active = parsed_lines.any? { |line_obj| line_obj.text == diff_line_text }
else else
@active = false @active = false
end end
...@@ -87,93 +110,45 @@ class LegacyDiffNote < Note ...@@ -87,93 +110,45 @@ class LegacyDiffNote < Note
@active @active
end end
def diff_file_index private
line_code.split('_')[0] if line_code
end
def diff_file_name
diff.new_path if diff
end
def file_path
if diff.new_path.present?
diff.new_path
elsif diff.old_path.present?
diff.old_path
end
end
def diff_old_line
line_code.split('_')[1].to_i if line_code
end
def diff_new_line
line_code.split('_')[2].to_i if line_code
end
def generate_line_code(line)
Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
end
def diff_line def find_diff
return @diff_line if @diff_line return nil unless noteable
return @diff if defined?(@diff)
if diff @diff = noteable.diffs(Commit.max_diff_options).find do |d|
diff_lines.each do |line| d.new_path && Digest::SHA1.hexdigest(d.new_path) == diff_file_hash
if generate_line_code(line) == self.line_code
@diff_line = line.text
end
end
end end
@diff_line
end end
def diff_line_type def set_diff
return @diff_line_type if @diff_line_type # First lets find notes with same diff
# before iterating over all mr diffs
if diff diff = diff_for_line_code unless for_merge_request?
diff_lines.each do |line| diff ||= find_diff
if generate_line_code(line) == self.line_code
@diff_line_type = line.type
end
end
end
@diff_line_type self.st_diff = diff.to_hash if diff
end end
def truncated_diff_lines def diff_for_line_code
max_number_of_lines = 16 attributes = {
prev_match_line = nil noteable_type: noteable_type,
prev_lines = [] line_code: line_code
}
highlighted_diff_lines.each do |line|
if line.type == "match"
prev_lines.clear
prev_match_line = line
else
prev_lines << line
break if generate_line_code(line) == self.line_code
prev_lines.shift if prev_lines.length >= max_number_of_lines if for_commit?
end attributes[:commit_id] = commit_id
else
attributes[:noteable_id] = noteable_id
end end
prev_lines self.class.where(attributes).last.try(:diff)
end
def diff_lines
@diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.each_line)
end end
def highlighted_diff_lines def generate_line_code(line)
Gitlab::Diff::Highlight.new(diff_lines).highlight Gitlab::Diff::LineCode.generate(diff_file_path, line.new_pos, line.old_pos)
end end
private
# Find the diff on noteable that matches our own # Find the diff on noteable that matches our own
def find_noteable_diff def find_noteable_diff
diffs = noteable.diffs(Commit.max_diff_options) diffs = noteable.diffs(Commit.max_diff_options)
......
...@@ -112,6 +112,10 @@ class Note < ActiveRecord::Base ...@@ -112,6 +112,10 @@ class Note < ActiveRecord::Base
false false
end end
def active?
true
end
def discussion_id def discussion_id
@discussion_id ||= @discussion_id ||=
if for_merge_request? if for_merge_request?
......
- if @note.legacy_diff_note? - if @note.legacy_diff_note?
%p.details %p.details
New comment on diff for New comment on diff for
= link_to @note.diff_file_name, @target_url = link_to @note.diff_file_path, @target_url
\: \:
= render 'note_message' = render 'note_message'
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
%table %table
- note.truncated_diff_lines.each do |line| - note.truncated_diff_lines.each do |line|
- type = line.type - type = line.type
- line_code = generate_line_code(note.file_path, line) - line_code = generate_line_code(note.diff_file_path, line)
%tr.line_holder{ id: line_code, class: "#{type}" } %tr.line_holder{ id: line_code, class: "#{type}" }
- if type == "match" - if type == "match"
%td.old_line.diff-line-num= "..." %td.old_line.diff-line-num= "..."
......
...@@ -227,7 +227,7 @@ module API ...@@ -227,7 +227,7 @@ module API
class CommitNote < Grape::Entity class CommitNote < Grape::Entity
expose :note expose :note
expose(:path) { |note| note.diff_file_name if note.legacy_diff_note? } expose(:path) { |note| note.diff_file_path if note.legacy_diff_note? }
expose(:line) { |note| note.diff_new_line if note.legacy_diff_note? } expose(:line) { |note| note.diff_new_line if note.legacy_diff_note? }
expose(:line_type) { |note| note.diff_line_type if note.legacy_diff_note? } expose(:line_type) { |note| note.diff_line_type if note.legacy_diff_note? }
expose :author, using: Entities::UserBasic expose :author, using: Entities::UserBasic
......
require 'spec_helper'
describe LegacyDiffNote, models: true do
describe "Commit diff line notes" do
let!(:note) { create(:note_on_commit_diff, note: "+1 from me") }
let!(:commit) { note.noteable }
it "should save a valid note" do
expect(note.commit_id).to eq(commit.id)
expect(note.noteable.id).to eq(commit.id)
end
it "should be recognized by #legacy_diff_note?" do
expect(note).to be_legacy_diff_note
end
end
describe '#active?' do
it 'is always true when the note has no associated diff' do
note = build(:note_on_merge_request_diff)
expect(note).to receive(:diff).and_return(nil)
expect(note).to be_active
end
it 'is never true when the note has no noteable associated' do
note = build(:note_on_merge_request_diff)
expect(note).to receive(:diff).and_return(double)
expect(note).to receive(:noteable).and_return(nil)
expect(note).not_to be_active
end
it 'returns the memoized value if defined' do
note = build(:note_on_merge_request_diff)
note.instance_variable_set(:@active, 'foo')
expect(note).not_to receive(:find_noteable_diff)
expect(note.active?).to eq 'foo'
end
context 'for a merge request noteable' do
it 'is false when noteable has no matching diff' do
merge = build_stubbed(:merge_request, :simple)
note = build(:note_on_merge_request_diff, noteable: merge)
allow(note).to receive(:diff).and_return(double)
expect(note).to receive(:find_noteable_diff).and_return(nil)
expect(note).not_to be_active
end
it 'is true when noteable has a matching diff' do
merge = create(:merge_request, :simple)
# Generate a real line_code value so we know it will match. We use a
# random line from a random diff just for funsies.
diff = merge.diffs.to_a.sample
line = Gitlab::Diff::Parser.new.parse(diff.diff.each_line).to_a.sample
code = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos)
# We're persisting in order to trigger the set_diff callback
note = create(:note_on_merge_request_diff, noteable: merge, line_code: code)
# Make sure we don't get a false positive from a guard clause
expect(note).to receive(:find_noteable_diff).and_call_original
expect(note).to be_active
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