Commit b88da58c authored by Robert Speicher's avatar Robert Speicher
Browse files

Add `reference_pattern` to Referable models

parent c1463cdd900e
......@@ -62,6 +62,19 @@ def ==(other)
(self.class === other) && (raw == other.raw)
end
def self.reference_prefix
'@'
end
# Pattern used to extract commit references from text
#
# The SHA can be between 6 and 40 hex characters.
#
# This pattern supports cross-project references.
def self.reference_pattern
%r{(?:#{Project.reference_pattern}#{reference_prefix})?(?<commit>\h{6,40})}
end
def to_reference(from_project = nil)
if cross_project_reference?(from_project)
"#{project.to_reference}@#{id}"
......
......@@ -29,10 +29,24 @@ class CommitRange
# See `exclude_start?`
attr_reader :exclude_start
# The beginning and ending SHA sums can be between 6 and 40 hex characters,
# and the range selection can be double- or triple-dot.
# The beginning and ending SHAs can be between 6 and 40 hex characters, and
# the range notation can be double- or triple-dot.
PATTERN = /\h{6,40}\.{2,3}\h{6,40}/
def self.reference_prefix
'@'
end
# Pattern used to extract commit range references from text
#
# This pattern supports cross-project references.
def self.reference_pattern
%r{
(?:#{Project.reference_pattern}#{reference_prefix})?
(?<commit_range>#{PATTERN})
}x
end
# Initialize a CommitRange
#
# range_string - The String commit range.
......
......@@ -35,6 +35,16 @@ module ClassMethods
def reference_prefix
''
end
# Regexp pattern used to match references to this object
#
# This must be overridden by the including class.
#
# Returns Regexp
def reference_pattern
raise NotImplementedError,
%Q{#{self} does not implement "reference_pattern"}
end
end
private
......
......@@ -9,10 +9,6 @@ def to_s
@issue_identifier.to_s
end
def to_reference(_from_project = nil)
id
end
def id
@issue_identifier.to_s
end
......@@ -32,4 +28,13 @@ def ==(other)
def project
@project
end
# Pattern used to extract `JIRA-123` issue references from text
def self.reference_pattern
%r{(?<issue>([A-Z\-]+-)\d+)}
end
def to_reference(_from_project = nil)
id
end
end
......@@ -40,7 +40,11 @@ def sort(method)
end
def reference_prefix
'@'
User.reference_prefix
end
def reference_pattern
User.reference_pattern
end
end
......
......@@ -50,12 +50,22 @@ class Issue < ActiveRecord::Base
state :closed
end
def hook_attrs
attributes
end
def self.reference_prefix
'#'
end
def hook_attrs
attributes
# Pattern used to extract `#123` issue references from text
#
# This pattern supports cross-project references.
def self.reference_pattern
%r{
#{Project.reference_pattern}?
#{Regexp.escape(reference_prefix)}(?<issue>\d+)
}x
end
def to_reference(from_project = nil)
......
......@@ -40,6 +40,22 @@ def self.reference_prefix
'~'
end
# Pattern used to extract label references from text
#
# TODO (rspeicher): Limit to double quotes (meh) or disallow single quotes in label names (bad).
def self.reference_pattern
%r{
#{reference_prefix}
(?:
(?<label_id>\d+) | # Integer-based label ID, or
(?<label_name>
[A-Za-z0-9_-]+ | # String-based single-word label title
['"][^&\?,]+['"] # String-based multi-word label surrounded in quotes
)
)
}x
end
# Returns the String necessary to reference this Label in Markdown
#
# format - Symbol format to use (default: :id, optional: :name)
......
......@@ -140,6 +140,16 @@ def self.reference_prefix
'!'
end
# Pattern used to extract `!123` merge request references from text
#
# This pattern supports cross-project references.
def self.reference_pattern
%r{
#{Project.reference_pattern}?
#{Regexp.escape(reference_prefix)}(?<merge_request>\d+)
}x
end
def to_reference(from_project = nil)
reference = "#{self.class.reference_prefix}#{iid}"
......
......@@ -248,6 +248,11 @@ def sort(method)
order_by(method)
end
end
def reference_pattern
name_pattern = Gitlab::Regex::NAMESPACE_REGEX_STR
%r{(?<project>#{name_pattern}/#{name_pattern})}
end
end
def team
......
......@@ -56,6 +56,16 @@ def self.reference_prefix
'$'
end
# Pattern used to extract `$123` snippet references from text
#
# This pattern supports cross-project references.
def self.reference_pattern
%r{
#{Project.reference_pattern}?
#{Regexp.escape(reference_prefix)}(?<snippet>\d+)
}x
end
def to_reference(from_project = nil)
reference = "#{self.class.reference_prefix}#{id}"
......
......@@ -253,6 +253,14 @@ def build_user(attrs = {})
def reference_prefix
'@'
end
# Pattern used to extract `@user` user references from text
def reference_pattern
%r{
#{Regexp.escape(reference_prefix)}
(?<user>#{Gitlab::Regex::NAMESPACE_REGEX_STR})
}x
end
end
#
......
......@@ -19,7 +19,7 @@ class CommitRangeReferenceFilter < ReferenceFilter
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(COMMIT_RANGE_PATTERN) do |match|
text.gsub(CommitRange.reference_pattern) do |match|
yield match, $~[:commit_range], $~[:project]
end
end
......@@ -30,13 +30,8 @@ def initialize(*args)
@commit_map = {}
end
# Pattern used to extract commit range references from text
#
# This pattern supports cross-project references.
COMMIT_RANGE_PATTERN = /(#{PROJECT_PATTERN}@)?(?<commit_range>#{CommitRange::PATTERN})/
def call
replace_text_nodes_matching(COMMIT_RANGE_PATTERN) do |content|
replace_text_nodes_matching(CommitRange.reference_pattern) do |content|
commit_range_link_filter(content)
end
end
......
......@@ -19,20 +19,13 @@ class CommitReferenceFilter < ReferenceFilter
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(COMMIT_PATTERN) do |match|
text.gsub(Commit.reference_pattern) do |match|
yield match, $~[:commit], $~[:project]
end
end
# Pattern used to extract commit references from text
#
# The SHA1 sum can be between 6 and 40 hex characters.
#
# This pattern supports cross-project references.
COMMIT_PATTERN = /(#{PROJECT_PATTERN}@)?(?<commit>\h{6,40})/
def call
replace_text_nodes_matching(COMMIT_PATTERN) do |content|
replace_text_nodes_matching(Commit.reference_pattern) do |content|
commit_link_filter(content)
end
end
......
......@@ -3,9 +3,6 @@ module Markdown
# Common methods for ReferenceFilters that support an optional cross-project
# reference.
module CrossProjectReference
NAMING_PATTERN = Gitlab::Regex::NAMESPACE_REGEX_STR
PROJECT_PATTERN = "(?<project>#{NAMING_PATTERN}/#{NAMING_PATTERN})"
# Given a cross-project reference string, get the Project record
#
# Defaults to value of `context[:project]` if:
......
......@@ -16,19 +16,16 @@ class ExternalIssueReferenceFilter < ReferenceFilter
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(ISSUE_PATTERN) do |match|
text.gsub(ExternalIssue.reference_pattern) do |match|
yield match, $~[:issue]
end
end
# Pattern used to extract `JIRA-123` issue references from text
ISSUE_PATTERN = /(?<issue>([A-Z\-]+-)\d+)/
def call
# Early return if the project isn't using an external tracker
return doc if project.nil? || project.default_issues_tracker?
replace_text_nodes_matching(ISSUE_PATTERN) do |content|
replace_text_nodes_matching(ExternalIssue.reference_pattern) do |content|
issue_link_filter(content)
end
end
......
......@@ -20,18 +20,13 @@ class IssueReferenceFilter < ReferenceFilter
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(ISSUE_PATTERN) do |match|
text.gsub(Issue.reference_pattern) do |match|
yield match, $~[:issue].to_i, $~[:project]
end
end
# Pattern used to extract `#123` issue references from text
#
# This pattern supports cross-project references.
ISSUE_PATTERN = /#{PROJECT_PATTERN}?\#(?<issue>([a-zA-Z\-]+-)?\d+)/
def call
replace_text_nodes_matching(ISSUE_PATTERN) do |content|
replace_text_nodes_matching(Issue.reference_pattern) do |content|
issue_link_filter(content)
end
end
......
......@@ -15,26 +15,13 @@ class LabelReferenceFilter < ReferenceFilter
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(LABEL_PATTERN) do |match|
text.gsub(Label.reference_pattern) do |match|
yield match, $~[:label_id].to_i, $~[:label_name]
end
end
# Pattern used to extract label references from text
#
# TODO (rspeicher): Limit to double quotes (meh) or disallow single quotes in label names (bad).
LABEL_PATTERN = %r{
~(
(?<label_id>\d+) | # Integer-based label ID, or
(?<label_name>
[A-Za-z0-9_-]+ | # String-based single-word label title
['"][^&\?,]+['"] # String-based multi-word label surrounded in quotes
)
)
}x
def call
replace_text_nodes_matching(LABEL_PATTERN) do |content|
replace_text_nodes_matching(Label.reference_pattern) do |content|
label_link_filter(content)
end
end
......
......@@ -20,18 +20,13 @@ class MergeRequestReferenceFilter < ReferenceFilter
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(MERGE_REQUEST_PATTERN) do |match|
text.gsub(MergeRequest.reference_pattern) do |match|
yield match, $~[:merge_request].to_i, $~[:project]
end
end
# Pattern used to extract `!123` merge request references from text
#
# This pattern supports cross-project references.
MERGE_REQUEST_PATTERN = /#{PROJECT_PATTERN}?!(?<merge_request>\d+)/
def call
replace_text_nodes_matching(MERGE_REQUEST_PATTERN) do |content|
replace_text_nodes_matching(MergeRequest.reference_pattern) do |content|
merge_request_link_filter(content)
end
end
......
......@@ -20,18 +20,13 @@ class SnippetReferenceFilter < ReferenceFilter
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(SNIPPET_PATTERN) do |match|
text.gsub(Snippet.reference_pattern) do |match|
yield match, $~[:snippet].to_i, $~[:project]
end
end
# Pattern used to extract `$123` snippet references from text
#
# This pattern supports cross-project references.
SNIPPET_PATTERN = /#{PROJECT_PATTERN}?\$(?<snippet>\d+)/
def call
replace_text_nodes_matching(SNIPPET_PATTERN) do |content|
replace_text_nodes_matching(Snippet.reference_pattern) do |content|
snippet_link_filter(content)
end
end
......
......@@ -16,16 +16,13 @@ class UserReferenceFilter < ReferenceFilter
#
# Returns a String replaced with the return of the block.
def self.references_in(text)
text.gsub(USER_PATTERN) do |match|
text.gsub(User.reference_pattern) do |match|
yield match, $~[:user]
end
end
# Pattern used to extract `@user` user references from text
USER_PATTERN = /@(?<user>#{Gitlab::Regex::NAMESPACE_REGEX_STR})/
def call
replace_text_nodes_matching(USER_PATTERN) do |content|
replace_text_nodes_matching(User.reference_pattern) do |content|
user_link_filter(content)
end
end
......
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