Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
0c2fdb1c
Commit
0c2fdb1c
authored
Dec 01, 2017
by
Jarka Kadlecova
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor banzai to support referencing from group context
parent
50eb1252
Changes
22
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
273 additions
and
166 deletions
+273
-166
app/helpers/markup_helper.rb
app/helpers/markup_helper.rb
+2
-0
app/models/epic.rb
app/models/epic.rb
+7
-3
lib/banzai/cross_project_reference.rb
lib/banzai/cross_project_reference.rb
+1
-1
lib/banzai/filter/abstract_reference_filter.rb
lib/banzai/filter/abstract_reference_filter.rb
+60
-38
lib/banzai/filter/epic_reference_filter.rb
lib/banzai/filter/epic_reference_filter.rb
+12
-0
lib/banzai/filter/issuable_reference_filter.rb
lib/banzai/filter/issuable_reference_filter.rb
+31
-0
lib/banzai/filter/issue_reference_filter.rb
lib/banzai/filter/issue_reference_filter.rb
+5
-27
lib/banzai/filter/label_reference_filter.rb
lib/banzai/filter/label_reference_filter.rb
+2
-2
lib/banzai/filter/merge_request_reference_filter.rb
lib/banzai/filter/merge_request_reference_filter.rb
+7
-30
lib/banzai/filter/milestone_reference_filter.rb
lib/banzai/filter/milestone_reference_filter.rb
+1
-1
lib/banzai/issuable_extractor.rb
lib/banzai/issuable_extractor.rb
+2
-2
lib/banzai/reference_parser/epic_parser.rb
lib/banzai/reference_parser/epic_parser.rb
+12
-0
lib/banzai/reference_parser/issuable_parser.rb
lib/banzai/reference_parser/issuable_parser.rb
+25
-0
lib/banzai/reference_parser/issue_parser.rb
lib/banzai/reference_parser/issue_parser.rb
+3
-9
lib/banzai/reference_parser/merge_request_parser.rb
lib/banzai/reference_parser/merge_request_parser.rb
+2
-22
lib/gitlab/reference_extractor.rb
lib/gitlab/reference_extractor.rb
+1
-1
spec/features/markdown_spec.rb
spec/features/markdown_spec.rb
+2
-1
spec/lib/banzai/cross_project_reference_spec.rb
spec/lib/banzai/cross_project_reference_spec.rb
+4
-4
spec/lib/banzai/filter/abstract_reference_filter_spec.rb
spec/lib/banzai/filter/abstract_reference_filter_spec.rb
+19
-19
spec/lib/banzai/filter/issue_reference_filter_spec.rb
spec/lib/banzai/filter/issue_reference_filter_spec.rb
+43
-4
spec/lib/banzai/reference_parser/issue_parser_spec.rb
spec/lib/banzai/reference_parser/issue_parser_spec.rb
+2
-2
spec/lib/gitlab/reference_extractor_spec.rb
spec/lib/gitlab/reference_extractor_spec.rb
+30
-0
No files found.
app/helpers/markup_helper.rb
View file @
0c2fdb1c
...
@@ -86,6 +86,8 @@ module MarkupHelper
...
@@ -86,6 +86,8 @@ module MarkupHelper
return
''
unless
text
.
present?
return
''
unless
text
.
present?
context
[
:project
]
||=
@project
context
[
:project
]
||=
@project
context
[
:group
]
||=
@group
html
=
markdown_unsafe
(
text
,
context
)
html
=
markdown_unsafe
(
text
,
context
)
prepare_for_rendering
(
html
,
context
)
prepare_for_rendering
(
html
,
context
)
end
end
...
...
app/models/epic.rb
View file @
0c2fdb1c
# Placeholder class for model that is implemented in EE
# Placeholder class for model that is implemented in EE
# It
will reserve (ee#3853)
'&' as a reference prefix, but the table does not exists in CE
# It
reserves
'&' as a reference prefix, but the table does not exists in CE
class
Epic
<
ActiveRecord
::
Base
class
Epic
<
ActiveRecord
::
Base
# TODO: this will be implemented as part of #3853
def
self
.
reference_prefix
def
to_reference
'&'
end
def
self
.
reference_prefix_escaped
'&'
end
end
end
end
lib/banzai/cross_project_reference.rb
View file @
0c2fdb1c
...
@@ -11,7 +11,7 @@ module Banzai
...
@@ -11,7 +11,7 @@ module Banzai
# ref - String reference.
# ref - String reference.
#
#
# Returns a Project, or nil if the reference can't be found
# Returns a Project, or nil if the reference can't be found
def
p
rojec
t_from_ref
(
ref
)
def
p
aren
t_from_ref
(
ref
)
return
context
[
:project
]
unless
ref
return
context
[
:project
]
unless
ref
Project
.
find_by_full_path
(
ref
)
Project
.
find_by_full_path
(
ref
)
...
...
lib/banzai/filter/abstract_reference_filter.rb
View file @
0c2fdb1c
...
@@ -82,9 +82,9 @@ module Banzai
...
@@ -82,9 +82,9 @@ module Banzai
end
end
end
end
def
project_
from_ref_cached
(
ref
)
def
from_ref_cached
(
ref
)
cached_call
(
:banzai_project_refs
,
ref
)
do
cached_call
(
"banzai_
#{
parent_type
}
_refs"
.
to_sym
,
ref
)
do
p
rojec
t_from_ref
(
ref
)
p
aren
t_from_ref
(
ref
)
end
end
end
end
...
@@ -153,15 +153,20 @@ module Banzai
...
@@ -153,15 +153,20 @@ module Banzai
# 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
,
pattern
,
link_content:
nil
,
link_reference:
false
)
def
object_link_filter
(
text
,
pattern
,
link_content:
nil
,
link_reference:
false
)
references_in
(
text
,
pattern
)
do
|
match
,
id
,
project_ref
,
namespace_ref
,
matches
|
references_in
(
text
,
pattern
)
do
|
match
,
id
,
project_ref
,
namespace_ref
,
matches
|
project_path
=
full_project_path
(
namespace_ref
,
project_ref
)
parent_path
=
if
parent_type
==
:group
project
=
project_from_ref_cached
(
project_path
)
full_group_path
(
namespace_ref
)
else
full_project_path
(
namespace_ref
,
project_ref
)
end
if
project
parent
=
from_ref_cached
(
parent_path
)
if
parent
object
=
object
=
if
link_reference
if
link_reference
find_object_from_link_cached
(
p
rojec
t
,
id
)
find_object_from_link_cached
(
p
aren
t
,
id
)
else
else
find_object_cached
(
p
rojec
t
,
id
)
find_object_cached
(
p
aren
t
,
id
)
end
end
end
end
...
@@ -169,13 +174,13 @@ module Banzai
...
@@ -169,13 +174,13 @@ module Banzai
title
=
object_link_title
(
object
)
title
=
object_link_title
(
object
)
klass
=
reference_class
(
object_sym
)
klass
=
reference_class
(
object_sym
)
data
=
data_attributes_for
(
link_content
||
match
,
p
rojec
t
,
object
,
link:
!!
link_content
)
data
=
data_attributes_for
(
link_content
||
match
,
p
aren
t
,
object
,
link:
!!
link_content
)
url
=
url
=
if
matches
.
names
.
include?
(
"url"
)
&&
matches
[
:url
]
if
matches
.
names
.
include?
(
"url"
)
&&
matches
[
:url
]
matches
[
:url
]
matches
[
:url
]
else
else
url_for_object_cached
(
object
,
p
rojec
t
)
url_for_object_cached
(
object
,
p
aren
t
)
end
end
content
=
link_content
||
object_link_text
(
object
,
matches
)
content
=
link_content
||
object_link_text
(
object
,
matches
)
...
@@ -224,17 +229,24 @@ module Banzai
...
@@ -224,17 +229,24 @@ module Banzai
# Returns a Hash containing all object references (e.g. issue IDs) per the
# Returns a Hash containing all object references (e.g. issue IDs) per the
# project they belong to.
# project they belong to.
def
references_per_project
def
references_per_parent
@references_per_project
||=
begin
@references_per
||=
{}
@references_per
[
parent_type
]
||=
begin
refs
=
Hash
.
new
{
|
hash
,
key
|
hash
[
key
]
=
Set
.
new
}
refs
=
Hash
.
new
{
|
hash
,
key
|
hash
[
key
]
=
Set
.
new
}
regex
=
Regexp
.
union
(
object_class
.
reference_pattern
,
object_class
.
link_reference_pattern
)
regex
=
Regexp
.
union
(
object_class
.
reference_pattern
,
object_class
.
link_reference_pattern
)
nodes
.
each
do
|
node
|
nodes
.
each
do
|
node
|
node
.
to_html
.
scan
(
regex
)
do
node
.
to_html
.
scan
(
regex
)
do
project_path
=
full_project_path
(
$~
[
:namespace
],
$~
[
:project
])
path
=
if
parent_type
==
:project
full_project_path
(
$~
[
:namespace
],
$~
[
:project
])
else
full_group_path
(
$~
[
:group
])
end
symbol
=
$~
[
object_sym
]
symbol
=
$~
[
object_sym
]
refs
[
p
roject_p
ath
]
<<
symbol
if
object_class
.
reference_valid?
(
symbol
)
refs
[
path
]
<<
symbol
if
object_class
.
reference_valid?
(
symbol
)
end
end
end
end
...
@@ -244,35 +256,41 @@ module Banzai
...
@@ -244,35 +256,41 @@ module Banzai
# Returns a Hash containing referenced projects grouped per their full
# Returns a Hash containing referenced projects grouped per their full
# path.
# path.
def
projects_per_reference
def
parent_per_reference
@projects_per_reference
||=
begin
@per_reference
||=
{}
@per_reference
[
parent_type
]
||=
begin
refs
=
Set
.
new
refs
=
Set
.
new
references_per_p
roject
.
each
do
|
project_
ref
,
_
|
references_per_p
arent
.
each
do
|
ref
,
_
|
refs
<<
project_
ref
refs
<<
ref
end
end
find_
projects_
for_paths
(
refs
.
to_a
).
index_by
(
&
:full_path
)
find_for_paths
(
refs
.
to_a
).
index_by
(
&
:full_path
)
end
end
end
end
def
projects_relation_for_paths
(
paths
)
def
relation_for_paths
(
paths
)
Project
.
where_full_path_in
(
paths
).
includes
(
:namespace
)
klass
=
parent_type
.
to_s
.
camelize
.
constantize
result
=
klass
.
where_full_path_in
(
paths
)
return
result
if
parent_type
==
:group
result
.
includes
(
:namespace
)
if
parent_type
==
:project
end
end
# Returns projects for the given paths.
# Returns projects for the given paths.
def
find_
projects_
for_paths
(
paths
)
def
find_for_paths
(
paths
)
if
RequestStore
.
active?
if
RequestStore
.
active?
cache
=
project_
refs_cache
cache
=
refs_cache
to_query
=
paths
-
cache
.
keys
to_query
=
paths
-
cache
.
keys
unless
to_query
.
empty?
unless
to_query
.
empty?
projects
=
projects_
relation_for_paths
(
to_query
)
records
=
relation_for_paths
(
to_query
)
found
=
[]
found
=
[]
projects
.
each
do
|
project
|
records
.
each
do
|
record
|
ref
=
project
.
full_path
ref
=
record
.
full_path
get_or_set_cache
(
cache
,
ref
)
{
project
}
get_or_set_cache
(
cache
,
ref
)
{
record
}
found
<<
ref
found
<<
ref
end
end
...
@@ -284,33 +302,37 @@ module Banzai
...
@@ -284,33 +302,37 @@ module Banzai
cache
.
slice
(
*
paths
).
values
.
compact
cache
.
slice
(
*
paths
).
values
.
compact
else
else
projects_
relation_for_paths
(
paths
)
relation_for_paths
(
paths
)
end
end
end
end
def
current_project_path
def
current_parent_path
return
unless
project
@current_parent_path
||=
parent
&
.
full_path
@current_project_path
||=
project
.
full_path
end
end
def
current_project_namespace_path
def
current_project_namespace_path
return
unless
project
@current_project_namespace_path
||=
project
&
.
namespace
&
.
full_path
@current_project_namespace_path
||=
project
.
namespace
.
full_path
end
end
private
private
def
full_project_path
(
namespace
,
project_ref
)
def
full_project_path
(
namespace
,
project_ref
)
return
current_p
rojec
t_path
unless
project_ref
return
current_p
aren
t_path
unless
project_ref
namespace_ref
=
namespace
||
current_project_namespace_path
namespace_ref
=
namespace
||
current_project_namespace_path
"
#{
namespace_ref
}
/
#{
project_ref
}
"
"
#{
namespace_ref
}
/
#{
project_ref
}
"
end
end
def
project_refs_cache
def
refs_cache
RequestStore
[
:banzai_project_refs
]
||=
{}
RequestStore
[
"banzai_
#{
parent_type
}
_refs"
.
to_sym
]
||=
{}
end
def
parent_type
:project
end
def
parent
parent_type
==
:project
?
project
:
group
end
end
end
end
end
end
...
...
lib/banzai/filter/epic_reference_filter.rb
0 → 100644
View file @
0c2fdb1c
module
Banzai
module
Filter
# The actual filter is implemented in the EE mixin
class
EpicReferenceFilter
<
IssuableReferenceFilter
self
.
reference_type
=
:epic
def
self
.
object_class
Epic
end
end
end
end
lib/banzai/filter/issuable_reference_filter.rb
0 → 100644
View file @
0c2fdb1c
module
Banzai
module
Filter
class
IssuableReferenceFilter
<
AbstractReferenceFilter
def
records_per_parent
@records_per_project
||=
{}
@records_per_project
[
object_class
.
to_s
.
underscore
]
||=
begin
hash
=
Hash
.
new
{
|
h
,
k
|
h
[
k
]
=
{}
}
parent_per_reference
.
each
do
|
path
,
parent
|
record_ids
=
references_per_parent
[
path
]
parent_records
(
parent
,
record_ids
).
each
do
|
record
|
hash
[
parent
][
record
.
iid
.
to_i
]
=
record
end
end
hash
end
end
def
find_object
(
parent
,
iid
)
records_per_parent
[
parent
][
iid
]
end
def
parent_from_ref
(
ref
)
parent_per_reference
[
ref
||
current_parent_path
]
end
end
end
end
lib/banzai/filter/issue_reference_filter.rb
View file @
0c2fdb1c
...
@@ -8,46 +8,24 @@ module Banzai
...
@@ -8,46 +8,24 @@ module Banzai
# When external issues tracker like Jira is activated we should not
# When external issues tracker like Jira is activated we should not
# use issue reference pattern, but we should still be able
# use issue reference pattern, but we should still be able
# to reference issues from other GitLab projects.
# to reference issues from other GitLab projects.
class
IssueReferenceFilter
<
Abstract
ReferenceFilter
class
IssueReferenceFilter
<
Issuable
ReferenceFilter
self
.
reference_type
=
:issue
self
.
reference_type
=
:issue
def
self
.
object_class
def
self
.
object_class
Issue
Issue
end
end
def
find_object
(
project
,
iid
)
issues_per_project
[
project
][
iid
]
end
def
url_for_object
(
issue
,
project
)
def
url_for_object
(
issue
,
project
)
IssuesHelper
.
url_for_issue
(
issue
.
iid
,
project
,
only_path:
context
[
:only_path
],
internal:
true
)
IssuesHelper
.
url_for_issue
(
issue
.
iid
,
project
,
only_path:
context
[
:only_path
],
internal:
true
)
end
end
def
project_from_ref
(
ref
)
projects_per_reference
[
ref
||
current_project_path
]
end
# Returns a Hash containing the issues per Project instance.
def
issues_per_project
@issues_per_project
||=
begin
hash
=
Hash
.
new
{
|
h
,
k
|
h
[
k
]
=
{}
}
projects_per_reference
.
each
do
|
path
,
project
|
issue_ids
=
references_per_project
[
path
]
issues
=
project
.
issues
.
where
(
iid:
issue_ids
.
to_a
)
issues
.
each
do
|
issue
|
hash
[
project
][
issue
.
iid
.
to_i
]
=
issue
end
end
hash
end
end
def
projects_relation_for_paths
(
paths
)
def
projects_relation_for_paths
(
paths
)
super
(
paths
).
includes
(
:gitlab_issue_tracker_service
)
super
(
paths
).
includes
(
:gitlab_issue_tracker_service
)
end
end
def
parent_records
(
parent
,
ids
)
parent
.
issues
.
where
(
iid:
ids
.
to_a
)
end
end
end
end
end
end
end
lib/banzai/filter/label_reference_filter.rb
View file @
0c2fdb1c
...
@@ -33,7 +33,7 @@ module Banzai
...
@@ -33,7 +33,7 @@ module Banzai
end
end
def
find_label
(
project_ref
,
label_id
,
label_name
)
def
find_label
(
project_ref
,
label_id
,
label_name
)
project
=
p
rojec
t_from_ref
(
project_ref
)
project
=
p
aren
t_from_ref
(
project_ref
)
return
unless
project
return
unless
project
label_params
=
label_params
(
label_id
,
label_name
)
label_params
=
label_params
(
label_id
,
label_name
)
...
@@ -66,7 +66,7 @@ module Banzai
...
@@ -66,7 +66,7 @@ module Banzai
def
object_link_text
(
object
,
matches
)
def
object_link_text
(
object
,
matches
)
project_path
=
full_project_path
(
matches
[
:namespace
],
matches
[
:project
])
project_path
=
full_project_path
(
matches
[
:namespace
],
matches
[
:project
])
project_from_ref
=
project_
from_ref_cached
(
project_path
)
project_from_ref
=
from_ref_cached
(
project_path
)
reference
=
project_from_ref
.
to_human_reference
(
project
)
reference
=
project_from_ref
.
to_human_reference
(
project
)
label_suffix
=
" <i>in
#{
reference
}
</i>"
if
reference
.
present?
label_suffix
=
" <i>in
#{
reference
}
</i>"
if
reference
.
present?
...
...
lib/banzai/filter/merge_request_reference_filter.rb
View file @
0c2fdb1c
...
@@ -4,48 +4,19 @@ module Banzai
...
@@ -4,48 +4,19 @@ module Banzai
# to merge requests that do not exist are ignored.
# to merge requests that do not exist are ignored.
#
#
# This filter supports cross-project references.
# This filter supports cross-project references.
class
MergeRequestReferenceFilter
<
Abstract
ReferenceFilter
class
MergeRequestReferenceFilter
<
Issuable
ReferenceFilter
self
.
reference_type
=
:merge_request
self
.
reference_type
=
:merge_request
def
self
.
object_class
def
self
.
object_class
MergeRequest
MergeRequest
end
end
def
find_object
(
project
,
iid
)
merge_requests_per_project
[
project
][
iid
]
end
def
url_for_object
(
mr
,
project
)
def
url_for_object
(
mr
,
project
)
h
=
Gitlab
::
Routing
.
url_helpers
h
=
Gitlab
::
Routing
.
url_helpers
h
.
project_merge_request_url
(
project
,
mr
,
h
.
project_merge_request_url
(
project
,
mr
,
only_path:
context
[
:only_path
])
only_path:
context
[
:only_path
])
end
end
def
project_from_ref
(
ref
)
projects_per_reference
[
ref
||
current_project_path
]
end
# Returns a Hash containing the merge_requests per Project instance.
def
merge_requests_per_project
@merge_requests_per_project
||=
begin
hash
=
Hash
.
new
{
|
h
,
k
|
h
[
k
]
=
{}
}
projects_per_reference
.
each
do
|
path
,
project
|
merge_request_ids
=
references_per_project
[
path
]
merge_requests
=
project
.
merge_requests
.
where
(
iid:
merge_request_ids
.
to_a
)
.
includes
(
target_project: :namespace
)
merge_requests
.
each
do
|
merge_request
|
hash
[
project
][
merge_request
.
iid
.
to_i
]
=
merge_request
end
end
hash
end
end
def
object_link_text_extras
(
object
,
matches
)
def
object_link_text_extras
(
object
,
matches
)
extras
=
super
extras
=
super
...
@@ -61,6 +32,12 @@ module Banzai
...
@@ -61,6 +32,12 @@ module Banzai
extras
extras
end
end
def
parent_records
(
parent
,
ids
)
parent
.
merge_requests
.
where
(
iid:
ids
.
to_a
)
.
includes
(
target_project: :namespace
)
end
end
end
end
end
end
end
lib/banzai/filter/milestone_reference_filter.rb
View file @
0c2fdb1c
...
@@ -38,7 +38,7 @@ module Banzai
...
@@ -38,7 +38,7 @@ module Banzai
def
find_milestone
(
project_ref
,
namespace_ref
,
milestone_id
,
milestone_name
)
def
find_milestone
(
project_ref
,
namespace_ref
,
milestone_id
,
milestone_name
)
project_path
=
full_project_path
(
namespace_ref
,
project_ref
)
project_path
=
full_project_path
(
namespace_ref
,
project_ref
)
project
=
p
rojec
t_from_ref
(
project_path
)
project
=
p
aren
t_from_ref
(
project_path
)
return
unless
project
return
unless
project
...
...
lib/banzai/issuable_extractor.rb
View file @
0c2fdb1c
...
@@ -28,8 +28,8 @@ module Banzai
...
@@ -28,8 +28,8 @@ module Banzai
issue_parser
=
Banzai
::
ReferenceParser
::
IssueParser
.
new
(
project
,
user
)
issue_parser
=
Banzai
::
ReferenceParser
::
IssueParser
.
new
(
project
,
user
)
merge_request_parser
=
Banzai
::
ReferenceParser
::
MergeRequestParser
.
new
(
project
,
user
)
merge_request_parser
=
Banzai
::
ReferenceParser
::
MergeRequestParser
.
new
(
project
,
user
)
issuables_for_nodes
=
issue_parser
.
issue
s_for_nodes
(
nodes
).
merge
(
issuables_for_nodes
=
issue_parser
.
record
s_for_nodes
(
nodes
).
merge
(
merge_request_parser
.
merge_request
s_for_nodes
(
nodes
)
merge_request_parser
.
record
s_for_nodes
(
nodes
)
)
)
# The project for the issue/MR might be pending for deletion!
# The project for the issue/MR might be pending for deletion!
...
...
lib/banzai/reference_parser/epic_parser.rb
0 → 100644
View file @
0c2fdb1c
module
Banzai
module
ReferenceParser
# The actual parser is implemented in the EE mixin
class
EpicParser
<
IssuableParser
self
.
reference_type
=
:epic
def
records_for_nodes
(
_nodes
)
{}
end
end
end
end
lib/banzai/reference_parser/issuable_parser.rb
0 → 100644
View file @
0c2fdb1c
module
Banzai
module
ReferenceParser
class
IssuableParser
<
BaseParser
def
nodes_visible_to_user
(
user
,
nodes
)
records
=
records_for_nodes
(
nodes
)
nodes
.
select
do
|
node
|
issuable
=
records
[
node
]
issuable
&&
can_read_reference?
(
user
,
issuable
)
end
end
def
referenced_by
(
nodes
)
records
=
records_for_nodes
(
nodes
)
nodes
.
map
{
|
node
|
records
[
node
]
}.
compact
.
uniq
end
def
can_read_reference?
(
user
,
issuable
)
can?
(
user
,
"read_
#{
issuable
.
class
.
to_s
.
underscore
}
"
.
to_sym
,
issuable
)
end
end
end
end
lib/banzai/reference_parser/issue_parser.rb
View file @
0c2fdb1c
module
Banzai
module
Banzai
module
ReferenceParser
module
ReferenceParser
class
IssueParser
<
Bas
eParser
class
IssueParser
<
Issuabl
eParser
self
.
reference_type
=
:issue
self
.
reference_type
=
:issue
def
nodes_visible_to_user
(
user
,
nodes
)
def
nodes_visible_to_user
(
user
,
nodes
)
issues
=
issue
s_for_nodes
(
nodes
)
issues
=
record
s_for_nodes
(
nodes
)
readable_issues
=
Ability
readable_issues
=
Ability
.
issues_readable_by_user
(
issues
.
values
,
user
).
to_set
.
issues_readable_by_user
(
issues
.
values
,
user
).
to_set
...
@@ -14,13 +14,7 @@ module Banzai
...
@@ -14,13 +14,7 @@ module Banzai
end
end
end
end
def
referenced_by
(
nodes
)
def
records_for_nodes
(
nodes
)
issues
=
issues_for_nodes
(
nodes
)
nodes
.
map
{
|
node
|
issues
[
node
]
}.
compact
.
uniq
end
def
issues_for_nodes
(
nodes
)
@issues_for_nodes
||=
grouped_objects_for_nodes
(
@issues_for_nodes
||=
grouped_objects_for_nodes
(
nodes
,
nodes
,
Issue
.
all
.
includes
(
Issue
.
all
.
includes
(
...
...
lib/banzai/reference_parser/merge_request_parser.rb
View file @
0c2fdb1c
module
Banzai
module
Banzai
module
ReferenceParser
module
ReferenceParser
class
MergeRequestParser
<
Bas
eParser
class
MergeRequestParser
<
Issuabl
eParser
self
.
reference_type
=
:merge_request
self
.
reference_type
=
:merge_request
def
nodes_visible_to_user
(
user
,
nodes
)
def
records_for_nodes
(
nodes
)
merge_requests
=
merge_requests_for_nodes
(
nodes
)
nodes
.
select
do
|
node
|
merge_request
=
merge_requests
[
node
]
merge_request
&&
can?
(
user
,
:read_merge_request
,
merge_request
.
project
)
end
end
def
referenced_by
(
nodes
)
merge_requests
=
merge_requests_for_nodes
(
nodes
)
nodes
.
map
{
|
node
|
merge_requests
[
node
]
}.
compact
.
uniq
end
def
merge_requests_for_nodes
(
nodes
)
@merge_requests_for_nodes
||=
grouped_objects_for_nodes
(
@merge_requests_for_nodes
||=
grouped_objects_for_nodes
(
nodes
,
nodes
,
MergeRequest
.
includes
(
MergeRequest
.
includes
(
...
@@ -40,10 +24,6 @@ module Banzai
...
@@ -40,10 +24,6 @@ module Banzai
self
.
class
.
data_attribute
self
.
class
.
data_attribute
)
)
end
end
def
can_read_reference?
(
user
,
ref_project
,
node
)
can?
(
user
,
:read_merge_request
,
ref_project
)
end
end
end
end
end
end
end
lib/gitlab/reference_extractor.rb
View file @
0c2fdb1c
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
<
Banzai
::
ReferenceExtractor
class
ReferenceExtractor
<
Banzai
::
ReferenceExtractor
REFERABLES
=
%i(user issue label milestone merge_request snippet commit commit_range directly_addressed_user)
.
freeze
REFERABLES
=
%i(user issue label milestone merge_request snippet commit commit_range directly_addressed_user
epic
)
.
freeze
attr_accessor
:project
,
:current_user
,
:author
attr_accessor
:project
,
:current_user
,
:author
def
initialize
(
project
,
current_user
=
nil
)
def
initialize
(
project
,
current_user
=
nil
)
...
...
spec/features/markdown_spec.rb
View file @
0c2fdb1c
...
@@ -207,8 +207,9 @@ describe 'GitLab Markdown' do
...
@@ -207,8 +207,9 @@ describe 'GitLab Markdown' do
before
do
before
do
@feat
=
MarkdownFeature
.
new
@feat
=
MarkdownFeature
.
new
# `markdown` helper expects a `@project` variable
# `markdown` helper expects a `@project`
and `@group`
variable
@project
=
@feat
.
project
@project
=
@feat
.
project
@group
=
@feat
.
group
end
end
context
'default pipeline'
do
context
'default pipeline'
do
...
...
spec/lib/banzai/cross_project_reference_spec.rb
View file @
0c2fdb1c
...
@@ -3,20 +3,20 @@ require 'spec_helper'
...
@@ -3,20 +3,20 @@ require 'spec_helper'
describe
Banzai
::
CrossProjectReference
do
describe
Banzai
::
CrossProjectReference
do
include
described_class
include
described_class
describe
'#p
rojec
t_from_ref'
do
describe
'#p
aren
t_from_ref'
do
context
'when no project was referenced'
do
context
'when no project was referenced'
do
it
'returns the project from context'
do
it
'returns the project from context'
do
project
=
double
project
=
double
allow
(
self
).
to
receive
(
:context
).
and_return
({
project:
project
})
allow
(
self
).
to
receive
(
:context
).
and_return
({
project:
project
})
expect
(
p
rojec
t_from_ref
(
nil
)).
to
eq
project
expect
(
p
aren
t_from_ref
(
nil
)).
to
eq
project
end
end
end
end
context
'when referenced project does not exist'
do
context
'when referenced project does not exist'
do
it
'returns nil'
do
it
'returns nil'
do
expect
(
p
rojec
t_from_ref
(
'invalid/reference'
)).
to
be_nil
expect
(
p
aren
t_from_ref
(
'invalid/reference'
)).
to
be_nil
end
end
end
end
...
@@ -27,7 +27,7 @@ describe Banzai::CrossProjectReference do
...
@@ -27,7 +27,7 @@ describe Banzai::CrossProjectReference do
expect
(
Project
).
to
receive
(
:find_by_full_path
)
expect
(
Project
).
to
receive
(
:find_by_full_path
)
.
with
(
'cross/reference'
).
and_return
(
project2
)
.
with
(
'cross/reference'
).
and_return
(
project2
)
expect
(
p
rojec
t_from_ref
(
'cross/reference'
)).
to
eq
project2
expect
(
p
aren
t_from_ref
(
'cross/reference'
)).
to
eq
project2
end
end
end
end
end
end
...
...
spec/lib/banzai/filter/abstract_reference_filter_spec.rb
View file @
0c2fdb1c
...
@@ -3,67 +3,67 @@ require 'spec_helper'
...
@@ -3,67 +3,67 @@ require 'spec_helper'
describe
Banzai
::
Filter
::
AbstractReferenceFilter
do
describe
Banzai
::
Filter
::
AbstractReferenceFilter
do
let
(
:project
)
{
create
(
:project
)
}
let
(
:project
)
{
create
(
:project
)
}
describe
'#references_per_p
rojec
t'
do
describe
'#references_per_p
aren
t'
do
it
'returns a Hash containing references grouped per p
rojec
t paths'
do
it
'returns a Hash containing references grouped per p
aren
t paths'
do
doc
=
Nokogiri
::
HTML
.
fragment
(
"#1
#{
project
.
full_path
}
#2"
)
doc
=
Nokogiri
::
HTML
.
fragment
(
"#1
#{
project
.
full_path
}
#2"
)
filter
=
described_class
.
new
(
doc
,
project:
project
)
filter
=
described_class
.
new
(
doc
,
project:
project
)
expect
(
filter
).
to
receive
(
:object_class
).
exactly
(
4
).
times
.
and_return
(
Issue
)
expect
(
filter
).
to
receive
(
:object_class
).
exactly
(
4
).
times
.
and_return
(
Issue
)
expect
(
filter
).
to
receive
(
:object_sym
).
twice
.
and_return
(
:issue
)
expect
(
filter
).
to
receive
(
:object_sym
).
twice
.
and_return
(
:issue
)
refs
=
filter
.
references_per_p
rojec
t
refs
=
filter
.
references_per_p
aren
t
expect
(
refs
).
to
be_an_instance_of
(
Hash
)
expect
(
refs
).
to
be_an_instance_of
(
Hash
)
expect
(
refs
[
project
.
full_path
]).
to
eq
(
Set
.
new
(
%w[1 2]
))
expect
(
refs
[
project
.
full_path
]).
to
eq
(
Set
.
new
(
%w[1 2]
))
end
end
end
end
describe
'#p
rojects
_per_reference'
do
describe
'#p
arent
_per_reference'
do
it
'returns a Hash containing projects grouped per p
rojec
t paths'
do
it
'returns a Hash containing projects grouped per p
aren
t paths'
do
doc
=
Nokogiri
::
HTML
.
fragment
(
''
)
doc
=
Nokogiri
::
HTML
.
fragment
(
''
)
filter
=
described_class
.
new
(
doc
,
project:
project
)
filter
=
described_class
.
new
(
doc
,
project:
project
)
expect
(
filter
).
to
receive
(
:references_per_p
rojec
t
)
expect
(
filter
).
to
receive
(
:references_per_p
aren
t
)
.
and_return
({
project
.
full_path
=>
Set
.
new
(
%w[1]
)
})
.
and_return
({
project
.
full_path
=>
Set
.
new
(
%w[1]
)
})
expect
(
filter
.
p
rojects
_per_reference
)
expect
(
filter
.
p
arent
_per_reference
)
.
to
eq
({
project
.
full_path
=>
project
})
.
to
eq
({
project
.
full_path
=>
project
})
end
end
end
end
describe
'#find_
projects_
for_paths'
do
describe
'#find_for_paths'
do
let
(
:doc
)
{
Nokogiri
::
HTML
.
fragment
(
''
)
}
let
(
:doc
)
{
Nokogiri
::
HTML
.
fragment
(
''
)
}
let
(
:filter
)
{
described_class
.
new
(
doc
,
project:
project
)
}
let
(
:filter
)
{
described_class
.
new
(
doc
,
project:
project
)
}
context
'with RequestStore disabled'
do
context
'with RequestStore disabled'
do
it
'returns a list of Projects for a list of paths'
do
it
'returns a list of Projects for a list of paths'
do
expect
(
filter
.
find_
projects_
for_paths
([
project
.
full_path
]))
expect
(
filter
.
find_for_paths
([
project
.
full_path
]))
.
to
eq
([
project
])
.
to
eq
([
project
])
end
end
it
"return an empty array for paths that don't exist"
do
it
"return an empty array for paths that don't exist"
do
expect
(
filter
.
find_
projects_
for_paths
([
'nonexistent/project'
]))
expect
(
filter
.
find_for_paths
([
'nonexistent/project'
]))
.
to
eq
([])
.
to
eq
([])
end
end
end
end
context
'with RequestStore enabled'
,
:request_store
do
context
'with RequestStore enabled'
,
:request_store
do
it
'returns a list of Projects for a list of paths'
do
it
'returns a list of Projects for a list of paths'
do
expect
(
filter
.
find_
projects_
for_paths
([
project
.
full_path
]))
expect
(
filter
.
find_for_paths
([
project
.
full_path
]))
.
to
eq
([
project
])
.
to
eq
([
project
])
end
end
context
"when no project with that path exists"
do
context
"when no project with that path exists"
do
it
"returns no value"
do
it
"returns no value"
do
expect
(
filter
.
find_
projects_
for_paths
([
'nonexistent/project'
]))
expect
(
filter
.
find_for_paths
([
'nonexistent/project'
]))
.
to
eq
([])
.
to
eq
([])
end
end
it
"adds the ref to the project refs cache"
do
it
"adds the ref to the project refs cache"
do
project_refs_cache
=
{}
project_refs_cache
=
{}
allow
(
filter
).
to
receive
(
:
project_
refs_cache
).
and_return
(
project_refs_cache
)
allow
(
filter
).
to
receive
(
:refs_cache
).
and_return
(
project_refs_cache
)
filter
.
find_
projects_
for_paths
([
'nonexistent/project'
])
filter
.
find_for_paths
([
'nonexistent/project'
])
expect
(
project_refs_cache
).
to
eq
({
'nonexistent/project'
=>
nil
})
expect
(
project_refs_cache
).
to
eq
({
'nonexistent/project'
=>
nil
})
end
end
...
@@ -71,11 +71,11 @@ describe Banzai::Filter::AbstractReferenceFilter do
...
@@ -71,11 +71,11 @@ describe Banzai::Filter::AbstractReferenceFilter do
context
'when the project refs cache includes nil values'
do
context
'when the project refs cache includes nil values'
do
before
do
before
do
# adds { 'nonexistent/project' => nil } to cache
# adds { 'nonexistent/project' => nil } to cache
filter
.
project_
from_ref_cached
(
'nonexistent/project'
)
filter
.
from_ref_cached
(
'nonexistent/project'
)
end
end
it
"return an empty array for paths that don't exist"
do
it
"return an empty array for paths that don't exist"
do
expect
(
filter
.
find_
projects_
for_paths
([
'nonexistent/project'
]))
expect
(
filter
.
find_for_paths
([
'nonexistent/project'
]))
.
to
eq
([])
.
to
eq
([])
end
end
end
end
...
@@ -83,12 +83,12 @@ describe Banzai::Filter::AbstractReferenceFilter do
...
@@ -83,12 +83,12 @@ describe Banzai::Filter::AbstractReferenceFilter do
end
end
end
end
describe
'#current_p
rojec
t_path'
do
describe
'#current_p
aren
t_path'
do
it
'returns the path of the current p
rojec
t'
do
it
'returns the path of the current p
aren
t'
do
doc
=
Nokogiri
::
HTML
.
fragment
(
''
)
doc
=
Nokogiri
::
HTML
.
fragment
(
''
)
filter
=
described_class
.
new
(
doc
,
project:
project
)
filter
=
described_class
.
new
(
doc
,
project:
project
)
expect
(
filter
.
current_p
rojec
t_path
).
to
eq
(
project
.
full_path
)
expect
(
filter
.
current_p
aren
t_path
).
to
eq
(
project
.
full_path
)
end
end
end
end
end
end
spec/lib/banzai/filter/issue_reference_filter_spec.rb
View file @
0c2fdb1c
...
@@ -157,6 +157,12 @@ describe Banzai::Filter::IssueReferenceFilter do
...
@@ -157,6 +157,12 @@ describe Banzai::Filter::IssueReferenceFilter do
expect
(
doc
.
text
).
to
eq
(
"Fixed (
#{
project2
.
full_path
}
#
#{
issue
.
iid
}
.)"
)
expect
(
doc
.
text
).
to
eq
(
"Fixed (
#{
project2
.
full_path
}
#
#{
issue
.
iid
}
.)"
)
end
end
it
'includes default classes'
do
doc
=
reference_filter
(
"Fixed (
#{
reference
}
.)"
)
expect
(
doc
.
css
(
'a'
).
first
.
attr
(
'class'
)).
to
eq
'gfm gfm-issue has-tooltip'
end
it
'ignores invalid issue IDs on the referenced project'
do
it
'ignores invalid issue IDs on the referenced project'
do
exp
=
act
=
"Fixed
#{
invalidate_reference
(
reference
)
}
"
exp
=
act
=
"Fixed
#{
invalidate_reference
(
reference
)
}
"
...
@@ -201,6 +207,12 @@ describe Banzai::Filter::IssueReferenceFilter do
...
@@ -201,6 +207,12 @@ describe Banzai::Filter::IssueReferenceFilter do
expect
(
doc
.
text
).
to
eq
(
"Fixed (
#{
project2
.
path
}
#
#{
issue
.
iid
}
.)"
)
expect
(
doc
.
text
).
to
eq
(
"Fixed (
#{
project2
.
path
}
#
#{
issue
.
iid
}
.)"
)
end
end
it
'includes default classes'
do
doc
=
reference_filter
(
"Fixed (
#{
reference
}
.)"
)
expect
(
doc
.
css
(
'a'
).
first
.
attr
(
'class'
)).
to
eq
'gfm gfm-issue has-tooltip'
end
it
'ignores invalid issue IDs on the referenced project'
do
it
'ignores invalid issue IDs on the referenced project'
do
exp
=
act
=
"Fixed
#{
invalidate_reference
(
reference
)
}
"
exp
=
act
=
"Fixed
#{
invalidate_reference
(
reference
)
}
"
...
@@ -245,6 +257,12 @@ describe Banzai::Filter::IssueReferenceFilter do
...
@@ -245,6 +257,12 @@ describe Banzai::Filter::IssueReferenceFilter do
expect
(
doc
.
text
).
to
eq
(
"Fixed (
#{
project2
.
path
}
#
#{
issue
.
iid
}
.)"
)
expect
(
doc
.
text
).
to
eq
(
"Fixed (
#{
project2
.
path
}
#
#{
issue
.
iid
}
.)"
)
end
end
it
'includes default classes'
do
doc
=
reference_filter
(
"Fixed (
#{
reference
}
.)"
)
expect
(
doc
.
css
(
'a'
).
first
.
attr
(
'class'
)).
to
eq
'gfm gfm-issue has-tooltip'
end
it
'ignores invalid issue IDs on the referenced project'
do
it
'ignores invalid issue IDs on the referenced project'
do
exp
=
act
=
"Fixed
#{
invalidate_reference
(
reference
)
}
"
exp
=
act
=
"Fixed
#{
invalidate_reference
(
reference
)
}
"
...
@@ -269,8 +287,15 @@ describe Banzai::Filter::IssueReferenceFilter do
...
@@ -269,8 +287,15 @@ describe Banzai::Filter::IssueReferenceFilter do
it
'links with adjacent text'
do
it
'links with adjacent text'
do
doc
=
reference_filter
(
"Fixed (
#{
reference
}
.)"
)
doc
=
reference_filter
(
"Fixed (
#{
reference
}
.)"
)
expect
(
doc
.
to_html
).
to
match
(
/\(<a.+>
#{
Regexp
.
escape
(
issue
.
to_reference
(
project
))
}
\(comment 123\)<\/a>\.\)/
)
expect
(
doc
.
to_html
).
to
match
(
/\(<a.+>
#{
Regexp
.
escape
(
issue
.
to_reference
(
project
))
}
\(comment 123\)<\/a>\.\)/
)
end
end
it
'includes default classes'
do
doc
=
reference_filter
(
"Fixed (
#{
reference
}
.)"
)
expect
(
doc
.
css
(
'a'
).
first
.
attr
(
'class'
)).
to
eq
'gfm gfm-issue has-tooltip'
end
end
end
context
'cross-project reference in link href'
do
context
'cross-project reference in link href'
do
...
@@ -291,8 +316,15 @@ describe Banzai::Filter::IssueReferenceFilter do
...
@@ -291,8 +316,15 @@ describe Banzai::Filter::IssueReferenceFilter do
it
'links with adjacent text'
do
it
'links with adjacent text'
do
doc
=
reference_filter
(
"Fixed (
#{
reference_link
}
.)"
)
doc
=
reference_filter
(
"Fixed (
#{
reference_link
}
.)"
)
expect
(
doc
.
to_html
).
to
match
(
/\(<a.+>Reference<\/a>\.\)/
)
expect
(
doc
.
to_html
).
to
match
(
/\(<a.+>Reference<\/a>\.\)/
)
end
end
it
'includes default classes'
do
doc
=
reference_filter
(
"Fixed (
#{
reference_link
}
.)"
)
expect
(
doc
.
css
(
'a'
).
first
.
attr
(
'class'
)).
to
eq
'gfm gfm-issue has-tooltip'
end
end
end
context
'cross-project URL in link href'
do
context
'cross-project URL in link href'
do
...
@@ -313,8 +345,15 @@ describe Banzai::Filter::IssueReferenceFilter do
...
@@ -313,8 +345,15 @@ describe Banzai::Filter::IssueReferenceFilter do
it
'links with adjacent text'
do
it
'links with adjacent text'
do
doc
=
reference_filter
(
"Fixed (
#{
reference_link
}
.)"
)
doc
=
reference_filter
(
"Fixed (
#{
reference_link
}
.)"
)
expect
(
doc
.
to_html
).
to
match
(
/\(<a.+>Reference<\/a>\.\)/
)
expect
(
doc
.
to_html
).
to
match
(
/\(<a.+>Reference<\/a>\.\)/
)
end
end
it
'includes default classes'
do
doc
=
reference_filter
(
"Fixed (
#{
reference_link
}
.)"
)
expect
(
doc
.
css
(
'a'
).
first
.
attr
(
'class'
)).
to
eq
'gfm gfm-issue has-tooltip'
end
end
end
context
'group context'
do
context
'group context'
do
...
@@ -387,19 +426,19 @@ describe Banzai::Filter::IssueReferenceFilter do
...
@@ -387,19 +426,19 @@ describe Banzai::Filter::IssueReferenceFilter do
end
end
end
end
describe
'#
issues_per_projec
t'
do
describe
'#
records_per_paren
t'
do
context
'using an internal issue tracker'
do
context
'using an internal issue tracker'
do
it
'returns a Hash containing the issues per project'
do
it
'returns a Hash containing the issues per project'
do
doc
=
Nokogiri
::
HTML
.
fragment
(
''
)
doc
=
Nokogiri
::
HTML
.
fragment
(
''
)
filter
=
described_class
.
new
(
doc
,
project:
project
)
filter
=
described_class
.
new
(
doc
,
project:
project
)
expect
(
filter
).
to
receive
(
:p
rojects
_per_reference
)
expect
(
filter
).
to
receive
(
:p
arent
_per_reference
)
.
and_return
({
project
.
full_path
=>
project
})
.
and_return
({
project
.
full_path
=>
project
})
expect
(
filter
).
to
receive
(
:references_per_p
rojec
t
)
expect
(
filter
).
to
receive
(
:references_per_p
aren
t
)
.
and_return
({
project
.
full_path
=>
Set
.
new
([
issue
.
iid
])
})
.
and_return
({
project
.
full_path
=>
Set
.
new
([
issue
.
iid
])
})
expect
(
filter
.
issues_per_projec
t
)
expect
(
filter
.
records_per_paren
t
)
.
to
eq
({
project
=>
{
issue
.
iid
=>
issue
}
})
.
to
eq
({
project
=>
{
issue
.
iid
=>
issue
}
})
end
end
end
end
...
...
spec/lib/banzai/reference_parser/issue_parser_spec.rb
View file @
0c2fdb1c
...
@@ -70,12 +70,12 @@ describe Banzai::ReferenceParser::IssueParser do
...
@@ -70,12 +70,12 @@ describe Banzai::ReferenceParser::IssueParser do
end
end
end
end
describe
'#
issue
s_for_nodes'
do
describe
'#
record
s_for_nodes'
do
it
'returns a Hash containing the issues for a list of nodes'
do
it
'returns a Hash containing the issues for a list of nodes'
do
link
[
'data-issue'
]
=
issue
.
id
.
to_s
link
[
'data-issue'
]
=
issue
.
id
.
to_s
nodes
=
[
link
]
nodes
=
[
link
]
expect
(
subject
.
issue
s_for_nodes
(
nodes
)).
to
eq
({
link
=>
issue
})
expect
(
subject
.
record
s_for_nodes
(
nodes
)).
to
eq
({
link
=>
issue
})
end
end
end
end
end
end
spec/lib/gitlab/reference_extractor_spec.rb
View file @
0c2fdb1c
...
@@ -250,4 +250,34 @@ describe Gitlab::ReferenceExtractor do
...
@@ -250,4 +250,34 @@ describe Gitlab::ReferenceExtractor do
subject
{
described_class
.
references_pattern
}
subject
{
described_class
.
references_pattern
}
it
{
is_expected
.
to
be_kind_of
Regexp
}
it
{
is_expected
.
to
be_kind_of
Regexp
}
end
end
describe
'referables prefixes'
do
def
prefixes
described_class
::
REFERABLES
.
each_with_object
({})
do
|
referable
,
result
|
klass
=
referable
.
to_s
.
camelize
.
constantize
next
unless
klass
.
respond_to?
(
:reference_prefix
)
prefix
=
klass
.
reference_prefix
result
[
prefix
]
||=
[]
result
[
prefix
]
<<
referable
end
end
it
'returns all supported prefixes'
do
expect
(
prefixes
.
keys
.
uniq
).
to
match_array
(
%w(@ # ~ % ! $ &)
)
end
it
'does not allow one prefix for multiple referables if not allowed specificly'
do
# make sure you are not overriding existing prefix before changing this hash
multiple_allowed
=
{
'@'
=>
3
}
prefixes
.
each
do
|
prefix
,
referables
|
expected_count
=
multiple_allowed
[
prefix
]
||
1
expect
(
referables
.
count
).
to
eq
(
expected_count
)
end
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment