summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOswaldo Ferreira <oswaldo@gitlab.com>2018-10-16 13:21:16 -0300
committerOswaldo Ferreira <oswaldo@gitlab.com>2018-10-30 11:35:28 -0300
commitf21e58a772d1abdbeb8be344c4261797cfffc54e (patch)
treea593083315e16ee3262d77f451ab3815ec6232e4
parent912741cfea06ead8dad95d20f2f0adb955a55732 (diff)
downloadgitlab-ce-f21e58a772d1abdbeb8be344c4261797cfffc54e.tar.gz
Comment on any expanded diff line on MRs
-rw-r--r--app/assets/javascripts/diffs/components/diff_line_gutter_content.vue1
-rw-r--r--app/assets/javascripts/diffs/components/diff_table_cell.vue1
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_table_row.vue1
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js9
-rw-r--r--app/controllers/projects/blob_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb7
-rw-r--r--app/models/diff_note.rb39
-rw-r--r--changelogs/unreleased/osw-comment-on-any-line-on-diffs.yml5
-rw-r--r--lib/gitlab/diff/expander.rb198
-rw-r--r--lib/gitlab/diff/file.rb46
-rw-r--r--lib/gitlab/diff/file_collection/merge_request_diff.rb3
-rw-r--r--lib/gitlab/diff/line.rb11
-rw-r--r--lib/gitlab/diff/position.rb8
-rw-r--r--spec/controllers/projects/blob_controller_spec.rb4
-rw-r--r--spec/features/merge_request/user_posts_diff_notes_spec.rb13
-rw-r--r--spec/lib/gitlab/diff/expander_spec.rb858
16 files changed, 1154 insertions, 52 deletions
diff --git a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
index 6eff3013dcd..9fe1903ee7c 100644
--- a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
+++ b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
@@ -81,7 +81,6 @@ export default {
this.showCommentButton &&
this.isHover &&
!this.isMatchLine &&
- !this.isContextLine &&
!this.isMetaLine &&
!this.hasDiscussions
);
diff --git a/app/assets/javascripts/diffs/components/diff_table_cell.vue b/app/assets/javascripts/diffs/components/diff_table_cell.vue
index 5d9a0b123fe..5201f681e16 100644
--- a/app/assets/javascripts/diffs/components/diff_table_cell.vue
+++ b/app/assets/javascripts/diffs/components/diff_table_cell.vue
@@ -91,7 +91,6 @@ export default {
this.isLoggedIn &&
this.isHover &&
!this.isMatchLine &&
- !this.isContextLine &&
!this.isMetaLine,
};
},
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
index fcc3b3e9117..5419aff23d2 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
@@ -48,7 +48,6 @@ export default {
},
classNameMap() {
return {
- [CONTEXT_LINE_CLASS_NAME]: this.isContextLine,
[PARALLEL_DIFF_VIEW_TYPE]: true,
};
},
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index 38a65f111a2..15619728fe6 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -65,7 +65,14 @@ export default {
const { highlightedDiffLines, parallelDiffLines } = diffFile;
removeMatchLine(diffFile, lineNumbers, bottom);
- const lines = addLineReferences(contextLines, lineNumbers, bottom);
+
+ const lines = addLineReferences(contextLines, lineNumbers, bottom)
+ .map(line => ({
+ ...line,
+ lineCode: line.lineCode || `${fileHash}_${line.oldLine}_${line.newLine}`,
+ discussions: line.discussions || [],
+ }));
+
addContextLines({
inlineLines: highlightedDiffLines,
parallelLines: parallelDiffLines,
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 56a884b8a2a..b35d602fb76 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -122,7 +122,7 @@ class Projects::BlobController < Projects::ApplicationController
@lines.map! do |line|
# These are marked as context lines but are loaded from blobs.
# We also have context lines loaded from diffs in other places.
- diff_line = Gitlab::Diff::Line.new(line, 'context', nil, nil, nil)
+ diff_line = Gitlab::Diff::Line.new(line, nil, nil, nil, nil)
diff_line.rich_text = line
diff_line
end
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index 5307cd0720a..0d9a991d21e 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -22,8 +22,13 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
def render_diffs
@environment = @merge_request.environments_for(current_user).last
+ notes_grouped_by_old_path = @notes.group_by { |note| note.position.old_path }
- @diffs.write_cache
+ # @diffs.write_cache
+ @diffs.diff_files.each do |diff_file|
+ notes = notes_grouped_by_old_path.fetch(diff_file.old_path, [])
+ notes.each { |note| diff_file.unfold_diff_lines(note.position) }
+ end
request = {
current_user: current_user,
diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb
index 95694377fe3..d1360d548f6 100644
--- a/app/models/diff_note.rb
+++ b/app/models/diff_note.rb
@@ -80,22 +80,29 @@ class DiffNote < Note
end
def fetch_diff_file
- if note_diff_file
- diff = Gitlab::Git::Diff.new(note_diff_file.to_hash)
- Gitlab::Diff::File.new(diff,
- repository: project.repository,
- diff_refs: original_position.diff_refs)
- elsif created_at_diff?(noteable.diff_refs)
- # We're able to use the already persisted diffs (Postgres) if we're
- # presenting a "current version" of the MR discussion diff.
- # So no need to make an extra Gitaly diff request for it.
- # As an extra benefit, the returned `diff_file` already
- # has `highlighted_diff_lines` data set from Redis on
- # `Diff::FileCollection::MergeRequestDiff`.
- noteable.diffs(original_position.diff_options).diff_files.first
- else
- original_position.diff_file(self.project.repository)
- end
+ file =
+ if note_diff_file
+ diff = Gitlab::Git::Diff.new(note_diff_file.to_hash)
+ Gitlab::Diff::File.new(diff,
+ repository: project.repository,
+ diff_refs: original_position.diff_refs)
+ elsif created_at_diff?(noteable.diff_refs)
+ # We're able to use the already persisted diffs (Postgres) if we're
+ # presenting a "current version" of the MR discussion diff.
+ # So no need to make an extra Gitaly diff request for it.
+ # As an extra benefit, the returned `diff_file` already
+ # has `highlighted_diff_lines` data set from Redis on
+ # `Diff::FileCollection::MergeRequestDiff`.
+ noteable.diffs(original_position.diff_options).diff_files.first
+ else
+ original_position.diff_file(self.project.repository)
+ end
+
+ # Since persisted diff files already have its content "unfolded"
+ # there's no need to make it pass through the unfolding process.
+ file&.unfold_diff_lines(position) unless note_diff_file
+
+ file
end
def supported?
diff --git a/changelogs/unreleased/osw-comment-on-any-line-on-diffs.yml b/changelogs/unreleased/osw-comment-on-any-line-on-diffs.yml
new file mode 100644
index 00000000000..de9d1ab16fe
--- /dev/null
+++ b/changelogs/unreleased/osw-comment-on-any-line-on-diffs.yml
@@ -0,0 +1,5 @@
+---
+title: Allow commenting on any diff line in Merge Requests
+merge_request:
+author:
+type: added
diff --git a/lib/gitlab/diff/expander.rb b/lib/gitlab/diff/expander.rb
new file mode 100644
index 00000000000..71c28f2e4d3
--- /dev/null
+++ b/lib/gitlab/diff/expander.rb
@@ -0,0 +1,198 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Diff
+ class Expander
+ include Gitlab::Utils::StrongMemoize
+
+ UNFOLD_COUNT = 20
+
+ def initialize(diff_file, position)
+ @diff_file = diff_file
+ @blob = diff_file.old_blob
+ @position = position
+ @unfold = true
+ end
+
+ # Returns merged diff lines with required blob lines for presenting.
+ def diff_lines
+ strong_memoize(:diff_lines) do
+ original_diff_lines = @diff_file.diff_lines
+
+ next original_diff_lines unless should_expand?
+
+ merged_diff_with_blob_lines(original_diff_lines)
+ end
+ end
+
+ # Returns the extracted lines from the old blob which should be merged
+ # with the current diff lines.
+ def blob_lines
+ strong_memoize(:blob_lines) do
+ @blob.load_all_data!
+
+ # Blob lines, unlike diffs, doesn't start with an empty line for
+ # unchanged line, so the parsing and highlighting step gets fuzzy.
+ line_prefix = ' '
+ blob_as_diff_lines = @blob.data.each_line.map { |line| "#{line_prefix}#{line}" }
+
+ lines = Gitlab::Diff::Parser.new.parse(blob_as_diff_lines, diff_file: @diff_file).to_a
+
+ from = from_blob_line - 1
+ to = to_blob_line - 1
+
+ lines[from..to]
+ end
+ end
+
+ private
+
+ def should_expand?
+ return false unless @diff_file.text?
+ return false if @blob.nil?
+ return false unless @position.old_line
+ return false if @diff_file.diff_lines.empty?
+ return false if @diff_file.line_for_position(@position)
+ return false unless expanded_line
+
+ true
+ end
+
+ def merged_diff_with_blob_lines(lines)
+ match_line = expanded_line
+ insert_index = bottom? ? -1 : match_line.index
+
+ lines -= [match_line] unless bottom?
+
+ lines.insert(insert_index, *blob_lines_with_new_match)
+
+ # The inserted blob lines have invalid indexes, so we need
+ # to reindex them.
+ reindex(lines)
+
+ lines
+ end
+
+ # Returns 'unchanged' blob lines with recalculated `old_pos` and
+ # `new_pos` and the recalculated new match line (needed if we for instance
+ # we unfolded once, but there are still folded lines).
+ def blob_lines_with_new_match
+ old_pos = from_blob_line
+ new_pos = from_blob_line + offset
+
+ new_blob_lines = []
+
+ blob_lines.each do |line|
+ new_blob_lines << Gitlab::Diff::Line.new(line.text, line.type, nil, old_pos, new_pos,
+ parent_file: @diff_file)
+
+ old_pos += 1
+ new_pos += 1
+ end
+
+ new_blob_lines.unshift(new_match_line) if new_match_line
+
+ new_blob_lines
+ end
+
+ def bottom?
+ @position.old_line > @diff_file.diff_lines.last.old_pos
+ end
+
+ def reindex(lines)
+ lines.each_with_index { |line, i| line.index = i }
+ end
+
+ def new_match_line
+ # The bottom line match addition is already handled on
+ # Diff::File#diff_lines_for_serializer
+ return if bottom?
+ return unless @unfold
+
+ blob_lines_length = blob_lines.length - 1
+
+ # This will change for bottom scenarios
+ old_pos = from_blob_line
+ new_pos = from_blob_line + offset
+
+ old_line_ref = [old_pos, blob_lines_length].join(',')
+ new_line_ref = [new_pos, blob_lines_length].join(',')
+ new_match_line_str = "@@ -#{old_line_ref}+#{new_line_ref} @@"
+
+ Gitlab::Diff::Line.new(new_match_line_str, 'match', nil, old_pos, new_pos)
+ end
+
+ # TODO: use similar approach used on `to_bottom_blob_line` (this will
+ # change)
+ def from_blob_line
+ return old_line_number + 1 if bottom?
+
+ unfold_times = 1
+ comment_position = @position.old_line
+ index_line = line_number_above_match
+
+ while (from = index_line - (UNFOLD_COUNT * unfold_times)) > comment_position
+ index_line -= 1
+ unfold_times += 1
+ end
+
+ prev_line_number = line_before_match&.old_pos || 0
+
+ if from <= prev_line_number + 1
+ @unfold = false
+ from = prev_line_number + 1
+ end
+
+ from
+ end
+
+ def to_blob_line
+ if bottom?
+ # Calculates unfolding times based on how many lines between the
+ # comment position and the bottom match line it has.
+ from = from_blob_line
+ comment_position = @position.old_line
+ unfold_times = ((comment_position - from_blob_line).to_f / (UNFOLD_COUNT + 1)).ceil
+ from + (UNFOLD_COUNT * unfold_times) + (unfold_times - 1)
+ else
+ line_number_above_match
+ end
+ end
+
+ def line_number_above_match
+ old_line_number - 1
+ end
+
+ def offset
+ new_line_number - old_line_number
+ end
+
+ def old_line_number
+ expanded_line.old_pos
+ end
+
+ def new_line_number
+ expanded_line.new_pos
+ end
+
+ def line_before_match
+ index = expanded_line&.index
+
+ @diff_file.diff_lines[index - 1] if index > 0
+ end
+
+ # Returns the line which needed to be expanded in order to send a comment
+ # in `@position`.
+ def expanded_line
+ strong_memoize(:expanded_line) do
+ if bottom?
+ @diff_file.diff_lines.last
+ else
+ @diff_file.diff_lines
+ .find { |line| line.old_pos > @position.old_line && line.type == 'match' }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index fb117baca9e..098633327fe 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -127,6 +127,7 @@ module Gitlab
new_blob || old_blob
end
+ attr_writer :diff_lines
attr_writer :highlighted_diff_lines
# Array of Gitlab::Diff::Line objects
@@ -135,11 +136,38 @@ module Gitlab
Gitlab::Diff::Parser.new.parse(raw_diff.each_line, diff_file: self).to_a
end
+ # Changes diff_lines according to the given position. That is,
+ # it checks whether the position requires blob lines into the diff
+ # in order to be presented.
+ def unfold_diff_lines(position)
+ return unless position
+
+ self.diff_lines = Gitlab::Diff::Expander.new(self, position).diff_lines
+ end
+
def highlighted_diff_lines
@highlighted_diff_lines ||=
Gitlab::Diff::Highlight.new(self, repository: self.repository).highlight
end
+ # This adds the bottom match line to the array if needed. It contains
+ # the data to load more context lines.
+ def diff_lines_for_serializer
+ lines = highlighted_diff_lines
+
+ return if lines.empty?
+ return if blob.nil?
+
+ last_line = lines.last
+
+ if last_line.new_pos < total_blob_lines(blob) && !deleted_file?
+ match_line = Gitlab::Diff::Line.new("", 'match', nil, last_line.old_pos, last_line.new_pos)
+ lines.push(match_line)
+ end
+
+ lines
+ end
+
# Array[<Hash>] with right/left keys that contains Gitlab::Diff::Line objects which text is hightlighted
def parallel_diff_lines
@parallel_diff_lines ||= Gitlab::Diff::ParallelDiff.new(self).parallelize
@@ -246,24 +274,6 @@ module Gitlab
simple_viewer.is_a?(DiffViewer::Text) && (ignore_errors || simple_viewer.render_error.nil?)
end
- # This adds the bottom match line to the array if needed. It contains
- # the data to load more context lines.
- def diff_lines_for_serializer
- lines = highlighted_diff_lines
-
- return if lines.empty?
- return if blob.nil?
-
- last_line = lines.last
-
- if last_line.new_pos < total_blob_lines(blob) && !deleted_file?
- match_line = Gitlab::Diff::Line.new("", 'match', nil, last_line.old_pos, last_line.new_pos)
- lines.push(match_line)
- end
-
- lines
- end
-
private
def total_blob_lines(blob)
diff --git a/lib/gitlab/diff/file_collection/merge_request_diff.rb b/lib/gitlab/diff/file_collection/merge_request_diff.rb
index 0dd073a3a8e..7d772e1a66d 100644
--- a/lib/gitlab/diff/file_collection/merge_request_diff.rb
+++ b/lib/gitlab/diff/file_collection/merge_request_diff.rb
@@ -17,7 +17,8 @@ module Gitlab
def diff_files
diff_files = super
- diff_files.each { |diff_file| cache.decorate(diff_file) }
+ # TODO: Fix highlight caching.
+ # diff_files.each { |diff_file| cache.decorate(diff_file) }
diff_files
end
diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb
index 5b67cd46c48..fcc4be42e4f 100644
--- a/lib/gitlab/diff/line.rb
+++ b/lib/gitlab/diff/line.rb
@@ -4,7 +4,7 @@ module Gitlab
SERIALIZE_KEYS = %i(line_code rich_text text type index old_pos new_pos).freeze
attr_reader :line_code, :type, :index, :old_pos, :new_pos
- attr_writer :rich_text
+ attr_writer :rich_text, :index
attr_accessor :text
def initialize(text, type, index, old_pos, new_pos, parent_file: nil, line_code: nil, rich_text: nil)
@@ -19,7 +19,14 @@ module Gitlab
end
def self.init_from_hash(hash)
- new(hash[:text], hash[:type], hash[:index], hash[:old_pos], hash[:new_pos], line_code: hash[:line_code], rich_text: hash[:rich_text])
+ new(hash[:text],
+ hash[:type],
+ hash[:index],
+ hash[:old_pos],
+ hash[:new_pos],
+ parent_file: hash[:parent_file],
+ line_code: hash[:line_code],
+ rich_text: hash[:rich_text])
end
def to_hash
diff --git a/lib/gitlab/diff/position.rb b/lib/gitlab/diff/position.rb
index f967494199e..89b01bf9296 100644
--- a/lib/gitlab/diff/position.rb
+++ b/lib/gitlab/diff/position.rb
@@ -134,7 +134,13 @@ module Gitlab
return unless diff_refs.complete?
return unless comparison = diff_refs.compare_in(repository.project)
- comparison.diffs(diff_options).diff_files.first
+ file = comparison.diffs(diff_options).diff_files.first
+
+ # We need to unfold diff lines according to the position in order
+ # to correctly calculate the line code and trace position changes.
+ file.unfold_diff_lines(self)
+
+ file
end
def get_formatter_class(type)
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index 64b589a6d83..f58aa25cbdd 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -157,7 +157,7 @@ describe Projects::BlobController do
match_line = JSON.parse(response.body).first
- expect(match_line['type']).to eq('context')
+ expect(match_line['type']).to be_nil
end
it 'adds bottom match line when "t"o is less than blob size' do
@@ -177,7 +177,7 @@ describe Projects::BlobController do
match_line = JSON.parse(response.body).last
- expect(match_line['type']).to eq('context')
+ expect(match_line['type']).to be_nil
end
end
end
diff --git a/spec/features/merge_request/user_posts_diff_notes_spec.rb b/spec/features/merge_request/user_posts_diff_notes_spec.rb
index fa148715855..51b78d3e7d1 100644
--- a/spec/features/merge_request/user_posts_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb
@@ -85,12 +85,13 @@ describe 'Merge request > User posts diff notes', :js do
# `.line_holder` will be an unfolded line.
let(:line_holder) { first('#a5cc2925ca8258af241be7e5b0381edf30266302 .line_holder') }
- it 'does not allow commenting on the left side' do
- should_not_allow_commenting(line_holder, 'left')
+ it 'allows commenting on the left side' do
+ should_allow_commenting(line_holder, 'left')
end
- it 'does not allow commenting on the right side' do
- should_not_allow_commenting(line_holder, 'right')
+ it 'allows commenting on the right side' do
+ # Automatically shifts comment box to left side.
+ should_allow_commenting(line_holder, 'right')
end
end
end
@@ -147,8 +148,8 @@ describe 'Merge request > User posts diff notes', :js do
# `.line_holder` will be an unfolded line.
let(:line_holder) { first('.line_holder[id="a5cc2925ca8258af241be7e5b0381edf30266302_1_1"]') }
- it 'does not allow commenting' do
- should_not_allow_commenting line_holder
+ it 'allows commenting' do
+ should_allow_commenting line_holder
end
end
diff --git a/spec/lib/gitlab/diff/expander_spec.rb b/spec/lib/gitlab/diff/expander_spec.rb
new file mode 100644
index 00000000000..50ab0a27b7a
--- /dev/null
+++ b/spec/lib/gitlab/diff/expander_spec.rb
@@ -0,0 +1,858 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Diff::Expander do
+ include RepoHelpers
+
+ let(:raw_diff) do
+ ["@@ -7,9 +7,6 @@\n",
+ " \"tags\": [\"devel\", \"development\", \"nightly\"],\n",
+ " \"desktop-file-name-prefix\": \"(Development) \",\n",
+ " \"finish-args\": [\n",
+ "- \"--share=ipc\", \"--socket=x11\",\n",
+ "- \"--socket=wayland\",\n",
+ "- \"--talk-name=org.gnome.OnlineAccounts\",\n",
+ " \"--talk-name=org.freedesktop.Tracker1\",\n",
+ " \"--filesystem=home\",\n",
+ " \"--talk-name=org.gtk.vfs\", \"--talk-name=org.gtk.vfs.*\",\n",
+ "@@ -62,7 +59,7 @@\n",
+ " },\n",
+ " {\n",
+ " \"name\": \"gnome-desktop\",\n",
+ "- \"config-opts\": [\"--disable-debug-tools\", \"--disable-udev\"],\n",
+ "+ \"config-opts\": [\"--disable-debug-tools\", \"--disable-\"],\n",
+ " \"sources\": [\n",
+ " {\n",
+ " \"type\": \"git\",\n",
+ "@@ -83,11 +80,6 @@\n",
+ " \"buildsystem\": \"meson\",\n",
+ " \"builddir\": true,\n",
+ " \"name\": \"nautilus\",\n",
+ "- \"config-opts\": [\n",
+ "- \"-Denable-desktop=false\",\n",
+ "- \"-Denable-selinux=false\",\n",
+ "- \"--libdir=/app/lib\"\n",
+ "- ],\n",
+ " \"sources\": [\n",
+ " {\n",
+ " \"type\": \"git\",\n"].join
+ end
+
+ let(:raw_old_blob) do
+ ["{\n",
+ " \"app-id\": \"org.gnome.Nautilus\",\n",
+ " \"runtime\": \"org.gnome.Platform\",\n",
+ " \"runtime-version\": \"master\",\n",
+ " \"sdk\": \"org.gnome.Sdk\",\n",
+ " \"command\": \"nautilus\",\n",
+ " \"tags\": [\"devel\", \"development\", \"nightly\"],\n",
+ " \"desktop-file-name-prefix\": \"(Development) \",\n",
+ " \"finish-args\": [\n",
+ " \"--share=ipc\", \"--socket=x11\",\n",
+ " \"--socket=wayland\",\n",
+ " \"--talk-name=org.gnome.OnlineAccounts\",\n",
+ " \"--talk-name=org.freedesktop.Tracker1\",\n",
+ " \"--filesystem=home\",\n",
+ " \"--talk-name=org.gtk.vfs\", \"--talk-name=org.gtk.vfs.*\",\n",
+ " \"--filesystem=xdg-run/dconf\", \"--filesystem=~/.config/dconf:ro\",\n",
+ " \"--talk-name=ca.desrt.dconf\", \"--env=DCONF_USER_CONFIG_DIR=.config/dconf\"\n",
+ " ],\n",
+ " \"cleanup\": [ \"/include\", \"/share/bash-completion\" ],\n",
+ " \"modules\": [\n",
+ " {\n",
+ " \"name\": \"exiv2\",\n",
+ " \"sources\": [\n",
+ " {\n",
+ " \"type\": \"archive\",\n",
+ " \"url\": \"http://exiv2.org/builds/exiv2-0.26-trunk.tar.gz\",\n",
+ " \"sha256\": \"c75e3c4a0811bf700d92c82319373b7a825a2331c12b8b37d41eb58e4f18eafb\"\n",
+ " },\n",
+ " {\n",
+ " \"type\": \"shell\",\n",
+ " \"commands\": [\n",
+ " \"cp -f /usr/share/gnu-config/config.sub ./config/\",\n",
+ " \"cp -f /usr/share/gnu-config/config.guess ./config/\"\n",
+ " ]\n",
+ " }\n",
+ " ]\n",
+ " },\n",
+ " {\n",
+ " \"name\": \"gexiv2\",\n",
+ " \"config-opts\": [ \"--disable-introspection\" ],\n",
+ " \"sources\": [\n",
+ " {\n",
+ " \"type\": \"git\",\n",
+ " \"url\": \"https://git.gnome.org/browse/gexiv2\"\n",
+ " }\n",
+ " ]\n",
+ " },\n",
+ " {\n",
+ " \"name\": \"tracker\",\n",
+ " \"cleanup\": [ \"/bin\", \"/etc\", \"/libexec\" ],\n",
+ " \"config-opts\": [ \"--disable-miner-apps\", \"--disable-static\",\n",
+ " \"--disable-tracker-extract\", \"--disable-tracker-needle\",\n",
+ " \"--disable-tracker-preferences\", \"--disable-artwork\",\n",
+ " \"--disable-tracker-writeback\", \"--disable-miner-user-guides\",\n",
+ " \"--with-bash-completion-dir=no\" ],\n",
+ " \"sources\": [\n",
+ " {\n",
+ " \"type\": \"git\",\n",
+ " \"url\": \"https://git.gnome.org/browse/tracker\"\n",
+ " }\n",
+ " ]\n",
+ " },\n",
+ " {\n",
+ " \"name\": \"gnome-desktop\",\n",
+ " \"config-opts\": [\"--disable-debug-tools\", \"--disable-udev\"],\n",
+ " \"sources\": [\n",
+ " {\n",
+ " \"type\": \"git\",\n",
+ " \"url\": \"https://git.gnome.org/browse/gnome-desktop\"\n",
+ " }\n",
+ " ]\n",
+ " },\n",
+ " {\n",
+ " \"name\": \"gnome-autoar\",\n",
+ " \"sources\": [\n",
+ " {\n",
+ " \"type\": \"git\",\n",
+ " \"url\": \"https://git.gnome.org/browse/gnome-autoar\"\n",
+ " }\n",
+ " ]\n",
+ " },\n",
+ " {\n",
+ " \"buildsystem\": \"meson\",\n",
+ " \"builddir\": true,\n",
+ " \"name\": \"nautilus\",\n",
+ " \"config-opts\": [\n",
+ " \"-Denable-desktop=false\",\n",
+ " \"-Denable-selinux=false\",\n",
+ " \"--libdir=/app/lib\"\n",
+ " ],\n",
+ " \"sources\": [\n",
+ " {\n",
+ " \"type\": \"git\",\n",
+ " \"url\": \"https://gitlab.gnome.org/GNOME/nautilus.git\"\n",
+ " }\n",
+ " ]\n",
+ " }\n",
+ " ]\n",
+ "},\n",
+ "{\n",
+ " \"app-id\": \"foo\",\n",
+ " \"runtime\": \"foo\",\n",
+ " \"runtime-version\": \"foo\",\n",
+ " \"sdk\": \"foo\",\n",
+ " \"command\": \"foo\",\n",
+ " \"tags\": [\"foo\", \"bar\", \"kux\"],\n",
+ " \"desktop-file-name-prefix\": \"(Foo) \",\n",
+ " {\n",
+ " \"buildsystem\": \"meson\",\n",
+ " \"builddir\": true,\n",
+ " \"name\": \"nautilus\",\n",
+ " \"sources\": [\n",
+ " {\n",
+ " \"type\": \"git\",\n",
+ " \"url\": \"https://gitlab.gnome.org/GNOME/nautilus.git\"\n",
+ " }\n",
+ " ]\n",
+ " }\n",
+ "},\n",
+ "{\n",
+ " \"app-id\": \"foo\",\n",
+ " \"runtime\": \"foo\",\n",
+ " \"runtime-version\": \"foo\",\n",
+ " \"sdk\": \"foo\",\n",
+ " \"command\": \"foo\",\n",
+ " \"tags\": [\"foo\", \"bar\", \"kux\"],\n",
+ " \"desktop-file-name-prefix\": \"(Foo) \",\n",
+ " {\n",
+ " \"buildsystem\": \"meson\",\n",
+ " \"builddir\": true,\n",
+ " \"name\": \"nautilus\",\n",
+ " \"sources\": [\n",
+ " {\n",
+ " \"type\": \"git\",\n",
+ " \"url\": \"https://gitlab.gnome.org/GNOME/nautilus.git\"\n",
+ " }\n",
+ " ]\n",
+ " }\n",
+ "}\n"].join
+ end
+
+ let(:project) { create(:project) }
+
+ let(:old_blob) { Gitlab::Git::Blob.new(data: raw_old_blob) }
+
+ let(:diff) do
+ Gitlab::Git::Diff.new(diff: raw_diff,
+ new_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ old_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ a_mode: "100644",
+ b_mode: "100644",
+ new_file: false,
+ renamed_file: false,
+ deleted_file: false,
+ too_large: false)
+ end
+
+ let(:diff_file) do
+ Gitlab::Diff::File.new(diff, repository: project.repository)
+ end
+
+ before do
+ allow(old_blob).to receive(:load_all_data!)
+ allow(diff_file).to receive(:old_blob) { old_blob }
+ end
+
+ subject { described_class.new(diff_file, position) }
+
+ context 'position requires a single middle expansion' do
+ let(:position) do
+ Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19",
+ start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19",
+ head_sha: "1487062132228de836236c522fe52fed4980a46c",
+ old_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ new_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ position_type: "text",
+ old_line: 43,
+ new_line: 40)
+ end
+
+ context 'blob lines' do
+ let(:expected_blob_lines) do
+ [[41, 41, " \"sources\": ["],
+ [42, 42, " {"],
+ [43, 43, " \"type\": \"git\","],
+ [44, 44, " \"url\": \"https://git.gnome.org/browse/gexiv2\""],
+ [45, 45, " }"],
+ [46, 46, " ]"],
+ [47, 47, " },"],
+ [48, 48, " {"],
+ [49, 49, " \"name\": \"tracker\","],
+ [50, 50, " \"cleanup\": [ \"/bin\", \"/etc\", \"/libexec\" ],"],
+ [51, 51, " \"config-opts\": [ \"--disable-miner-apps\", \"--disable-static\","],
+ [52, 52, " \"--disable-tracker-extract\", \"--disable-tracker-needle\","],
+ [53, 53, " \"--disable-tracker-preferences\", \"--disable-artwork\","],
+ [54, 54, " \"--disable-tracker-writeback\", \"--disable-miner-user-guides\","],
+ [55, 55, " \"--with-bash-completion-dir=no\" ],"],
+ [56, 56, " \"sources\": ["],
+ [57, 57, " {"],
+ [58, 58, " \"type\": \"git\","],
+ [59, 59, " \"url\": \"https://git.gnome.org/browse/tracker\""],
+ [60, 60, " }"],
+ [61, 61, " ]"]]
+ end
+
+ it 'returns the extracted blob lines correctly' do
+ extracted_lines = subject.blob_lines
+
+ expect(extracted_lines.size).to eq(21)
+
+ extracted_lines.each_with_index do |line, i|
+ expect([line.old_line, line.new_line, line.text]).to eq(expected_blob_lines[i])
+ end
+ end
+ end
+
+ context 'diff lines' do
+ let(:expected_diff_lines) do
+ [[7, 7, "@@ -7,9 +7,6 @@"],
+ [7, 7, " \"tags\": [\"devel\", \"development\", \"nightly\"],"],
+ [8, 8, " \"desktop-file-name-prefix\": \"(Development) \","],
+ [9, 9, " \"finish-args\": ["],
+ [10, 10, "- \"--share=ipc\", \"--socket=x11\","],
+ [11, 10, "- \"--socket=wayland\","],
+ [12, 10, "- \"--talk-name=org.gnome.OnlineAccounts\","],
+ [13, 10, " \"--talk-name=org.freedesktop.Tracker1\","],
+ [14, 11, " \"--filesystem=home\","],
+ [15, 12, " \"--talk-name=org.gtk.vfs\", \"--talk-name=org.gtk.vfs.*\","],
+
+ # New match line
+ [41, 38, "@@ -41,20+38,20 @@"],
+
+ # Injected blob lines
+ [41, 38, " \"sources\": ["],
+ [42, 39, " {"],
+ [43, 40, " \"type\": \"git\","],
+ [44, 41, " \"url\": \"https://git.gnome.org/browse/gexiv2\""],
+ [45, 42, " }"],
+ [46, 43, " ]"],
+ [47, 44, " },"],
+ [48, 45, " {"],
+ [49, 46, " \"name\": \"tracker\","],
+ [50, 47, " \"cleanup\": [ \"/bin\", \"/etc\", \"/libexec\" ],"],
+ [51, 48, " \"config-opts\": [ \"--disable-miner-apps\", \"--disable-static\","],
+ [52, 49, " \"--disable-tracker-extract\", \"--disable-tracker-needle\","],
+ [53, 50, " \"--disable-tracker-preferences\", \"--disable-artwork\","],
+ [54, 51, " \"--disable-tracker-writeback\", \"--disable-miner-user-guides\","],
+ [55, 52, " \"--with-bash-completion-dir=no\" ],"],
+ [56, 53, " \"sources\": ["],
+ [57, 54, " {"],
+ [58, 55, " \"type\": \"git\","],
+ [59, 56, " \"url\": \"https://git.gnome.org/browse/tracker\""],
+ [60, 57, " }"],
+ [61, 58, " ]"],
+ # end
+
+ [62, 59, " },"],
+ [63, 60, " {"],
+ [64, 61, " \"name\": \"gnome-desktop\","],
+ [65, 62, "- \"config-opts\": [\"--disable-debug-tools\", \"--disable-udev\"],"],
+ [66, 62, "+ \"config-opts\": [\"--disable-debug-tools\", \"--disable-\"],"],
+ [66, 63, " \"sources\": ["],
+ [67, 64, " {"],
+ [68, 65, " \"type\": \"git\","],
+ [83, 80, "@@ -83,11 +80,6 @@"],
+ [83, 80, " \"buildsystem\": \"meson\","],
+ [84, 81, " \"builddir\": true,"],
+ [85, 82, " \"name\": \"nautilus\","],
+ [86, 83, "- \"config-opts\": ["],
+ [87, 83, "- \"-Denable-desktop=false\","],
+ [88, 83, "- \"-Denable-selinux=false\","],
+ [89, 83, "- \"--libdir=/app/lib\""],
+ [90, 83, "- ],"],
+ [91, 83, " \"sources\": ["],
+ [92, 84, " {"],
+ [93, 85, " \"type\": \"git\","]]
+ end
+
+ it 'return merge of blob lines with diff lines correctly' do
+ new_diff_lines = subject.diff_lines
+
+ expected_diff_lines.each_with_index do |expected_line, i|
+ line = new_diff_lines[i]
+
+ expect([line.old_pos, line.new_pos, line.text])
+ .to eq([expected_line[0], expected_line[1], expected_line[2]])
+ end
+ end
+
+ it 'merged lines have correct line codes' do
+ new_diff_lines = subject.diff_lines
+
+ new_diff_lines.each_with_index do |line, i|
+ old_pos, new_pos = expected_diff_lines[i][0], expected_diff_lines[i][1]
+
+ unless line.type == 'match'
+ expect(line.line_code).to eq(Gitlab::Git.diff_line_code(diff_file.file_path, new_pos, old_pos))
+ end
+ end
+ end
+ end
+ end
+
+ context 'position requires a short top expansion' do
+ let(:position) do
+ Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19",
+ start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19",
+ head_sha: "1487062132228de836236c522fe52fed4980a46c",
+ old_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ new_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ position_type: "text",
+ old_line: 4,
+ new_line: 4)
+ end
+
+ context 'blob lines' do
+ let(:expected_blob_lines) do
+ [[1, 1, " {"],
+ [2, 2, " \"app-id\": \"org.gnome.Nautilus\","],
+ [3, 3, " \"runtime\": \"org.gnome.Platform\","],
+ [4, 4, " \"runtime-version\": \"master\","],
+ [5, 5, " \"sdk\": \"org.gnome.Sdk\","],
+ [6, 6, " \"command\": \"nautilus\","]]
+ end
+
+ it 'returns the extracted blob lines correctly' do
+ extracted_lines = subject.blob_lines
+
+ expect(extracted_lines.size).to eq(6)
+
+ extracted_lines.each_with_index do |line, i|
+ expect([line.old_line, line.new_line, line.text]).to eq(expected_blob_lines[i])
+ end
+ end
+ end
+
+ context 'diff lines' do
+ let(:expected_diff_lines) do
+ # Injected blob lines
+ [[1, 1, " {"],
+ [2, 2, " \"app-id\": \"org.gnome.Nautilus\","],
+ [3, 3, " \"runtime\": \"org.gnome.Platform\","],
+ [4, 4, " \"runtime-version\": \"master\","],
+ [5, 5, " \"sdk\": \"org.gnome.Sdk\","],
+ [6, 6, " \"command\": \"nautilus\","],
+ #
+ # No generated match
+
+ [7, 7, " \"tags\": [\"devel\", \"development\", \"nightly\"],"],
+ [8, 8, " \"desktop-file-name-prefix\": \"(Development) \","],
+ [9, 9, " \"finish-args\": ["],
+ [10, 10, "- \"--share=ipc\", \"--socket=x11\","],
+ [11, 10, "- \"--socket=wayland\","],
+ [12, 10, "- \"--talk-name=org.gnome.OnlineAccounts\","],
+ [13, 10, " \"--talk-name=org.freedesktop.Tracker1\","],
+ [14, 11, " \"--filesystem=home\","],
+ [15, 12, " \"--talk-name=org.gtk.vfs\", \"--talk-name=org.gtk.vfs.*\","],
+ [62, 59, "@@ -62,7 +59,7 @@"],
+ [62, 59, " },"],
+ [63, 60, " {"],
+ [64, 61, " \"name\": \"gnome-desktop\","],
+ [65, 62, "- \"config-opts\": [\"--disable-debug-tools\", \"--disable-udev\"],"],
+ [66, 62, "+ \"config-opts\": [\"--disable-debug-tools\", \"--disable-\"],"],
+ [66, 63, " \"sources\": ["],
+ [67, 64, " {"],
+ [68, 65, " \"type\": \"git\","],
+ [83, 80, "@@ -83,11 +80,6 @@"],
+ [83, 80, " \"buildsystem\": \"meson\","],
+ [84, 81, " \"builddir\": true,"],
+ [85, 82, " \"name\": \"nautilus\","],
+ [86, 83, "- \"config-opts\": ["],
+ [87, 83, "- \"-Denable-desktop=false\","],
+ [88, 83, "- \"-Denable-selinux=false\","],
+ [89, 83, "- \"--libdir=/app/lib\""],
+ [90, 83, "- ],"],
+ [91, 83, " \"sources\": ["],
+ [92, 84, " {"],
+ [93, 85, " \"type\": \"git\","]]
+ end
+
+ it 'return merge of blob lines with diff lines correctly' do
+ new_diff_lines = subject.diff_lines
+
+ expected_diff_lines.each_with_index do |expected_line, i|
+ line = new_diff_lines[i]
+
+ expect([line.old_pos, line.new_pos, line.text])
+ .to eq([expected_line[0], expected_line[1], expected_line[2]])
+ end
+ end
+
+ it 'merged lines have correct line codes' do
+ new_diff_lines = subject.diff_lines
+
+ new_diff_lines.each_with_index do |line, i|
+ old_pos, new_pos = expected_diff_lines[i][0], expected_diff_lines[i][1]
+
+ unless line.type == 'match'
+ expect(line.line_code).to eq(Gitlab::Git.diff_line_code(diff_file.file_path, new_pos, old_pos))
+ end
+ end
+ end
+ end
+ end
+
+ context 'position requires more than one middle expansion' do
+ let(:position) do
+ Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19",
+ start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19",
+ head_sha: "1487062132228de836236c522fe52fed4980a46c",
+ old_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ new_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ position_type: "text",
+ old_line: 20,
+ new_line: 17)
+ end
+
+ context 'blob lines' do
+ let(:expected_blob_lines) do
+ # Second expansion
+ [[20, 20, " \"modules\": ["],
+ [21, 21, " {"],
+ [22, 22, " \"name\": \"exiv2\","],
+ [23, 23, " \"sources\": ["],
+ [24, 24, " {"],
+ [25, 25, " \"type\": \"archive\","],
+ [26, 26, " \"url\": \"http://exiv2.org/builds/exiv2-0.26-trunk.tar.gz\","],
+ [27, 27, " \"sha256\": \"c75e3c4a0811bf700d92c82319373b7a825a2331c12b8b37d41eb58e4f18eafb\""],
+ [28, 28, " },"],
+ [29, 29, " {"],
+ [30, 30, " \"type\": \"shell\","],
+ [31, 31, " \"commands\": ["],
+ [32, 32, " \"cp -f /usr/share/gnu-config/config.sub ./config/\","],
+ [33, 33, " \"cp -f /usr/share/gnu-config/config.guess ./config/\""],
+ [34, 34, " ]"],
+ [35, 35, " }"],
+ [36, 36, " ]"],
+ [37, 37, " },"],
+ [38, 38, " {"],
+ [39, 39, " \"name\": \"gexiv2\","],
+ [40, 40, " \"config-opts\": [ \"--disable-introspection\" ],"],
+ # First expansion
+ [41, 41, " \"sources\": ["],
+ [42, 42, " {"],
+ [43, 43, " \"type\": \"git\","],
+ [44, 44, " \"url\": \"https://git.gnome.org/browse/gexiv2\""],
+ [45, 45, " }"],
+ [46, 46, " ]"],
+ [47, 47, " },"],
+ [48, 48, " {"],
+ [49, 49, " \"name\": \"tracker\","],
+ [50, 50, " \"cleanup\": [ \"/bin\", \"/etc\", \"/libexec\" ],"],
+ [51, 51, " \"config-opts\": [ \"--disable-miner-apps\", \"--disable-static\","],
+ [52, 52, " \"--disable-tracker-extract\", \"--disable-tracker-needle\","],
+ [53, 53, " \"--disable-tracker-preferences\", \"--disable-artwork\","],
+ [54, 54, " \"--disable-tracker-writeback\", \"--disable-miner-user-guides\","],
+ [55, 55, " \"--with-bash-completion-dir=no\" ],"],
+ [56, 56, " \"sources\": ["],
+ [57, 57, " {"],
+ [58, 58, " \"type\": \"git\","],
+ [59, 59, " \"url\": \"https://git.gnome.org/browse/tracker\""],
+ [60, 60, " }"],
+ [61, 61, " ]"]]
+ end
+
+ it 'returns the extracted blob lines correctly' do
+ extracted_lines = subject.blob_lines
+
+ expect(extracted_lines.size).to eq(42)
+
+ extracted_lines.each_with_index do |line, i|
+ expect([line.old_line, line.new_line, line.text]).to eq(expected_blob_lines[i])
+ end
+ end
+ end
+
+ context 'diff lines' do
+ let(:expected_diff_lines) do
+ [[7, 7, "@@ -7,9 +7,6 @@"],
+ [7, 7, " \"tags\": [\"devel\", \"development\", \"nightly\"],"],
+ [8, 8, " \"desktop-file-name-prefix\": \"(Development) \","],
+ [9, 9, " \"finish-args\": ["],
+ [10, 10, "- \"--share=ipc\", \"--socket=x11\","],
+ [11, 10, "- \"--socket=wayland\","],
+ [12, 10, "- \"--talk-name=org.gnome.OnlineAccounts\","],
+ [13, 10, " \"--talk-name=org.freedesktop.Tracker1\","],
+ [14, 11, " \"--filesystem=home\","],
+ [15, 12, " \"--talk-name=org.gtk.vfs\", \"--talk-name=org.gtk.vfs.*\","],
+ # Generated match line
+ [20, 17, "@@ -20,41+17,41 @@"],
+ # Second expansion
+ [20, 17, " \"modules\": ["],
+ [21, 18, " {"],
+ [22, 19, " \"name\": \"exiv2\","],
+ [23, 20, " \"sources\": ["],
+ [24, 21, " {"],
+ [25, 22, " \"type\": \"archive\","],
+ [26, 23, " \"url\": \"http://exiv2.org/builds/exiv2-0.26-trunk.tar.gz\","],
+ [27, 24, " \"sha256\": \"c75e3c4a0811bf700d92c82319373b7a825a2331c12b8b37d41eb58e4f18eafb\""],
+ [28, 25, " },"],
+ [29, 26, " {"],
+ [30, 27, " \"type\": \"shell\","],
+ [31, 28, " \"commands\": ["],
+ [32, 29, " \"cp -f /usr/share/gnu-config/config.sub ./config/\","],
+ [33, 30, " \"cp -f /usr/share/gnu-config/config.guess ./config/\""],
+ [34, 31, " ]"],
+ [35, 32, " }"],
+ [36, 33, " ]"],
+ [37, 34, " },"],
+ [38, 35, " {"],
+ [39, 36, " \"name\": \"gexiv2\","],
+ [40, 37, " \"config-opts\": [ \"--disable-introspection\" ],"],
+ # First expansion
+ [41, 38, " \"sources\": ["],
+ [42, 39, " {"],
+ [43, 40, " \"type\": \"git\","],
+ [44, 41, " \"url\": \"https://git.gnome.org/browse/gexiv2\""],
+ [45, 42, " }"],
+ [46, 43, " ]"],
+ [47, 44, " },"],
+ [48, 45, " {"],
+ [49, 46, " \"name\": \"tracker\","],
+ [50, 47, " \"cleanup\": [ \"/bin\", \"/etc\", \"/libexec\" ],"],
+ [51, 48, " \"config-opts\": [ \"--disable-miner-apps\", \"--disable-static\","],
+ [52, 49, " \"--disable-tracker-extract\", \"--disable-tracker-needle\","],
+ [53, 50, " \"--disable-tracker-preferences\", \"--disable-artwork\","],
+ [54, 51, " \"--disable-tracker-writeback\", \"--disable-miner-user-guides\","],
+ [55, 52, " \"--with-bash-completion-dir=no\" ],"],
+ [56, 53, " \"sources\": ["],
+ [57, 54, " {"],
+ [58, 55, " \"type\": \"git\","],
+ [59, 56, " \"url\": \"https://git.gnome.org/browse/tracker\""],
+ [60, 57, " }"],
+ [61, 58, " ]"],
+ # end
+ [62, 59, " },"],
+ [63, 60, " {"],
+ [64, 61, " \"name\": \"gnome-desktop\","],
+ [65, 62, "- \"config-opts\": [\"--disable-debug-tools\", \"--disable-udev\"],"],
+ [66, 62, "+ \"config-opts\": [\"--disable-debug-tools\", \"--disable-\"],"],
+ [66, 63, " \"sources\": ["],
+ [67, 64, " {"],
+ [68, 65, " \"type\": \"git\","],
+ [83, 80, "@@ -83,11 +80,6 @@"],
+ [83, 80, " \"buildsystem\": \"meson\","],
+ [84, 81, " \"builddir\": true,"],
+ [85, 82, " \"name\": \"nautilus\","],
+ [86, 83, "- \"config-opts\": ["],
+ [87, 83, "- \"-Denable-desktop=false\","],
+ [88, 83, "- \"-Denable-selinux=false\","],
+ [89, 83, "- \"--libdir=/app/lib\""],
+ [90, 83, "- ],"],
+ [91, 83, " \"sources\": ["],
+ [92, 84, " {"],
+ [93, 85, " \"type\": \"git\","]]
+ end
+
+ it 'return merge of blob lines with diff lines correctly' do
+ new_diff_lines = subject.diff_lines
+
+ expected_diff_lines.each_with_index do |expected_line, i|
+ line = new_diff_lines[i]
+
+ expect([line.old_pos, line.new_pos, line.text])
+ .to eq([expected_line[0], expected_line[1], expected_line[2]])
+ end
+ end
+
+ it 'merged lines have correct line codes' do
+ new_diff_lines = subject.diff_lines
+
+ new_diff_lines.each_with_index do |line, i|
+ old_pos, new_pos = expected_diff_lines[i][0], expected_diff_lines[i][1]
+
+ unless line.type == 'match'
+ expect(line.line_code).to eq(Gitlab::Git.diff_line_code(diff_file.file_path, new_pos, old_pos))
+ end
+ end
+ end
+ end
+ end
+
+ context 'position sits between two match lines (no expasion needed)' do
+ let(:position) do
+ Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19",
+ start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19",
+ head_sha: "1487062132228de836236c522fe52fed4980a46c",
+ old_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ new_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ position_type: "text",
+ old_line: 64,
+ new_line: 61)
+ end
+
+ context 'diff lines' do
+ let(:expected_diff_lines) do
+ # No blob lines
+ [[7, 7, "@@ -7,9 +7,6 @@"],
+ [7, 7, " \"tags\": [\"devel\", \"development\", \"nightly\"],"],
+ [8, 8, " \"desktop-file-name-prefix\": \"(Development) \","],
+ [9, 9, " \"finish-args\": ["],
+ [10, 10, "- \"--share=ipc\", \"--socket=x11\","],
+ [11, 10, "- \"--socket=wayland\","],
+ [12, 10, "- \"--talk-name=org.gnome.OnlineAccounts\","],
+ [13, 10, " \"--talk-name=org.freedesktop.Tracker1\","],
+ [14, 11, " \"--filesystem=home\","],
+ [15, 12, " \"--talk-name=org.gtk.vfs\", \"--talk-name=org.gtk.vfs.*\","],
+ [62, 59, "@@ -62,7 +59,7 @@"],
+ [62, 59, " },"],
+ [63, 60, " {"],
+ [64, 61, " \"name\": \"gnome-desktop\","],
+ [65, 62, "- \"config-opts\": [\"--disable-debug-tools\", \"--disable-udev\"],"],
+ [66, 62, "+ \"config-opts\": [\"--disable-debug-tools\", \"--disable-\"],"],
+ [66, 63, " \"sources\": ["],
+ [67, 64, " {"],
+ [68, 65, " \"type\": \"git\","],
+ [83, 80, "@@ -83,11 +80,6 @@"],
+ [83, 80, " \"buildsystem\": \"meson\","],
+ [84, 81, " \"builddir\": true,"],
+ [85, 82, " \"name\": \"nautilus\","],
+ [86, 83, "- \"config-opts\": ["],
+ [87, 83, "- \"-Denable-desktop=false\","],
+ [88, 83, "- \"-Denable-selinux=false\","],
+ [89, 83, "- \"--libdir=/app/lib\""],
+ [90, 83, "- ],"],
+ [91, 83, " \"sources\": ["],
+ [92, 84, " {"],
+ [93, 85, " \"type\": \"git\","]]
+ end
+
+ it 'return original diff lines' do
+ new_diff_lines = subject.diff_lines
+
+ expected_diff_lines.each_with_index do |expected_line, i|
+ line = new_diff_lines[i]
+
+ expect([line.old_pos, line.new_pos, line.text])
+ .to eq([expected_line[0], expected_line[1], expected_line[2]])
+ end
+ end
+ end
+ end
+
+ context 'bottom position (expansion needed)' do
+ let(:position) do
+ Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19",
+ start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19",
+ head_sha: "1487062132228de836236c522fe52fed4980a46c",
+ old_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ new_path: "build-aux/flatpak/org.gnome.Nautilus.json",
+ position_type: "text",
+ old_line: 135,
+ new_line: 127)
+ end
+
+ context 'blob lines' do
+ let(:expected_blob_lines) do
+ [[94, 94, " \"url\": \"https://gitlab.gnome.org/GNOME/nautilus.git\""],
+ [95, 95, " }"],
+ [96, 96, " ]"],
+ [97, 97, " }"],
+ [98, 98, " ]"],
+ [99, 99, " },"],
+ [100, 100, " {"],
+ [101, 101, " \"app-id\": \"foo\","],
+ [102, 102, " \"runtime\": \"foo\","],
+ [103, 103, " \"runtime-version\": \"foo\","],
+ [104, 104, " \"sdk\": \"foo\","],
+ [105, 105, " \"command\": \"foo\","],
+ [106, 106, " \"tags\": [\"foo\", \"bar\", \"kux\"],"],
+ [107, 107, " \"desktop-file-name-prefix\": \"(Foo) \","],
+ [108, 108, " {"],
+ [109, 109, " \"buildsystem\": \"meson\","],
+ [110, 110, " \"builddir\": true,"],
+ [111, 111, " \"name\": \"nautilus\","],
+ [112, 112, " \"sources\": ["],
+ [113, 113, " {"],
+ [114, 114, " \"type\": \"git\","],
+ [115, 115, " \"url\": \"https://gitlab.gnome.org/GNOME/nautilus.git\""],
+ [116, 116, " }"],
+ [117, 117, " ]"],
+ [118, 118, " }"],
+ [119, 119, " },"],
+ [120, 120, " {"],
+ [121, 121, " \"app-id\": \"foo\","],
+ [122, 122, " \"runtime\": \"foo\","],
+ [123, 123, " \"runtime-version\": \"foo\","],
+ [124, 124, " \"sdk\": \"foo\","],
+ [125, 125, " \"command\": \"foo\","],
+ [126, 126, " \"tags\": [\"foo\", \"bar\", \"kux\"],"],
+ [127, 127, " \"desktop-file-name-prefix\": \"(Foo) \","],
+ [128, 128, " {"],
+ [129, 129, " \"buildsystem\": \"meson\","],
+ [130, 130, " \"builddir\": true,"],
+ [131, 131, " \"name\": \"nautilus\","],
+ [132, 132, " \"sources\": ["],
+ [133, 133, " {"],
+ [134, 134, " \"type\": \"git\","],
+ [135, 135, " \"url\": \"https://gitlab.gnome.org/GNOME/nautilus.git\""]]
+ end
+
+ it 'returns the extracted blob lines correctly' do
+ extracted_lines = subject.blob_lines
+
+ expect(extracted_lines.size).to eq(42)
+
+ extracted_lines.each_with_index do |line, i|
+ expect([line.old_line, line.new_line, line.text]).to eq(expected_blob_lines[i])
+ end
+ end
+ end
+
+ context 'diff lines' do
+ let(:expected_diff_lines) do
+ [[7, 7, "@@ -7,9 +7,6 @@"],
+ [7, 7, " \"tags\": [\"devel\", \"development\", \"nightly\"],"],
+ [8, 8, " \"desktop-file-name-prefix\": \"(Development) \","],
+ [9, 9, " \"finish-args\": ["],
+ [10, 10, "- \"--share=ipc\", \"--socket=x11\","],
+ [11, 10, "- \"--socket=wayland\","],
+ [12, 10, "- \"--talk-name=org.gnome.OnlineAccounts\","],
+ [13, 10, " \"--talk-name=org.freedesktop.Tracker1\","],
+ [14, 11, " \"--filesystem=home\","],
+ [15, 12, " \"--talk-name=org.gtk.vfs\", \"--talk-name=org.gtk.vfs.*\","],
+ [62, 59, "@@ -62,7 +59,7 @@"],
+ [62, 59, " },"],
+ [63, 60, " {"],
+ [64, 61, " \"name\": \"gnome-desktop\","],
+ [65, 62, "- \"config-opts\": [\"--disable-debug-tools\", \"--disable-udev\"],"],
+ [66, 62, "+ \"config-opts\": [\"--disable-debug-tools\", \"--disable-\"],"],
+ [66, 63, " \"sources\": ["],
+ [67, 64, " {"],
+ [68, 65, " \"type\": \"git\","],
+ [83, 80, "@@ -83,11 +80,6 @@"],
+ [83, 80, " \"buildsystem\": \"meson\","],
+ [84, 81, " \"builddir\": true,"],
+ [85, 82, " \"name\": \"nautilus\","],
+ [86, 83, "- \"config-opts\": ["],
+ [87, 83, "- \"-Denable-desktop=false\","],
+ [88, 83, "- \"-Denable-selinux=false\","],
+ [89, 83, "- \"--libdir=/app/lib\""],
+ [90, 83, "- ],"],
+ [91, 83, " \"sources\": ["],
+ [92, 84, " {"],
+ [93, 85, " \"type\": \"git\","],
+
+ # Injected blob lines
+ [94, 86, " \"url\": \"https://gitlab.gnome.org/GNOME/nautilus.git\""],
+ [95, 87, " }"],
+ [96, 88, " ]"],
+ [97, 89, " }"],
+ [98, 90, " ]"],
+ [99, 91, " },"],
+ [100, 92, " {"],
+ [101, 93, " \"app-id\": \"foo\","],
+ [102, 94, " \"runtime\": \"foo\","],
+ [103, 95, " \"runtime-version\": \"foo\","],
+ [104, 96, " \"sdk\": \"foo\","],
+ [105, 97, " \"command\": \"foo\","],
+ [106, 98, " \"tags\": [\"foo\", \"bar\", \"kux\"],"],
+ [107, 99, " \"desktop-file-name-prefix\": \"(Foo) \","],
+ [108, 100, " {"],
+ [109, 101, " \"buildsystem\": \"meson\","],
+ [110, 102, " \"builddir\": true,"],
+ [111, 103, " \"name\": \"nautilus\","],
+ [112, 104, " \"sources\": ["],
+ [113, 105, " {"],
+ [114, 106, " \"type\": \"git\","],
+ [115, 107, " \"url\": \"https://gitlab.gnome.org/GNOME/nautilus.git\""],
+ [116, 108, " }"],
+ [117, 109, " ]"],
+ [118, 110, " }"],
+ [119, 111, " },"],
+ [120, 112, " {"],
+ [121, 113, " \"app-id\": \"foo\","],
+ [122, 114, " \"runtime\": \"foo\","],
+ [123, 115, " \"runtime-version\": \"foo\","],
+ [124, 116, " \"sdk\": \"foo\","],
+ [125, 117, " \"command\": \"foo\","],
+ [126, 118, " \"tags\": [\"foo\", \"bar\", \"kux\"],"],
+ [127, 119, " \"desktop-file-name-prefix\": \"(Foo) \","],
+ [128, 120, " {"],
+ [129, 121, " \"buildsystem\": \"meson\","],
+ [130, 122, " \"builddir\": true,"],
+ [131, 123, " \"name\": \"nautilus\","],
+ [132, 124, " \"sources\": ["],
+ [133, 125, " {"],
+ [134, 126, " \"type\": \"git\","],
+ [135, 127, " \"url\": \"https://gitlab.gnome.org/GNOME/nautilus.git\""]]
+ end
+
+ it 'return merge of blob lines with diff lines correctly' do
+ new_diff_lines = subject.diff_lines
+
+ expected_diff_lines.each_with_index do |expected_line, i|
+ line = new_diff_lines[i]
+
+ expect([line.old_pos, line.new_pos, line.text])
+ .to eq([expected_line[0], expected_line[1], expected_line[2]])
+ end
+ end
+
+ it 'merged lines have correct line codes' do
+ new_diff_lines = subject.diff_lines
+
+ new_diff_lines.each_with_index do |line, i|
+ old_pos, new_pos = expected_diff_lines[i][0], expected_diff_lines[i][1]
+
+ unless line.type == 'match'
+ expect(line.line_code).to eq(Gitlab::Git.diff_line_code(diff_file.file_path, new_pos, old_pos))
+ end
+ end
+ end
+ end
+ end
+end