diff options
-rw-r--r-- | app/models/concerns/mentionable.rb | 8 | ||||
-rw-r--r-- | lib/gitlab/closing_issue_extractor.rb | 6 | ||||
-rw-r--r-- | lib/gitlab/reference_extractor.rb | 70 |
3 files changed, 41 insertions, 43 deletions
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb index d96e07034ec..52eb87d1dbc 100644 --- a/app/models/concerns/mentionable.rb +++ b/app/models/concerns/mentionable.rb @@ -65,12 +65,10 @@ module Mentionable # Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference. def references(p = project, text = mentionable_text) return [] if text.blank? - ext = Gitlab::ReferenceExtractor.new - ext.analyze(text, p) + ext = Gitlab::ReferenceExtractor.new(p) + ext.analyze(text) - (ext.issues_for(p) + - ext.merge_requests_for(p) + - ext.commits_for(p)).uniq - [local_reference] + (ext.issues + ext.merge_requests + ext.commits).uniq - [local_reference] end # Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+. diff --git a/lib/gitlab/closing_issue_extractor.rb b/lib/gitlab/closing_issue_extractor.rb index a9fd59f03d9..5643d60c807 100644 --- a/lib/gitlab/closing_issue_extractor.rb +++ b/lib/gitlab/closing_issue_extractor.rb @@ -9,9 +9,9 @@ module Gitlab md = message.scan(ISSUE_CLOSING_REGEX) md.each do |ref| - extractor = Gitlab::ReferenceExtractor.new - extractor.analyze(ref[0], project) - issues += extractor.issues_for(project) + extractor = Gitlab::ReferenceExtractor.new(project) + extractor.analyze(ref[0]) + issues += extractor.issues end end diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 1058d4c43d9..90e04818719 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -1,89 +1,89 @@ module Gitlab # Extract possible GFM references from an arbitrary String for further processing. class ReferenceExtractor - attr_accessor :users, :labels, :issues, :merge_requests, :snippets, :commits, :commit_ranges + attr_accessor :project, :references include Markdown - def initialize - @users, @labels, @issues, @merge_requests, @snippets, @commits, @commit_ranges = - [], [], [], [], [], [], [] + def initialize(project) + @project = project + + @references = Hash.new { [] } end - def analyze(string, project) - text = string.dup + def analyze(text) + text = text.dup # Remove preformatted/code blocks so that references are not included text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) { |match| '' } text.gsub!(%r{^```.*?^```}m) { |match| '' } - parse_references(text, project) + parse_references(text) end # Given a valid project, resolve the extracted identifiers of the requested type to # model objects. - def users_for(project) - users.map do |entry| + def users + references[:users].map do |entry| project.users.where(username: entry[:id]).first - end.reject(&:nil?) + end.compact end - def labels_for(project = nil) - labels.map do |entry| + def labels + references[:labels].map do |entry| project.labels.where(id: entry[:id]).first - end.reject(&:nil?) + end.compact end - def issues_for(project = nil) - issues.map do |entry| - if should_lookup?(project, entry[:project]) + def issues + references[:issues].map do |entry| + if should_lookup?(entry[:project]) entry[:project].issues.where(iid: entry[:id]).first end - end.reject(&:nil?) + end.compact end - def merge_requests_for(project = nil) - merge_requests.map do |entry| - if should_lookup?(project, entry[:project]) + def merge_requests + references[:merge_requests].map do |entry| + if should_lookup?(entry[:project]) entry[:project].merge_requests.where(iid: entry[:id]).first end - end.reject(&:nil?) + end.compact end - def snippets_for(project) - snippets.map do |entry| + def snippets + references[:snippets].map do |entry| project.snippets.where(id: entry[:id]).first - end.reject(&:nil?) + end.compact end - def commits_for(project = nil) - commits.map do |entry| + def commits + references[:commits].map do |entry| repo = entry[:project].repository if entry[:project] - if should_lookup?(project, entry[:project]) + if should_lookup?(entry[:project]) repo.commit(entry[:id]) if repo end - end.reject(&:nil?) + end.compact end - def commit_ranges_for(project = nil) - commit_ranges.map do |entry| + def commit_ranges + references[:commit_ranges].map do |entry| repo = entry[:project].repository if entry[:project] - if repo && should_lookup?(project, entry[:project]) + if repo && should_lookup?(entry[:project]) from_id, to_id = entry[:id].split(/\.{2,3}/, 2) [repo.commit(from_id), repo.commit(to_id)] end - end.reject(&:nil?) + end.compact end private def reference_link(type, identifier, project, _) - # Append identifier to the appropriate collection. - send("#{type}s") << { project: project, id: identifier } + references[type] << { project: project, id: identifier } end - def should_lookup?(project, entry_project) + def should_lookup?(entry_project) if entry_project.nil? false else |