From 29d574868a044fbfdf7a2458fbb3d951cfe58171 Mon Sep 17 00:00:00 2001
From: Douwe Maan <douwe@selenight.nl>
Date: Mon, 20 Jun 2016 19:23:46 +0200
Subject: [PATCH] Display new diff notes and allow creation through the web
 interface

---
 app/assets/javascripts/notes.js.coffee        |  13 +-
 app/assets/stylesheets/pages/diff.scss        |  10 -
 app/controllers/projects/notes_controller.rb  |  21 +-
 app/helpers/notes_helper.rb                   |  56 +-
 app/mailers/emails/projects.rb                |   3 +-
 app/views/projects/diffs/_line.html.haml      |  15 +-
 .../projects/diffs/_parallel_view.html.haml   |  14 +-
 app/views/projects/diffs/_text_file.html.haml |  13 +-
 app/views/projects/notes/_form.html.haml      |   1 +
 .../discussions/_diff_with_notes.html.haml    |  16 +-
 features/steps/shared/diff_note.rb            |  12 +-
 lib/gitlab/diff/parallel_diff.rb              |  16 +-
 spec/features/notes_on_merge_requests_spec.rb |   6 +-
 spec/fixtures/parallel_diff_result.yml        | 504 +++++++++++++++++-
 14 files changed, 622 insertions(+), 78 deletions(-)

diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 7c1d943667b..0b7d8f64456 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -240,12 +240,16 @@ class @Notes
 
     @note_ids.push(note.id)
     form = $("#new-discussion-note-form-#{note.discussion_id}")
+    if note.original_discussion_id? and form.length is 0
+      form = $("#new-discussion-note-form-#{note.original_discussion_id}")
     row = form.closest("tr")
     note_html = $(note.html)
     note_html.syntaxHighlight()
 
     # is this the first note of discussion?
     discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']")
+    if note.original_discussion_id? and discussionContainer.length is 0
+      discussionContainer = $(".notes[data-discussion-id='" + note.original_discussion_id + "']")
     if discussionContainer.length is 0
       # insert the note and the reply button after the temp row
       row.after note.discussion_html
@@ -318,6 +322,7 @@ class @Notes
     form.addClass "js-main-target-form"
 
     form.find("#note_line_code").remove()
+    form.find("#note_position").remove()
     form.find("#note_type").remove()
 
   ###
@@ -335,10 +340,12 @@ class @Notes
 
     new Autosave textarea, [
       "Note"
-      form.find("#note_commit_id").val()
-      form.find("#note_line_code").val()
       form.find("#note_noteable_type").val()
       form.find("#note_noteable_id").val()
+      form.find("#note_commit_id").val()
+      form.find("#note_type").val()
+      form.find("#note_line_code").val()
+      form.find("#note_position").val()
     ]
 
   ###
@@ -512,10 +519,12 @@ class @Notes
   setupDiscussionNoteForm: (dataHolder, form) =>
     # setup note target
     form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}"
+    form.attr "data-line-code", dataHolder.data("lineCode")
     form.find("#note_type").val dataHolder.data("noteType")
     form.find("#line_type").val dataHolder.data("lineType")
     form.find("#note_commit_id").val dataHolder.data("commitId")
     form.find("#note_line_code").val dataHolder.data("lineCode")
+    form.find("#note_position").val dataHolder.attr("data-position")
     form.find("#note_noteable_type").val dataHolder.data("noteableType")
     form.find("#note_noteable_id").val dataHolder.data("noteableId")
     form.find('.js-note-discard')
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 5286b73cc50..21b1c223c88 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -434,13 +434,3 @@
     }
   }
 }
-
-.discussion {
-  .diff-content {
-    .diff-line-num {
-      &:before {
-        content: attr(data-linenumber);
-      }
-    }
-  }
-}
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index e14fe26dde7..3eacdbbd067 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -128,7 +128,7 @@ class Projects::NotesController < Projects::ApplicationController
     elsif note.valid?
       Banzai::NoteRenderer.render([note], @project, current_user)
 
-      {
+      attrs = {
         valid: true,
         id: note.id,
         discussion_id: note.discussion_id,
@@ -138,6 +138,23 @@ class Projects::NotesController < Projects::ApplicationController
         discussion_html: note_to_discussion_html(note),
         discussion_with_diff_html: note_to_discussion_with_diff_html(note)
       }
+
+      # The discussion_id is used to add the comment to the correct discussion
+      # element on the merge request page. Among other things, the discussion_id
+      # contains the sha of head commit of the merge request.
+      # When new commits are pushed into the merge request after the initial
+      # load of the merge request page, the discussion elements will still have
+      # the old discussion_ids, with the old head commit sha. The new comment,
+      # however, will have the new discussion_id with the new commit sha.
+      # To ensure that these new comments will still end up in the correct
+      # discussion element, we also send the original discussion_id, with the
+      # old commit sha, along, and fall back on this value when no discussion
+      # element with the new discussion_id could be found.
+      if note.new_diff_note? && note.position != note.original_position
+        attrs[:original_discussion_id] = note.original_discussion_id
+      end
+
+      attrs
     else
       {
         valid: false,
@@ -154,7 +171,7 @@ class Projects::NotesController < Projects::ApplicationController
   def note_params
     params.require(:note).permit(
       :note, :noteable, :noteable_id, :noteable_type, :project_id,
-      :attachment, :line_code, :commit_id, :type
+      :attachment, :line_code, :commit_id, :type, :position
     )
   end
 
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 721dfcf265f..2302e65c537 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -24,23 +24,55 @@ module NotesHelper
     }.to_json
   end
 
-  def link_to_new_diff_note(line_code, line_type = nil)
-    discussion_id = LegacyDiffNote.build_discussion_id(
-      @comments_target[:noteable_type],
-      @comments_target[:noteable_id] || @comments_target[:commit_id],
-      line_code
-    )
+  def link_to_new_diff_note(line_code, position, line_type = nil)
+    use_legacy_diff_note = @use_legacy_diff_notes
+    # If the controller doesn't force the use of legacy diff notes, we
+    # determine this on a line-by-line basis by seeing if there already exist
+    # active legacy diff notes at this line, in which case newly created notes
+    # will use the legacy technology as well.
+    # We do this because the discussion_id values of legacy and "new" diff
+    # notes, which are used to group notes on the merge request discussion tab,
+    # are incompatible.
+    # If we didn't, diff notes that would show for the same line on the changes
+    # tab, would show in different discussions on the discussion tab.
+    use_legacy_diff_note ||= begin
+      line_diff_notes = @grouped_diff_notes[line_code]
+      line_diff_notes && line_diff_notes.any?(&:legacy_diff_note?)
+    end
 
     data = {
       noteable_type: @comments_target[:noteable_type],
       noteable_id:   @comments_target[:noteable_id],
       commit_id:     @comments_target[:commit_id],
       line_type:     line_type,
-      line_code:     line_code,
-      note_type:     LegacyDiffNote.name,
-      discussion_id: discussion_id
+      line_code:     line_code
     }
 
+    if use_legacy_diff_note
+      discussion_id = LegacyDiffNote.build_discussion_id(
+        @comments_target[:noteable_type],
+        @comments_target[:noteable_id] || @comments_target[:commit_id],
+        line_code
+      )
+
+      data.merge!(
+        note_type: LegacyDiffNote.name,
+        discussion_id: discussion_id
+      )
+    else
+      discussion_id = DiffNote.build_discussion_id(
+        @comments_target[:noteable_type],
+        @comments_target[:noteable_id] || @comments_target[:commit_id],
+        position
+      )
+
+      data.merge!(
+        position: position.to_json,
+        note_type: DiffNote.name,
+        discussion_id: discussion_id
+      )
+    end
+
     button_tag(class: 'btn add-diff-note js-add-diff-note-button',
                data: data,
                title: 'Add a comment to this line') do
@@ -65,8 +97,10 @@ module NotesHelper
       data.merge!(note.diff_attributes)
     end
 
-    button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
-                           data: data, title: 'Add a reply'
+    content_tag(:div, class: "discussion-reply-holder") do
+      button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
+                             data: data, title: 'Add a reply'
+    end
   end
 
   def note_max_access_for_user(note)
diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index e0af7081411..236b6ab00d8 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -29,8 +29,7 @@ module Emails
       # used in notify layout
       @target_url = @message.target_url
       @project = Project.find(project_id)
-      @diff_notes_disabled = true
-
+      
       add_project_headers
       headers['X-GitLab-Author'] = @message.author_username
 
diff --git a/app/views/projects/diffs/_line.html.haml b/app/views/projects/diffs/_line.html.haml
index dbdbb6eb754..2e7fdc832ed 100644
--- a/app/views/projects/diffs/_line.html.haml
+++ b/app/views/projects/diffs/_line.html.haml
@@ -1,4 +1,6 @@
+- plain = local_assigns.fetch(:plain, false)
 - line_code = diff_file.line_code(line)
+- position = diff_file.position(line)
 - type = line.type
 %tr.line_holder{ id: line_code, class: type }
   - case type
@@ -10,18 +12,19 @@
     %td.new_line.diff-line-num
     %td.line_content.match= line.text
   - else
-    %td.old_line.diff-line-num{ class: type, data: { linenumber: line.new_pos } }
+    %td.old_line.diff-line-num{ class: type, data: { linenumber: line.old_pos } }
       - link_text = type == "new" ? "&nbsp;".html_safe : line.old_pos
-      - if defined?(plain) && plain
+      - if plain
         = link_text
       - else
         = link_to "", "##{line_code}", id: line_code, data: { linenumber: link_text }
-      - if !@diff_notes_disabled && can?(current_user, :create_note, @project)
-        = link_to_new_diff_note(line_code)
+
+      - if !plain && !@diff_notes_disabled && can?(current_user, :create_note, @project)
+        = link_to_new_diff_note(line_code, position)
     %td.new_line.diff-line-num{ class: type, data: { linenumber: line.new_pos } }
       - link_text = type == "old" ? "&nbsp;".html_safe : line.new_pos
-      - if defined?(plain) && plain
+      - if plain
         = link_text
       - else
         = link_to "", "##{line_code}", id: line_code, data: { linenumber: link_text }
-    %td.line_content{ class: ['noteable_line', type, line_code], data: { line_code: line_code } }= diff_line_content(line.text, type)
+    %td.line_content{ class: ['noteable_line', type, line_code], data: { line_code: line_code, position: position.to_json } }= diff_line_content(line.text, type)
diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml
index 4ecc9528bd2..59603f6071d 100644
--- a/app/views/projects/diffs/_parallel_view.html.haml
+++ b/app/views/projects/diffs/_parallel_view.html.haml
@@ -17,27 +17,25 @@
           %td.old_line.diff-line-num{id: left[:line_code], class: "#{left[:type]} #{'empty-cell' if !left[:number]}"}
             = link_to raw(left[:number]), "##{left[:line_code]}", id: left[:line_code]
             - if !@diff_notes_disabled && can?(current_user, :create_note, @project)
-              = link_to_new_diff_note(left[:line_code], 'old')
-          %td.line_content{class: "parallel noteable_line #{left[:type]} #{left[:line_code]} #{'empty-cell' if left[:text].empty?}", data: { line_code: left[:line_code] }}= diff_line_content(left[:text])
+              = link_to_new_diff_note(left[:line_code], left[:position], 'old')
+          %td.line_content{class: "parallel noteable_line #{left[:type]} #{left[:line_code]} #{'empty-cell' if left[:text].empty?}", data: { line_code: left[:line_code], position: left[:position].to_json }}= diff_line_content(left[:text])
 
           - if right[:type] == 'new'
             - new_line_class = 'new'
             - new_line_code = right[:line_code]
+            - new_position = right[:position]
           - else
             - new_line_class = nil
             - new_line_code = left[:line_code]
+            - new_position = left[:position]
 
           %td.new_line.diff-line-num{id: new_line_code, class: "#{new_line_class} #{'empty-cell' if !right[:number]}", data: { linenumber: right[:number] }}
             = link_to raw(right[:number]), "##{new_line_code}", id: new_line_code
             - if !@diff_notes_disabled && can?(current_user, :create_note, @project)
-              = link_to_new_diff_note(new_line_code, 'new')
-          %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code} #{'empty-cell' if right[:text].empty?}", data: { line_code: new_line_code }}= diff_line_content(right[:text])
+              = link_to_new_diff_note(new_line_code, new_position, 'new')
+          %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code} #{'empty-cell' if right[:text].empty?}", data: { line_code: new_line_code, position: new_position.to_json }}= diff_line_content(right[:text])
 
       - unless @diff_notes_disabled
         - notes_left, notes_right = organize_comments(left, right)
         - if notes_left.present? || notes_right.present?
           = render "projects/notes/diff_notes_with_reply_parallel", notes_left: notes_left, notes_right: notes_right
-
-- if diff_file.diff.diff.blank? && diff_file.mode_changed?
-  .file-mode-changed
-    File mode changed
diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml
index 068593a7dd1..192093d1273 100644
--- a/app/views/projects/diffs/_text_file.html.haml
+++ b/app/views/projects/diffs/_text_file.html.haml
@@ -4,22 +4,17 @@
     %a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show.
 
 %table.text-file.code.js-syntax-highlight{ class: too_big ? 'hide' : '' }
-
   - last_line = 0
-  - diff_file.highlighted_diff_lines.each_with_index do |line, index|
-    - line_code = generate_line_code(diff_file.file_path, line)
+  - diff_file.highlighted_diff_lines.each do |line|
     - last_line = line.new_pos
-    = render "projects/diffs/line", {line: line, diff_file: diff_file, line_code: line_code}
+    = render "projects/diffs/line", line: line, diff_file: diff_file
 
     - unless @diff_notes_disabled
-      - diff_notes = @grouped_diff_notes[line_code]
+      - line_code = diff_file.line_code(line)
+      - diff_notes = @grouped_diff_notes[line_code] if line_code
       - if diff_notes
         = render "projects/notes/diff_notes_with_reply", notes: diff_notes
 
   - if last_line > 0
     = render "projects/diffs/match_line", { line: "",
       line_old: last_line, line_new: last_line, bottom: true, new_file: diff_file.new_file }
-
-- if diff_file.diff.blank? && diff_file.mode_changed?
-  .file-mode-changed
-    File mode changed
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index 03b3f6935d1..7c61ba750fe 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -7,6 +7,7 @@
   = f.hidden_field :noteable_id
   = f.hidden_field :noteable_type
   = f.hidden_field :type
+  = f.hidden_field :position
 
   = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do
     = render 'projects/zen', f: f, attr: :note, classes: 'note-textarea js-note-text', placeholder: "Write a comment or drag your files here..."
diff --git a/app/views/projects/notes/discussions/_diff_with_notes.html.haml b/app/views/projects/notes/discussions/_diff_with_notes.html.haml
index 3866de0f7fa..4a69b8f8840 100644
--- a/app/views/projects/notes/discussions/_diff_with_notes.html.haml
+++ b/app/views/projects/notes/discussions/_diff_with_notes.html.haml
@@ -11,17 +11,7 @@
   .diff-content.code.js-syntax-highlight
     %table
       - note.truncated_diff_lines.each do |line|
-        - type = line.type
-        - line_code = diff_file.line_code(line)
-        %tr.line_holder{ id: line_code, class: "#{type}" }
-          - if type == "match"
-            %td.old_line.diff-line-num= "..."
-            %td.new_line.diff-line-num= "..."
-            %td.line_content.match= line.text
-          - else
-            %td.old_line.diff-line-num{ data: { linenumber: type == "new" ? "&nbsp;".html_safe : line.old_pos } }
-            %td.new_line.diff-line-num{ data: { linenumber: type == "old" ? "&nbsp;".html_safe : line.new_pos } }
-            %td.line_content{ class: ['noteable_line', type, line_code], line_code: line_code }= diff_line_content(line.text, type)
+        = render "projects/diffs/line", line: line, diff_file: diff_file, plain: true
 
-            - if note.for_line?(line)
-              = render "projects/notes/diff_notes_with_reply", notes: discussion_notes
+        - if note.for_line?(line)
+          = render "projects/notes/diff_notes_with_reply", notes: discussion_notes
diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb
index e8b1e4b4879..56ef44ec969 100644
--- a/features/steps/shared/diff_note.rb
+++ b/features/steps/shared/diff_note.rb
@@ -23,7 +23,7 @@ module SharedDiffNote
     page.within(diff_file_selector) do
       click_diff_line(sample_commit.line_code)
 
-      page.within("form[id$='#{sample_commit.line_code}-true']") do
+      page.within("form[data-line-code='#{sample_commit.line_code}']") do
         fill_in "note[note]", with: "Typo, please fix"
         find(".js-comment-button").trigger("click")
         sleep 0.05
@@ -33,7 +33,7 @@ module SharedDiffNote
 
   step 'I leave a diff comment in a parallel view on the left side like "Old comment"' do
     click_parallel_diff_line(sample_commit.line_code, 'old')
-    page.within("#{diff_file_selector} form[id$='#{sample_commit.line_code}-true']") do
+    page.within("#{diff_file_selector} form[data-line-code='#{sample_commit.line_code}']") do
       fill_in "note[note]", with: "Old comment"
       find(".js-comment-button").trigger("click")
     end
@@ -41,7 +41,7 @@ module SharedDiffNote
 
   step 'I leave a diff comment in a parallel view on the right side like "New comment"' do
     click_parallel_diff_line(sample_commit.line_code, 'new')
-    page.within("#{diff_file_selector} form[id$='#{sample_commit.line_code}-true']") do
+    page.within("#{diff_file_selector} form[data-line-code='#{sample_commit.line_code}']") do
       fill_in "note[note]", with: "New comment"
       find(".js-comment-button").trigger("click")
     end
@@ -51,7 +51,7 @@ module SharedDiffNote
     page.within(diff_file_selector) do
       click_diff_line(sample_commit.line_code)
 
-      page.within("form[id$='#{sample_commit.line_code}-true']") do
+      page.within("form[data-line-code='#{sample_commit.line_code}']") do
         fill_in "note[note]", with: "Should fix it :smile:"
         find('.js-md-preview-button').click
       end
@@ -62,7 +62,7 @@ module SharedDiffNote
     page.within(diff_file_selector) do
       click_diff_line(sample_commit.del_line_code)
 
-      page.within("form[id$='#{sample_commit.del_line_code}-true']") do
+      page.within("form[data-line-code='#{sample_commit.del_line_code}']") do
         fill_in "note[note]", with: "DRY this up"
         find('.js-md-preview-button').click
       end
@@ -91,7 +91,7 @@ module SharedDiffNote
     page.within(diff_file_selector) do
       click_diff_line(sample_commit.line_code)
 
-      page.within("form[id$='#{sample_commit.line_code}-true']") do
+      page.within("form[data-line-code='#{sample_commit.line_code}']") do
         fill_in 'note[note]', with: ':smile:'
         click_button('Comment')
       end
