summaryrefslogtreecommitdiff
path: root/app/models/note.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/note.rb')
-rw-r--r--app/models/note.rb165
1 files changed, 141 insertions, 24 deletions
diff --git a/app/models/note.rb b/app/models/note.rb
index 6f1b1a4da94..9ca3e4d7e97 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -49,7 +49,7 @@ class Note < ActiveRecord::Base
scope :not_inline, ->{ where(line_code: [nil, '']) }
scope :system, ->{ where(system: true) }
scope :common, ->{ where(noteable_type: ["", nil]) }
- scope :fresh, ->{ order("created_at ASC, id ASC") }
+ scope :fresh, ->{ order(created_at: :asc, id: :asc) }
scope :inc_author_project, ->{ includes(:project, :author) }
scope :inc_author, ->{ includes(:author) }
@@ -80,7 +80,7 @@ class Note < ActiveRecord::Base
note_options = {
project: project,
author: author,
- note: "_mentioned in #{gfm_reference}_",
+ note: cross_reference_note_content(gfm_reference),
system: true
}
@@ -90,7 +90,7 @@ class Note < ActiveRecord::Base
note_options.merge!(noteable: noteable)
end
- create(note_options)
+ create(note_options) unless cross_reference_disallowed?(noteable, mentioner)
end
def create_milestone_change_note(noteable, project, author, milestone)
@@ -121,18 +121,71 @@ class Note < ActiveRecord::Base
})
end
- def create_new_commits_note(noteable, project, author, commits)
- commits_text = ActionController::Base.helpers.pluralize(commits.size, 'new commit')
+ def create_labels_change_note(noteable, project, author, added_labels, removed_labels)
+ labels_count = added_labels.count + removed_labels.count
+ added_labels = added_labels.map{ |label| "~#{label.id}" }.join(' ')
+ removed_labels = removed_labels.map{ |label| "~#{label.id}" }.join(' ')
+ message = ''
+
+ if added_labels.present?
+ message << "added #{added_labels}"
+ end
+
+ if added_labels.present? && removed_labels.present?
+ message << ' and '
+ end
+
+ if removed_labels.present?
+ message << "removed #{removed_labels}"
+ end
+
+ message << ' ' << 'label'.pluralize(labels_count)
+ body = "_#{message.capitalize}_"
+
+ create(
+ noteable: noteable,
+ project: project,
+ author: author,
+ note: body,
+ system: true
+ )
+ end
+
+ def create_new_commits_note(merge_request, project, author, new_commits, existing_commits = [])
+ total_count = new_commits.length + existing_commits.length
+ commits_text = ActionController::Base.helpers.pluralize(total_count, 'commit')
body = "Added #{commits_text}:\n\n"
- commits.each do |commit|
+ if existing_commits.length > 0
+ commit_ids =
+ if existing_commits.length == 1
+ existing_commits.first.short_id
+ else
+ "#{existing_commits.first.short_id}..#{existing_commits.last.short_id}"
+ end
+
+ commits_text = ActionController::Base.helpers.pluralize(existing_commits.length, 'commit')
+
+ branch =
+ if merge_request.for_fork?
+ "#{merge_request.target_project_namespace}:#{merge_request.target_branch}"
+ else
+ merge_request.target_branch
+ end
+
+ message = "* #{commit_ids} - _#{commits_text} from branch `#{branch}`_"
+ body << message
+ body << "\n"
+ end
+
+ new_commits.each do |commit|
message = "* #{commit.short_id} - #{commit.title}"
body << message
body << "\n"
end
create(
- noteable: noteable,
+ noteable: merge_request,
project: project,
author: author,
note: body,
@@ -165,6 +218,15 @@ class Note < ActiveRecord::Base
[:discussion, type.try(:underscore), id, line_code].join("-").to_sym
end
+ # Determine if cross reference note should be created.
+ # eg. mentioning a commit in MR comments which exists inside a MR
+ # should not create "mentioned in" note.
+ def cross_reference_disallowed?(noteable, mentioner)
+ if mentioner.kind_of?(MergeRequest)
+ mentioner.commits.map(&:id).include? noteable.id
+ end
+ end
+
# Determine whether or not a cross-reference note already exists.
def cross_reference_exists?(noteable, mentioner)
gfm_reference = mentioner_gfm_ref(noteable, mentioner)
@@ -174,7 +236,7 @@ class Note < ActiveRecord::Base
where(noteable_id: noteable.id)
end
- notes.where('note like ?', "_mentioned in #{gfm_reference}_").
+ notes.where('note like ?', cross_reference_note_content(gfm_reference)).
system.any?
end
@@ -182,8 +244,16 @@ class Note < ActiveRecord::Base
where("note like :query", query: "%#{query}%")
end
+ def cross_reference_note_prefix
+ '_mentioned in '
+ end
+
private
+ def cross_reference_note_content(gfm_reference)
+ cross_reference_note_prefix + "#{gfm_reference}_"
+ end
+
# Prepend the mentioner's namespaced project path to the GFM reference for
# cross-project references. For same-project references, return the
# unmodified GFM reference.
@@ -243,12 +313,16 @@ class Note < ActiveRecord::Base
def commit_author
@commit_author ||=
- project.users.find_by(email: noteable.author_email) ||
- project.users.find_by(name: noteable.author_name)
+ project.team.users.find_by(email: noteable.author_email) ||
+ project.team.users.find_by(name: noteable.author_name)
rescue
nil
end
+ def cross_reference?
+ note.start_with?(self.class.cross_reference_note_prefix)
+ end
+
def find_diff
return nil unless noteable && noteable.diffs.present?
@@ -257,6 +331,10 @@ class Note < ActiveRecord::Base
end
end
+ def hook_attrs
+ attributes
+ end
+
def set_diff
# First lets find notes with same diff
# before iterating over all mr diffs
@@ -275,6 +353,7 @@ class Note < ActiveRecord::Base
# If not - its outdated diff
def active?
return true unless self.diff
+ return false unless noteable
noteable.diffs.each do |mr_diff|
next unless mr_diff.new_path == self.diff.new_path
@@ -296,7 +375,7 @@ class Note < ActiveRecord::Base
end
def diff_file_index
- line_code.split('_')[0]
+ line_code.split('_')[0] if line_code
end
def diff_file_name
@@ -312,11 +391,11 @@ class Note < ActiveRecord::Base
end
def diff_old_line
- line_code.split('_')[1].to_i
+ line_code.split('_')[1].to_i if line_code
end
def diff_new_line
- line_code.split('_')[2].to_i
+ line_code.split('_')[2].to_i if line_code
end
def generate_line_code(line)
@@ -337,25 +416,39 @@ class Note < ActiveRecord::Base
@diff_line
end
+ def diff_line_type
+ return @diff_line_type if @diff_line_type
+
+ if diff
+ diff_lines.each do |line|
+ if generate_line_code(line) == self.line_code
+ @diff_line_type = line.type
+ end
+ end
+ end
+
+ @diff_line_type
+ end
+
def truncated_diff_lines
max_number_of_lines = 16
prev_match_line = nil
prev_lines = []
diff_lines.each do |line|
- if generate_line_code(line) != self.line_code
- if line.type == "match"
- prev_lines.clear
- prev_match_line = line
- else
- prev_lines.push(line)
- prev_lines.shift if prev_lines.length >= max_number_of_lines
- end
+ if line.type == "match"
+ prev_lines.clear
+ prev_match_line = line
else
prev_lines << line
- return prev_lines
+
+ break if generate_line_code(line) == self.line_code
+
+ prev_lines.shift if prev_lines.length >= max_number_of_lines
end
end
+
+ prev_lines
end
def diff_lines
@@ -400,6 +493,10 @@ class Note < ActiveRecord::Base
for_merge_request? && for_diff_line?
end
+ def for_project_snippet?
+ noteable_type == "Snippet"
+ end
+
# override to return commits, which are not active record
def noteable
if for_commit?
@@ -423,6 +520,26 @@ class Note < ActiveRecord::Base
)
end
+ def superceded?(notes)
+ return false unless vote?
+
+ notes.each do |note|
+ next if note == self
+
+ if note.vote? &&
+ self[:author_id] == note[:author_id] &&
+ self[:created_at] <= note[:created_at]
+ return true
+ end
+ end
+
+ false
+ end
+
+ def vote?
+ upvote? || downvote?
+ end
+
def votable?
for_issue? || (for_merge_request? && !for_diff_line?)
end
@@ -444,7 +561,7 @@ class Note < ActiveRecord::Base
end
# FIXME: Hack for polymorphic associations with STI
- # For more information wisit http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Polymorphic+Associations
+ # For more information visit http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Polymorphic+Associations
def noteable_type=(sType)
super(sType.to_s.classify.constantize.base_class.to_s)
end
@@ -467,6 +584,6 @@ class Note < ActiveRecord::Base
end
def editable?
- !system
+ !read_attribute(:system)
end
end