Recognize issue/MR/snippet/commit links as references.
This commit is contained in:
parent
a7be01cd07
commit
d6a5b45c8e
|
@ -73,16 +73,23 @@ class Commit
|
||||||
# This pattern supports cross-project references.
|
# This pattern supports cross-project references.
|
||||||
def self.reference_pattern
|
def self.reference_pattern
|
||||||
%r{
|
%r{
|
||||||
|
#{link_reference_pattern} |
|
||||||
|
(?:
|
||||||
(?:#{Project.reference_pattern}#{reference_prefix})?
|
(?:#{Project.reference_pattern}#{reference_prefix})?
|
||||||
(?<commit>\h{6,40})
|
(?<commit>\h{6,40})
|
||||||
|
)
|
||||||
}x
|
}x
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.link_reference_pattern
|
||||||
|
super("commit", /(?<commit>\h{6,40})/)
|
||||||
|
end
|
||||||
|
|
||||||
def to_reference(from_project = nil)
|
def to_reference(from_project = nil)
|
||||||
if cross_project_reference?(from_project)
|
if cross_project_reference?(from_project)
|
||||||
"#{project.to_reference}@#{id}"
|
project.to_reference + self.class.reference_prefix + self.short_id
|
||||||
else
|
else
|
||||||
id
|
self.short_id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -42,11 +42,18 @@ class CommitRange
|
||||||
# This pattern supports cross-project references.
|
# This pattern supports cross-project references.
|
||||||
def self.reference_pattern
|
def self.reference_pattern
|
||||||
%r{
|
%r{
|
||||||
|
#{link_reference_pattern} |
|
||||||
|
(?:
|
||||||
(?:#{Project.reference_pattern}#{reference_prefix})?
|
(?:#{Project.reference_pattern}#{reference_prefix})?
|
||||||
(?<commit_range>#{PATTERN})
|
(?<commit_range>#{PATTERN})
|
||||||
|
)
|
||||||
}x
|
}x
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.link_reference_pattern
|
||||||
|
super("compare", /(?<commit_range>#{PATTERN})/)
|
||||||
|
end
|
||||||
|
|
||||||
# Initialize a CommitRange
|
# Initialize a CommitRange
|
||||||
#
|
#
|
||||||
# range_string - The String commit range.
|
# range_string - The String commit range.
|
||||||
|
|
|
@ -44,6 +44,25 @@ module Referable
|
||||||
def reference_pattern
|
def reference_pattern
|
||||||
raise NotImplementedError, "#{self} does not implement #{__method__}"
|
raise NotImplementedError, "#{self} does not implement #{__method__}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def link_reference_pattern(route, pattern)
|
||||||
|
%r{
|
||||||
|
(?<url>
|
||||||
|
#{Regexp.escape(Gitlab.config.gitlab.url)}
|
||||||
|
\/#{Project.reference_pattern}
|
||||||
|
\/#{Regexp.escape(route)}
|
||||||
|
\/#{pattern}
|
||||||
|
(?<path>
|
||||||
|
(\/[a-z0-9_=-]+)*
|
||||||
|
)?
|
||||||
|
(?<query>
|
||||||
|
\?[a-z0-9_=-]+
|
||||||
|
(&[a-z0-9_=-]+)*
|
||||||
|
)?
|
||||||
|
(?<anchor>\#[a-z0-9_-]+)?
|
||||||
|
)
|
||||||
|
}x
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -64,11 +64,18 @@ class Issue < ActiveRecord::Base
|
||||||
# This pattern supports cross-project references.
|
# This pattern supports cross-project references.
|
||||||
def self.reference_pattern
|
def self.reference_pattern
|
||||||
%r{
|
%r{
|
||||||
|
#{link_reference_pattern} |
|
||||||
|
(?:
|
||||||
(#{Project.reference_pattern})?
|
(#{Project.reference_pattern})?
|
||||||
#{Regexp.escape(reference_prefix)}(?<issue>\d+)
|
#{Regexp.escape(reference_prefix)}(?<issue>\d+)
|
||||||
|
)
|
||||||
}x
|
}x
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.link_reference_pattern
|
||||||
|
super("issues", /(?<issue>\d+)/)
|
||||||
|
end
|
||||||
|
|
||||||
def to_reference(from_project = nil)
|
def to_reference(from_project = nil)
|
||||||
reference = "#{self.class.reference_prefix}#{iid}"
|
reference = "#{self.class.reference_prefix}#{iid}"
|
||||||
|
|
||||||
|
|
|
@ -146,11 +146,18 @@ class MergeRequest < ActiveRecord::Base
|
||||||
# This pattern supports cross-project references.
|
# This pattern supports cross-project references.
|
||||||
def self.reference_pattern
|
def self.reference_pattern
|
||||||
%r{
|
%r{
|
||||||
|
#{link_reference_pattern} |
|
||||||
|
(?:
|
||||||
(#{Project.reference_pattern})?
|
(#{Project.reference_pattern})?
|
||||||
#{Regexp.escape(reference_prefix)}(?<merge_request>\d+)
|
#{Regexp.escape(reference_prefix)}(?<merge_request>\d+)
|
||||||
|
)
|
||||||
}x
|
}x
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.link_reference_pattern
|
||||||
|
super("merge_requests", /(?<merge_request>\d+)/)
|
||||||
|
end
|
||||||
|
|
||||||
def to_reference(from_project = nil)
|
def to_reference(from_project = nil)
|
||||||
reference = "#{self.class.reference_prefix}#{iid}"
|
reference = "#{self.class.reference_prefix}#{iid}"
|
||||||
|
|
||||||
|
|
|
@ -60,11 +60,18 @@ class Snippet < ActiveRecord::Base
|
||||||
# This pattern supports cross-project references.
|
# This pattern supports cross-project references.
|
||||||
def self.reference_pattern
|
def self.reference_pattern
|
||||||
%r{
|
%r{
|
||||||
|
#{link_reference_pattern} |
|
||||||
|
(?:
|
||||||
(#{Project.reference_pattern})?
|
(#{Project.reference_pattern})?
|
||||||
#{Regexp.escape(reference_prefix)}(?<snippet>\d+)
|
#{Regexp.escape(reference_prefix)}(?<snippet>\d+)
|
||||||
|
)
|
||||||
}x
|
}x
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.link_reference_pattern
|
||||||
|
super("snippets", /(?<snippet>\d+)/)
|
||||||
|
end
|
||||||
|
|
||||||
def to_reference(from_project = nil)
|
def to_reference(from_project = nil)
|
||||||
reference = "#{self.class.reference_prefix}#{id}"
|
reference = "#{self.class.reference_prefix}#{id}"
|
||||||
|
|
||||||
|
|
|
@ -181,8 +181,6 @@ module Gitlab
|
||||||
Gitlab::Markdown::RelativeLinkFilter,
|
Gitlab::Markdown::RelativeLinkFilter,
|
||||||
Gitlab::Markdown::EmojiFilter,
|
Gitlab::Markdown::EmojiFilter,
|
||||||
Gitlab::Markdown::TableOfContentsFilter,
|
Gitlab::Markdown::TableOfContentsFilter,
|
||||||
Gitlab::Markdown::AutolinkFilter,
|
|
||||||
Gitlab::Markdown::ExternalLinkFilter,
|
|
||||||
|
|
||||||
Gitlab::Markdown::UserReferenceFilter,
|
Gitlab::Markdown::UserReferenceFilter,
|
||||||
Gitlab::Markdown::IssueReferenceFilter,
|
Gitlab::Markdown::IssueReferenceFilter,
|
||||||
|
@ -193,6 +191,9 @@ module Gitlab
|
||||||
Gitlab::Markdown::CommitReferenceFilter,
|
Gitlab::Markdown::CommitReferenceFilter,
|
||||||
Gitlab::Markdown::LabelReferenceFilter,
|
Gitlab::Markdown::LabelReferenceFilter,
|
||||||
|
|
||||||
|
Gitlab::Markdown::AutolinkFilter,
|
||||||
|
Gitlab::Markdown::ExternalLinkFilter,
|
||||||
|
|
||||||
Gitlab::Markdown::TaskListFilter
|
Gitlab::Markdown::TaskListFilter
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,7 +40,7 @@ module Gitlab
|
||||||
# Returns a String replaced with the return of the block.
|
# Returns a String replaced with the return of the block.
|
||||||
def self.references_in(text)
|
def self.references_in(text)
|
||||||
text.gsub(object_class.reference_pattern) do |match|
|
text.gsub(object_class.reference_pattern) do |match|
|
||||||
yield match, $~[object_sym].to_i, $~[:project]
|
yield match, $~[object_sym].to_i, $~[:project], $~
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -74,26 +74,41 @@ module Gitlab
|
||||||
# Returns a String with references replaced with links. All links
|
# Returns a String with references replaced with links. All links
|
||||||
# have `gfm` and `gfm-OBJECT_NAME` class names attached for styling.
|
# have `gfm` and `gfm-OBJECT_NAME` class names attached for styling.
|
||||||
def object_link_filter(text)
|
def object_link_filter(text)
|
||||||
references_in(text) do |match, id, project_ref|
|
references_in(text) do |match, id, project_ref, matches|
|
||||||
project = project_from_ref(project_ref)
|
project = project_from_ref(project_ref)
|
||||||
|
|
||||||
if project && object = find_object(project, id)
|
if project && object = find_object(project, id)
|
||||||
title = escape_once("#{object_title}: #{object.title}")
|
title = escape_once(object_link_title(object))
|
||||||
klass = reference_class(object_sym)
|
klass = reference_class(object_sym)
|
||||||
data = data_attribute(project: project.id, object_sym => object.id)
|
data = data_attribute(project: project.id, object_sym => object.id, original: match)
|
||||||
url = url_for_object(object, project)
|
url = matches[:url] || url_for_object(object, project)
|
||||||
|
|
||||||
|
text = object.to_reference(context[:project])
|
||||||
|
|
||||||
|
extras = object_link_text_extras(object, matches)
|
||||||
|
text += " (#{extras.join(", ")})" if extras.any?
|
||||||
|
|
||||||
%(<a href="#{url}" #{data}
|
%(<a href="#{url}" #{data}
|
||||||
title="#{title}"
|
title="#{title}"
|
||||||
class="#{klass}">#{match}</a>)
|
class="#{klass}">#{text}</a>)
|
||||||
else
|
else
|
||||||
match
|
match
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def object_title
|
def object_link_text_extras(object, matches)
|
||||||
object_class.name.titleize
|
extras = []
|
||||||
|
|
||||||
|
if matches[:anchor] && matches[:anchor] =~ /\A\#note_(\d+)\z/
|
||||||
|
extras << "comment #{$1}"
|
||||||
|
end
|
||||||
|
|
||||||
|
extras
|
||||||
|
end
|
||||||
|
|
||||||
|
def object_link_title(object)
|
||||||
|
"#{object_class.name.titleize}: #{object.title}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,24 +5,14 @@ module Gitlab
|
||||||
# HTML filter that replaces commit range references with links.
|
# HTML filter that replaces commit range references with links.
|
||||||
#
|
#
|
||||||
# This filter supports cross-project references.
|
# This filter supports cross-project references.
|
||||||
class CommitRangeReferenceFilter < ReferenceFilter
|
class CommitRangeReferenceFilter < AbstractReferenceFilter
|
||||||
include CrossProjectReference
|
def self.object_class
|
||||||
|
CommitRange
|
||||||
|
end
|
||||||
|
|
||||||
# Public: Find commit range references in text
|
|
||||||
#
|
|
||||||
# CommitRangeReferenceFilter.references_in(text) do |match, commit_range, project_ref|
|
|
||||||
# "<a href=...>#{commit_range}</a>"
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# text - String text to search.
|
|
||||||
#
|
|
||||||
# Yields the String match, the String commit range, and an optional String
|
|
||||||
# of the external project reference.
|
|
||||||
#
|
|
||||||
# Returns a String replaced with the return of the block.
|
|
||||||
def self.references_in(text)
|
def self.references_in(text)
|
||||||
text.gsub(CommitRange.reference_pattern) do |match|
|
text.gsub(CommitRange.reference_pattern) do |match|
|
||||||
yield match, $~[:commit_range], $~[:project]
|
yield match, $~[:commit_range], $~[:project], $~
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,9 +21,9 @@ module Gitlab
|
||||||
return unless project
|
return unless project
|
||||||
|
|
||||||
id = node.attr("data-commit-range")
|
id = node.attr("data-commit-range")
|
||||||
range = CommitRange.new(id, project)
|
range = find_object(project, id)
|
||||||
|
|
||||||
return unless range.valid_commits?
|
return unless range
|
||||||
|
|
||||||
{ commit_range: range }
|
{ commit_range: range }
|
||||||
end
|
end
|
||||||
|
@ -44,49 +34,25 @@ module Gitlab
|
||||||
@commit_map = {}
|
@commit_map = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def call
|
def self.find_object(project, id)
|
||||||
replace_text_nodes_matching(CommitRange.reference_pattern) do |content|
|
|
||||||
commit_range_link_filter(content)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Replace commit range references in text with links to compare the commit
|
|
||||||
# ranges.
|
|
||||||
#
|
|
||||||
# text - String text to replace references in.
|
|
||||||
#
|
|
||||||
# Returns a String with commit range references replaced with links. All
|
|
||||||
# links have `gfm` and `gfm-commit_range` class names attached for
|
|
||||||
# styling.
|
|
||||||
def commit_range_link_filter(text)
|
|
||||||
self.class.references_in(text) do |match, id, project_ref|
|
|
||||||
project = self.project_from_ref(project_ref)
|
|
||||||
|
|
||||||
range = CommitRange.new(id, project)
|
range = CommitRange.new(id, project)
|
||||||
|
|
||||||
if range.valid_commits?
|
range.valid_commits? ? range : nil
|
||||||
url = url_for_commit_range(project, range)
|
|
||||||
|
|
||||||
title = range.reference_title
|
|
||||||
klass = reference_class(:commit_range)
|
|
||||||
data = data_attribute(project: project.id, commit_range: id)
|
|
||||||
|
|
||||||
project_ref += '@' if project_ref
|
|
||||||
|
|
||||||
%(<a href="#{url}" #{data}
|
|
||||||
title="#{title}"
|
|
||||||
class="#{klass}">#{project_ref}#{range}</a>)
|
|
||||||
else
|
|
||||||
match
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def url_for_commit_range(project, range)
|
def find_object(*args)
|
||||||
|
self.class.find_object(*args)
|
||||||
|
end
|
||||||
|
|
||||||
|
def url_for_object(range, project)
|
||||||
h = Gitlab::Application.routes.url_helpers
|
h = Gitlab::Application.routes.url_helpers
|
||||||
h.namespace_project_compare_url(project.namespace, project,
|
h.namespace_project_compare_url(project.namespace, project,
|
||||||
range.to_param.merge(only_path: context[:only_path]))
|
range.to_param.merge(only_path: context[:only_path]))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def object_link_title(range)
|
||||||
|
range.reference_title
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,24 +5,14 @@ module Gitlab
|
||||||
# HTML filter that replaces commit references with links.
|
# HTML filter that replaces commit references with links.
|
||||||
#
|
#
|
||||||
# This filter supports cross-project references.
|
# This filter supports cross-project references.
|
||||||
class CommitReferenceFilter < ReferenceFilter
|
class CommitReferenceFilter < AbstractReferenceFilter
|
||||||
include CrossProjectReference
|
def self.object_class
|
||||||
|
Commit
|
||||||
|
end
|
||||||
|
|
||||||
# Public: Find commit references in text
|
|
||||||
#
|
|
||||||
# CommitReferenceFilter.references_in(text) do |match, commit, project_ref|
|
|
||||||
# "<a href=...>#{commit}</a>"
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# text - String text to search.
|
|
||||||
#
|
|
||||||
# Yields the String match, the String commit identifier, and an optional
|
|
||||||
# String of the external project reference.
|
|
||||||
#
|
|
||||||
# Returns a String replaced with the return of the block.
|
|
||||||
def self.references_in(text)
|
def self.references_in(text)
|
||||||
text.gsub(Commit.reference_pattern) do |match|
|
text.gsub(Commit.reference_pattern) do |match|
|
||||||
yield match, $~[:commit], $~[:project]
|
yield match, $~[:commit], $~[:project], $~
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,58 +21,32 @@ module Gitlab
|
||||||
return unless project
|
return unless project
|
||||||
|
|
||||||
id = node.attr("data-commit")
|
id = node.attr("data-commit")
|
||||||
commit = commit_from_ref(project, id)
|
commit = find_object(project, id)
|
||||||
|
|
||||||
return unless commit
|
return unless commit
|
||||||
|
|
||||||
{ commit: commit }
|
{ commit: commit }
|
||||||
end
|
end
|
||||||
|
|
||||||
def call
|
def self.find_object(project, id)
|
||||||
replace_text_nodes_matching(Commit.reference_pattern) do |content|
|
|
||||||
commit_link_filter(content)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Replace commit references in text with links to the commit specified.
|
|
||||||
#
|
|
||||||
# text - String text to replace references in.
|
|
||||||
#
|
|
||||||
# Returns a String with commit references replaced with links. All links
|
|
||||||
# have `gfm` and `gfm-commit` class names attached for styling.
|
|
||||||
def commit_link_filter(text)
|
|
||||||
self.class.references_in(text) do |match, id, project_ref|
|
|
||||||
project = self.project_from_ref(project_ref)
|
|
||||||
|
|
||||||
if commit = self.class.commit_from_ref(project, id)
|
|
||||||
url = url_for_commit(project, commit)
|
|
||||||
|
|
||||||
title = escape_once(commit.link_title)
|
|
||||||
klass = reference_class(:commit)
|
|
||||||
data = data_attribute(project: project.id, commit: id)
|
|
||||||
|
|
||||||
project_ref += '@' if project_ref
|
|
||||||
|
|
||||||
%(<a href="#{url}" #{data}
|
|
||||||
title="#{title}"
|
|
||||||
class="#{klass}">#{project_ref}#{commit.short_id}</a>)
|
|
||||||
else
|
|
||||||
match
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.commit_from_ref(project, id)
|
|
||||||
if project && project.valid_repo?
|
if project && project.valid_repo?
|
||||||
project.commit(id)
|
project.commit(id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def url_for_commit(project, commit)
|
def find_object(*args)
|
||||||
|
self.class.find_object(*args)
|
||||||
|
end
|
||||||
|
|
||||||
|
def url_for_object(commit, project)
|
||||||
h = Gitlab::Application.routes.url_helpers
|
h = Gitlab::Application.routes.url_helpers
|
||||||
h.namespace_project_commit_url(project.namespace, project, commit,
|
h.namespace_project_commit_url(project.namespace, project, commit,
|
||||||
only_path: context[:only_path])
|
only_path: context[:only_path])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def object_link_title(commit)
|
||||||
|
commit.link_title
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,9 @@ module Gitlab
|
||||||
doc.search('a').each do |node|
|
doc.search('a').each do |node|
|
||||||
next unless node.has_attribute?('href')
|
next unless node.has_attribute?('href')
|
||||||
|
|
||||||
|
klass = node.attribute('class')
|
||||||
|
next if klass && klass.include?('gfm')
|
||||||
|
|
||||||
link = node.attribute('href').value
|
link = node.attribute('href').value
|
||||||
|
|
||||||
# Skip non-HTTP(S) links
|
# Skip non-HTTP(S) links
|
||||||
|
|
|
@ -20,6 +20,16 @@ module Gitlab
|
||||||
h.namespace_project_merge_request_url(project.namespace, project, mr,
|
h.namespace_project_merge_request_url(project.namespace, project, mr,
|
||||||
only_path: context[:only_path])
|
only_path: context[:only_path])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def object_link_text_extras(object, matches)
|
||||||
|
extras = super
|
||||||
|
|
||||||
|
if matches[:path] && matches[:path] == '/diffs'
|
||||||
|
extras.unshift "diffs"
|
||||||
|
end
|
||||||
|
|
||||||
|
extras
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,7 +12,10 @@ module Gitlab
|
||||||
def call
|
def call
|
||||||
doc.css('a.gfm').each do |node|
|
doc.css('a.gfm').each do |node|
|
||||||
unless user_can_reference?(node)
|
unless user_can_reference?(node)
|
||||||
node.replace(node.text)
|
# The reference should be replaced by the original text,
|
||||||
|
# which is not always the same as the rendered text.
|
||||||
|
text = node.attribute('data-original') || node.text
|
||||||
|
node.replace(text)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,44 @@ module Gitlab::Markdown
|
||||||
it 'links with adjacent text' do
|
it 'links with adjacent text' do
|
||||||
doc = filter("Fixed (#{reference}.)")
|
doc = filter("Fixed (#{reference}.)")
|
||||||
|
|
||||||
exp = Regexp.escape("#{project2.to_reference}@#{range.to_s}")
|
exp = Regexp.escape("#{project2.to_reference}@#{range.to_reference}")
|
||||||
|
expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'ignores invalid commit IDs on the referenced project' do
|
||||||
|
exp = act = "Fixed #{project2.to_reference}@#{commit1.id.reverse}...#{commit2.id}"
|
||||||
|
expect(filter(act).to_html).to eq exp
|
||||||
|
|
||||||
|
exp = act = "Fixed #{project2.to_reference}@#{commit1.id}...#{commit2.id.reverse}"
|
||||||
|
expect(filter(act).to_html).to eq exp
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds to the results hash' do
|
||||||
|
result = reference_pipeline_result("See #{reference}")
|
||||||
|
expect(result[:references][:commit_range]).not_to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'URL cross-project reference' do
|
||||||
|
let(:namespace) { create(:namespace, name: 'cross-reference') }
|
||||||
|
let(:project2) { create(:project, :public, namespace: namespace) }
|
||||||
|
let(:reference) { urls.namespace_project_compare_url(project2.namespace, project2, range.to_param) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
range.project = project2
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'links to a valid reference' do
|
||||||
|
doc = filter("See #{reference}")
|
||||||
|
|
||||||
|
expect(doc.css('a').first.attr('href')).
|
||||||
|
to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'links with adjacent text' do
|
||||||
|
doc = filter("Fixed (#{reference}.)")
|
||||||
|
|
||||||
|
exp = Regexp.escape(range.to_reference(project))
|
||||||
expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
|
expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -131,5 +131,36 @@ module Gitlab::Markdown
|
||||||
expect(result[:references][:commit]).not_to be_empty
|
expect(result[:references][:commit]).not_to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'URL cross-project reference' do
|
||||||
|
let(:namespace) { create(:namespace, name: 'cross-reference') }
|
||||||
|
let(:project2) { create(:project, :public, namespace: namespace) }
|
||||||
|
let(:commit) { project2.commit }
|
||||||
|
let(:reference) { urls.namespace_project_commit_url(project2.namespace, project2, commit.id) }
|
||||||
|
|
||||||
|
it 'links to a valid reference' do
|
||||||
|
doc = filter("See #{reference}")
|
||||||
|
|
||||||
|
expect(doc.css('a').first.attr('href')).
|
||||||
|
to eq urls.namespace_project_commit_url(project2.namespace, project2, commit.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'links with adjacent text' do
|
||||||
|
doc = filter("Fixed (#{reference}.)")
|
||||||
|
|
||||||
|
exp = Regexp.escape(project2.to_reference)
|
||||||
|
expect(doc.to_html).to match(/\(<a.+>#{commit.to_reference(project)}<\/a>\.\)/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'ignores invalid commit IDs on the referenced project' do
|
||||||
|
exp = act = "Committed #{invalidate_reference(reference)}"
|
||||||
|
expect(filter(act).to_html).to eq exp
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds to the results hash' do
|
||||||
|
result = reference_pipeline_result("See #{reference}")
|
||||||
|
expect(result[:references][:commit]).not_to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -135,5 +135,37 @@ module Gitlab::Markdown
|
||||||
expect(result[:references][:issue]).to eq [issue]
|
expect(result[:references][:issue]).to eq [issue]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'URL cross-project reference' do
|
||||||
|
let(:namespace) { create(:namespace, name: 'cross-reference') }
|
||||||
|
let(:project2) { create(:empty_project, :public, namespace: namespace) }
|
||||||
|
let(:issue) { create(:issue, project: project2) }
|
||||||
|
let(:reference) { helper.url_for_issue(issue.iid, project2) + "#note_123" }
|
||||||
|
|
||||||
|
it 'ignores valid references when cross-reference project uses external tracker' do
|
||||||
|
expect_any_instance_of(Project).to receive(:get_issue).
|
||||||
|
with(issue.iid).and_return(nil)
|
||||||
|
|
||||||
|
exp = act = "Issue #{reference}"
|
||||||
|
expect(filter(act).to_html).to eq exp
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'links to a valid reference' do
|
||||||
|
doc = filter("See #{reference}")
|
||||||
|
|
||||||
|
expect(doc.css('a').first.attr('href')).
|
||||||
|
to eq reference
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'links with adjacent text' do
|
||||||
|
doc = filter("Fixed (#{reference}.)")
|
||||||
|
expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(issue.to_reference(project))} \(comment 123\)<\/a>\.\)/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds to the results hash' do
|
||||||
|
result = reference_pipeline_result("Fixed #{reference}")
|
||||||
|
expect(result[:references][:issue]).to eq [issue]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -89,7 +89,7 @@ module Gitlab::Markdown
|
||||||
context 'cross-project reference' do
|
context 'cross-project reference' do
|
||||||
let(:namespace) { create(:namespace, name: 'cross-reference') }
|
let(:namespace) { create(:namespace, name: 'cross-reference') }
|
||||||
let(:project2) { create(:project, :public, namespace: namespace) }
|
let(:project2) { create(:project, :public, namespace: namespace) }
|
||||||
let(:merge) { create(:merge_request, source_project: project2) }
|
let(:merge) { create(:merge_request, source_project: project2, target_project: project2) }
|
||||||
let(:reference) { merge.to_reference(project) }
|
let(:reference) { merge.to_reference(project) }
|
||||||
|
|
||||||
it 'links to a valid reference' do
|
it 'links to a valid reference' do
|
||||||
|
@ -97,7 +97,7 @@ module Gitlab::Markdown
|
||||||
|
|
||||||
expect(doc.css('a').first.attr('href')).
|
expect(doc.css('a').first.attr('href')).
|
||||||
to eq urls.namespace_project_merge_request_url(project2.namespace,
|
to eq urls.namespace_project_merge_request_url(project2.namespace,
|
||||||
project, merge)
|
project2, merge)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'links with adjacent text' do
|
it 'links with adjacent text' do
|
||||||
|
@ -116,5 +116,30 @@ module Gitlab::Markdown
|
||||||
expect(result[:references][:merge_request]).to eq [merge]
|
expect(result[:references][:merge_request]).to eq [merge]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'URL cross-project reference' do
|
||||||
|
let(:namespace) { create(:namespace, name: 'cross-reference') }
|
||||||
|
let(:project2) { create(:project, :public, namespace: namespace) }
|
||||||
|
let(:merge) { create(:merge_request, source_project: project2, target_project: project2) }
|
||||||
|
let(:reference) { urls.namespace_project_merge_request_url(project2.namespace,
|
||||||
|
project2, merge) + '/diffs#note_123' }
|
||||||
|
|
||||||
|
it 'links to a valid reference' do
|
||||||
|
doc = filter("See #{reference}")
|
||||||
|
|
||||||
|
expect(doc.css('a').first.attr('href')).
|
||||||
|
to eq reference
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'links with adjacent text' do
|
||||||
|
doc = filter("Merge (#{reference}.)")
|
||||||
|
expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(merge.to_reference(project))} \(diffs, comment 123\)<\/a>\.\)/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds to the results hash' do
|
||||||
|
result = reference_pipeline_result("Merge #{reference}")
|
||||||
|
expect(result[:references][:merge_request]).to eq [merge]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -114,5 +114,35 @@ module Gitlab::Markdown
|
||||||
expect(result[:references][:snippet]).to eq [snippet]
|
expect(result[:references][:snippet]).to eq [snippet]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'URL cross-project reference' do
|
||||||
|
let(:namespace) { create(:namespace, name: 'cross-reference') }
|
||||||
|
let(:project2) { create(:empty_project, :public, namespace: namespace) }
|
||||||
|
let(:snippet) { create(:project_snippet, project: project2) }
|
||||||
|
let(:reference) { urls.namespace_project_snippet_url(project2.namespace, project2, snippet) }
|
||||||
|
|
||||||
|
it 'links to a valid reference' do
|
||||||
|
doc = filter("See #{reference}")
|
||||||
|
|
||||||
|
expect(doc.css('a').first.attr('href')).
|
||||||
|
to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'links with adjacent text' do
|
||||||
|
doc = filter("See (#{reference}.)")
|
||||||
|
expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(snippet.to_reference(project))}<\/a>\.\)/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'ignores invalid snippet IDs on the referenced project' do
|
||||||
|
exp = act = "See #{invalidate_reference(reference)}"
|
||||||
|
|
||||||
|
expect(filter(act).to_html).to eq exp
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds to the results hash' do
|
||||||
|
result = reference_pipeline_result("Snippet #{reference}")
|
||||||
|
expect(result[:references][:snippet]).to eq [snippet]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue