Commit b1ef1aa5 authored by Douwe Maan's avatar Douwe Maan

Slightly refactor ReferenceExtractor.

parent 254698d6
...@@ -65,12 +65,10 @@ module Mentionable ...@@ -65,12 +65,10 @@ module Mentionable
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference. # Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
def references(p = project, text = mentionable_text) def references(p = project, text = mentionable_text)
return [] if text.blank? return [] if text.blank?
ext = Gitlab::ReferenceExtractor.new ext = Gitlab::ReferenceExtractor.new(p)
ext.analyze(text, p) ext.analyze(text)
(ext.issues_for(p) + (ext.issues + ext.merge_requests + ext.commits).uniq - [local_reference]
ext.merge_requests_for(p) +
ext.commits_for(p)).uniq - [local_reference]
end end
# Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+. # Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
......
...@@ -9,9 +9,9 @@ module Gitlab ...@@ -9,9 +9,9 @@ module Gitlab
md = message.scan(ISSUE_CLOSING_REGEX) md = message.scan(ISSUE_CLOSING_REGEX)
md.each do |ref| md.each do |ref|
extractor = Gitlab::ReferenceExtractor.new extractor = Gitlab::ReferenceExtractor.new(project)
extractor.analyze(ref[0], project) extractor.analyze(ref[0])
issues += extractor.issues_for(project) issues += extractor.issues
end end
end end
......
module Gitlab module Gitlab
# Extract possible GFM references from an arbitrary String for further processing. # Extract possible GFM references from an arbitrary String for further processing.
class ReferenceExtractor class ReferenceExtractor
attr_accessor :users, :labels, :issues, :merge_requests, :snippets, :commits, :commit_ranges attr_accessor :project, :references
include Markdown include Markdown
def initialize def initialize(project)
@users, @labels, @issues, @merge_requests, @snippets, @commits, @commit_ranges = @project = project
[], [], [], [], [], [], []
@references = Hash.new { [] }
end end
def analyze(string, project) def analyze(text)
text = string.dup text = text.dup
# Remove preformatted/code blocks so that references are not included # Remove preformatted/code blocks so that references are not included
text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) { |match| '' } text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) { |match| '' }
text.gsub!(%r{^```.*?^```}m) { |match| '' } text.gsub!(%r{^```.*?^```}m) { |match| '' }
parse_references(text, project) parse_references(text)
end end
# Given a valid project, resolve the extracted identifiers of the requested type to # Given a valid project, resolve the extracted identifiers of the requested type to
# model objects. # model objects.
def users_for(project) def users
users.map do |entry| references[:users].map do |entry|
project.users.where(username: entry[:id]).first project.users.where(username: entry[:id]).first
end.reject(&:nil?) end.compact
end end
def labels_for(project = nil) def labels
labels.map do |entry| references[:labels].map do |entry|
project.labels.where(id: entry[:id]).first project.labels.where(id: entry[:id]).first
end.reject(&:nil?) end.compact
end end
def issues_for(project = nil) def issues
issues.map do |entry| references[:issues].map do |entry|
if should_lookup?(project, entry[:project]) if should_lookup?(entry[:project])
entry[:project].issues.where(iid: entry[:id]).first entry[:project].issues.where(iid: entry[:id]).first
end end
end.reject(&:nil?) end.compact
end end
def merge_requests_for(project = nil) def merge_requests
merge_requests.map do |entry| references[:merge_requests].map do |entry|
if should_lookup?(project, entry[:project]) if should_lookup?(entry[:project])
entry[:project].merge_requests.where(iid: entry[:id]).first entry[:project].merge_requests.where(iid: entry[:id]).first
end end
end.reject(&:nil?) end.compact
end end
def snippets_for(project) def snippets
snippets.map do |entry| references[:snippets].map do |entry|
project.snippets.where(id: entry[:id]).first project.snippets.where(id: entry[:id]).first
end.reject(&:nil?) end.compact
end end
def commits_for(project = nil) def commits
commits.map do |entry| references[:commits].map do |entry|
repo = entry[:project].repository if entry[:project] repo = entry[:project].repository if entry[:project]
if should_lookup?(project, entry[:project]) if should_lookup?(entry[:project])
repo.commit(entry[:id]) if repo repo.commit(entry[:id]) if repo
end end
end.reject(&:nil?) end.compact
end end
def commit_ranges_for(project = nil) def commit_ranges
commit_ranges.map do |entry| references[:commit_ranges].map do |entry|
repo = entry[:project].repository if entry[:project] 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) from_id, to_id = entry[:id].split(/\.{2,3}/, 2)
[repo.commit(from_id), repo.commit(to_id)] [repo.commit(from_id), repo.commit(to_id)]
end end
end.reject(&:nil?) end.compact
end end
private private
def reference_link(type, identifier, project, _) def reference_link(type, identifier, project, _)
# Append identifier to the appropriate collection. references[type] << { project: project, id: identifier }
send("#{type}s") << { project: project, id: identifier }
end end
def should_lookup?(project, entry_project) def should_lookup?(entry_project)
if entry_project.nil? if entry_project.nil?
false false
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment