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
Léo-Paul Géneau
gitlab-ce
Commits
123669a5
Commit
123669a5
authored
Oct 14, 2015
by
Robert Speicher
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'simplify-cross-references' into 'master'
Simplify code around (cross)-references See merge request !1568
parents
a3a80eac
276b3a7b
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
70 additions
and
113 deletions
+70
-113
app/controllers/projects/issues_controller.rb
app/controllers/projects/issues_controller.rb
+1
-1
app/controllers/projects/merge_requests_controller.rb
app/controllers/projects/merge_requests_controller.rb
+1
-1
app/models/concerns/mentionable.rb
app/models/concerns/mentionable.rb
+22
-22
app/models/concerns/participable.rb
app/models/concerns/participable.rb
+8
-14
app/models/note.rb
app/models/note.rb
+3
-10
app/services/git_push_service.rb
app/services/git_push_service.rb
+16
-34
app/services/issues/create_service.rb
app/services/issues/create_service.rb
+1
-1
app/services/issues/update_service.rb
app/services/issues/update_service.rb
+1
-1
app/services/merge_requests/create_service.rb
app/services/merge_requests/create_service.rb
+1
-1
app/services/merge_requests/update_service.rb
app/services/merge_requests/update_service.rb
+1
-1
app/services/notes/create_service.rb
app/services/notes/create_service.rb
+1
-7
app/services/notes/update_service.rb
app/services/notes/update_service.rb
+1
-1
lib/gitlab/reference_extractor.rb
lib/gitlab/reference_extractor.rb
+2
-0
spec/models/commit_spec.rb
spec/models/commit_spec.rb
+2
-2
spec/models/concerns/mentionable_spec.rb
spec/models/concerns/mentionable_spec.rb
+1
-1
spec/models/issue_spec.rb
spec/models/issue_spec.rb
+1
-1
spec/models/note_spec.rb
spec/models/note_spec.rb
+2
-3
spec/services/git_push_service_spec.rb
spec/services/git_push_service_spec.rb
+1
-1
spec/support/mentionable_shared_examples.rb
spec/support/mentionable_shared_examples.rb
+4
-11
No files found.
app/controllers/projects/issues_controller.rb
View file @
123669a5
...
...
@@ -55,7 +55,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def
show
@participants
=
@issue
.
participants
(
current_user
,
@project
)
@participants
=
@issue
.
participants
(
current_user
)
@note
=
@project
.
notes
.
new
(
noteable:
@issue
)
@notes
=
@issue
.
notes
.
inc_author
.
fresh
@noteable
=
@issue
...
...
app/controllers/projects/merge_requests_controller.rb
View file @
123669a5
...
...
@@ -246,7 +246,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def
define_show_vars
@participants
=
@merge_request
.
participants
(
current_user
,
@project
)
@participants
=
@merge_request
.
participants
(
current_user
)
# Build a note object for comment form
@note
=
@project
.
notes
.
new
(
noteable:
@merge_request
)
...
...
app/models/concerns/mentionable.rb
View file @
123669a5
...
...
@@ -41,55 +41,49 @@ module Mentionable
self
end
# Determine whether or not a cross-reference Note has already been created between this Mentionable and
# the specified target.
def
has_mentioned?
(
targe
t
)
SystemNoteService
.
cross_reference_exists?
(
target
,
local_reference
)
def
all_references
(
current_user
=
self
.
author
,
text
=
self
.
mentionable_text
)
ext
=
Gitlab
::
ReferenceExtractor
.
new
(
self
.
project
,
current_user
)
ext
.
analyze
(
tex
t
)
ext
end
def
mentioned_users
(
current_user
=
nil
)
return
[]
if
mentionable_text
.
blank?
ext
=
Gitlab
::
ReferenceExtractor
.
new
(
self
.
project
,
current_user
)
ext
.
analyze
(
mentionable_text
)
ext
.
users
.
uniq
all_references
(
current_user
).
users
.
uniq
end
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
def
reference
s
(
p
=
project
,
current_user
=
self
.
author
,
text
=
mentionable_text
)
def
reference
d_mentionables
(
current_user
=
self
.
author
,
text
=
self
.
mentionable_text
)
return
[]
if
text
.
blank?
ext
=
Gitlab
::
ReferenceExtractor
.
new
(
p
,
current_user
)
ext
.
analyze
(
text
)
(
ext
.
issues
+
ext
.
merge_requests
+
ext
.
commits
).
uniq
-
[
local_reference
]
refs
=
all_references
(
current_user
,
text
)
(
refs
.
issues
+
refs
.
merge_requests
+
refs
.
commits
).
uniq
-
[
local_reference
]
end
# Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
def
create_cross_references!
(
p
=
project
,
a
=
author
,
without
=
[]
)
refs
=
reference
s
(
p
)
def
create_cross_references!
(
author
=
self
.
author
,
without
=
[],
text
=
self
.
mentionable_text
)
refs
=
reference
d_mentionables
(
author
,
text
)
# We're using this method instead of Array diffing because that requires
# both of the object's `hash` values to be the same, which may not be the
# case for otherwise identical Commit objects.
refs
.
reject!
{
|
ref
|
without
.
include?
(
ref
)
}
refs
.
reject!
{
|
ref
|
without
.
include?
(
ref
)
||
cross_reference_exists?
(
ref
)
}
refs
.
each
do
|
ref
|
SystemNoteService
.
cross_reference
(
ref
,
local_reference
,
a
)
SystemNoteService
.
cross_reference
(
ref
,
local_reference
,
a
uthor
)
end
end
# When a mentionable field is changed, creates cross-reference notes that
# don't already exist
def
create_new_cross_references!
(
p
=
project
,
a
=
author
)
def
create_new_cross_references!
(
author
=
self
.
author
)
changes
=
detect_mentionable_changes
return
if
changes
.
empty?
original_text
=
changes
.
collect
{
|
_
,
vals
|
vals
.
first
}.
join
(
' '
)
preexisting
=
reference
s
(
p
,
self
.
author
,
original_text
)
create_cross_references!
(
p
,
a
,
preexisting
)
preexisting
=
reference
d_mentionables
(
author
,
original_text
)
create_cross_references!
(
author
,
preexisting
)
end
private
...
...
@@ -111,4 +105,10 @@ module Mentionable
# Only include changed fields that are mentionable
source
.
select
{
|
key
,
val
|
mentionable
.
include?
(
key
)
}
end
# Determine whether or not a cross-reference Note has already been created between this Mentionable and
# the specified target.
def
cross_reference_exists?
(
target
)
SystemNoteService
.
cross_reference_exists?
(
target
,
local_reference
)
end
end
app/models/concerns/participable.rb
View file @
123669a5
...
...
@@ -37,8 +37,8 @@ module Participable
# Be aware that this method makes a lot of sql queries.
# Save result into variable if you are going to reuse it inside same request
def
participants
(
current_user
=
self
.
author
,
project
=
self
.
project
)
participants
=
self
.
class
.
participant_attrs
.
flat_map
do
|
attr
|
def
participants
(
current_user
=
self
.
author
)
self
.
class
.
participant_attrs
.
flat_map
do
|
attr
|
meth
=
method
(
attr
)
value
=
...
...
@@ -48,28 +48,22 @@ module Participable
meth
.
call
end
participants_for
(
value
,
current_user
,
project
)
end
.
compact
.
uniq
if
project
participants
.
select!
do
|
user
|
user
.
can?
(
:read_project
,
project
)
end
participants_for
(
value
,
current_user
)
end
.
compact
.
uniq
.
select
do
|
user
|
user
.
can?
(
:read_project
,
self
.
project
)
end
participants
end
private
def
participants_for
(
value
,
current_user
=
nil
,
project
=
nil
)
def
participants_for
(
value
,
current_user
=
nil
)
case
value
when
User
[
value
]
when
Enumerable
,
ActiveRecord
::
Relation
value
.
flat_map
{
|
v
|
participants_for
(
v
,
current_user
,
project
)
}
value
.
flat_map
{
|
v
|
participants_for
(
v
,
current_user
)
}
when
Participable
value
.
participants
(
current_user
,
project
)
value
.
participants
(
current_user
)
end
end
end
app/models/note.rb
View file @
123669a5
...
...
@@ -62,7 +62,6 @@ class Note < ActiveRecord::Base
serialize
:st_diff
before_create
:set_diff
,
if:
->
(
n
)
{
n
.
line_code
.
present?
}
after_update
:set_references
class
<<
self
def
discussions_from_notes
(
notes
)
...
...
@@ -333,15 +332,13 @@ class Note < ActiveRecord::Base
end
def
noteable_type_name
if
noteable_type
.
present?
noteable_type
.
downcase
end
noteable_type
.
downcase
if
noteable_type
.
present?
end
# FIXME: Hack for polymorphic associations with STI
# For more information visit http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Polymorphic+Associations
def
noteable_type
=
(
sT
ype
)
super
(
sT
ype
.
to_s
.
classify
.
constantize
.
base_class
.
to_s
)
def
noteable_type
=
(
noteable_t
ype
)
super
(
noteable_t
ype
.
to_s
.
classify
.
constantize
.
base_class
.
to_s
)
end
# Reset notes events cache
...
...
@@ -357,10 +354,6 @@ class Note < ActiveRecord::Base
Event
.
reset_event_cache_for
(
self
)
end
def
set_references
create_new_cross_references!
(
project
,
author
)
end
def
system?
read_attribute
(
:system
)
end
...
...
app/services/git_push_service.rb
View file @
123669a5
...
...
@@ -74,48 +74,30 @@ class GitPushService
def
process_commit_messages
(
ref
)
is_default_branch
=
is_default_branch?
(
ref
)
@push_commits
.
each
do
|
commit
|
# Close issues if these commits were pushed to the project's default branch and the commit message matches the
# closing regex. Exclude any mentioned Issues from cross-referencing even if the commits are being pushed to
# a different branch.
issues_to_close
=
commit
.
closes_issues
(
user
)
authors
=
Hash
.
new
do
|
hash
,
commit
|
email
=
commit
.
author_email
return
hash
[
email
]
if
hash
.
has_key?
(
email
)
# Load commit author only if needed.
# For push with 1k commits it prevents 900+ requests in database
author
=
nil
hash
[
email
]
=
commit_user
(
commit
)
end
@push_commits
.
each
do
|
commit
|
# Keep track of the issues that will be actually closed because they are on a default branch.
# Hence, when creating cross-reference notes, the not-closed issues (on non-default branches)
# will also have cross-reference.
actually_closed_issues
=
[]
if
issues_to_close
.
present?
&&
is_default_branch
author
||=
commit_user
(
commit
)
actually_closed_issues
=
issues_to_close
issues_to_close
.
each
do
|
issue
|
Issues
::
CloseService
.
new
(
project
,
author
,
{}).
execute
(
issue
,
commit
)
end
end
closed_issues
=
[]
if
project
.
default_issues_tracker?
create_cross_reference_notes
(
commit
,
actually_closed_issues
)
end
if
is_default_branch
# Close issues if these commits were pushed to the project's default branch and the commit message matches the
# closing regex. Exclude any mentioned Issues from cross-referencing even if the commits are being pushed to
# a different branch.
closed_issues
=
commit
.
closes_issues
(
user
)
closed_issues
.
each
do
|
issue
|
Issues
::
CloseService
.
new
(
project
,
authors
[
commit
],
{}).
execute
(
issue
,
commit
)
end
end
def
create_cross_reference_notes
(
commit
,
issues_to_close
)
# Create cross-reference notes for any other references than those given in issues_to_close.
# Omit any issues that were referenced in an issue-closing phrase, or have already been
# mentioned from this commit (probably from this commit being pushed to a different branch).
refs
=
commit
.
references
(
project
,
user
)
-
issues_to_close
refs
.
reject!
{
|
r
|
commit
.
has_mentioned?
(
r
)
}
if
refs
.
present?
author
||=
commit_user
(
commit
)
refs
.
each
do
|
r
|
SystemNoteService
.
cross_reference
(
r
,
commit
,
author
)
end
commit
.
create_cross_references!
(
authors
[
commit
],
closed_issues
)
end
end
...
...
app/services/issues/create_service.rb
View file @
123669a5
...
...
@@ -10,7 +10,7 @@ module Issues
issue
.
update_attributes
(
label_ids:
label_params
)
notification_service
.
new_issue
(
issue
,
current_user
)
event_service
.
open_issue
(
issue
,
current_user
)
issue
.
create_cross_references!
(
issue
.
project
,
current_user
)
issue
.
create_cross_references!
(
current_user
)
execute_hooks
(
issue
,
'open'
)
end
...
...
app/services/issues/update_service.rb
View file @
123669a5
...
...
@@ -35,7 +35,7 @@ module Issues
create_title_change_note
(
issue
,
issue
.
previous_changes
[
'title'
].
first
)
end
issue
.
create_new_cross_references!
(
issue
.
project
,
current_user
)
issue
.
create_new_cross_references!
execute_hooks
(
issue
,
'update'
)
end
...
...
app/services/merge_requests/create_service.rb
View file @
123669a5
...
...
@@ -18,7 +18,7 @@ module MergeRequests
merge_request
.
update_attributes
(
label_ids:
label_params
)
event_service
.
open_mr
(
merge_request
,
current_user
)
notification_service
.
new_merge_request
(
merge_request
,
current_user
)
merge_request
.
create_cross_references!
(
merge_request
.
project
,
current_user
)
merge_request
.
create_cross_references!
(
current_user
)
execute_hooks
(
merge_request
)
end
...
...
app/services/merge_requests/update_service.rb
View file @
123669a5
...
...
@@ -59,7 +59,7 @@ module MergeRequests
merge_request
.
mark_as_unchecked
end
merge_request
.
create_new_cross_references!
(
merge_request
.
project
,
current_user
)
merge_request
.
create_new_cross_references!
execute_hooks
(
merge_request
,
'update'
)
end
...
...
app/services/notes/create_service.rb
View file @
123669a5
...
...
@@ -11,13 +11,7 @@ module Notes
# Skip system notes, like status changes and cross-references.
unless
note
.
system
event_service
.
leave_note
(
note
,
note
.
author
)
# Create a cross-reference note if this Note contains GFM that names an
# issue, merge request, or commit.
note
.
references
.
each
do
|
mentioned
|
SystemNoteService
.
cross_reference
(
mentioned
,
note
.
noteable
,
note
.
author
)
end
note
.
create_cross_references!
execute_hooks
(
note
)
end
end
...
...
app/services/notes/update_service.rb
View file @
123669a5
...
...
@@ -4,7 +4,7 @@ module Notes
return
note
unless
note
.
editable?
note
.
update_attributes
(
params
.
merge
(
updated_by:
current_user
))
note
.
create_new_cross_references!
note
.
reset_events_cache
note
...
...
lib/gitlab/reference_extractor.rb
View file @
123669a5
...
...
@@ -39,6 +39,8 @@ module Gitlab
#
# Returns the results Array for the requested filter type
def
pipeline_result
(
filter_type
)
return
[]
if
@text
.
blank?
klass
=
filter_type
.
to_s
.
camelize
+
'ReferenceFilter'
filter
=
Gitlab
::
Markdown
.
const_get
(
klass
)
...
...
spec/models/commit_spec.rb
View file @
123669a5
...
...
@@ -89,9 +89,9 @@ eos
end
it_behaves_like
'a mentionable'
do
subject
{
commit
}
subject
{
c
reate
(
:project
).
c
ommit
}
let
(
:author
)
{
create
(
:user
,
email:
commi
t
.
author_email
)
}
let
(
:author
)
{
create
(
:user
,
email:
subjec
t
.
author_email
)
}
let
(
:backref_text
)
{
"commit
#{
subject
.
id
}
"
}
let
(
:set_mentionable_text
)
do
->
(
txt
)
{
allow
(
subject
).
to
receive
(
:safe_message
).
and_return
(
txt
)
}
...
...
spec/models/concerns/mentionable_spec.rb
View file @
123669a5
...
...
@@ -25,7 +25,7 @@ describe Issue, "Mentionable" do
it
'correctly removes already-mentioned Commits'
do
expect
(
SystemNoteService
).
not_to
receive
(
:cross_reference
)
issue
.
create_cross_references!
(
project
,
author
,
[
commit2
])
issue
.
create_cross_references!
(
author
,
[
commit2
])
end
end
...
...
spec/models/issue_spec.rb
View file @
123669a5
...
...
@@ -69,7 +69,7 @@ describe Issue do
end
it_behaves_like
'an editable mentionable'
do
subject
{
create
(
:issue
,
project:
project
)
}
subject
{
create
(
:issue
)
}
let
(
:backref_text
)
{
"issue
#{
subject
.
to_reference
}
"
}
let
(
:set_mentionable_text
)
{
->
(
txt
){
subject
.
description
=
txt
}
}
...
...
spec/models/note_spec.rb
View file @
123669a5
...
...
@@ -192,10 +192,9 @@ describe Note do
end
it_behaves_like
'an editable mentionable'
do
subject
{
create
:note
,
noteable:
issue
,
project:
project
}
subject
{
create
:note
,
noteable:
issue
,
project:
issue
.
project
}
let
(
:project
)
{
create
(
:project
)
}
let
(
:issue
)
{
create
:issue
,
project:
project
}
let
(
:issue
)
{
create
:issue
}
let
(
:backref_text
)
{
issue
.
gfm_reference
}
let
(
:set_mentionable_text
)
{
->
(
txt
)
{
subject
.
note
=
txt
}
}
end
...
...
spec/services/git_push_service_spec.rb
View file @
123669a5
...
...
@@ -155,7 +155,7 @@ describe GitPushService do
before
do
allow
(
commit
).
to
receive_messages
(
safe_message:
"this commit
\n
mentions #
#{
issue
.
id
}
"
,
safe_message:
"this commit
\n
mentions
#
{
issue
.
to_reference
}
"
,
references:
[
issue
],
author_name:
commit_author
.
name
,
author_email:
commit_author
.
email
...
...
spec/support/mentionable_shared_examples.rb
View file @
123669a5
...
...
@@ -5,7 +5,7 @@
# - let(:set_mentionable_text) { lambda { |txt| "block that assigns txt to the subject's mentionable_text" } }
def
common_mentionable_setup
let
(
:project
)
{
create
:
project
}
let
(
:project
)
{
subject
.
project
}
let
(
:author
)
{
subject
.
author
}
let
(
:mentioned_issue
)
{
create
(
:issue
,
project:
project
)
}
...
...
@@ -65,7 +65,7 @@ shared_examples 'a mentionable' do
it
"extracts references from its reference property"
do
# De-duplicate and omit itself
refs
=
subject
.
reference
s
(
project
)
refs
=
subject
.
reference
d_mentionables
expect
(
refs
.
size
).
to
eq
(
6
)
expect
(
refs
).
to
include
(
mentioned_issue
)
expect
(
refs
).
to
include
(
mentioned_mr
)
...
...
@@ -84,14 +84,7 @@ shared_examples 'a mentionable' do
with
(
referenced
,
subject
.
local_reference
,
author
)
end
subject
.
create_cross_references!
(
project
,
author
)
end
it
'detects existing cross-references'
do
SystemNoteService
.
cross_reference
(
mentioned_issue
,
subject
.
local_reference
,
author
)
expect
(
subject
).
to
have_mentioned
(
mentioned_issue
)
expect
(
subject
).
not_to
have_mentioned
(
mentioned_mr
)
subject
.
create_cross_references!
end
end
...
...
@@ -143,6 +136,6 @@ shared_examples 'an editable mentionable' do
end
set_mentionable_text
.
call
(
new_text
)
subject
.
create_new_cross_references!
(
project
,
author
)
subject
.
create_new_cross_references!
(
author
)
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