Read about our upcoming Code of Conduct on this issue

Commit f272ee6e authored by Oswaldo Ferreira's avatar Oswaldo Ferreira
Browse files

Add shorthand support to gitlab markdown references

parent 7706b77848d1
......@@ -174,7 +174,7 @@ def truncate_if_block(node, truncated)
# Returns a String
def cross_project_reference(project, entity)
if entity.respond_to?(:to_reference)
"#{project.to_reference}#{entity.to_reference}"
entity.to_reference(project)
else
''
end
......
......@@ -82,12 +82,6 @@ def render_colored_label(label, label_suffix = '', tooltip: true)
span.html_safe
end
def render_colored_cross_project_label(label, source_project = nil, tooltip: true)
label_suffix = source_project ? source_project.name_with_namespace : label.project.name_with_namespace
label_suffix = " <i>in #{escape_once(label_suffix)}</i>"
render_colored_label(label, label_suffix, tooltip: tooltip)
end
def suggested_colors
[
'#0033CC',
......@@ -166,6 +160,5 @@ def label_deletion_confirm_text(label)
end
# Required for Banzai::Filter::LabelReferenceFilter
module_function :render_colored_label, :render_colored_cross_project_label,
:text_color_for_bg, :escape_once
module_function :render_colored_label, :text_color_for_bg, :escape_once
end
......@@ -92,19 +92,11 @@ def self.link_reference_pattern
end
def to_reference(from_project = nil)
if cross_project_reference?(from_project)
project.to_reference + self.class.reference_prefix + self.id
else
self.id
end
commit_reference(from_project, id)
end
def reference_link_text(from_project = nil)
if cross_project_reference?(from_project)
project.to_reference + self.class.reference_prefix + self.short_id
else
self.short_id
end
commit_reference(from_project, short_id)
end
def diff_line_count
......@@ -329,6 +321,16 @@ def diffs(diff_options = nil)
private
def commit_reference(from_project, referable_commit_id)
reference = project.to_reference(from_project)
if reference.present?
"#{reference}#{self.class.reference_prefix}#{referable_commit_id}"
else
referable_commit_id
end
end
def find_author_by_any_email
User.find_by_any_email(author_email.downcase)
end
......
......@@ -90,22 +90,25 @@ def to_s
alias_method :id, :to_s
def to_reference(from_project = nil)
if cross_project_reference?(from_project)
project.to_reference + self.class.reference_prefix + self.id
project_reference = project.to_reference(from_project)
if project_reference.present?
project_reference + self.class.reference_prefix + self.id
else
self.id
end
end
def reference_link_text(from_project = nil)
project_reference = project.to_reference(from_project)
reference = ref_from + notation + ref_to
if cross_project_reference?(from_project)
reference = project.to_reference + self.class.reference_prefix + reference
end
if project_reference.present?
project_reference + self.class.reference_prefix + reference
else
reference
end
end
# Return a Hash of parameters for passing to a URL helper
#
......
......@@ -72,17 +72,4 @@ def link_reference_pattern(route, pattern)
}x
end
end
private
# Check if a reference is being done cross-project
#
# from_project - Refering Project object
def cross_project_reference?(from_project)
if self.is_a?(Project)
self != from_project
else
from_project && self.project && self.project != from_project
end
end
end
......@@ -153,11 +153,7 @@ def self.sort(method, excluded_labels: [])
def to_reference(from_project = nil)
reference = "#{self.class.reference_prefix}#{iid}"
if cross_project_reference?(from_project)
reference = project.to_reference + reference
end
reference
"#{project.to_reference(from_project)}#{reference}"
end
def referenced_merge_requests(current_user = nil)
......
......@@ -146,7 +146,8 @@ def title=(value)
#
# Label.first.to_reference # => "~1"
# Label.first.to_reference(format: :name) # => "~\"bug\""
# Label.first.to_reference(project1, project2) # => "gitlab-org/gitlab-ce~1"
# Label.first.to_reference(project, same_namespace_project) # => "gitlab-ce~1"
# Label.first.to_reference(project, another_namespace_project) # => "gitlab-org/gitlab-ce~1"
#
# Returns a String
#
......@@ -154,8 +155,8 @@ def to_reference(source_project = nil, target_project = nil, format: :id)
format_reference = label_format_reference(format)
reference = "#{self.class.reference_prefix}#{format_reference}"
if cross_project_reference?(source_project, target_project)
source_project.to_reference + reference
if source_project
"#{source_project.to_reference(target_project)}#{reference}"
else
reference
end
......@@ -169,10 +170,6 @@ def as_json(options = {})
private
def cross_project_reference?(source_project, target_project)
source_project && target_project && source_project != target_project
end
def issues_count(user, params = {})
params.merge!(subject_foreign_key => subject.id, label_name: title, scope: 'all')
IssuesFinder.new(user, params.with_indifferent_access).execute.count
......
......@@ -176,11 +176,7 @@ def self.wip_title(title)
def to_reference(from_project = nil)
reference = "#{self.class.reference_prefix}#{iid}"
if cross_project_reference?(from_project)
reference = project.to_reference + reference
end
reference
"#{project.to_reference(from_project)}#{reference}"
end
def first_commit
......
......@@ -115,17 +115,14 @@ def self.upcoming_ids_by_projects(projects)
#
# Milestone.first.to_reference # => "%1"
# Milestone.first.to_reference(format: :name) # => "%\"goal\""
# Milestone.first.to_reference(project) # => "gitlab-org/gitlab-ce%1"
# Milestone.first.to_reference(cross_namespace_project) # => "gitlab-org/gitlab-ce%1"
# Milestone.first.to_reference(same_namespace_project) # => "gitlab-ce%1"
#
def to_reference(from_project = nil, format: :iid)
format_reference = milestone_format_reference(format)
reference = "#{self.class.reference_prefix}#{format_reference}"
if cross_project_reference?(from_project)
project.to_reference + reference
else
reference
end
"#{project.to_reference(from_project)}#{reference}"
end
def reference_link_text(from_project = nil)
......
......@@ -419,7 +419,11 @@ def sort(method)
def reference_pattern
name_pattern = Gitlab::Regex::NAMESPACE_REGEX_STR
%r{(?<project>#{name_pattern}/#{name_pattern})}
%r{
((?<namespace>#{name_pattern})\/)?
(?<project>#{name_pattern})
}x
end
def trending
......@@ -650,8 +654,20 @@ def to_param
end
end
def to_reference(_from_project = nil)
def to_reference(from_project = nil)
if cross_namespace_reference?(from_project)
path_with_namespace
elsif cross_project_reference?(from_project)
path
end
end
def to_human_reference(from_project = nil)
if cross_namespace_reference?(from_project)
name_with_namespace
elsif cross_project_reference?(from_project)
name
end
end
def web_url
......@@ -1327,10 +1343,21 @@ def environments_recently_updated_on_branch(branch)
private
# Check if a reference is being done cross-project
#
# from_project - Refering Project object
def cross_project_reference?(from_project)
from_project && self != from_project
end
def pushes_since_gc_redis_key
"projects/#{id}/pushes_since_gc"
end
def cross_namespace_reference?(from_project)
from_project && namespace != from_project.namespace
end
def default_branch_protected?
current_application_settings.default_branch_protection == Gitlab::Access::PROTECTION_FULL ||
current_application_settings.default_branch_protection == Gitlab::Access::PROTECTION_DEV_CAN_MERGE
......
......@@ -67,12 +67,12 @@ def self.link_reference_pattern
def to_reference(from_project = nil)
reference = "#{self.class.reference_prefix}#{id}"
if cross_project_reference?(from_project)
reference = project.to_reference + reference
end
if project.present?
"#{project.to_reference(from_project)}#{reference}"
else
reference
end
end
def self.content_types
[
......
---
title: Add shorthand support to gitlab markdown references
merge_request: 7255
author: Oswaldo Ferreira
......@@ -33,7 +33,7 @@ def self.object_sym
# Returns a String replaced with the return of the block.
def self.references_in(text, pattern = object_class.reference_pattern)
text.gsub(pattern) do |match|
yield match, $~[object_sym].to_i, $~[:project], $~
yield match, $~[object_sym].to_i, $~[:project], $~[:namespace], $~
end
end
......@@ -145,8 +145,9 @@ def call
# Returns a String with references replaced with links. All links
# have `gfm` and `gfm-OBJECT_NAME` class names attached for styling.
def object_link_filter(text, pattern, link_content: nil)
references_in(text, pattern) do |match, id, project_ref, matches|
project = project_from_ref_cached(project_ref)
references_in(text, pattern) do |match, id, project_ref, namespace_ref, matches|
project_path = full_project_path(namespace_ref, project_ref)
project = project_from_ref_cached(project_path)
if project && object = find_object_cached(project, id)
title = object_link_title(object)
......@@ -217,10 +218,9 @@ def references_per_project
nodes.each do |node|
node.to_html.scan(regex) do
project = $~[:project] || current_project_path
project_path = full_project_path($~[:namespace], $~[:project])
symbol = $~[object_sym]
refs[project] << symbol if object_class.reference_valid?(symbol)
refs[project_path] << symbol if object_class.reference_valid?(symbol)
end
end
......@@ -272,8 +272,19 @@ def current_project_path
@current_project_path ||= project.path_with_namespace
end
def current_project_namespace_path
@current_project_namespace_path ||= project.namespace.path
end
private
def full_project_path(namespace, project_ref)
return current_project_path unless project_ref
namespace_ref = namespace || current_project_namespace_path
"#{namespace_ref}/#{project_ref}"
end
def project_refs_cache
RequestStore[:banzai_project_refs] ||= {}
end
......
......@@ -12,7 +12,7 @@ def self.object_class
def self.references_in(text, pattern = CommitRange.reference_pattern)
text.gsub(pattern) do |match|
yield match, $~[:commit_range], $~[:project], $~
yield match, $~[:commit_range], $~[:project], $~[:namespace], $~
end
end
......
......@@ -12,7 +12,7 @@ def self.object_class
def self.references_in(text, pattern = Commit.reference_pattern)
text.gsub(pattern) do |match|
yield match, $~[:commit], $~[:project], $~
yield match, $~[:commit], $~[:project], $~[:namespace], $~
end
end
......
......@@ -14,16 +14,18 @@ def find_object(project, id)
def self.references_in(text, pattern = Label.reference_pattern)
unescape_html_entities(text).gsub(pattern) do |match|
yield match, $~[:label_id].to_i, $~[:label_name], $~[:project], $~
yield match, $~[:label_id].to_i, $~[:label_name], $~[:project], $~[:namespace], $~
end
end
def references_in(text, pattern = Label.reference_pattern)
unescape_html_entities(text).gsub(pattern) do |match|
label = find_label($~[:project], $~[:label_id], $~[:label_name])
namespace, project = $~[:namespace], $~[:project]
project_path = full_project_path(namespace, project)
label = find_label(project_path, $~[:label_id], $~[:label_name])
if label
yield match, label.id, $~[:project], $~
yield match, label.id, project, namespace, $~
else
match
end
......@@ -64,48 +66,12 @@ def url_for_object(label, project)
end
def object_link_text(object, matches)
if same_group?(object) && namespace_match?(matches)
render_same_project_label(object)
elsif same_project?(object)
render_same_project_label(object)
else
render_cross_project_label(object, matches)
end
end
def same_group?(object)
object.is_a?(GroupLabel) && object.group == project.group
end
def namespace_match?(matches)
matches[:project].blank? || matches[:project] == project.path_with_namespace
end
def same_project?(object)
object.is_a?(ProjectLabel) && object.project == project
end
def user
context[:current_user] || context[:author]
end
def project
context[:project]
end
def render_same_project_label(object)
LabelsHelper.render_colored_label(object)
end
def render_cross_project_label(object, matches)
source_project =
if matches[:project]
Project.find_with_namespace(matches[:project])
else
object.project
end
project_path = full_project_path(matches[:namespace], matches[:project])
project_from_ref = project_from_ref_cached(project_path)
reference = project_from_ref.to_human_reference(project)
label_suffix = " <i>in #{reference}</i>" if reference.present?
LabelsHelper.render_colored_cross_project_label(object, source_project)
LabelsHelper.render_colored_label(object, label_suffix)
end
def unescape_html_entities(text)
......
......@@ -19,18 +19,20 @@ def references_in(text, pattern = Milestone.reference_pattern)
return super(text, pattern) if pattern != Milestone.reference_pattern
text.gsub(pattern) do |match|
milestone = find_milestone($~[:project], $~[:milestone_iid], $~[:milestone_name])
milestone = find_milestone($~[:project], $~[:namespace], $~[:milestone_iid], $~[:milestone_name])
if milestone
yield match, milestone.iid, $~[:project], $~
yield match, milestone.iid, $~[:project], $~[:namespace], $~
else
match
end
end
end
def find_milestone(project_ref, milestone_id, milestone_name)
project = project_from_ref(project_ref)
def find_milestone(project_ref, namespace_ref, milestone_id, milestone_name)
project_path = full_project_path(namespace_ref, project_ref)
project = project_from_ref(project_path)
return unless project
milestone_params = milestone_params(milestone_id, milestone_name)
......@@ -52,11 +54,13 @@ def url_for_object(milestone, project)
end
def object_link_text(object, matches)
if context[:project] == object.project
super
milestone_link = escape_once(super)
reference = object.project.to_reference(project)
if reference.present?
"#{milestone_link} <i>in #{reference}</i>".html_safe
else
"#{escape_once(super)} <i>in #{escape_once(object.project.path_with_namespace)}</i>".
html_safe
milestone_link
end
end
......
......@@ -28,7 +28,7 @@
let(:new_project) { create(:project) }
let(:new_project_search) { create(:project) }
let(:text) { "Text with #{mr.to_reference}" }
let(:cross_reference) { old_project.to_reference }
let(:cross_reference) { old_project.to_reference(new_project) }
background do
old_project.team << [user, :reporter]
......
......@@ -40,7 +40,7 @@
visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_project_id: private_project.id })
expect(page).not_to have_content private_project.to_reference
expect(page).not_to have_content private_project.path_with_namespace
end
end
......
......@@ -7,7 +7,7 @@
context 'without subject' do
it "uses the label's project" do
expect(link_to_label(label)).to match %r{<a href="/#{label.project.to_reference}/issues\?label_name%5B%5D=#{label.name}">.*</a>}
expect(link_to_label(label)).to match %r{<a href="/#{label.project.path_with_namespace}/issues\?label_name%5B%5D=#{label.name}">.*</a>}
end
end
......@@ -32,7 +32,7 @@
['issue', :issue, 'merge_request', :merge_request].each do |type|
context "set to #{type}" do
it 'links to correct page' do
expect(link_to_label(label, type: type)).to match %r{<a href="/#{label.project.to_reference}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>}
expect(link_to_label(label, type: type)).to match %r{<a href="/#{label.project.path_with_namespace}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>}
end
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