debian-mirror-gitlab/lib/gitlab/github_import/importer/diff_note_importer.rb
2022-05-07 20:08:51 +05:30

138 lines
4.8 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module GithubImport
module Importer
class DiffNoteImporter
DiffNoteCreationError = Class.new(ActiveRecord::RecordInvalid)
# note - An instance of `Gitlab::GithubImport::Representation::DiffNote`
# project - An instance of `Project`
# client - An instance of `Gitlab::GithubImport::Client`
def initialize(note, project, client)
@note = note
@project = project
@client = client
end
def execute
return if merge_request_id.blank?
note.project = project
note.merge_request = merge_request
build_author_attributes
# Diff notes with suggestions are imported with DiffNote, which is
# slower to import than LegacyDiffNote. Importing DiffNote is slower
# because it cannot use the BulkImporting strategy, which skips
# callbacks and validations. For this reason, notes that don't have
# suggestions are still imported with LegacyDiffNote
if note.contains_suggestion?
import_with_diff_note
else
import_with_legacy_diff_note
end
rescue ::DiffNote::NoteDiffFileCreationError, DiffNoteCreationError => e
Logger.warn(message: e.message, 'error.class': e.class.name)
import_with_legacy_diff_note
rescue ActiveRecord::InvalidForeignKey => e
# It's possible the project and the issue have been deleted since
# scheduling this job. In this case we'll just skip creating the note
Logger.info(
message: e.message,
github_identifiers: note.github_identifiers
)
end
private
attr_reader :note, :project, :client, :author_id, :author_found
def build_author_attributes
@author_id, @author_found = user_finder.author_id_for(note)
end
# rubocop:disable Gitlab/BulkInsert
def import_with_legacy_diff_note
log_diff_note_creation('LegacyDiffNote')
# It's possible that during an import we'll insert tens of thousands
# of diff notes. If we were to use the Note/LegacyDiffNote model here
# we'd also have to run additional queries for both validations and
# callbacks, putting a lot of pressure on the database.
#
# To work around this we're using bulk_insert with a single row. This
# allows us to efficiently insert data (even if it's just 1 row)
# without having to use all sorts of hacks to disable callbacks.
ApplicationRecord.legacy_bulk_insert(LegacyDiffNote.table_name, [{
noteable_type: note.noteable_type,
system: false,
type: 'LegacyDiffNote',
discussion_id: note.discussion_id,
noteable_id: merge_request_id,
project_id: project.id,
author_id: author_id,
note: note_body,
commit_id: note.original_commit_id,
line_code: note.line_code,
created_at: note.created_at,
updated_at: note.updated_at,
st_diff: note.diff_hash.to_yaml
}])
end
# rubocop:enabled Gitlab/BulkInsert
def import_with_diff_note
log_diff_note_creation('DiffNote')
record = ::Import::Github::Notes::CreateService.new(project, author, {
noteable_type: note.noteable_type,
system: false,
type: 'DiffNote',
noteable_id: merge_request_id,
project_id: project.id,
note: note_body,
discussion_id: note.discussion_id,
commit_id: note.original_commit_id,
created_at: note.created_at,
updated_at: note.updated_at,
position: note.diff_position
}).execute
raise DiffNoteCreationError, record unless record.persisted?
end
def note_body
@note_body ||= MarkdownText.format(note.note, note.author, author_found)
end
def author
@author ||= User.find(author_id)
end
def merge_request
@merge_request ||= MergeRequest.find(merge_request_id)
end
# Returns the ID of the merge request this note belongs to.
def merge_request_id
@merge_request_id ||= GithubImport::IssuableFinder.new(project, note).database_id
end
def user_finder
@user_finder ||= GithubImport::UserFinder.new(project, client)
end
def log_diff_note_creation(model)
Logger.info(
project_id: project.id,
importer: self.class.name,
github_identifiers: note.github_identifiers,
model: model
)
end
end
end
end
end