Commit af5faaf0e1e001558302704a421eb01f5e7a26ea
1 parent
8f05fbba
Exists in
master
and in
4 other branches
Move diff parsing to own class. Correctly identify note diff line
Showing
8 changed files
with
99 additions
and
64 deletions
Show diff stats
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 |
| @@ -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 = { '&' => '&', '>' => '>', '<' => '<', '"' => '"', "'" => ''' } | ||
| 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 |