From b88da58cb6272a86b6df2e4efe392f10e689a6b2 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 14 May 2015 16:59:39 -0400 Subject: Add `reference_pattern` to Referable models --- app/models/commit.rb | 13 +++++++++++++ app/models/commit_range.rb | 18 ++++++++++++++++-- app/models/concerns/referable.rb | 10 ++++++++++ app/models/external_issue.rb | 13 +++++++++---- app/models/group.rb | 6 +++++- app/models/issue.rb | 14 ++++++++++++-- app/models/label.rb | 16 ++++++++++++++++ app/models/merge_request.rb | 10 ++++++++++ app/models/project.rb | 5 +++++ app/models/snippet.rb | 10 ++++++++++ app/models/user.rb | 8 ++++++++ lib/gitlab/markdown/commit_range_reference_filter.rb | 9 ++------- lib/gitlab/markdown/commit_reference_filter.rb | 11 ++--------- lib/gitlab/markdown/cross_project_reference.rb | 3 --- lib/gitlab/markdown/external_issue_reference_filter.rb | 7 ++----- lib/gitlab/markdown/issue_reference_filter.rb | 9 ++------- lib/gitlab/markdown/label_reference_filter.rb | 17 ++--------------- lib/gitlab/markdown/merge_request_reference_filter.rb | 9 ++------- lib/gitlab/markdown/snippet_reference_filter.rb | 9 ++------- lib/gitlab/markdown/user_reference_filter.rb | 7 ++----- 20 files changed, 130 insertions(+), 74 deletions(-) diff --git a/app/models/commit.rb b/app/models/commit.rb index 085f4e6398f..2c244fc0410 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -62,6 +62,19 @@ class Commit (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})?(?\h{6,40})} + end + def to_reference(from_project = nil) if cross_project_reference?(from_project) "#{project.to_reference}@#{id}" diff --git a/app/models/commit_range.rb b/app/models/commit_range.rb index fb1f6d09be6..86fc9eb01a3 100644 --- a/app/models/commit_range.rb +++ b/app/models/commit_range.rb @@ -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})? + (?#{PATTERN}) + }x + end + # Initialize a CommitRange # # range_string - The String commit range. diff --git a/app/models/concerns/referable.rb b/app/models/concerns/referable.rb index b41df301c3f..e3c1c6d268e 100644 --- a/app/models/concerns/referable.rb +++ b/app/models/concerns/referable.rb @@ -35,6 +35,16 @@ module Referable 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 diff --git a/app/models/external_issue.rb b/app/models/external_issue.rb index 6fda4a2ab77..49f6c95e045 100644 --- a/app/models/external_issue.rb +++ b/app/models/external_issue.rb @@ -9,10 +9,6 @@ class ExternalIssue @issue_identifier.to_s end - def to_reference(_from_project = nil) - id - end - def id @issue_identifier.to_s end @@ -32,4 +28,13 @@ class ExternalIssue def project @project end + + # Pattern used to extract `JIRA-123` issue references from text + def self.reference_pattern + %r{(?([A-Z\-]+-)\d+)} + end + + def to_reference(_from_project = nil) + id + end end diff --git a/app/models/group.rb b/app/models/group.rb index 33d72e0d9ee..b4e908c5602 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -40,7 +40,11 @@ class Group < Namespace end def reference_prefix - '@' + User.reference_prefix + end + + def reference_pattern + User.reference_pattern end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 31803b57b3f..ea6b9329b07 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -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)}(?\d+) + }x end def to_reference(from_project = nil) diff --git a/app/models/label.rb b/app/models/label.rb index 013e6bf5978..8980049cef8 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -40,6 +40,22 @@ class Label < ActiveRecord::Base '~' 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} + (?: + (?\d+) | # Integer-based label ID, or + (? + [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) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 60b0ce6c018..6c90d09b866 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -140,6 +140,16 @@ class MergeRequest < ActiveRecord::Base '!' 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)}(?\d+) + }x + end + def to_reference(from_project = nil) reference = "#{self.class.reference_prefix}#{iid}" diff --git a/app/models/project.rb b/app/models/project.rb index c943114449a..3c9f0dad28b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -248,6 +248,11 @@ class Project < ActiveRecord::Base order_by(method) end end + + def reference_pattern + name_pattern = Gitlab::Regex::NAMESPACE_REGEX_STR + %r{(?#{name_pattern}/#{name_pattern})} + end end def team diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 8c3167833aa..d1619071f49 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -56,6 +56,16 @@ class Snippet < ActiveRecord::Base '$' 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)}(?\d+) + }x + end + def to_reference(from_project = nil) reference = "#{self.class.reference_prefix}#{id}" diff --git a/app/models/user.rb b/app/models/user.rb index f546dc015c2..50ca4bc5acc 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -253,6 +253,14 @@ class User < ActiveRecord::Base def reference_prefix '@' end + + # Pattern used to extract `@user` user references from text + def reference_pattern + %r{ + #{Regexp.escape(reference_prefix)} + (?#{Gitlab::Regex::NAMESPACE_REGEX_STR}) + }x + end end # diff --git a/lib/gitlab/markdown/commit_range_reference_filter.rb b/lib/gitlab/markdown/commit_range_reference_filter.rb index 8764f7e474f..61591a9914b 100644 --- a/lib/gitlab/markdown/commit_range_reference_filter.rb +++ b/lib/gitlab/markdown/commit_range_reference_filter.rb @@ -19,7 +19,7 @@ module Gitlab # # 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 @@ module Gitlab @commit_map = {} end - # Pattern used to extract commit range references from text - # - # This pattern supports cross-project references. - COMMIT_RANGE_PATTERN = /(#{PROJECT_PATTERN}@)?(?#{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 diff --git a/lib/gitlab/markdown/commit_reference_filter.rb b/lib/gitlab/markdown/commit_reference_filter.rb index b20b29f5d0c..f6932e76e70 100644 --- a/lib/gitlab/markdown/commit_reference_filter.rb +++ b/lib/gitlab/markdown/commit_reference_filter.rb @@ -19,20 +19,13 @@ module Gitlab # # 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}@)?(?\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 diff --git a/lib/gitlab/markdown/cross_project_reference.rb b/lib/gitlab/markdown/cross_project_reference.rb index c436fabd658..66c256c5104 100644 --- a/lib/gitlab/markdown/cross_project_reference.rb +++ b/lib/gitlab/markdown/cross_project_reference.rb @@ -3,9 +3,6 @@ module Gitlab # Common methods for ReferenceFilters that support an optional cross-project # reference. module CrossProjectReference - NAMING_PATTERN = Gitlab::Regex::NAMESPACE_REGEX_STR - PROJECT_PATTERN = "(?#{NAMING_PATTERN}/#{NAMING_PATTERN})" - # Given a cross-project reference string, get the Project record # # Defaults to value of `context[:project]` if: diff --git a/lib/gitlab/markdown/external_issue_reference_filter.rb b/lib/gitlab/markdown/external_issue_reference_filter.rb index 0fc3f4cca06..2e74c6e45e2 100644 --- a/lib/gitlab/markdown/external_issue_reference_filter.rb +++ b/lib/gitlab/markdown/external_issue_reference_filter.rb @@ -16,19 +16,16 @@ module Gitlab # # 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 = /(?([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 diff --git a/lib/gitlab/markdown/issue_reference_filter.rb b/lib/gitlab/markdown/issue_reference_filter.rb index 1e885615163..2815626e247 100644 --- a/lib/gitlab/markdown/issue_reference_filter.rb +++ b/lib/gitlab/markdown/issue_reference_filter.rb @@ -20,18 +20,13 @@ module Gitlab # # 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}?\#(?([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 diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb index 1a77becee89..9f8c85b7012 100644 --- a/lib/gitlab/markdown/label_reference_filter.rb +++ b/lib/gitlab/markdown/label_reference_filter.rb @@ -15,26 +15,13 @@ module Gitlab # # 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{ - ~( - (?\d+) | # Integer-based label ID, or - (? - [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 diff --git a/lib/gitlab/markdown/merge_request_reference_filter.rb b/lib/gitlab/markdown/merge_request_reference_filter.rb index 740d72abb36..fddc050635f 100644 --- a/lib/gitlab/markdown/merge_request_reference_filter.rb +++ b/lib/gitlab/markdown/merge_request_reference_filter.rb @@ -20,18 +20,13 @@ module Gitlab # # 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}?!(?\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 diff --git a/lib/gitlab/markdown/snippet_reference_filter.rb b/lib/gitlab/markdown/snippet_reference_filter.rb index 64a0a2696f7..f22f08de27c 100644 --- a/lib/gitlab/markdown/snippet_reference_filter.rb +++ b/lib/gitlab/markdown/snippet_reference_filter.rb @@ -20,18 +20,13 @@ module Gitlab # # 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}?\$(?\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 diff --git a/lib/gitlab/markdown/user_reference_filter.rb b/lib/gitlab/markdown/user_reference_filter.rb index 28ec041b1d4..ca7fd7b0338 100644 --- a/lib/gitlab/markdown/user_reference_filter.rb +++ b/lib/gitlab/markdown/user_reference_filter.rb @@ -16,16 +16,13 @@ module Gitlab # # 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 = /@(?#{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 -- cgit v1.2.3