BigW Consortium Gitlab

legacy_diff_note.rb 3.52 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
class LegacyDiffNote < Note
  serialize :st_diff

  validates :line_code, presence: true, line_code: true

  before_create :set_diff

  class << self
    def build_discussion_id(noteable_type, noteable_id, line_code, active = true)
      [super(noteable_type, noteable_id), line_code, active].join("-")
    end
  end

  def diff_note?
    true
  end

  def legacy_diff_note?
    true
  end

  def discussion_id
    @discussion_id ||= self.class.build_discussion_id(noteable_type, noteable_id || commit_id, line_code, active?)
  end

26 27
  def diff_file_hash
    line_code.split('_')[0] if line_code
28 29
  end

30 31 32
  def diff_old_line
    line_code.split('_')[1].to_i if line_code
  end
33

34 35
  def diff_new_line
    line_code.split('_')[2].to_i if line_code
36 37 38 39 40 41
  end

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

42 43 44
  def diff_file_path
    diff.new_path.presence || diff.old_path
  end
45

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
  def diff_lines
    @diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.each_line)
  end

  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
82 83
    end

84
    prev_lines
85 86 87 88 89 90 91 92 93 94
  end

  # 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.
  def active?
95
    return @active if defined?(@active)
96 97 98 99 100 101 102 103 104
    return true if for_commit?
    return true unless self.diff
    return false unless noteable

    noteable_diff = find_noteable_diff

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

105
      @active = parsed_lines.any? { |line_obj| line_obj.text == diff_line_text }
106 107 108 109 110 111 112
    else
      @active = false
    end

    @active
  end

113 114 115 116
  def award_emoji_supported?
    false
  end

117
  private
118

119 120 121
  def find_diff
    return nil unless noteable
    return @diff if defined?(@diff)
122

123 124
    @diff = noteable.diffs(Commit.max_diff_options).find do |d|
      d.new_path && Digest::SHA1.hexdigest(d.new_path) == diff_file_hash
125 126 127
    end
  end

128 129 130 131 132
  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
133

134
    self.st_diff = diff.to_hash if diff
135 136
  end

137 138 139 140 141
  def diff_for_line_code
    attributes = {
      noteable_type: noteable_type,
      line_code: line_code
    }
142

143 144 145 146
    if for_commit?
      attributes[:commit_id] = commit_id
    else
      attributes[:noteable_id] = noteable_id
147 148
    end

149
    self.class.where(attributes).last.try(:diff)
150 151
  end

152 153
  def generate_line_code(line)
    Gitlab::Diff::LineCode.generate(diff_file_path, line.new_pos, line.old_pos)
154 155 156 157 158 159 160 161
  end

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