Commit af5faaf0e1e001558302704a421eb01f5e7a26ea

Authored by Dmitriy Zaporozhets
1 parent 8f05fbba

Move diff parsing to own class. Correctly identify note diff line

app/helpers/commits_helper.rb
@@ -15,63 +15,9 @@ module CommitsHelper @@ -15,63 +15,9 @@ module CommitsHelper
15 commit_person_link(commit, options.merge(source: :committer)) 15 commit_person_link(commit, options.merge(source: :committer))
16 end 16 end
17 17
18 - def identification_type(line)  
19 - if line[0] == "+"  
20 - "new"  
21 - elsif line[0] == "-"  
22 - "old"  
23 - else  
24 - nil  
25 - end  
26 - end  
27 -  
28 - def build_line_anchor(diff, line_new, line_old)  
29 - "#{hexdigest(diff.new_path)}_#{line_old}_#{line_new}"  
30 - end  
31 -  
32 def each_diff_line(diff, index) 18 def each_diff_line(diff, index)
33 - diff_arr = diff.diff.lines.to_a  
34 -  
35 - line_old = 1  
36 - line_new = 1  
37 - type = nil  
38 -  
39 - lines_arr = ::Gitlab::InlineDiff.processing diff_arr  
40 - lines_arr.each do |line|  
41 - raw_line = line.dup  
42 -  
43 - next if line.match(/^\-\-\- \/dev\/null/)  
44 - next if line.match(/^\+\+\+ \/dev\/null/)  
45 - next if line.match(/^\-\-\- a/)  
46 - next if line.match(/^\+\+\+ b/)  
47 -  
48 - full_line = html_escape(line.gsub(/\n/, ''))  
49 - full_line = ::Gitlab::InlineDiff.replace_markers full_line  
50 -  
51 - if line.match(/^@@ -/)  
52 - type = "match"  
53 -  
54 - line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0  
55 - line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0  
56 -  
57 - next if line_old == 1 && line_new == 1 #top of file  
58 - yield(full_line, type, nil, nil, nil)  
59 - next  
60 - else  
61 - type = identification_type(line)  
62 - line_code = build_line_anchor(diff, line_new, line_old)  
63 - yield(full_line, type, line_code, line_new, line_old, raw_line)  
64 - end  
65 -  
66 -  
67 - if line[0] == "+"  
68 - line_new += 1  
69 - elsif line[0] == "-"  
70 - line_old += 1  
71 - else  
72 - line_new += 1  
73 - line_old += 1  
74 - end 19 + Gitlab::DiffParser.new(diff).each do |full_line, type, line_code, line_new, line_old|
  20 + yield(full_line, type, line_code, line_new, line_old)
