Class: DiffNote

Inherits:
Note show all
Includes:
DiffPositionableNote, Gitlab::Utils::StrongMemoize, NoteOnDiff
Defined in:
app/models/diff_note.rb

Overview

A note on merge request or commit diffs

A note of this type can be resolvable.

Constant Summary collapse

NoteDiffFileCreationError =
Class.new(StandardError)
DIFF_LINE_NOT_FOUND_MESSAGE =
"Failed to find diff line for: %{file_path}, old_line: %{old_line}, new_line: %{new_line}"
DIFF_FILE_NOT_FOUND_MESSAGE =
"Failed to find diff file"

Constants inherited from Note

Note::TYPES_RESTRICTED_BY_ABILITY

Constants included from ThrottledTouch

ThrottledTouch::TOUCH_INTERVAL

Constants included from Gitlab::SQL::Pattern

Gitlab::SQL::Pattern::MIN_CHARS_FOR_PARTIAL_MATCHING, Gitlab::SQL::Pattern::REGEX_QUOTED_WORD

Constants included from ResolvableNote

ResolvableNote::RESOLVABLE_TYPES

Constants included from CacheMarkdownField

CacheMarkdownField::INVALIDATED_BY

Constants included from Redactable

Redactable::UNSUBSCRIBE_PATTERN

Instance Attribute Summary

Attributes inherited from Note

#commands_changes, #redacted_note_html, #special_role, #total_reference_count, #user_visible_reference_count

Attributes included from Importable

#imported, #importing

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Gitlab::Utils::StrongMemoize

#clear_memoization, #strong_memoize, #strong_memoized?

Methods included from DiffPositionableNote

#active?, #diff_refs_match_commit, #set_original_position, #update_position

Methods included from NoteOnDiff

#active?, #diff_attributes, #diff_note?

Methods inherited from Note

#active?, #award_emoji?, #can_be_award_emoji?, #can_be_discussion_note?, #can_create_todo?, #commit, #confidential?, #contains_emoji_only?, count_for_collection, #diff_note?, #discussion, #discussion_id, discussions, #editable?, #edited?, #emoji_awardable?, #expire_etag_cache, find_discussion, #for_alert_mangement_alert?, #for_commit?, #for_design?, #for_issuable?, #for_issue?, #for_merge_request?, #for_personal_snippet?, #for_project_noteable?, #for_snippet?, grouped_diff_discussions, #has_special_role?, has_special_role?, #hook_attrs, #in_reply_to?, #max_attachment_size, #merge_requests, model_name, #noteable, #noteable_ability_name, #noteable_assignee_or_author?, #noteable_type=, #notify_after_create, #notify_after_destroy, #parent_user, #part_of_discussion?, positions, #readable_by?, #references, #resource_parent, #retrieve_upload, search, #skip_notification?, #skip_project_check?, #specialize_for_first_contribution!, #start_of_discussion?, #system_note_with_references?, #system_note_with_references_visible_for?, #to_ability_name, #to_discussion, #touch, #touch_noteable, #user_mentions

Methods included from ThrottledTouch

#touch

Methods included from Editable

#edited?, #last_edited_by

Methods included from ResolvableNote

#potentially_resolvable?, #resolvable?, #resolve!, #resolve_without_save, #resolved?, #to_be_resolved?, #unresolve!, #unresolve_without_save

Methods included from AfterCommitQueue

#run_after_commit, #run_after_commit_or_now

Methods included from CacheMarkdownField

#attribute_invalidated?, #cached_html_for, #cached_html_up_to_date?, #can_cache_field?, #invalidated_markdown_cache?, #latest_cached_markdown_version, #local_version, #parent_user, #refresh_markdown_cache, #refresh_markdown_cache!, #rendered_field_content, #skip_project_check?, #updated_cached_html_for

Methods included from FasterCacheKeys

#cache_key

Methods included from Awardable

#awarded_emoji?, #downvotes, #emoji_awardable?, #grouped_awards, #upvotes, #user_authored?, #user_can_award?

Methods included from Mentionable

#all_references, #create_cross_references!, #create_new_cross_references!, #directly_addressed_users, #extractors, #gfm_reference, #local_reference, #matches_cross_reference_regex?, #mentioned_users, #referenced_group_users, #referenced_groups, #referenced_mentionables, #referenced_project_users, #referenced_projects, #referenced_users, #store_mentions!

Methods included from Participable

#participants

Methods inherited from ApplicationRecord

at_most, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, underscore, without_order

Class Method Details

.noteable_typesObject


11
12
13
# File 'app/models/diff_note.rb', line 11

def self.noteable_types
  %w(MergeRequest Commit DesignManagement::Design)
end

Instance Method Details

#banzai_render_context(field) ⇒ Object


110
111
112
# File 'app/models/diff_note.rb', line 110

def banzai_render_context(field)
  super.merge(suggestions_filter_enabled: true)
end

#create_diff_fileObject


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'app/models/diff_note.rb', line 38

def create_diff_file
  return unless should_create_diff_file?

  diff_file = fetch_diff_file
  raise NoteDiffFileCreationError, DIFF_FILE_NOT_FOUND_MESSAGE unless diff_file

  diff_line = diff_file.line_for_position(self.original_position)
  unless diff_line
    raise NoteDiffFileCreationError, DIFF_LINE_NOT_FOUND_MESSAGE % {
        file_path: diff_file.file_path,
        old_line: original_position.old_line,
        new_line: original_position.new_line
    }
  end

  creation_params = diff_file.diff.to_hash
    .except(:too_large)
    .merge(diff: diff_file.diff_hunk(diff_line))

  create_note_diff_file(creation_params)
end

#created_at_diff?(diff_refs) ⇒ Boolean

Returns:

  • (Boolean)

90
91
92
93
94
95
# File 'app/models/diff_note.rb', line 90

def created_at_diff?(diff_refs)
  return false unless supported?
  return true if for_commit?

  self.original_position.diff_refs == diff_refs
end

#diff_fileObject

Returns the diff file from `original_position`


70
71
72
73
74
75
76
77
78
# File 'app/models/diff_note.rb', line 70

def diff_file
  strong_memoize(:diff_file) do
    next if for_design?

    enqueue_diff_file_creation_job if should_create_diff_file?

    fetch_diff_file
  end
end

#diff_lineObject


80
81
82
# File 'app/models/diff_note.rb', line 80

def diff_line
  @diff_line ||= diff_file&.line_for_position(self.original_position)
end

#discussion_classObject


34
35
36
# File 'app/models/diff_note.rb', line 34

def discussion_class(*)
  DiffDiscussion
end

#latest_diff_fileObject

Returns the diff file from `position`


61
62
63
64
65
66
67
# File 'app/models/diff_note.rb', line 61

def latest_diff_file
  strong_memoize(:latest_diff_file) do
    next if for_design?

    position.diff_file(repository)
  end
end

#original_line_codeObject


84
85
86
87
88
# File 'app/models/diff_note.rb', line 84

def original_line_code
  return unless on_text?

  self.diff_file.line_code(self.diff_line)
end

#supports_suggestion?Boolean

Checks if the current `position` line in the diff exists and is suggestible (not a deletion).

Avoid using in iterations as it requests Gitaly.

Returns:

  • (Boolean)

101
102
103
104
105
106
107
108
# File 'app/models/diff_note.rb', line 101

def supports_suggestion?
  return false unless noteable&.supports_suggestion? && on_text?
  # We don't want to trigger side-effects of `diff_file` call.
  return false unless file = latest_diff_file
  return false unless line = file.line_for_position(self.position)

  line&.suggestible?
end