diff options
Diffstat (limited to 'app/services/discussions/capture_diff_note_position_service.rb')
-rw-r--r-- | app/services/discussions/capture_diff_note_position_service.rb | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/app/services/discussions/capture_diff_note_position_service.rb b/app/services/discussions/capture_diff_note_position_service.rb new file mode 100644 index 00000000000..273a60f7e55 --- /dev/null +++ b/app/services/discussions/capture_diff_note_position_service.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +module Discussions + class CaptureDiffNotePositionService + def initialize(merge_request, paths) + @project = merge_request.project + @tracer = build_tracer(merge_request, paths) + end + + def execute(discussion) + # The service has been implemented for text only + # The impact of image notes on this service is being investigated in + # https://gitlab.com/gitlab-org/gitlab/-/issues/213989 + return unless discussion.on_text? + + result = tracer&.trace(discussion.position) + return unless result + + position = result[:position] + + # Currently position data is copied across all notes of a discussion + # It makes sense to store a position only for the first note instead + # Within the newly introduced table we can start doing just that + DiffNotePosition.create_or_update_for(discussion.notes.first, + diff_type: :head, + position: position, + line_code: position.line_code(project.repository)) + end + + private + + attr_reader :tracer, :project + + def build_tracer(merge_request, paths) + return if paths.blank? + + old_diff_refs, new_diff_refs = build_diff_refs(merge_request) + + return unless old_diff_refs && new_diff_refs + + Gitlab::Diff::PositionTracer.new( + project: project, + old_diff_refs: old_diff_refs, + new_diff_refs: new_diff_refs, + paths: paths.uniq) + end + + def build_diff_refs(merge_request) + merge_ref_head = merge_request.merge_ref_head + return unless merge_ref_head + + start_sha, base_sha = merge_ref_head.parent_ids + new_diff_refs = Gitlab::Diff::DiffRefs.new( + base_sha: base_sha, + start_sha: start_sha, + head_sha: merge_ref_head.id) + + old_diff_refs = merge_request.diff_refs + + return if new_diff_refs == old_diff_refs + + [old_diff_refs, new_diff_refs] + end + end +end |