75 end 21 end
76 end 22 end
77 23
app/models/note.rb
@@ -51,7 +51,7 @@ class Note < ActiveRecord::Base @@ -51,7 +51,7 @@ class Note < ActiveRecord::Base
51 scope :inc_author, ->{ includes(:author) } 51 scope :inc_author, ->{ includes(:author) }
52 52
53 serialize :st_diff 53 serialize :st_diff
54 - before_create :set_diff, if: ->(n) { n.noteable_type == 'MergeRequest' && n.line_code.present? } 54 + before_create :set_diff, if: ->(n) { n.line_code.present? }
55 55
56 def self.create_status_change_note(noteable, author, status) 56 def self.create_status_change_note(noteable, author, status)
57 create({ 57 create({
@@ -81,7 +81,7 @@ class Note < ActiveRecord::Base @@ -81,7 +81,7 @@ class Note < ActiveRecord::Base
81 def set_diff 81 def set_diff
82 # First lets find notes with same diff 82 # First lets find notes with same diff
83 # before iterating over all mr diffs 83 # before iterating over all mr diffs
84 - diff = self.noteable.notes.where(line_code: self.line_code).last.try(:diff) 84 + diff = Note.where(noteable_id: self.noteable_id, noteable_type: self.noteable_type, line_code: self.line_code).last.try(:diff)
85 diff ||= find_diff 85 diff ||= find_diff
86 86
87 self.st_diff = diff.to_hash if diff 87 self.st_diff = diff.to_hash if diff
@@ -91,6 +91,12 @@ class Note < ActiveRecord::Base @@ -91,6 +91,12 @@ class Note < ActiveRecord::Base
91 @diff ||= Gitlab::Git::Diff.new(st_diff) if st_diff.respond_to?(:map) 91 @diff ||= Gitlab::Git::Diff.new(st_diff) if st_diff.respond_to?(:map)
92 end 92 end
93 93
  94 + def active?
  95 + # TODO: determine if discussion is outdated
  96 + # according to recent MR diff or not
  97 + true
  98 + end
  99 +
94 def diff_file_index 100 def diff_file_index
95 line_code.split('_')[0] 101 line_code.split('_')[0]
96 end 102 end
@@ -108,10 +114,15 @@ class Note < ActiveRecord::Base @@ -108,10 +114,15 @@ class Note < ActiveRecord::Base
108 end 114 end
109 115
110 def diff_line 116 def diff_line
  117 + return @diff_line if @diff_line
  118 +
111 if diff 119 if diff
112 - @diff_line ||= diff.diff.lines.select { |line| line =~ /\A\+/ }[diff_new_line] ||  
113 - diff.diff.lines.select { |line| line =~ /\A\-/ }[diff_old_line] 120 + Gitlab::DiffParser.new(diff).each do |full_line, type, line_code, line_new, line_old|
  121 + @diff_line = full_line if line_code == self.line_code
  122 + end
114 end 123 end
  124 +
  125 + @diff_line
115 end 126 end
116 127
117 def discussion_id 128 def discussion_id
app/views/projects/commits/_text_file.html.haml
@@ -20,4 +20,4 @@ @@ -20,4 +20,4 @@
20 - if @reply_allowed 20 - if @reply_allowed
21 - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at) 21 - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at)
22 - unless comments.empty? 22 - unless comments.empty?
23 - = render "projects/notes/diff_notes_with_reply", notes: comments, raw_line: raw_line 23 + = render "projects/notes/diff_notes_with_reply", notes: comments, line: line
app/views/projects/notes/_diff_notes_with_reply.html.haml
1 - note = notes.first # example note 1 - note = notes.first # example note
2 -# Check if line want not changed since comment was left 2 -# Check if line want not changed since comment was left
3 -- if !defined?(raw_line) || raw_line == note.diff_line 3 +- if !defined?(line) || line == note.diff_line
4 %tr.notes_holder 4 %tr.notes_holder
5 %td.notes_line{ colspan: 2 } 5 %td.notes_line{ colspan: 2 }
6 %span.btn.disabled 6 %span.btn.disabled
app/views/projects/notes/_discussion.html.haml
@@ -36,7 +36,7 @@ @@ -36,7 +36,7 @@
36 ago 36 ago
37 .discussion-body 37 .discussion-body
38 - if note.for_diff_line? 38 - if note.for_diff_line?
39 - - if note.diff 39 + - if note.active?
40 .content 40 .content
41 .file= render "projects/notes/discussion_diff", discussion_notes: discussion_notes, note: note 41 .file= render "projects/notes/discussion_diff", discussion_notes: discussion_notes, note: note
42 - else 42 - else
doc/update/5.4-to-6.0.md
@@ -61,6 +61,7 @@ sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production @@ -61,6 +61,7 @@ sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
61 sudo -u git -H bundle exec rake migrate_groups RAILS_ENV=production 61 sudo -u git -H bundle exec rake migrate_groups RAILS_ENV=production
62 sudo -u git -H bundle exec rake migrate_global_projects RAILS_ENV=production 62 sudo -u git -H bundle exec rake migrate_global_projects RAILS_ENV=production
63 sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production 63 sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production
  64 +sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production
64 65
65 ``` 66 ```
66 67
lib/gitlab/diff_parser.rb 0 → 100644
@@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
  1 +module Gitlab
  2 + class DiffParser
  3 + include Enumerable
  4 +
  5 + attr_reader :lines, :new_path
  6 +
  7 + def initialize(diff)
  8 + @lines = diff.diff.lines.to_a
  9 + @new_path = diff.new_path
  10 + end
  11 +
  12 + def each
  13 + line_old = 1
  14 + line_new = 1
  15 + type = nil
  16 +
  17 + lines_arr = ::Gitlab::InlineDiff.processing lines
  18 + lines_arr.each do |line|
  19 + raw_line = line.dup
  20 +
  21 + next if line.match(/^\-\-\- \/dev\/null/)
  22 + next if line.match(/^\+\+\+ \/dev\/null/)
  23 + next if line.match(/^\-\-\- a/)
  24 + next if line.match(/^\+\+\+ b/)
  25 +
  26 + full_line = html_escape(line.gsub(/\n/, ''))
  27 + full_line = ::Gitlab::InlineDiff.replace_markers full_line
  28 +
  29 + if line.match(/^@@ -/)
  30 + type = "match"
  31 +
  32 + line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
  33 + line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
  34 +
  35 + next if line_old == 1 && line_new == 1 #top of file
  36 + yield(full_line, type, nil, nil, nil)
  37 + next
  38 + else
  39 + type = identification_type(line)
  40 + line_code = generate_line_code(new_path, line_new, line_old)
  41 + yield(full_line, type, line_code, line_new, line_old, raw_line)
  42 + end
  43 +
  44 +
  45 + if line[0] == "+"
  46 + line_new += 1
  47 + elsif line[0] == "-"
  48 + line_old += 1
  49 + else
  50 + line_new += 1
  51 + line_old += 1
  52 + end
  53 + end
  54 + end
  55 +
  56 + private
  57 +
  58 + def identification_type(line)
  59 + if line[0] == "+"
  60 + "new"
  61 + elsif line[0] == "-"
  62 + "old"
  63 + else
  64 + nil
  65 + end
  66 + end
  67 +
  68 + def generate_line_code(path, line_new, line_old)
  69 + "#{Digest::SHA1.hexdigest(path)}_#{line_old}_#{line_new}"
  70 + end
  71 +
  72 + def html_escape str
  73 + replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
  74 + str.gsub(/[&"'><]/, replacements)
  75 + end
  76 + end
  77 +end
lib/tasks/migrate/migrate_inline_notes.rake
1 desc "GITLAB | Migrate inline notes" 1 desc "GITLAB | Migrate inline notes"
2 task migrate_inline_notes: :environment do 2 task migrate_inline_notes: :environment do
3 - Note.where(noteable_type: 'MergeRequest').find_each(batch_size: 100) do |note| 3 + Note.where('line_code IS NOT NULL').find_each(batch_size: 100) do |note|
4 begin 4 begin
5 note.set_diff 5 note.set_diff
6 if note.save 6 if note.save