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
0
Merge Requests
0
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
Boxiang Sun
gitlab-ce
Commits
8f8a8ab3
Commit
8f8a8ab3
authored
Apr 15, 2015
by
Robert Speicher
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor ReferenceExtractor to use pipeline filters
parent
a6defd15
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
36 additions
and
193 deletions
+36
-193
lib/gitlab/reference_extractor.rb
lib/gitlab/reference_extractor.rb
+36
-119
spec/lib/gitlab/reference_extractor_spec.rb
spec/lib/gitlab/reference_extractor_spec.rb
+0
-74
No files found.
lib/gitlab/reference_extractor.rb
View file @
8f8a8ab3
...
...
@@ -8,151 +8,68 @@ module Gitlab
@current_user
=
current_user
end
def
can?
(
user
,
action
,
subject
)
Ability
.
abilities
.
allowed?
(
user
,
action
,
subject
)
end
def
analyze
(
text
)
text
=
text
.
dup
# Remove preformatted/code blocks so that references are not included
text
.
gsub!
(
/^```.*?^```/m
,
''
)
text
.
gsub!
(
/[^`]`[^`]*?`[^`]/
,
''
)
@references
=
Hash
.
new
{
|
hash
,
type
|
hash
[
type
]
=
[]
}
parse_references
(
text
)
@_text
=
text
.
dup
end
# Given a valid project, resolve the extracted identifiers of the requested type to
# model objects.
def
users
references
[
:user
].
uniq
.
map
do
|
project
,
identifier
|
if
identifier
==
"all"
project
.
team
.
members
.
flatten
elsif
namespace
=
Namespace
.
find_by
(
path:
identifier
)
if
namespace
.
is_a?
(
Group
)
namespace
.
users
if
can?
(
current_user
,
:read_group
,
namespace
)
else
namespace
.
owner
end
end
end
.
flatten
.
compact
.
uniq
result
=
pipeline_result
(
:user
)
result
[
:references
][
:user
].
flatten
.
compact
.
uniq
end
def
labels
references
[
:label
].
uniq
.
map
do
|
project
,
identifier
|
project
.
labels
.
where
(
id:
identifier
).
first
end
.
compact
.
uniq
result
=
pipeline_result
(
:label
)
result
[
:references
][
:label
].
compact
.
uniq
end
def
issues
references
[
:issue
].
uniq
.
map
do
|
project
,
identifier
|
if
project
.
default_issues_tracker?
project
.
issues
.
where
(
iid:
identifier
).
first
end
end
.
compact
.
uniq
# TODO (rspeicher): What about external issues?
result
=
pipeline_result
(
:issue
)
result
[
:references
][
:issue
].
compact
.
uniq
end
def
merge_requests
references
[
:merge_request
].
uniq
.
map
do
|
project
,
identifier
|
project
.
merge_requests
.
where
(
iid:
identifier
).
first
end
.
compact
.
uniq
result
=
pipeline_result
(
:merge_request
)
result
[
:references
][
:merge_request
].
compact
.
uniq
end
def
snippets
references
[
:snippet
].
uniq
.
map
do
|
project
,
identifier
|
project
.
snippets
.
where
(
id:
identifier
).
first
end
.
compact
.
uniq
result
=
pipeline_result
(
:snippet
)
result
[
:references
][
:snippet
].
compact
.
uniq
end
def
commits
references
[
:commit
].
uniq
.
map
do
|
project
,
identifier
|
repo
=
project
.
repository
repo
.
commit
(
identifier
)
if
repo
end
.
compact
.
uniq
result
=
pipeline_result
(
:commit
)
result
[
:references
][
:commit
].
compact
.
uniq
end
def
commit_ranges
references
[
:commit_range
].
uniq
.
map
do
|
project
,
identifier
|
repo
=
project
.
repository
if
repo
from_id
,
to_id
=
identifier
.
split
(
/\.{2,3}/
,
2
)
[
repo
.
commit
(
from_id
),
repo
.
commit
(
to_id
)]
end
end
.
compact
.
uniq
result
=
pipeline_result
(
:commit_range
)
result
[
:references
][
:commit_range
].
compact
.
uniq
end
private
NAME_STR
=
Gitlab
::
Regex
::
NAMESPACE_REGEX_STR
PROJ_STR
=
"(?<project>
#{
NAME_STR
}
/
#{
NAME_STR
}
)"
REFERENCE_PATTERN
=
%r{
(?<prefix>
\W
)? # Prefix
( # Reference
@(?<user>
#{
NAME_STR
}
) # User name
|~(?<label>
\d
+) # Label ID
|(?<issue>([A-Z
\-
]+-)
\d
+) # JIRA Issue ID
|
#{
PROJ_STR
}
?
\#
(?<issue>([a-zA-Z
\-
]+-)?
\d
+) # Issue ID
|
#{
PROJ_STR
}
?!(?<merge_request>
\d
+) # MR ID
|
\$
(?<snippet>
\d
+) # Snippet ID
|(
#{
PROJ_STR
}
@)?(?<commit_range>[
\h
]{6,40}
\.
{2,3}[
\h
]{6,40}) # Commit range
|(
#{
PROJ_STR
}
@)?(?<commit>[
\h
]{6,40}) # Commit ID
)
(?<suffix>
\W
)? # Suffix
}x
.
freeze
TYPES
=
%i(user issue label merge_request snippet commit commit_range)
.
freeze
def
parse_references
(
text
,
project
=
@project
)
# parse reference links
text
.
gsub!
(
REFERENCE_PATTERN
)
do
|
match
|
type
=
TYPES
.
detect
{
|
t
|
$~
[
t
].
present?
}
actual_project
=
project
project_prefix
=
nil
project_path
=
$LAST_MATCH_INFO
[
:project
]
if
project_path
actual_project
=
::
Project
.
find_with_namespace
(
project_path
)
actual_project
=
nil
unless
can?
(
current_user
,
:read_project
,
actual_project
)
project_prefix
=
project_path
end
parse_result
(
$LAST_MATCH_INFO
,
type
,
actual_project
,
project_prefix
)
||
match
end
end
# Called from #parse_references. Attempts to build a gitlab reference
# link. Returns nil if +type+ is nil, if the match string is an HTML
# entity, if the reference is invalid, or if the matched text includes an
# invalid project path.
def
parse_result
(
match_info
,
type
,
project
,
project_prefix
)
prefix
=
match_info
[
:prefix
]
suffix
=
match_info
[
:suffix
]
return
nil
if
html_entity?
(
prefix
,
suffix
)
||
type
.
nil?
return
nil
if
project
.
nil?
&&
!
project_prefix
.
nil?
identifier
=
match_info
[
type
]
ref_link
=
reference_link
(
type
,
identifier
,
project
,
project_prefix
)
if
ref_link
"
#{
prefix
}#{
ref_link
}#{
suffix
}
"
else
nil
end
end
# Return true if the +prefix+ and +suffix+ indicate that the matched string
# is an HTML entity like &
def
html_entity?
(
prefix
,
suffix
)
prefix
&&
suffix
&&
prefix
[
0
]
==
'&'
&&
suffix
[
-
1
]
==
';'
end
def
reference_link
(
type
,
identifier
,
project
,
_
)
references
[
type
]
<<
[
project
,
identifier
]
# Instantiate and call HTML::Pipeline with a single reference filter type,
# returning the result
#
# filter_type - Symbol reference type (e.g., :commit, :issue, etc.)
#
# Returns the results Hash
def
pipeline_result
(
filter_type
)
klass
=
filter_type
.
to_s
.
camelize
+
'ReferenceFilter'
filter
=
"Gitlab::Markdown::
#{
klass
}
"
.
constantize
context
=
{
project:
project
,
current_user:
current_user
,
# We don't actually care about the links generated
only_path:
true
}
pipeline
=
HTML
::
Pipeline
.
new
([
filter
],
context
)
pipeline
.
call
(
@_text
)
end
end
end
spec/lib/gitlab/reference_extractor_spec.rb
View file @
8f8a8ab3
...
...
@@ -4,80 +4,6 @@ describe Gitlab::ReferenceExtractor do
let
(
:project
)
{
create
(
:project
)
}
subject
{
Gitlab
::
ReferenceExtractor
.
new
(
project
,
project
.
creator
)
}
it
'extracts username references'
do
subject
.
analyze
(
'this contains a @user reference'
)
expect
(
subject
.
references
[
:user
]).
to
eq
([[
project
,
'user'
]])
end
it
'extracts issue references'
do
subject
.
analyze
(
'this one talks about issue #1234'
)
expect
(
subject
.
references
[
:issue
]).
to
eq
([[
project
,
'1234'
]])
end
it
'extracts JIRA issue references'
do
subject
.
analyze
(
'this one talks about issue JIRA-1234'
)
expect
(
subject
.
references
[
:issue
]).
to
eq
([[
project
,
'JIRA-1234'
]])
end
it
'extracts merge request references'
do
subject
.
analyze
(
"and here's !43, a merge request"
)
expect
(
subject
.
references
[
:merge_request
]).
to
eq
([[
project
,
'43'
]])
end
it
'extracts snippet ids'
do
subject
.
analyze
(
'snippets like $12 get extracted as well'
)
expect
(
subject
.
references
[
:snippet
]).
to
eq
([[
project
,
'12'
]])
end
it
'extracts commit shas'
do
subject
.
analyze
(
'commit shas 98cf0ae3 are pulled out as Strings'
)
expect
(
subject
.
references
[
:commit
]).
to
eq
([[
project
,
'98cf0ae3'
]])
end
it
'extracts commit ranges'
do
subject
.
analyze
(
'here you go, a commit range: 98cf0ae3...98cf0ae4'
)
expect
(
subject
.
references
[
:commit_range
]).
to
eq
([[
project
,
'98cf0ae3...98cf0ae4'
]])
end
it
'extracts multiple references and preserves their order'
do
subject
.
analyze
(
'@me and @you both care about this'
)
expect
(
subject
.
references
[
:user
]).
to
eq
([
[
project
,
'me'
],
[
project
,
'you'
]
])
end
it
'leaves the original note unmodified'
do
text
=
'issue #123 is just the worst, @user'
subject
.
analyze
(
text
)
expect
(
text
).
to
eq
(
'issue #123 is just the worst, @user'
)
end
it
'extracts no references for <pre>..</pre> blocks'
do
subject
.
analyze
(
"<pre>def puts '#1 issue'
\n
end
\n
</pre>```"
)
expect
(
subject
.
issues
).
to
be_blank
end
it
'extracts no references for <code>..</code> blocks'
do
subject
.
analyze
(
"<code>def puts '!1 request'
\n
end
\n
</code>```"
)
expect
(
subject
.
merge_requests
).
to
be_blank
end
it
'extracts no references for code blocks with language'
do
subject
.
analyze
(
"this code:
\n
```ruby
\n
def puts '#1 issue'
\n
end
\n
```"
)
expect
(
subject
.
issues
).
to
be_blank
end
it
'extracts issue references for invalid code blocks'
do
subject
.
analyze
(
'test: ```this one talks about issue #1234```'
)
expect
(
subject
.
references
[
:issue
]).
to
eq
([[
project
,
'1234'
]])
end
it
'handles all possible kinds of references'
do
accessors
=
described_class
::
TYPES
.
map
{
|
t
|
"
#{
t
}
s"
.
to_sym
}
expect
(
subject
).
to
respond_to
(
*
accessors
)
end
it
'accesses valid user objects'
do
@u_foo
=
create
(
:user
,
username:
'foo'
)
@u_bar
=
create
(
:user
,
username:
'bar'
)
...
...
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