diff --git a/lib/gitlab/diff/parallel_diff.rb b/lib/gitlab/diff/parallel_diff.rb
index 2d15b64fdb0..1c1fc148123 100644
--- a/lib/gitlab/diff/parallel_diff.rb
+++ b/lib/gitlab/diff/parallel_diff.rb
@@ -18,6 +18,7 @@ module Gitlab
           line_code = diff_file.line_code(line)
           line_new = line.new_pos
           line_old = line.old_pos
+          position = diff_file.position(line)
 
           next_line = diff_file.next_line(line.index)
 
@@ -26,6 +27,7 @@ module Gitlab
             full_next_line = next_line.text
             next_line_code = diff_file.line_code(next_line)
             next_type = next_line.type
+            next_position = diff_file.position(next_line)
           end
 
           case type
@@ -37,12 +39,14 @@ module Gitlab
                 number:     line_old,
                 text:       full_line,
                 line_code:  line_code,
+                position:   position
               },
               right: {
                 type:       type,
                 number:     line_new,
                 text:       full_line,
-                line_code:  line_code
+                line_code:  line_code,
+                position:   position
               }
             }
           when 'old'
@@ -55,12 +59,14 @@ module Gitlab
                   number:     line_old,
                   text:       full_line,
                   line_code:  line_code,
+                  position:   position
                 },
                 right: {
                   type:       next_type,
                   number:     line_new,
                   text:       full_next_line,
                   line_code:  next_line_code,
+                  position:   next_position,
                 }
               }
               skip_next = true
@@ -73,12 +79,14 @@ module Gitlab
                   number:     line_old,
                   text:       full_line,
                   line_code:  line_code,
+                  position:   position
                 },
                 right: {
                   type:       next_type,
                   number:     nil,
                   text:       "",
-                  line_code:  nil
+                  line_code:  nil,
+                  position:   nil
                 }
               }
             end
@@ -95,12 +103,14 @@ module Gitlab
                   number:     nil,
                   text:       "",
                   line_code:  line_code,
+                  position:   position
                 },
                 right: {
                   type:       type,
                   number:     line_new,
                   text:       full_line,
-                  line_code:  line_code
+                  line_code:  line_code,
+                  position:   position
                 }
               }
             end
diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb
index 737efcef45d..5174168713c 100644
--- a/spec/features/notes_on_merge_requests_spec.rb
+++ b/spec/features/notes_on_merge_requests_spec.rb
@@ -166,12 +166,14 @@ describe 'Comments', feature: true do
           click_diff_line
 
           is_expected.
-            to have_css("tr[id='#{line_code}'] + .js-temp-notes-holder form",
+            to have_css("form[data-line-code='#{line_code}']",
                         count: 1)
         end
 
         it 'should be removed when canceled' do
-          page.within(".diff-file form[id$='#{line_code}-true']") do
+          is_expected.to have_css('.js-temp-notes-holder')
+
+          page.within("form[data-line-code='#{line_code}']") do
             find('.js-close-discussion-note-form').trigger('click')
           end
 
diff --git a/spec/fixtures/parallel_diff_result.yml b/spec/fixtures/parallel_diff_result.yml
index a8b7907d4ba..7d01183e3ef 100644
--- a/spec/fixtures/parallel_diff_result.yml
+++ b/spec/fixtures/parallel_diff_result.yml
@@ -3,322 +3,818 @@
     :type: match
     :number: 6
     :text: "@@ -6,12 +6,18 @@ module Popen"
-    :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6
+    :line_code:
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line:
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: match
     :number: 6
     :text: "@@ -6,12 +6,18 @@ module Popen"
-    :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6
+    :line_code:
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line:
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 6
     :text: |2
        <span id="LC6" class="line"></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 6
+        :new_line: 6
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 6
     :text: |2
        <span id="LC6" class="line"></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 6
+        :new_line: 6
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 7
     :text: |2
        <span id="LC7" class="line">  <span class="k">def</span> <span class="nf">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 7
+        :new_line: 7
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 7
     :text: |2
        <span id="LC7" class="line">  <span class="k">def</span> <span class="nf">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 7
+        :new_line: 7
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 8
     :text: |2
        <span id="LC8" class="line">    <span class="k">unless</span> <span class="n">cmd</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="no">Array</span><span class="p">)</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 8
+        :new_line: 8
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 8
     :text: |2
        <span id="LC8" class="line">    <span class="k">unless</span> <span class="n">cmd</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="no">Array</span><span class="p">)</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 8
+        :new_line: 8
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type: old
     :number: 9
     :text: |
       -<span id="LC9" class="line">      <span class="k">raise</span> <span class="s2">&quot;System commands must be given as an array of strings&quot;</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 9
+        :new_line:
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: new
     :number: 9
     :text: |
       +<span id="LC9" class="line">      <span class="k">raise</span> <span class="no"><span class='idiff left'>RuntimeError</span></span><span class="p"><span class='idiff'>,</span></span><span class='idiff right'> </span><span class="s2">&quot;System commands must be given as an array of strings&quot;</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 9
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 10
     :text: |2
        <span id="LC10" class="line">    <span class="k">end</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 10
+        :new_line: 10
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 10
     :text: |2
        <span id="LC10" class="line">    <span class="k">end</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 10
+        :new_line: 10
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 11
     :text: |2
        <span id="LC11" class="line"></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 11
+        :new_line: 11
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 11
     :text: |2
        <span id="LC11" class="line"></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 11
+        :new_line: 11
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 12
     :text: |2
        <span id="LC12" class="line">    <span class="n">path</span> <span class="o">||=</span> <span class="no">Dir</span><span class="p">.</span><span class="nf">pwd</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 12
+        :new_line: 12
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 12
     :text: |2
        <span id="LC12" class="line">    <span class="n">path</span> <span class="o">||=</span> <span class="no">Dir</span><span class="p">.</span><span class="nf">pwd</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 12
+        :new_line: 12
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type: old
     :number: 13
     :text: |
       -<span id="LC13" class="line">    <span class="n">vars</span> <span class="o">=</span> <span class="p">{</span> <span class="s2">&quot;PWD&quot;</span> <span class="o">=&gt;</span> <span class="n">path</span> <span class="p">}</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 13
+        :new_line:
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: old
     :number:
     :text: ''
     :line_code:
+    :position:
 - :left:
     :type: old
     :number: 14
     :text: |
       -<span id="LC14" class="line">    <span class="n">options</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">chdir: </span><span class="n">path</span> <span class="p">}</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_13
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 14
+        :new_line:
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: new
     :number: 13
     :text: |
       +<span id="LC13" class="line"></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_13
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 13
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number:
     :text: ''
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 14
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: new
     :number: 14
     :text: |
       +<span id="LC14" class="line">    <span class="n">vars</span> <span class="o">=</span> <span class="p">{</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 14
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number:
     :text: ''
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 15
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: new
     :number: 15
     :text: |
       +<span id="LC15" class="line">      <span class="s2">&quot;PWD&quot;</span> <span class="o">=&gt;</span> <span class="n">path</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 15
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number:
     :text: ''
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 16
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: new
     :number: 16
     :text: |
       +<span id="LC16" class="line">    <span class="p">}</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 16
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number:
     :text: ''
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 17
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: new
     :number: 17
     :text: |
       +<span id="LC17" class="line"></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 17
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number:
     :text: ''
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 18
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: new
     :number: 18
     :text: |
       +<span id="LC18" class="line">    <span class="n">options</span> <span class="o">=</span> <span class="p">{</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 18
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number:
     :text: ''
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 19
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: new
     :number: 19
     :text: |
       +<span id="LC19" class="line">      <span class="ss">chdir: </span><span class="n">path</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 19
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number:
     :text: ''
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 20
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: new
     :number: 20
     :text: |
       +<span id="LC20" class="line">    <span class="p">}</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 20
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 15
     :text: |2
        <span id="LC21" class="line"></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 15
+        :new_line: 21
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 21
     :text: |2
        <span id="LC21" class="line"></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 15
+        :new_line: 21
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 16
     :text: |2
        <span id="LC22" class="line">    <span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">directory?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 16
+        :new_line: 22
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 22
     :text: |2
        <span id="LC22" class="line">    <span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">directory?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 16
+        :new_line: 22
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 17
     :text: |2
        <span id="LC23" class="line">      <span class="no">FileUtils</span><span class="p">.</span><span class="nf">mkdir_p</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 17
+        :new_line: 23
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 23
     :text: |2
        <span id="LC23" class="line">      <span class="no">FileUtils</span><span class="p">.</span><span class="nf">mkdir_p</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 17
+        :new_line: 23
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type: match
     :number: 19
     :text: "@@ -19,6 +25,7 @@ module Popen"
-    :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25
+    :line_code:
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line:
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: match
     :number: 25
     :text: "@@ -19,6 +25,7 @@ module Popen"
-    :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25
+    :line_code:
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line:
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 19
     :text: |2
        <span id="LC25" class="line"></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 19
+        :new_line: 25
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 25
     :text: |2
        <span id="LC25" class="line"></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 19
+        :new_line: 25
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 20
     :text: |2
        <span id="LC26" class="line">    <span class="vi">@cmd_output</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 20
+        :new_line: 26
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 26
     :text: |2
        <span id="LC26" class="line">    <span class="vi">@cmd_output</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 20
+        :new_line: 26
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 21
     :text: |2
        <span id="LC27" class="line">    <span class="vi">@cmd_status</span> <span class="o">=</span> <span class="mi">0</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 21
+        :new_line: 27
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 27
     :text: |2
        <span id="LC27" class="line">    <span class="vi">@cmd_status</span> <span class="o">=</span> <span class="mi">0</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 21
+        :new_line: 27
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number:
     :text: ''
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 28
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type: new
     :number: 28
     :text: |
       +<span id="LC28" class="line"></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line:
+        :new_line: 28
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 22
     :text: |2
        <span id="LC29" class="line">    <span class="no">Open3</span><span class="p">.</span><span class="nf">popen3</span><span class="p">(</span><span class="n">vars</span><span class="p">,</span> <span class="o">*</span><span class="n">cmd</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">stdin</span><span class="p">,</span> <span class="n">stdout</span><span class="p">,</span> <span class="n">stderr</span><span class="p">,</span> <span class="n">wait_thr</span><span class="o">|</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 22
+        :new_line: 29
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 29
     :text: |2
        <span id="LC29" class="line">    <span class="no">Open3</span><span class="p">.</span><span class="nf">popen3</span><span class="p">(</span><span class="n">vars</span><span class="p">,</span> <span class="o">*</span><span class="n">cmd</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">stdin</span><span class="p">,</span> <span class="n">stdout</span><span class="p">,</span> <span class="n">stderr</span><span class="p">,</span> <span class="n">wait_thr</span><span class="o">|</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 22
+        :new_line: 29
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 23
     :text: |2
        <span id="LC30" class="line">      <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stdout</span><span class="p">.</span><span class="nf">read</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 23
+        :new_line: 30
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 30
     :text: |2
        <span id="LC30" class="line">      <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stdout</span><span class="p">.</span><span class="nf">read</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 23
+        :new_line: 30
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
 - :left:
     :type:
     :number: 24
     :text: |2
        <span id="LC31" class="line">      <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stderr</span><span class="p">.</span><span class="nf">read</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 24
+        :new_line: 31
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
   :right:
     :type:
     :number: 31
     :text: |2
        <span id="LC31" class="line">      <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stderr</span><span class="p">.</span><span class="nf">read</span></span>
     :line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31
+    :position: !ruby/object:Gitlab::Diff::Position
+      attributes:
+        :old_path: files/ruby/popen.rb
+        :new_path: files/ruby/popen.rb
+        :old_line: 24
+        :new_line: 31
+        :base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+        :head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
-- 
2.30.9