BigW Consortium Gitlab

legacy_diff_note.rb 2.96 KB
Newer Older
Douwe Maan committed
1
# A note on merge request or commit diffs, using the legacy implementation.
2
#
Douwe Maan committed
3 4
# All new diff notes are of the type `DiffNote`, but any diff notes created
# before the introduction of the new implementation still use `LegacyDiffNote`.
5 6
#
# A note of this type is never resolvable.
7
class LegacyDiffNote < Note
8 9
  include NoteOnDiff

10
  serialize :st_diff # rubocop:disable Cop/ActiveRecordSerialize
11 12 13 14 15

  validates :line_code, presence: true, line_code: true

  before_create :set_diff

16 17
  def discussion_class(*)
    LegacyDiffDiscussion
18 19
  end

20 21 22 23 24 25 26 27
  def project_repository
    if RequestStore.active?
      RequestStore.fetch("project:#{project_id}:repository") { self.project.repository }
    else
      self.project.repository
    end
  end

28 29
  def diff_file_hash
    line_code.split('_')[0] if line_code
30 31 32 33 34 35
  end

  def diff
    @diff ||= Gitlab::Git::Diff.new(st_diff) if st_diff.respond_to?(:map)
  end

36
  def diff_file
37
    @diff_file ||= Gitlab::Diff::File.new(diff, repository: project_repository) if diff
38 39 40
  end

  def diff_line
41
    @diff_line ||= diff_file.line_for_line_code(self.line_code) if diff_file
42 43
  end

44
  def for_line?(line)
45
    line.discussable? && diff_file.line_code(line) == self.line_code
46 47
  end

48 49 50 51
  def original_line_code
    self.line_code
  end

52 53 54 55 56 57 58
  # Check if this note is part of an "active" discussion
  #
  # This will always return true for anything except MergeRequest noteables,
  # which have special logic.
  #
  # If the note's current diff cannot be matched in the MergeRequest's current
  # diff, it's considered inactive.
59
  def active?(diff_refs = nil)
60
    return @active if defined?(@active)
61
    return true if for_commit?
62
    return true unless diff_line
63
    return false unless noteable
64
    return false if diff_refs && diff_refs != noteable.diff_refs
65 66 67 68 69 70

    noteable_diff = find_noteable_diff

    if noteable_diff
      parsed_lines = Gitlab::Diff::Parser.new.parse(noteable_diff.diff.each_line)

71
      @active = parsed_lines.any? { |line_obj| line_obj.text == diff_line.text }
72 73 74 75 76 77 78
    else
      @active = false
    end

    @active
  end

79
  private
80

81 82 83
  def find_diff
    return nil unless noteable
    return @diff if defined?(@diff)
84

85
    @diff = noteable.raw_diffs(Commit.max_diff_options).find do |d|
86
      d.new_path && Digest::SHA1.hexdigest(d.new_path) == diff_file_hash
87 88 89
    end
  end

90 91 92 93 94
  def set_diff
    # First lets find notes with same diff
    # before iterating over all mr diffs
    diff = diff_for_line_code unless for_merge_request?
    diff ||= find_diff
95

96
    self.st_diff = diff.to_hash if diff
97 98
  end

99 100 101 102 103
  def diff_for_line_code
    attributes = {
      noteable_type: noteable_type,
      line_code: line_code
    }
104

105 106 107 108
    if for_commit?
      attributes[:commit_id] = commit_id
    else
      attributes[:noteable_id] = noteable_id
109 110
    end

111
    self.class.where(attributes).last.try(:diff)
112 113 114 115
  end

  # Find the diff on noteable that matches our own
  def find_noteable_diff
116
    diffs = noteable.raw_diffs(Commit.max_diff_options)
117 118 119
    diffs.find { |d| d.new_path == self.diff.new_path }
  end
end