BigW Consortium Gitlab
Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
gitlab-ce
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Forest Godfrey
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
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
36 additions
and
193 deletions
+36
-193
reference_extractor.rb
lib/gitlab/reference_extractor.rb
+36
-119
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