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
Tatuya Kamada
gitlab-ce
Commits
707ce837
Commit
707ce837
authored
Feb 06, 2017
by
Marin Jankovski
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce
parents
a8b4c75f
efe38da9
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
2715 additions
and
235 deletions
+2715
-235
app/assets/stylesheets/framework/animations.scss
app/assets/stylesheets/framework/animations.scss
+7
-5
app/services/system_note_service.rb
app/services/system_note_service.rb
+13
-9
app/views/admin/projects/index.html.haml
app/views/admin/projects/index.html.haml
+5
-8
app/views/projects/snippets/_actions.html.haml
app/views/projects/snippets/_actions.html.haml
+2
-0
app/views/shared/projects/_dropdown.html.haml
app/views/shared/projects/_dropdown.html.haml
+1
-1
app/views/snippets/_actions.html.haml
app/views/snippets/_actions.html.haml
+23
-23
changelogs/unreleased/26863-Remove-hover-animation-from-row-elements.yml
...leased/26863-Remove-hover-animation-from-row-elements.yml
+4
-0
changelogs/unreleased/9-0-api-changes.yml
changelogs/unreleased/9-0-api-changes.yml
+4
-0
changelogs/unreleased/pms-lowercase-system-notes.yml
changelogs/unreleased/pms-lowercase-system-notes.yml
+4
-0
changelogs/unreleased/redesign-searchbar-admin-project-26794.yml
...ogs/unreleased/redesign-searchbar-admin-project-26794.yml
+4
-0
doc/api/issues.md
doc/api/issues.md
+0
-1
doc/api/merge_requests.md
doc/api/merge_requests.md
+1
-2
doc/api/v3_to_v4.md
doc/api/v3_to_v4.md
+3
-0
lib/api/api.rb
lib/api/api.rb
+2
-0
lib/api/issues.rb
lib/api/issues.rb
+0
-3
lib/api/merge_requests.rb
lib/api/merge_requests.rb
+131
-143
lib/api/v3/issues.rb
lib/api/v3/issues.rb
+231
-0
lib/api/v3/merge_requests.rb
lib/api/v3/merge_requests.rb
+280
-0
spec/requests/api/issues_spec.rb
spec/requests/api/issues_spec.rb
+0
-17
spec/requests/api/merge_requests_spec.rb
spec/requests/api/merge_requests_spec.rb
+10
-18
spec/requests/api/v3/issues_spec.rb
spec/requests/api/v3/issues_spec.rb
+1259
-0
spec/requests/api/v3/merge_requests_spec.rb
spec/requests/api/v3/merge_requests_spec.rb
+726
-0
spec/services/system_note_service_spec.rb
spec/services/system_note_service_spec.rb
+5
-5
No files found.
app/assets/stylesheets/framework/animations.scss
View file @
707ce837
...
@@ -137,11 +137,13 @@ a {
...
@@ -137,11 +137,13 @@ a {
@include
transition
(
background-color
,
color
,
border
);
@include
transition
(
background-color
,
color
,
border
);
}
}
.tree-table
td
,
.well-list
>
li
{
@include
transition
(
background-color
,
border-color
);
}
.stage-nav-item
{
.stage-nav-item
{
@include
transition
(
background-color
,
box-shadow
);
@include
transition
(
background-color
,
box-shadow
);
}
}
.nav-sidebar
a
,
.dropdown-menu
a
,
.dropdown-menu
button
,
.dropdown-menu-nav
a
{
transition
:
none
;
}
app/services/system_note_service.rb
View file @
707ce837
...
@@ -118,16 +118,18 @@ module SystemNoteService
...
@@ -118,16 +118,18 @@ module SystemNoteService
#
#
# Example Note text:
# Example Note text:
#
#
# "Changed estimate of this issue to 3d 5h"
# "removed time estimate"
#
# "changed time estimate to 3d 5h"
#
#
# Returns the created Note object
# Returns the created Note object
def
change_time_estimate
(
noteable
,
project
,
author
)
def
change_time_estimate
(
noteable
,
project
,
author
)
parsed_time
=
Gitlab
::
TimeTrackingFormatter
.
output
(
noteable
.
time_estimate
)
parsed_time
=
Gitlab
::
TimeTrackingFormatter
.
output
(
noteable
.
time_estimate
)
body
=
if
noteable
.
time_estimate
==
0
body
=
if
noteable
.
time_estimate
==
0
"
Removed time estimate on this
#{
noteable
.
human_class_name
}
"
"
removed time estimate
"
else
else
"
Changed time estimate of this
#{
noteable
.
human_class_name
}
to
#{
parsed_time
}
"
"
changed time estimate
to
#{
parsed_time
}
"
end
end
create_note
(
noteable:
noteable
,
project:
project
,
author:
author
,
note:
body
)
create_note
(
noteable:
noteable
,
project:
project
,
author:
author
,
note:
body
)
...
@@ -142,7 +144,9 @@ module SystemNoteService
...
@@ -142,7 +144,9 @@ module SystemNoteService
#
#
# Example Note text:
# Example Note text:
#
#
# "Added 2h 30m of time spent on this issue"
# "removed time spent"
#
# "added 2h 30m of time spent"
#
#
# Returns the created Note object
# Returns the created Note object
...
@@ -150,11 +154,11 @@ module SystemNoteService
...
@@ -150,11 +154,11 @@ module SystemNoteService
time_spent
=
noteable
.
time_spent
time_spent
=
noteable
.
time_spent
if
time_spent
==
:reset
if
time_spent
==
:reset
body
=
"
Removed time spent on this
#{
noteable
.
human_class_name
}
"
body
=
"
removed time spent
"
else
else
parsed_time
=
Gitlab
::
TimeTrackingFormatter
.
output
(
time_spent
.
abs
)
parsed_time
=
Gitlab
::
TimeTrackingFormatter
.
output
(
time_spent
.
abs
)
action
=
time_spent
>
0
?
'
Added'
:
'S
ubtracted'
action
=
time_spent
>
0
?
'
added'
:
's
ubtracted'
body
=
"
#{
action
}
#{
parsed_time
}
of time spent
on this
#{
noteable
.
human_class_name
}
"
body
=
"
#{
action
}
#{
parsed_time
}
of time spent"
end
end
create_note
(
noteable:
noteable
,
project:
project
,
author:
author
,
note:
body
)
create_note
(
noteable:
noteable
,
project:
project
,
author:
author
,
note:
body
)
...
@@ -221,7 +225,7 @@ module SystemNoteService
...
@@ -221,7 +225,7 @@ module SystemNoteService
end
end
def
discussion_continued_in_issue
(
discussion
,
project
,
author
,
issue
)
def
discussion_continued_in_issue
(
discussion
,
project
,
author
,
issue
)
body
=
"
Add
ed
#{
issue
.
to_reference
}
to continue this discussion"
body
=
"
creat
ed
#{
issue
.
to_reference
}
to continue this discussion"
note_attributes
=
discussion
.
reply_attributes
.
merge
(
project:
project
,
author:
author
,
note:
body
)
note_attributes
=
discussion
.
reply_attributes
.
merge
(
project:
project
,
author:
author
,
note:
body
)
note_attributes
[
:type
]
=
note_attributes
.
delete
(
:note_type
)
note_attributes
[
:type
]
=
note_attributes
.
delete
(
:note_type
)
...
@@ -260,7 +264,7 @@ module SystemNoteService
...
@@ -260,7 +264,7 @@ module SystemNoteService
#
#
# Example Note text:
# Example Note text:
#
#
# "made the issue confidential"
#
"made the issue confidential"
#
#
# Returns the created Note object
# Returns the created Note object
def
change_issue_confidentiality
(
issue
,
project
,
author
)
def
change_issue_confidentiality
(
issue
,
project
,
author
)
...
...
app/views/admin/projects/index.html.haml
View file @
707ce837
...
@@ -27,7 +27,7 @@
...
@@ -27,7 +27,7 @@
=
icon
(
"search"
,
class:
"search-icon"
)
=
icon
(
"search"
,
class:
"search-icon"
)
.dropdown
.dropdown
-
toggle_text
=
'
Search for
Namespace'
-
toggle_text
=
'Namespace'
-
if
params
[
:namespace_id
].
present?
-
if
params
[
:namespace_id
].
present?
-
namespace
=
Namespace
.
find
(
params
[
:namespace_id
])
-
namespace
=
Namespace
.
find
(
params
[
:namespace_id
])
-
toggle_text
=
"
#{
namespace
.
kind
}
:
#{
namespace
.
path
}
"
-
toggle_text
=
"
#{
namespace
.
kind
}
:
#{
namespace
.
path
}
"
...
@@ -37,8 +37,10 @@
...
@@ -37,8 +37,10 @@
=
dropdown_filter
(
"Search for Namespace"
)
=
dropdown_filter
(
"Search for Namespace"
)
=
dropdown_content
=
dropdown_content
=
dropdown_loading
=
dropdown_loading
=
render
'shared/projects/dropdown'
=
button_tag
"Search"
,
class:
"btn btn-primary btn-search"
=
link_to
new_project_path
,
class:
'btn btn-new'
do
New Project
=
button_tag
"Search"
,
class:
"btn btn-primary btn-search hide"
%ul
.nav-links
%ul
.nav-links
-
opts
=
params
[
:visibility_level
].
present?
?
{}
:
{
page:
admin_projects_path
}
-
opts
=
params
[
:visibility_level
].
present?
?
{}
:
{
page:
admin_projects_path
}
...
@@ -56,11 +58,6 @@
...
@@ -56,11 +58,6 @@
=
link_to
admin_projects_path
(
visibility_level:
Gitlab
::
VisibilityLevel
::
PUBLIC
)
do
=
link_to
admin_projects_path
(
visibility_level:
Gitlab
::
VisibilityLevel
::
PUBLIC
)
do
Public
Public
.nav-controls
=
render
'shared/projects/dropdown'
=
link_to
new_project_path
,
class:
'btn btn-new'
do
New Project
.projects-list-holder
.projects-list-holder
-
if
@projects
.
any?
-
if
@projects
.
any?
%ul
.projects-list.content-list
%ul
.projects-list.content-list
...
...
app/views/projects/snippets/_actions.html.haml
View file @
707ce837
-
return
unless
current_user
.hidden-xs
.hidden-xs
-
if
can?
(
current_user
,
:update_project_snippet
,
@snippet
)
-
if
can?
(
current_user
,
:update_project_snippet
,
@snippet
)
=
link_to
edit_namespace_project_snippet_path
(
@project
.
namespace
,
@project
,
@snippet
),
class:
"btn btn-grouped"
do
=
link_to
edit_namespace_project_snippet_path
(
@project
.
namespace
,
@project
,
@snippet
),
class:
"btn btn-grouped"
do
...
...
app/views/shared/projects/_dropdown.html.haml
View file @
707ce837
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
-
personal
=
params
[
:personal
]
-
personal
=
params
[
:personal
]
-
archived
=
params
[
:archived
]
-
archived
=
params
[
:archived
]
-
namespace_id
=
params
[
:namespace_id
]
-
namespace_id
=
params
[
:namespace_id
]
.dropdown
.inline
.dropdown
-
toggle_text
=
projects_sort_options_hash
[
@sort
]
-
toggle_text
=
projects_sort_options_hash
[
@sort
]
=
dropdown_toggle
(
toggle_text
,
{
toggle:
'dropdown'
},
{
id:
'sort-projects-dropdown'
})
=
dropdown_toggle
(
toggle_text
,
{
toggle:
'dropdown'
},
{
id:
'sort-projects-dropdown'
})
%ul
.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable
%ul
.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable
...
...
app/views/snippets/_actions.html.haml
View file @
707ce837
-
return
unless
current_user
.hidden-xs
.hidden-xs
-
if
can?
(
current_user
,
:update_personal_snippet
,
@snippet
)
-
if
can?
(
current_user
,
:update_personal_snippet
,
@snippet
)
=
link_to
edit_snippet_path
(
@snippet
),
class:
"btn btn-grouped"
do
=
link_to
edit_snippet_path
(
@snippet
),
class:
"btn btn-grouped"
do
...
@@ -5,29 +7,27 @@
...
@@ -5,29 +7,27 @@
-
if
can?
(
current_user
,
:admin_personal_snippet
,
@snippet
)
-
if
can?
(
current_user
,
:admin_personal_snippet
,
@snippet
)
=
link_to
snippet_path
(
@snippet
),
method: :delete
,
data:
{
confirm:
"Are you sure?"
},
class:
"btn btn-grouped btn-inverted btn-remove"
,
title:
'Delete Snippet'
do
=
link_to
snippet_path
(
@snippet
),
method: :delete
,
data:
{
confirm:
"Are you sure?"
},
class:
"btn btn-grouped btn-inverted btn-remove"
,
title:
'Delete Snippet'
do
Delete
Delete
-
if
current_user
=
link_to
new_snippet_path
,
class:
"btn btn-grouped btn-inverted btn-create"
,
title:
"New snippet"
do
=
link_to
new_snippet_path
,
class:
"btn btn-grouped btn-inverted btn-create"
,
title:
"New snippet"
do
New snippet
New snippet
-
if
@snippet
.
submittable_as_spam?
&&
current_user
.
admin?
-
if
@snippet
.
submittable_as_spam?
&&
current_user
.
admin?
=
link_to
'Submit as spam'
,
mark_as_spam_snippet_path
(
@snippet
),
method: :post
,
class:
'btn btn-grouped btn-spam'
,
title:
'Submit as spam'
=
link_to
'Submit as spam'
,
mark_as_spam_snippet_path
(
@snippet
),
method: :post
,
class:
'btn btn-grouped btn-spam'
,
title:
'Submit as spam'
-
if
current_user
.visible-xs-block.dropdown
.visible-xs-block.dropdown
%button
.btn.btn-default.btn-block.append-bottom-0.prepend-top-5
{
data:
{
toggle:
"dropdown"
}
}
%button
.btn.btn-default.btn-block.append-bottom-0.prepend-top-5
{
data:
{
toggle:
"dropdown"
}
}
Options
Options
=
icon
(
'caret-down'
)
=
icon
(
'caret-down'
)
.dropdown-menu.dropdown-menu-full-width
.dropdown-menu.dropdown-menu-full-width
%ul
%ul
%li
=
link_to
new_snippet_path
,
title:
"New snippet"
do
New snippet
-
if
can?
(
current_user
,
:admin_personal_snippet
,
@snippet
)
%li
%li
=
link_to
new_snippet_path
,
title:
"New snippet"
do
=
link_to
snippet_path
(
@snippet
),
method: :delete
,
data:
{
confirm:
"Are you sure?"
},
title:
'Delete Snippet'
do
New snippet
Delete
-
if
can?
(
current_user
,
:admin_personal_snippet
,
@snippet
)
-
if
can?
(
current_user
,
:update_personal_snippet
,
@snippet
)
%li
%li
=
link_to
snippet_path
(
@snippet
),
method: :delete
,
data:
{
confirm:
"Are you sure?"
},
title:
'Delete Snippet'
do
=
link_to
edit_snippet_path
(
@snippet
)
do
Delete
Edit
-
if
can?
(
current_user
,
:update_personal_snippet
,
@snippet
)
-
if
@snippet
.
submittable_as_spam?
&&
current_user
.
admin?
%li
%li
=
link_to
edit_snippet_path
(
@snippet
)
do
=
link_to
'Submit as spam'
,
mark_as_spam_snippet_path
(
@snippet
),
method: :post
Edit
-
if
@snippet
.
submittable_as_spam?
&&
current_user
.
admin?
%li
=
link_to
'Submit as spam'
,
mark_as_spam_snippet_path
(
@snippet
),
method: :post
changelogs/unreleased/26863-Remove-hover-animation-from-row-elements.yml
0 → 100644
View file @
707ce837
---
title
:
Remove hover animation from row elements
merge_request
:
author
:
changelogs/unreleased/9-0-api-changes.yml
0 → 100644
View file @
707ce837
---
title
:
Remove deprecated MR and Issue endpoints and preserve V3 namespace
merge_request
:
8967
author
:
changelogs/unreleased/pms-lowercase-system-notes.yml
0 → 100644
View file @
707ce837
---
title
:
Make all system notes lowercase
merge_request
:
8807
author
:
changelogs/unreleased/redesign-searchbar-admin-project-26794.yml
0 → 100644
View file @
707ce837
---
title
:
Redesign searchbar in admin project list
merge_request
:
8776
author
:
doc/api/issues.md
View file @
707ce837
...
@@ -181,7 +181,6 @@ GET /projects/:id/issues?labels=foo,bar
...
@@ -181,7 +181,6 @@ GET /projects/:id/issues?labels=foo,bar
GET /projects/:id/issues?labels=foo,bar&state=opened
GET /projects/:id/issues?labels=foo,bar&state=opened
GET /projects/:id/issues?milestone=1.0.0
GET /projects/:id/issues?milestone=1.0.0
GET /projects/:id/issues?milestone=1.0.0&state=opened
GET /projects/:id/issues?milestone=1.0.0&state=opened
GET /projects/:id/issues?iid=42
```
```
| Attribute | Type | Required | Description |
| Attribute | Type | Required | Description |
...
...
doc/api/merge_requests.md
View file @
707ce837
...
@@ -10,8 +10,7 @@ The pagination parameters `page` and `per_page` can be used to restrict the list
...
@@ -10,8 +10,7 @@ The pagination parameters `page` and `per_page` can be used to restrict the list
GET /projects/:id/merge_requests
GET /projects/:id/merge_requests
GET /projects/:id/merge_requests?state=opened
GET /projects/:id/merge_requests?state=opened
GET /projects/:id/merge_requests?state=all
GET /projects/:id/merge_requests?state=all
GET /projects/:id/merge_requests?iid=42
GET /projects/:id/merge_requests?iids[]=42&iids[]=43
GET /projects/:id/merge_requests?iid[]=42&iid[]=43
```
```
Parameters:
Parameters:
...
...
doc/api/v3_to_v4.md
View file @
707ce837
...
@@ -7,4 +7,7 @@ changes are in V4:
...
@@ -7,4 +7,7 @@ changes are in V4:
### Changes
### Changes
-
Removed
`/projects/:search`
(use:
`/projects?search=x`
)
-
Removed
`/projects/:search`
(use:
`/projects?search=x`
)
-
`iid`
filter has been removed from
`projects/:id/issues`
-
`projects/:id/merge_requests?iid[]=x&iid[]=y`
array filter has been renamed to
`iids`
-
Endpoints under
`projects/merge_request/:id`
have been removed (use:
`projects/merge_requests/:id`
)
lib/api/api.rb
View file @
707ce837
...
@@ -5,6 +5,8 @@ module API
...
@@ -5,6 +5,8 @@ module API
version
%w(v3 v4)
,
using: :path
version
%w(v3 v4)
,
using: :path
version
'v3'
,
using: :path
do
version
'v3'
,
using: :path
do
mount
::
API
::
V3
::
Issues
mount
::
API
::
V3
::
MergeRequests
mount
::
API
::
V3
::
Projects
mount
::
API
::
V3
::
Projects
end
end
...
...
lib/api/issues.rb
View file @
707ce837
...
@@ -15,8 +15,6 @@ module API
...
@@ -15,8 +15,6 @@ module API
labels
=
args
.
delete
(
:labels
)
labels
=
args
.
delete
(
:labels
)
args
[
:label_name
]
=
labels
if
match_all_labels
args
[
:label_name
]
=
labels
if
match_all_labels
args
[
:search
]
=
"
#{
Issue
.
reference_prefix
}#{
args
.
delete
(
:iid
)
}
"
if
args
.
key?
(
:iid
)
issues
=
IssuesFinder
.
new
(
current_user
,
args
).
execute
.
inc_notes_with_associations
issues
=
IssuesFinder
.
new
(
current_user
,
args
).
execute
.
inc_notes_with_associations
# TODO: Remove in 9.0 pass `label_name: args.delete(:labels)` to IssuesFinder
# TODO: Remove in 9.0 pass `label_name: args.delete(:labels)` to IssuesFinder
...
@@ -97,7 +95,6 @@ module API
...
@@ -97,7 +95,6 @@ module API
params
do
params
do
optional
:state
,
type:
String
,
values:
%w[opened closed all]
,
default:
'all'
,
optional
:state
,
type:
String
,
values:
%w[opened closed all]
,
default:
'all'
,
desc:
'Return opened, closed, or all issues'
desc:
'Return opened, closed, or all issues'
optional
:iid
,
type:
Integer
,
desc:
'Return the issue having the given `iid`'
use
:issues_params
use
:issues_params
end
end
get
":id/issues"
do
get
":id/issues"
do
...
...
lib/api/merge_requests.rb
View file @
707ce837
...
@@ -2,8 +2,6 @@ module API
...
@@ -2,8 +2,6 @@ module API
class
MergeRequests
<
Grape
::
API
class
MergeRequests
<
Grape
::
API
include
PaginationParams
include
PaginationParams
DEPRECATION_MESSAGE
=
'This endpoint is deprecated and will be removed in GitLab 9.0.'
.
freeze
before
{
authenticate!
}
before
{
authenticate!
}
params
do
params
do
...
@@ -46,14 +44,14 @@ module API
...
@@ -46,14 +44,14 @@ module API
desc:
'Return merge requests ordered by `created_at` or `updated_at` fields.'
desc:
'Return merge requests ordered by `created_at` or `updated_at` fields.'
optional
:sort
,
type:
String
,
values:
%w[asc desc]
,
default:
'desc'
,
optional
:sort
,
type:
String
,
values:
%w[asc desc]
,
default:
'desc'
,
desc:
'Return merge requests sorted in `asc` or `desc` order.'
desc:
'Return merge requests sorted in `asc` or `desc` order.'
optional
:iid
,
type:
Array
[
Integer
],
desc:
'The IID of the
merge requests'
optional
:iid
s
,
type:
Array
[
Integer
],
desc:
'The IID array of
merge requests'
use
:pagination
use
:pagination
end
end
get
":id/merge_requests"
do
get
":id/merge_requests"
do
authorize!
:read_merge_request
,
user_project
authorize!
:read_merge_request
,
user_project
merge_requests
=
user_project
.
merge_requests
.
inc_notes_with_associations
merge_requests
=
user_project
.
merge_requests
.
inc_notes_with_associations
merge_requests
=
filter_by_iid
(
merge_requests
,
params
[
:iid
])
if
params
[
:iid
].
present?
merge_requests
=
filter_by_iid
(
merge_requests
,
params
[
:iid
s
])
if
params
[
:iids
].
present?
merge_requests
=
merge_requests
=
case
params
[
:state
]
case
params
[
:state
]
...
@@ -104,177 +102,167 @@ module API
...
@@ -104,177 +102,167 @@ module API
merge_request
.
destroy
merge_request
.
destroy
end
end
# Routing "merge_request/:merge_request_id/..." is DEPRECATED and WILL BE REMOVED in version 9.0
# Use "merge_requests/:merge_request_id/..." instead.
#
params
do
params
do
requires
:merge_request_id
,
type:
Integer
,
desc:
'The ID of a merge request'
requires
:merge_request_id
,
type:
Integer
,
desc:
'The ID of a merge request'
end
end
{
":id/merge_request/:merge_request_id"
=>
:deprecated
,
":id/merge_requests/:merge_request_id"
=>
:ok
}.
each
do
|
path
,
status
|
desc
'Get a single merge request'
do
desc
'Get a single merge request'
do
success
Entities
::
MergeRequest
if
status
==
:deprecated
end
detail
DEPRECATION_MESSAGE
get
':id/merge_requests/:merge_request_id'
do
end
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
success
Entities
::
MergeRequest
end
get
path
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
present
merge_request
,
with:
Entities
::
MergeRequest
,
current_user:
current_user
,
project:
user_project
present
merge_request
,
with:
Entities
::
MergeRequest
,
current_user:
current_user
,
project:
user_project
end
end
desc
'Get the commits of a merge request'
do
desc
'Get the commits of a merge request'
do
success
Entities
::
RepoCommit
success
Entities
::
RepoCommit
end
end
get
"
#{
path
}
/commits"
do
get
':id/merge_requests/:merge_request_id/commits'
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
present
merge_request
.
commits
,
with:
Entities
::
RepoCommit
present
merge_request
.
commits
,
with:
Entities
::
RepoCommit
end
end
desc
'Show the merge request changes'
do
desc
'Show the merge request changes'
do
success
Entities
::
MergeRequestChanges
success
Entities
::
MergeRequestChanges
end
end
get
"
#{
path
}
/changes"
do
get
':id/merge_requests/:merge_request_id/changes'
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
present
merge_request
,
with:
Entities
::
MergeRequestChanges
,
current_user:
current_user
present
merge_request
,
with:
Entities
::
MergeRequestChanges
,
current_user:
current_user
end
end
desc
'Update a merge request'
do
desc
'Update a merge request'
do
success
Entities
::
MergeRequest
success
Entities
::
MergeRequest
end
end
params
do
params
do
optional
:title
,
type:
String
,
allow_blank:
false
,
desc:
'The title of the merge request'
optional
:title
,
type:
String
,
allow_blank:
false
,
desc:
'The title of the merge request'
optional
:target_branch
,
type:
String
,
allow_blank:
false
,
desc:
'The target branch'
optional
:target_branch
,
type:
String
,
allow_blank:
false
,
desc:
'The target branch'
optional
:state_event
,
type:
String
,
values:
%w[close reopen merge]
,
optional
:state_event
,
type:
String
,
values:
%w[close reopen merge]
,
desc:
'Status of the merge request'
desc:
'Status of the merge request'
use
:optional_params
use
:optional_params
at_least_one_of
:title
,
:target_branch
,
:description
,
:assignee_id
,
at_least_one_of
:title
,
:target_branch
,
:description
,
:assignee_id
,
:milestone_id
,
:labels
,
:state_event
,
:milestone_id
,
:labels
,
:state_event
,
:remove_source_branch
:remove_source_branch
end
end
put
path
do
put
':id/merge_requests/:merge_request_id'
do
merge_request
=
find_merge_request_with_access
(
params
.
delete
(
:merge_request_id
),
:update_merge_request
)
merge_request
=
find_merge_request_with_access
(
params
.
delete
(
:merge_request_id
),
:update_merge_request
)
mr_params
=
declared_params
(
include_missing:
false
)
mr_params
=
declared_params
(
include_missing:
false
)
mr_params
[
:force_remove_source_branch
]
=
mr_params
.
delete
(
:remove_source_branch
)
if
mr_params
[
:remove_source_branch
].
present?
mr_params
[
:force_remove_source_branch
]
=
mr_params
.
delete
(
:remove_source_branch
)
if
mr_params
[
:remove_source_branch
].
present?
merge_request
=
::
MergeRequests
::
UpdateService
.
new
(
user_project
,
current_user
,
mr_params
).
execute
(
merge_request
)
merge_request
=
::
MergeRequests
::
UpdateService
.
new
(
user_project
,
current_user
,
mr_params
).
execute
(
merge_request
)
if
merge_request
.
valid?
if
merge_request
.
valid?
present
merge_request
,
with:
Entities
::
MergeRequest
,
current_user:
current_user
,
project:
user_project
present
merge_request
,
with:
Entities
::
MergeRequest
,
current_user:
current_user
,
project:
user_project
else
else
handle_merge_request_errors!
merge_request
.
errors
handle_merge_request_errors!
merge_request
.
errors
end
end
end
end
desc
'Merge a merge request'
do
desc
'Merge a merge request'
do
success
Entities
::
MergeRequest
success
Entities
::
MergeRequest
end
end
params
do
params
do
optional
:merge_commit_message
,
type:
String
,
desc:
'Custom merge commit message'
optional
:merge_commit_message
,
type:
String
,
desc:
'Custom merge commit message'
optional
:should_remove_source_branch
,
type:
Boolean
,
optional
:should_remove_source_branch
,
type:
Boolean
,
desc:
'When true, the source branch will be deleted if possible'
desc:
'When true, the source branch will be deleted if possible'
optional
:merge_when_build_succeeds
,
type:
Boolean
,
optional
:merge_when_build_succeeds
,
type:
Boolean
,
desc:
'When true, this merge request will be merged when the pipeline succeeds'
desc:
'When true, this merge request will be merged when the pipeline succeeds'
optional
:sha
,
type:
String
,
desc:
'When present, must have the HEAD SHA of the source branch'
optional
:sha
,
type:
String
,
desc:
'When present, must have the HEAD SHA of the source branch'
end
end
put
"
#{
path
}
/merge"
do
put
':id/merge_requests/:merge_request_id/merge'
do
merge_request
=
find_project_merge_request
(
params
[
:merge_request_id
])
merge_request
=
find_project_merge_request
(
params
[
:merge_request_id
])
# Merge request can not be merged
# Merge request can not be merged
# because user dont have permissions to push into target branch
# because user dont have permissions to push into target branch
unauthorized!
unless
merge_request
.
can_be_merged_by?
(
current_user
)
unauthorized!
unless
merge_request
.
can_be_merged_by?
(
current_user
)
not_allowed!
unless
merge_request
.
mergeable_state?
not_allowed!
unless
merge_request
.
mergeable_state?
render_api_error!
(
'Branch cannot be merged'
,
406
)
unless
merge_request
.
mergeable?
render_api_error!
(
'Branch cannot be merged'
,
406
)
unless
merge_request
.
mergeable?
if
params
[
:sha
]
&&
merge_request
.
diff_head_sha
!=
params
[
:sha
]
if
params
[
:sha
]
&&
merge_request
.
diff_head_sha
!=
params
[
:sha
]
render_api_error!
(
"SHA does not match HEAD of source branch:
#{
merge_request
.
diff_head_sha
}
"
,
409
)
render_api_error!
(
"SHA does not match HEAD of source branch:
#{
merge_request
.
diff_head_sha
}
"
,
409
)
end
end
merge_params
=
{
merge_params
=
{
commit_message:
params
[
:merge_commit_message
],
commit_message:
params
[
:merge_commit_message
],
should_remove_source_branch:
params
[
:should_remove_source_branch
]
should_remove_source_branch:
params
[
:should_remove_source_branch
]
}
}
if
params
[
:merge_when_build_succeeds
]
&&
merge_request
.
head_pipeline
&&
merge_request
.
head_pipeline
.
active?
::
MergeRequests
::
MergeWhenPipelineSucceedsService
.
new
(
merge_request
.
target_project
,
current_user
,
merge_params
)
.
execute
(
merge_request
)
else
::
MergeRequests
::
MergeService
.
new
(
merge_request
.
target_project
,
current_user
,
merge_params
)
.
execute
(
merge_request
)
end
present
merge_request
,
with:
Entities
::
MergeRequest
,
current_user:
current_user
,
project:
user_project
if
params
[
:merge_when_build_succeeds
]
&&
merge_request
.
head_pipeline
&&
merge_request
.
head_pipeline
.
active?
::
MergeRequests
::
MergeWhenPipelineSucceedsService
.
new
(
merge_request
.
target_project
,
current_user
,
merge_params
)
.
execute
(
merge_request
)
else
::
MergeRequests
::
MergeService
.
new
(
merge_request
.
target_project
,
current_user
,
merge_params
)
.
execute
(
merge_request
)
end
end
desc
'Cancel merge if "Merge When Pipeline Succeeds" is enabled'
do
present
merge_request
,
with:
Entities
::
MergeRequest
,
current_user:
current_user
,
project:
user_project
success
Entities
::
MergeRequest
end
end
post
"
#{
path
}
/cancel_merge_when_build_succeeds"
do
merge_request
=
find_project_merge_request
(
params
[
:merge_request_id
])
unauthorized!
unless
merge_request
.
can_cancel_merge_when_build_succeeds?
(
current_user
)
desc
'Cancel merge if "Merge When Pipeline Succeeds" is enabled'
do
success
Entities
::
MergeRequest
end
post
':id/merge_requests/:merge_request_id/cancel_merge_when_build_succeeds'
do
merge_request
=
find_project_merge_request
(
params
[
:merge_request_id
])
::
MergeRequest
::
MergeWhenPipelineSucceedsService
unauthorized!
unless
merge_request
.
can_cancel_merge_when_build_succeeds?
(
current_user
)
.
new
(
merge_request
.
target_project
,
current_user
)
.
cancel
(
merge_request
)
end
desc
'Get the comments of a merge request'
do
::
MergeRequest
::
MergeWhenPipelineSucceedsService
detail
'Duplicate. DEPRECATED and WILL BE REMOVED in 9.0'
.
new
(
merge_request
.
target_project
,
current_user
)
success
Entities
::
MRNote
.
cancel
(
merge_request
)
end
end
params
do
use
:pagination
end
get
"
#{
path
}
/comments"
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
present
paginate
(
merge_request
.
notes
.
fresh
),
with:
Entities
::
MRNote
end
desc
'Post a comment to a merge request'
do
desc
'Get the comments of a merge request'
do
detail
'Duplicate. DEPRECATED and WILL BE REMOVED in 9.0'
success
Entities
::
MRNote
success
Entities
::
MRNote
end
end
params
do
params
do
use
:pagination
requires
:note
,
type:
String
,
desc:
'The text of the comment'
end
end
get
':id/merge_requests/:merge_request_id/comments'
do
post
"
#{
path
}
/comments"
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
],
:create_note
)
present
paginate
(
merge_request
.
notes
.
fresh
),
with:
Entities
::
MRNote
end
opts
=
{
desc
'Post a comment to a merge request'
do
note:
params
[
:note
],
success
Entities
::
MRNote
noteable_type:
'MergeRequest'
,
end
noteable_id:
merge_request
.
id
params
do
}
requires
:note
,
type:
String
,
desc:
'The text of the comment'
end
post
':id/merge_requests/:merge_request_id/comments'
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
],
:create_note
)
note
=
::
Notes
::
CreateService
.
new
(
user_project
,
current_user
,
opts
).
execute
opts
=
{
note:
params
[
:note
],
noteable_type:
'MergeRequest'
,
noteable_id:
merge_request
.
id
}
if
note
.
save
note
=
::
Notes
::
CreateService
.
new
(
user_project
,
current_user
,
opts
).
execute
present
note
,
with:
Entities
::
MRNote
else
render_api_error!
(
"Failed to save note
#{
note
.
errors
.
messages
}
"
,
400
)
end
end
desc
'List issues that will be closed on merge'
do
if
note
.
save
success
Entities
::
MRNote
present
note
,
with:
Entities
::
MRNote
end
else
params
do
render_api_error!
(
"Failed to save note
#{
note
.
errors
.
messages
}
"
,
400
)
use
:pagination
end
get
"
#{
path
}
/closes_issues"
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
issues
=
::
Kaminari
.
paginate_array
(
merge_request
.
closes_issues
(
current_user
))
present
paginate
(
issues
),
with:
issue_entity
(
user_project
),
current_user:
current_user
end
end
end
end
desc
'List issues that will be closed on merge'
do
success
Entities
::
MRNote
end
params
do
use
:pagination
end
get
':id/merge_requests/:merge_request_id/closes_issues'
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
issues
=
::
Kaminari
.
paginate_array
(
merge_request
.
closes_issues
(
current_user
))
present
paginate
(
issues
),
with:
issue_entity
(
user_project
),
current_user:
current_user
end
end
end
end
end
end
end
lib/api/v3/issues.rb
0 → 100644
View file @
707ce837
module
API
module
V3
class
Issues
<
Grape
::
API
include
PaginationParams
before
{
authenticate!
}
helpers
do
def
find_issues
(
args
=
{})
args
=
params
.
merge
(
args
)
args
.
delete
(
:id
)
args
[
:milestone_title
]
=
args
.
delete
(
:milestone
)
match_all_labels
=
args
.
delete
(
:match_all_labels
)
labels
=
args
.
delete
(
:labels
)
args
[
:label_name
]
=
labels
if
match_all_labels
args
[
:search
]
=
"
#{
Issue
.
reference_prefix
}#{
args
.
delete
(
:iid
)
}
"
if
args
.
key?
(
:iid
)
issues
=
IssuesFinder
.
new
(
current_user
,
args
).
execute
.
inc_notes_with_associations
if
!
match_all_labels
&&
labels
.
present?
issues
=
issues
.
includes
(
:labels
).
where
(
'labels.title'
=>
labels
.
split
(
','
))
end
issues
.
reorder
(
args
[
:order_by
]
=>
args
[
:sort
])
end
params
:issues_params
do
optional
:labels
,
type:
String
,
desc:
'Comma-separated list of label names'
optional
:milestone
,
type:
String
,
desc:
'Milestone title'
optional
:order_by
,
type:
String
,
values:
%w[created_at updated_at]
,
default:
'created_at'
,
desc:
'Return issues ordered by `created_at` or `updated_at` fields.'
optional
:sort
,
type:
String
,
values:
%w[asc desc]
,
default:
'desc'
,
desc:
'Return issues sorted in `asc` or `desc` order.'
optional
:milestone
,
type:
String
,
desc:
'Return issues for a specific milestone'
use
:pagination
end
params
:issue_params
do
optional
:description
,
type:
String
,
desc:
'The description of an issue'
optional
:assignee_id
,
type:
Integer
,
desc:
'The ID of a user to assign issue'
optional
:milestone_id
,
type:
Integer
,
desc:
'The ID of a milestone to assign issue'
optional
:labels
,
type:
String
,
desc:
'Comma-separated list of label names'
optional
:due_date
,
type:
String
,
desc:
'Date time string in the format YEAR-MONTH-DAY'
optional
:confidential
,
type:
Boolean
,
desc:
'Boolean parameter if the issue should be confidential'
end
end
resource
:issues
do
desc
"Get currently authenticated user's issues"
do
success
Entities
::
Issue
end
params
do
optional
:state
,
type:
String
,
values:
%w[opened closed all]
,
default:
'all'
,
desc:
'Return opened, closed, or all issues'
use
:issues_params
end
get
do
issues
=
find_issues
(
scope:
'authored'
)
present
paginate
(
issues
),
with:
Entities
::
Issue
,
current_user:
current_user
end
end
params
do
requires
:id
,
type:
String
,
desc:
'The ID of a group'
end
resource
:groups
do
desc
'Get a list of group issues'
do
success
Entities
::
Issue
end
params
do
optional
:state
,
type:
String
,
values:
%w[opened closed all]
,
default:
'opened'
,
desc:
'Return opened, closed, or all issues'
use
:issues_params
end
get
":id/issues"
do
group
=
find_group!
(
params
[
:id
])
issues
=
find_issues
(
group_id:
group
.
id
,
state:
params
[
:state
]
||
'opened'
,
match_all_labels:
true
)
present
paginate
(
issues
),
with:
Entities
::
Issue
,
current_user:
current_user
end
end
params
do
requires
:id
,
type:
String
,
desc:
'The ID of a project'
end
resource
:projects
do
include
TimeTrackingEndpoints
desc
'Get a list of project issues'
do
detail
'iid filter is deprecated have been removed on V4'
success
Entities
::
Issue
end
params
do
optional
:state
,
type:
String
,
values:
%w[opened closed all]
,
default:
'all'
,
desc:
'Return opened, closed, or all issues'
optional
:iid
,
type:
Integer
,
desc:
'Return the issue having the given `iid`'
use
:issues_params
end
get
":id/issues"
do
project
=
find_project
(
params
[
:id
])
issues
=
find_issues
(
project_id:
project
.
id
)
present
paginate
(
issues
),
with:
Entities
::
Issue
,
current_user:
current_user
,
project:
user_project
end
desc
'Get a single project issue'
do
success
Entities
::
Issue
end
params
do
requires
:issue_id
,
type:
Integer
,
desc:
'The ID of a project issue'
end
get
":id/issues/:issue_id"
do
issue
=
find_project_issue
(
params
[
:issue_id
])
present
issue
,
with:
Entities
::
Issue
,
current_user:
current_user
,
project:
user_project
end
desc
'Create a new project issue'
do
success
Entities
::
Issue
end
params
do
requires
:title
,
type:
String
,
desc:
'The title of an issue'
optional
:created_at
,
type:
DateTime
,
desc:
'Date time when the issue was created. Available only for admins and project owners.'
optional
:merge_request_for_resolving_discussions
,
type:
Integer
,
desc:
'The IID of a merge request for which to resolve discussions'
use
:issue_params
end
post
':id/issues'
do
# Setting created_at time only allowed for admins and project owners
unless
current_user
.
admin?
||
user_project
.
owner
==
current_user
params
.
delete
(
:created_at
)
end
issue_params
=
declared_params
(
include_missing:
false
)
if
merge_request_iid
=
params
[
:merge_request_for_resolving_discussions
]
issue_params
[
:merge_request_for_resolving_discussions
]
=
MergeRequestsFinder
.
new
(
current_user
,
project_id:
user_project
.
id
).
execute
.
find_by
(
iid:
merge_request_iid
)
end
issue
=
::
Issues
::
CreateService
.
new
(
user_project
,
current_user
,
issue_params
.
merge
(
request:
request
,
api:
true
)).
execute
if
issue
.
spam?
render_api_error!
({
error:
'Spam detected'
},
400
)
end
if
issue
.
valid?
present
issue
,
with:
Entities
::
Issue
,
current_user:
current_user
,
project:
user_project
else
render_validation_error!
(
issue
)
end
end
desc
'Update an existing issue'
do
success
Entities
::
Issue
end
params
do
requires
:issue_id
,
type:
Integer
,
desc:
'The ID of a project issue'
optional
:title
,
type:
String
,
desc:
'The title of an issue'
optional
:updated_at
,
type:
DateTime
,
desc:
'Date time when the issue was updated. Available only for admins and project owners.'
optional
:state_event
,
type:
String
,
values:
%w[reopen close]
,
desc:
'State of the issue'
use
:issue_params
at_least_one_of
:title
,
:description
,
:assignee_id
,
:milestone_id
,
:labels
,
:created_at
,
:due_date
,
:confidential
,
:state_event
end
put
':id/issues/:issue_id'
do
issue
=
user_project
.
issues
.
find
(
params
.
delete
(
:issue_id
))
authorize!
:update_issue
,
issue
# Setting created_at time only allowed for admins and project owners
unless
current_user
.
admin?
||
user_project
.
owner
==
current_user
params
.
delete
(
:updated_at
)
end
issue
=
::
Issues
::
UpdateService
.
new
(
user_project
,
current_user
,
declared_params
(
include_missing:
false
)).
execute
(
issue
)
if
issue
.
valid?
present
issue
,
with:
Entities
::
Issue
,
current_user:
current_user
,
project:
user_project
else
render_validation_error!
(
issue
)
end
end
desc
'Move an existing issue'
do
success
Entities
::
Issue
end
params
do
requires
:issue_id
,
type:
Integer
,
desc:
'The ID of a project issue'
requires
:to_project_id
,
type:
Integer
,
desc:
'The ID of the new project'
end
post
':id/issues/:issue_id/move'
do
issue
=
user_project
.
issues
.
find_by
(
id:
params
[
:issue_id
])
not_found!
(
'Issue'
)
unless
issue
new_project
=
Project
.
find_by
(
id:
params
[
:to_project_id
])
not_found!
(
'Project'
)
unless
new_project
begin
issue
=
::
Issues
::
MoveService
.
new
(
user_project
,
current_user
).
execute
(
issue
,
new_project
)
present
issue
,
with:
Entities
::
Issue
,
current_user:
current_user
,
project:
user_project
rescue
::
Issues
::
MoveService
::
MoveError
=>
error
render_api_error!
(
error
.
message
,
400
)
end
end
desc
'Delete a project issue'
params
do
requires
:issue_id
,
type:
Integer
,
desc:
'The ID of a project issue'
end
delete
":id/issues/:issue_id"
do
issue
=
user_project
.
issues
.
find_by
(
id:
params
[
:issue_id
])
not_found!
(
'Issue'
)
unless
issue
authorize!
(
:destroy_issue
,
issue
)
issue
.
destroy
end
end
end
end
end
lib/api/v3/merge_requests.rb
0 → 100644
View file @
707ce837
module
API
module
V3
class
MergeRequests
<
Grape
::
API
include
PaginationParams
DEPRECATION_MESSAGE
=
'This endpoint is deprecated and has been removed on V4'
.
freeze
before
{
authenticate!
}
params
do
requires
:id
,
type:
String
,
desc:
'The ID of a project'
end
resource
:projects
do
include
TimeTrackingEndpoints
helpers
do
def
handle_merge_request_errors!
(
errors
)
if
errors
[
:project_access
].
any?
error!
(
errors
[
:project_access
],
422
)
elsif
errors
[
:branch_conflict
].
any?
error!
(
errors
[
:branch_conflict
],
422
)
elsif
errors
[
:validate_fork
].
any?
error!
(
errors
[
:validate_fork
],
422
)
elsif
errors
[
:validate_branches
].
any?
conflict!
(
errors
[
:validate_branches
])
end
render_api_error!
(
errors
,
400
)
end
params
:optional_params
do
optional
:description
,
type:
String
,
desc:
'The description of the merge request'
optional
:assignee_id
,
type:
Integer
,
desc:
'The ID of a user to assign the merge request'
optional
:milestone_id
,
type:
Integer
,
desc:
'The ID of a milestone to assign the merge request'
optional
:labels
,
type:
String
,
desc:
'Comma-separated list of label names'
optional
:remove_source_branch
,
type:
Boolean
,
desc:
'Remove source branch when merging'
end
end
desc
'List merge requests'
do
detail
'iid filter is deprecated have been removed on V4'
success
Entities
::
MergeRequest
end
params
do
optional
:state
,
type:
String
,
values:
%w[opened closed merged all]
,
default:
'all'
,
desc:
'Return opened, closed, merged, or all merge requests'
optional
:order_by
,
type:
String
,
values:
%w[created_at updated_at]
,
default:
'created_at'
,
desc:
'Return merge requests ordered by `created_at` or `updated_at` fields.'
optional
:sort
,
type:
String
,
values:
%w[asc desc]
,
default:
'desc'
,
desc:
'Return merge requests sorted in `asc` or `desc` order.'
optional
:iid
,
type:
Array
[
Integer
],
desc:
'The IID of the merge requests'
use
:pagination
end
get
":id/merge_requests"
do
authorize!
:read_merge_request
,
user_project
merge_requests
=
user_project
.
merge_requests
.
inc_notes_with_associations
merge_requests
=
filter_by_iid
(
merge_requests
,
params
[
:iid
])
if
params
[
:iid
].
present?
merge_requests
=
case
params
[
:state
]
when
'opened'
then
merge_requests
.
opened
when
'closed'
then
merge_requests
.
closed
when
'merged'
then
merge_requests
.
merged
else
merge_requests
end
merge_requests
=
merge_requests
.
reorder
(
params
[
:order_by
]
=>
params
[
:sort
])
present
paginate
(
merge_requests
),
with:
Entities
::
MergeRequest
,
current_user:
current_user
,
project:
user_project
end
desc
'Create a merge request'
do
success
Entities
::
MergeRequest
end
params
do
requires
:title
,
type:
String
,
desc:
'The title of the merge request'
requires
:source_branch
,
type:
String
,
desc:
'The source branch'
requires
:target_branch
,
type:
String
,
desc:
'The target branch'
optional
:target_project_id
,
type:
Integer
,
desc:
'The target project of the merge request defaults to the :id of the project'
use
:optional_params
end
post
":id/merge_requests"
do
authorize!
:create_merge_request
,
user_project
mr_params
=
declared_params
(
include_missing:
false
)
mr_params
[
:force_remove_source_branch
]
=
mr_params
.
delete
(
:remove_source_branch
)
if
mr_params
[
:remove_source_branch
].
present?
merge_request
=
::
MergeRequests
::
CreateService
.
new
(
user_project
,
current_user
,
mr_params
).
execute
if
merge_request
.
valid?
present
merge_request
,
with:
Entities
::
MergeRequest
,
current_user:
current_user
,
project:
user_project
else
handle_merge_request_errors!
merge_request
.
errors
end
end
desc
'Delete a merge request'
params
do
requires
:merge_request_id
,
type:
Integer
,
desc:
'The ID of a merge request'
end
delete
":id/merge_requests/:merge_request_id"
do
merge_request
=
find_project_merge_request
(
params
[
:merge_request_id
])
authorize!
(
:destroy_merge_request
,
merge_request
)
merge_request
.
destroy
end
params
do
requires
:merge_request_id
,
type:
Integer
,
desc:
'The ID of a merge request'
end
{
":id/merge_request/:merge_request_id"
=>
:deprecated
,
":id/merge_requests/:merge_request_id"
=>
:ok
}.
each
do
|
path
,
status
|
desc
'Get a single merge request'
do
if
status
==
:deprecated
detail
DEPRECATION_MESSAGE
end
success
Entities
::
MergeRequest
end
get
path
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
present
merge_request
,
with:
Entities
::
MergeRequest
,
current_user:
current_user
,
project:
user_project
end
desc
'Get the commits of a merge request'
do
success
Entities
::
RepoCommit
end
get
"
#{
path
}
/commits"
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
present
merge_request
.
commits
,
with:
Entities
::
RepoCommit
end
desc
'Show the merge request changes'
do
success
Entities
::
MergeRequestChanges
end
get
"
#{
path
}
/changes"
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
present
merge_request
,
with:
Entities
::
MergeRequestChanges
,
current_user:
current_user
end
desc
'Update a merge request'
do
success
Entities
::
MergeRequest
end
params
do
optional
:title
,
type:
String
,
allow_blank:
false
,
desc:
'The title of the merge request'
optional
:target_branch
,
type:
String
,
allow_blank:
false
,
desc:
'The target branch'
optional
:state_event
,
type:
String
,
values:
%w[close reopen merge]
,
desc:
'Status of the merge request'
use
:optional_params
at_least_one_of
:title
,
:target_branch
,
:description
,
:assignee_id
,
:milestone_id
,
:labels
,
:state_event
,
:remove_source_branch
end
put
path
do
merge_request
=
find_merge_request_with_access
(
params
.
delete
(
:merge_request_id
),
:update_merge_request
)
mr_params
=
declared_params
(
include_missing:
false
)
mr_params
[
:force_remove_source_branch
]
=
mr_params
.
delete
(
:remove_source_branch
)
if
mr_params
[
:remove_source_branch
].
present?
merge_request
=
::
MergeRequests
::
UpdateService
.
new
(
user_project
,
current_user
,
mr_params
).
execute
(
merge_request
)
if
merge_request
.
valid?
present
merge_request
,
with:
Entities
::
MergeRequest
,
current_user:
current_user
,
project:
user_project
else
handle_merge_request_errors!
merge_request
.
errors
end
end
desc
'Merge a merge request'
do
success
Entities
::
MergeRequest
end
params
do
optional
:merge_commit_message
,
type:
String
,
desc:
'Custom merge commit message'
optional
:should_remove_source_branch
,
type:
Boolean
,
desc:
'When true, the source branch will be deleted if possible'
optional
:merge_when_build_succeeds
,
type:
Boolean
,
desc:
'When true, this merge request will be merged when the pipeline succeeds'
optional
:sha
,
type:
String
,
desc:
'When present, must have the HEAD SHA of the source branch'
end
put
"
#{
path
}
/merge"
do
merge_request
=
find_project_merge_request
(
params
[
:merge_request_id
])
# Merge request can not be merged
# because user dont have permissions to push into target branch
unauthorized!
unless
merge_request
.
can_be_merged_by?
(
current_user
)
not_allowed!
unless
merge_request
.
mergeable_state?
render_api_error!
(
'Branch cannot be merged'
,
406
)
unless
merge_request
.
mergeable?
if
params
[
:sha
]
&&
merge_request
.
diff_head_sha
!=
params
[
:sha
]
render_api_error!
(
"SHA does not match HEAD of source branch:
#{
merge_request
.
diff_head_sha
}
"
,
409
)
end
merge_params
=
{
commit_message:
params
[
:merge_commit_message
],
should_remove_source_branch:
params
[
:should_remove_source_branch
]
}
if
params
[
:merge_when_build_succeeds
]
&&
merge_request
.
head_pipeline
&&
merge_request
.
head_pipeline
.
active?
::
MergeRequests
::
MergeWhenPipelineSucceedsService
.
new
(
merge_request
.
target_project
,
current_user
,
merge_params
)
.
execute
(
merge_request
)
else
::
MergeRequests
::
MergeService
.
new
(
merge_request
.
target_project
,
current_user
,
merge_params
)
.
execute
(
merge_request
)
end
present
merge_request
,
with:
Entities
::
MergeRequest
,
current_user:
current_user
,
project:
user_project
end
desc
'Cancel merge if "Merge When Pipeline Succeeds" is enabled'
do
success
Entities
::
MergeRequest
end
post
"
#{
path
}
/cancel_merge_when_build_succeeds"
do
merge_request
=
find_project_merge_request
(
params
[
:merge_request_id
])
unauthorized!
unless
merge_request
.
can_cancel_merge_when_build_succeeds?
(
current_user
)
::
MergeRequest
::
MergeWhenPipelineSucceedsService
.
new
(
merge_request
.
target_project
,
current_user
)
.
cancel
(
merge_request
)
end
desc
'Get the comments of a merge request'
do
detail
'Duplicate. DEPRECATED and HAS BEEN REMOVED in V4'
success
Entities
::
MRNote
end
params
do
use
:pagination
end
get
"
#{
path
}
/comments"
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
present
paginate
(
merge_request
.
notes
.
fresh
),
with:
Entities
::
MRNote
end
desc
'Post a comment to a merge request'
do
detail
'Duplicate. DEPRECATED and HAS BEEN REMOVED in V4'
success
Entities
::
MRNote
end
params
do
requires
:note
,
type:
String
,
desc:
'The text of the comment'
end
post
"
#{
path
}
/comments"
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
],
:create_note
)
opts
=
{
note:
params
[
:note
],
noteable_type:
'MergeRequest'
,
noteable_id:
merge_request
.
id
}
note
=
::
Notes
::
CreateService
.
new
(
user_project
,
current_user
,
opts
).
execute
if
note
.
save
present
note
,
with:
Entities
::
MRNote
else
render_api_error!
(
"Failed to save note
#{
note
.
errors
.
messages
}
"
,
400
)
end
end
desc
'List issues that will be closed on merge'
do
success
Entities
::
MRNote
end
params
do
use
:pagination
end
get
"
#{
path
}
/closes_issues"
do
merge_request
=
find_merge_request_with_access
(
params
[
:merge_request_id
])
issues
=
::
Kaminari
.
paginate_array
(
merge_request
.
closes_issues
(
current_user
))
present
paginate
(
issues
),
with:
issue_entity
(
user_project
),
current_user:
current_user
end
end
end
end
end
end
spec/requests/api/issues_spec.rb
View file @
707ce837
...
@@ -612,23 +612,6 @@ describe API::Issues, api: true do
...
@@ -612,23 +612,6 @@ describe API::Issues, api: true do
expect
(
json_response
[
'iid'
]).
to
eq
(
issue
.
iid
)
expect
(
json_response
[
'iid'
]).
to
eq
(
issue
.
iid
)
end
end
it
'returns a project issue by iid'
do
get
api
(
"/projects/
#{
project
.
id
}
/issues?iid=
#{
issue
.
iid
}
"
,
user
)
expect
(
response
.
status
).
to
eq
200
expect
(
json_response
.
length
).
to
eq
1
expect
(
json_response
.
first
[
'title'
]).
to
eq
issue
.
title
expect
(
json_response
.
first
[
'id'
]).
to
eq
issue
.
id
expect
(
json_response
.
first
[
'iid'
]).
to
eq
issue
.
iid
end
it
'returns an empty array for an unknown project issue iid'
do
get
api
(
"/projects/
#{
project
.
id
}
/issues?iid=
#{
issue
.
iid
+
10
}
"
,
user
)
expect
(
response
.
status
).
to
eq
200
expect
(
json_response
.
length
).
to
eq
0
end
it
"returns 404 if issue id not found"
do
it
"returns 404 if issue id not found"
do
get
api
(
"/projects/
#{
project
.
id
}
/issues/54321"
,
user
)
get
api
(
"/projects/
#{
project
.
id
}
/issues/54321"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
expect
(
response
).
to
have_http_status
(
404
)
...
...
spec/requests/api/merge_requests_spec.rb
View file @
707ce837
...
@@ -73,6 +73,16 @@ describe API::MergeRequests, api: true do
...
@@ -73,6 +73,16 @@ describe API::MergeRequests, api: true do
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
merge_request_merged
.
title
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
merge_request_merged
.
title
)
end
end
it
'returns merge_request by "iids" array'
do
get
api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
iids:
[
merge_request
.
iid
,
merge_request_closed
.
iid
]
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
merge_request_closed
.
title
expect
(
json_response
.
first
[
'id'
]).
to
eq
merge_request_closed
.
id
end
context
"with ordering"
do
context
"with ordering"
do
before
do
before
do
@mr_later
=
mr_with_later_created_and_updated_at_time
@mr_later
=
mr_with_later_created_and_updated_at_time
...
@@ -159,24 +169,6 @@ describe API::MergeRequests, api: true do
...
@@ -159,24 +169,6 @@ describe API::MergeRequests, api: true do
expect
(
json_response
[
'force_close_merge_request'
]).
to
be_falsy
expect
(
json_response
[
'force_close_merge_request'
]).
to
be_falsy
end
end
it
'returns merge_request by iid'
do
url
=
"/projects/
#{
project
.
id
}
/merge_requests?iid=
#{
merge_request
.
iid
}
"
get
api
(
url
,
user
)
expect
(
response
.
status
).
to
eq
200
expect
(
json_response
.
first
[
'title'
]).
to
eq
merge_request
.
title
expect
(
json_response
.
first
[
'id'
]).
to
eq
merge_request
.
id
end
it
'returns merge_request by iid array'
do
get
api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
iid:
[
merge_request
.
iid
,
merge_request_closed
.
iid
]
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
merge_request_closed
.
title
expect
(
json_response
.
first
[
'id'
]).
to
eq
merge_request_closed
.
id
end
it
"returns a 404 error if merge_request_id not found"
do
it
"returns a 404 error if merge_request_id not found"
do
get
api
(
"/projects/
#{
project
.
id
}
/merge_requests/999"
,
user
)
get
api
(
"/projects/
#{
project
.
id
}
/merge_requests/999"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
expect
(
response
).
to
have_http_status
(
404
)
...
...
spec/requests/api/v3/issues_spec.rb
0 → 100644
View file @
707ce837
require
'spec_helper'
describe
API
::
V3
::
Issues
,
api:
true
do
include
ApiHelpers
include
EmailHelpers
let
(
:user
)
{
create
(
:user
)
}
let
(
:user2
)
{
create
(
:user
)
}
let
(
:non_member
)
{
create
(
:user
)
}
let
(
:guest
)
{
create
(
:user
)
}
let
(
:author
)
{
create
(
:author
)
}
let
(
:assignee
)
{
create
(
:assignee
)
}
let
(
:admin
)
{
create
(
:user
,
:admin
)
}
let!
(
:project
)
{
create
(
:empty_project
,
:public
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let!
(
:closed_issue
)
do
create
:closed_issue
,
author:
user
,
assignee:
user
,
project:
project
,
state: :closed
,
milestone:
milestone
,
created_at:
generate
(
:issue_created_at
),
updated_at:
3
.
hours
.
ago
end
let!
(
:confidential_issue
)
do
create
:issue
,
:confidential
,
project:
project
,
author:
author
,
assignee:
assignee
,
created_at:
generate
(
:issue_created_at
),
updated_at:
2
.
hours
.
ago
end
let!
(
:issue
)
do
create
:issue
,
author:
user
,
assignee:
user
,
project:
project
,
milestone:
milestone
,
created_at:
generate
(
:issue_created_at
),
updated_at:
1
.
hour
.
ago
end
let!
(
:label
)
do
create
(
:label
,
title:
'label'
,
color:
'#FFAABB'
,
project:
project
)
end
let!
(
:label_link
)
{
create
(
:label_link
,
label:
label
,
target:
issue
)
}
let!
(
:milestone
)
{
create
(
:milestone
,
title:
'1.0.0'
,
project:
project
)
}
let!
(
:empty_milestone
)
do
create
(
:milestone
,
title:
'2.0.0'
,
project:
project
)
end
let!
(
:note
)
{
create
(
:note_on_issue
,
author:
user
,
project:
project
,
noteable:
issue
)
}
let
(
:no_milestone_title
)
{
URI
.
escape
(
Milestone
::
None
.
title
)
}
before
do
project
.
team
<<
[
user
,
:reporter
]
project
.
team
<<
[
guest
,
:guest
]
end
describe
"GET /issues"
do
context
"when unauthenticated"
do
it
"returns authentication error"
do
get
v3_api
(
"/issues"
)
expect
(
response
).
to
have_http_status
(
401
)
end
end
context
"when authenticated"
do
it
"returns an array of issues"
do
get
v3_api
(
"/issues"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
issue
.
title
)
expect
(
json_response
.
last
).
to
have_key
(
'web_url'
)
end
it
'returns an array of closed issues'
do
get
v3_api
(
'/issues?state=closed'
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
closed_issue
.
id
)
end
it
'returns an array of opened issues'
do
get
v3_api
(
'/issues?state=opened'
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
issue
.
id
)
end
it
'returns an array of all issues'
do
get
v3_api
(
'/issues?state=all'
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
issue
.
id
)
expect
(
json_response
.
second
[
'id'
]).
to
eq
(
closed_issue
.
id
)
end
it
'returns an array of labeled issues'
do
get
v3_api
(
"/issues?labels=
#{
label
.
title
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'labels'
]).
to
eq
([
label
.
title
])
end
it
'returns an array of labeled issues when at least one label matches'
do
get
v3_api
(
"/issues?labels=
#{
label
.
title
}
,foo,bar"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'labels'
]).
to
eq
([
label
.
title
])
end
it
'returns an empty array if no issue matches labels'
do
get
v3_api
(
'/issues?labels=foo,bar'
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'returns an array of labeled issues matching given state'
do
get
v3_api
(
"/issues?labels=
#{
label
.
title
}
&state=opened"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'labels'
]).
to
eq
([
label
.
title
])
expect
(
json_response
.
first
[
'state'
]).
to
eq
(
'opened'
)
end
it
'returns an empty array if no issue matches labels and state filters'
do
get
v3_api
(
"/issues?labels=
#{
label
.
title
}
&state=closed"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'returns an empty array if no issue matches milestone'
do
get
v3_api
(
"/issues?milestone=
#{
empty_milestone
.
title
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'returns an empty array if milestone does not exist'
do
get
v3_api
(
"/issues?milestone=foo"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'returns an array of issues in given milestone'
do
get
v3_api
(
"/issues?milestone=
#{
milestone
.
title
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
issue
.
id
)
expect
(
json_response
.
second
[
'id'
]).
to
eq
(
closed_issue
.
id
)
end
it
'returns an array of issues matching state in milestone'
do
get
v3_api
(
"/issues?milestone=
#{
milestone
.
title
}
"
,
user
),
'&state=closed'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
closed_issue
.
id
)
end
it
'returns an array of issues with no milestone'
do
get
v3_api
(
"/issues?milestone=
#{
no_milestone_title
}
"
,
author
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
confidential_issue
.
id
)
end
it
'sorts by created_at descending by default'
do
get
v3_api
(
'/issues'
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'created_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
.
reverse
)
end
it
'sorts ascending when requested'
do
get
v3_api
(
'/issues?sort=asc'
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'created_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
)
end
it
'sorts by updated_at descending when requested'
do
get
v3_api
(
'/issues?order_by=updated_at'
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'updated_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
.
reverse
)
end
it
'sorts by updated_at ascending when requested'
do
get
v3_api
(
'/issues?order_by=updated_at&sort=asc'
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'updated_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
)
end
end
end
describe
"GET /groups/:id/issues"
do
let!
(
:group
)
{
create
(
:group
)
}
let!
(
:group_project
)
{
create
(
:empty_project
,
:public
,
creator_id:
user
.
id
,
namespace:
group
)
}
let!
(
:group_closed_issue
)
do
create
:closed_issue
,
author:
user
,
assignee:
user
,
project:
group_project
,
state: :closed
,
milestone:
group_milestone
,
updated_at:
3
.
hours
.
ago
end
let!
(
:group_confidential_issue
)
do
create
:issue
,
:confidential
,
project:
group_project
,
author:
author
,
assignee:
assignee
,
updated_at:
2
.
hours
.
ago
end
let!
(
:group_issue
)
do
create
:issue
,
author:
user
,
assignee:
user
,
project:
group_project
,
milestone:
group_milestone
,
updated_at:
1
.
hour
.
ago
end
let!
(
:group_label
)
do
create
(
:label
,
title:
'group_lbl'
,
color:
'#FFAABB'
,
project:
group_project
)
end
let!
(
:group_label_link
)
{
create
(
:label_link
,
label:
group_label
,
target:
group_issue
)
}
let!
(
:group_milestone
)
{
create
(
:milestone
,
title:
'3.0.0'
,
project:
group_project
)
}
let!
(
:group_empty_milestone
)
do
create
(
:milestone
,
title:
'4.0.0'
,
project:
group_project
)
end
let!
(
:group_note
)
{
create
(
:note_on_issue
,
author:
user
,
project:
group_project
,
noteable:
group_issue
)
}
before
do
group_project
.
team
<<
[
user
,
:reporter
]
end
let
(
:base_url
)
{
"/groups/
#{
group
.
id
}
/issues"
}
it
'returns group issues without confidential issues for non project members'
do
get
v3_api
(
base_url
,
non_member
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
group_issue
.
title
)
end
it
'returns group confidential issues for author'
do
get
v3_api
(
base_url
,
author
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
end
it
'returns group confidential issues for assignee'
do
get
v3_api
(
base_url
,
assignee
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
end
it
'returns group issues with confidential issues for project members'
do
get
v3_api
(
base_url
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
end
it
'returns group confidential issues for admin'
do
get
v3_api
(
base_url
,
admin
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
end
it
'returns an array of labeled group issues'
do
get
v3_api
(
"
#{
base_url
}
?labels=
#{
group_label
.
title
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'labels'
]).
to
eq
([
group_label
.
title
])
end
it
'returns an array of labeled group issues where all labels match'
do
get
v3_api
(
"
#{
base_url
}
?labels=
#{
group_label
.
title
}
,foo,bar"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'returns an empty array if no group issue matches labels'
do
get
v3_api
(
"
#{
base_url
}
?labels=foo,bar"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'returns an empty array if no issue matches milestone'
do
get
v3_api
(
"
#{
base_url
}
?milestone=
#{
group_empty_milestone
.
title
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'returns an empty array if milestone does not exist'
do
get
v3_api
(
"
#{
base_url
}
?milestone=foo"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'returns an array of issues in given milestone'
do
get
v3_api
(
"
#{
base_url
}
?milestone=
#{
group_milestone
.
title
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
group_issue
.
id
)
end
it
'returns an array of issues matching state in milestone'
do
get
v3_api
(
"
#{
base_url
}
?milestone=
#{
group_milestone
.
title
}
"
,
user
),
'&state=closed'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
group_closed_issue
.
id
)
end
it
'returns an array of issues with no milestone'
do
get
v3_api
(
"
#{
base_url
}
?milestone=
#{
no_milestone_title
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
group_confidential_issue
.
id
)
end
it
'sorts by created_at descending by default'
do
get
v3_api
(
base_url
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'created_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
.
reverse
)
end
it
'sorts ascending when requested'
do
get
v3_api
(
"
#{
base_url
}
?sort=asc"
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'created_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
)
end
it
'sorts by updated_at descending when requested'
do
get
v3_api
(
"
#{
base_url
}
?order_by=updated_at"
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'updated_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
.
reverse
)
end
it
'sorts by updated_at ascending when requested'
do
get
v3_api
(
"
#{
base_url
}
?order_by=updated_at&sort=asc"
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'updated_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
)
end
end
describe
"GET /projects/:id/issues"
do
let
(
:base_url
)
{
"/projects/
#{
project
.
id
}
"
}
it
"returns 404 on private projects for other users"
do
private_project
=
create
(
:empty_project
,
:private
)
create
(
:issue
,
project:
private_project
)
get
v3_api
(
"/projects/
#{
private_project
.
id
}
/issues"
,
non_member
)
expect
(
response
).
to
have_http_status
(
404
)
end
it
'returns no issues when user has access to project but not issues'
do
restricted_project
=
create
(
:empty_project
,
:public
,
issues_access_level:
ProjectFeature
::
PRIVATE
)
create
(
:issue
,
project:
restricted_project
)
get
v3_api
(
"/projects/
#{
restricted_project
.
id
}
/issues"
,
non_member
)
expect
(
json_response
).
to
eq
([])
end
it
'returns project issues without confidential issues for non project members'
do
get
v3_api
(
"
#{
base_url
}
/issues"
,
non_member
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
issue
.
title
)
end
it
'returns project issues without confidential issues for project members with guest role'
do
get
v3_api
(
"
#{
base_url
}
/issues"
,
guest
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
issue
.
title
)
end
it
'returns project confidential issues for author'
do
get
v3_api
(
"
#{
base_url
}
/issues"
,
author
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
3
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
issue
.
title
)
end
it
'returns project confidential issues for assignee'
do
get
v3_api
(
"
#{
base_url
}
/issues"
,
assignee
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
3
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
issue
.
title
)
end
it
'returns project issues with confidential issues for project members'
do
get
v3_api
(
"
#{
base_url
}
/issues"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
3
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
issue
.
title
)
end
it
'returns project confidential issues for admin'
do
get
v3_api
(
"
#{
base_url
}
/issues"
,
admin
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
3
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
issue
.
title
)
end
it
'returns an array of labeled project issues'
do
get
v3_api
(
"
#{
base_url
}
/issues?labels=
#{
label
.
title
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'labels'
]).
to
eq
([
label
.
title
])
end
it
'returns an array of labeled project issues where all labels match'
do
get
v3_api
(
"
#{
base_url
}
/issues?labels=
#{
label
.
title
}
,foo,bar"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'labels'
]).
to
eq
([
label
.
title
])
end
it
'returns an empty array if no project issue matches labels'
do
get
v3_api
(
"
#{
base_url
}
/issues?labels=foo,bar"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'returns an empty array if no issue matches milestone'
do
get
v3_api
(
"
#{
base_url
}
/issues?milestone=
#{
empty_milestone
.
title
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'returns an empty array if milestone does not exist'
do
get
v3_api
(
"
#{
base_url
}
/issues?milestone=foo"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'returns an array of issues in given milestone'
do
get
v3_api
(
"
#{
base_url
}
/issues?milestone=
#{
milestone
.
title
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
issue
.
id
)
expect
(
json_response
.
second
[
'id'
]).
to
eq
(
closed_issue
.
id
)
end
it
'returns an array of issues matching state in milestone'
do
get
v3_api
(
"
#{
base_url
}
/issues?milestone=
#{
milestone
.
title
}
"
,
user
),
'&state=closed'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
closed_issue
.
id
)
end
it
'returns an array of issues with no milestone'
do
get
v3_api
(
"
#{
base_url
}
/issues?milestone=
#{
no_milestone_title
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
confidential_issue
.
id
)
end
it
'sorts by created_at descending by default'
do
get
v3_api
(
"
#{
base_url
}
/issues"
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'created_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
.
reverse
)
end
it
'sorts ascending when requested'
do
get
v3_api
(
"
#{
base_url
}
/issues?sort=asc"
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'created_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
)
end
it
'sorts by updated_at descending when requested'
do
get
v3_api
(
"
#{
base_url
}
/issues?order_by=updated_at"
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'updated_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
.
reverse
)
end
it
'sorts by updated_at ascending when requested'
do
get
v3_api
(
"
#{
base_url
}
/issues?order_by=updated_at&sort=asc"
,
user
)
response_dates
=
json_response
.
map
{
|
issue
|
issue
[
'updated_at'
]
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
)
end
end
describe
"GET /projects/:id/issues/:issue_id"
do
it
'exposes known attributes'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'id'
]).
to
eq
(
issue
.
id
)
expect
(
json_response
[
'iid'
]).
to
eq
(
issue
.
iid
)
expect
(
json_response
[
'project_id'
]).
to
eq
(
issue
.
project
.
id
)
expect
(
json_response
[
'title'
]).
to
eq
(
issue
.
title
)
expect
(
json_response
[
'description'
]).
to
eq
(
issue
.
description
)
expect
(
json_response
[
'state'
]).
to
eq
(
issue
.
state
)
expect
(
json_response
[
'created_at'
]).
to
be_present
expect
(
json_response
[
'updated_at'
]).
to
be_present
expect
(
json_response
[
'labels'
]).
to
eq
(
issue
.
label_names
)
expect
(
json_response
[
'milestone'
]).
to
be_a
Hash
expect
(
json_response
[
'assignee'
]).
to
be_a
Hash
expect
(
json_response
[
'author'
]).
to
be_a
Hash
expect
(
json_response
[
'confidential'
]).
to
be_falsy
end
it
"returns a project issue by id"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
issue
.
title
)
expect
(
json_response
[
'iid'
]).
to
eq
(
issue
.
iid
)
end
it
'returns a project issue by iid'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/issues?iid=
#{
issue
.
iid
}
"
,
user
)
expect
(
response
.
status
).
to
eq
200
expect
(
json_response
.
length
).
to
eq
1
expect
(
json_response
.
first
[
'title'
]).
to
eq
issue
.
title
expect
(
json_response
.
first
[
'id'
]).
to
eq
issue
.
id
expect
(
json_response
.
first
[
'iid'
]).
to
eq
issue
.
iid
end
it
'returns an empty array for an unknown project issue iid'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/issues?iid=
#{
issue
.
iid
+
10
}
"
,
user
)
expect
(
response
.
status
).
to
eq
200
expect
(
json_response
.
length
).
to
eq
0
end
it
"returns 404 if issue id not found"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/issues/54321"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
context
'confidential issues'
do
it
"returns 404 for non project members"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
non_member
)
expect
(
response
).
to
have_http_status
(
404
)
end
it
"returns 404 for project members with guest role"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
guest
)
expect
(
response
).
to
have_http_status
(
404
)
end
it
"returns confidential issue for project members"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
confidential_issue
.
title
)
expect
(
json_response
[
'iid'
]).
to
eq
(
confidential_issue
.
iid
)
end
it
"returns confidential issue for author"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
author
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
confidential_issue
.
title
)
expect
(
json_response
[
'iid'
]).
to
eq
(
confidential_issue
.
iid
)
end
it
"returns confidential issue for assignee"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
assignee
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
confidential_issue
.
title
)
expect
(
json_response
[
'iid'
]).
to
eq
(
confidential_issue
.
iid
)
end
it
"returns confidential issue for admin"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
admin
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
confidential_issue
.
title
)
expect
(
json_response
[
'iid'
]).
to
eq
(
confidential_issue
.
iid
)
end
end
end
describe
"POST /projects/:id/issues"
do
it
'creates a new project issue'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
title:
'new issue'
,
labels:
'label, label2'
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'title'
]).
to
eq
(
'new issue'
)
expect
(
json_response
[
'description'
]).
to
be_nil
expect
(
json_response
[
'labels'
]).
to
eq
([
'label'
,
'label2'
])
expect
(
json_response
[
'confidential'
]).
to
be_falsy
end
it
'creates a new confidential project issue'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
title:
'new issue'
,
confidential:
true
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'title'
]).
to
eq
(
'new issue'
)
expect
(
json_response
[
'confidential'
]).
to
be_truthy
end
it
'creates a new confidential project issue with a different param'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
title:
'new issue'
,
confidential:
'y'
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'title'
]).
to
eq
(
'new issue'
)
expect
(
json_response
[
'confidential'
]).
to
be_truthy
end
it
'creates a public issue when confidential param is false'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
title:
'new issue'
,
confidential:
false
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'title'
]).
to
eq
(
'new issue'
)
expect
(
json_response
[
'confidential'
]).
to
be_falsy
end
it
'creates a public issue when confidential param is invalid'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
title:
'new issue'
,
confidential:
'foo'
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'error'
]).
to
eq
(
'confidential is invalid'
)
end
it
"sends notifications for subscribers of newly added labels"
do
label
=
project
.
labels
.
first
label
.
toggle_subscription
(
user2
,
project
)
perform_enqueued_jobs
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
title:
'new issue'
,
labels:
label
.
title
end
should_email
(
user2
)
end
it
"returns a 400 bad request if title not given"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
labels:
'label, label2'
expect
(
response
).
to
have_http_status
(
400
)
end
it
'allows special label names'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
title:
'new issue'
,
labels:
'label, label?, label&foo, ?, &'
expect
(
response
.
status
).
to
eq
(
201
)
expect
(
json_response
[
'labels'
]).
to
include
'label'
expect
(
json_response
[
'labels'
]).
to
include
'label?'
expect
(
json_response
[
'labels'
]).
to
include
'label&foo'
expect
(
json_response
[
'labels'
]).
to
include
'?'
expect
(
json_response
[
'labels'
]).
to
include
'&'
end
it
'returns 400 if title is too long'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
title:
'g'
*
256
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
][
'title'
]).
to
eq
([
'is too long (maximum is 255 characters)'
])
end
context
'resolving issues in a merge request'
do
let
(
:discussion
)
{
Discussion
.
for_diff_notes
([
create
(
:diff_note_on_merge_request
)]).
first
}
let
(
:merge_request
)
{
discussion
.
noteable
}
let
(
:project
)
{
merge_request
.
source_project
}
before
do
project
.
team
<<
[
user
,
:master
]
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
title:
'New Issue'
,
merge_request_for_resolving_discussions:
merge_request
.
iid
end
it
'creates a new project issue'
do
expect
(
response
).
to
have_http_status
(
:created
)
end
it
'resolves the discussions in a merge request'
do
discussion
.
first_note
.
reload
expect
(
discussion
.
resolved?
).
to
be
(
true
)
end
it
'assigns a description to the issue mentioning the merge request'
do
expect
(
json_response
[
'description'
]).
to
include
(
merge_request
.
to_reference
)
end
end
context
'with due date'
do
it
'creates a new project issue'
do
due_date
=
2
.
weeks
.
from_now
.
strftime
(
'%Y-%m-%d'
)
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
title:
'new issue'
,
due_date:
due_date
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'title'
]).
to
eq
(
'new issue'
)
expect
(
json_response
[
'description'
]).
to
be_nil
expect
(
json_response
[
'due_date'
]).
to
eq
(
due_date
)
end
end
context
'when an admin or owner makes the request'
do
it
'accepts the creation date to be set'
do
creation_time
=
2
.
weeks
.
ago
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
title:
'new issue'
,
labels:
'label, label2'
,
created_at:
creation_time
expect
(
response
).
to
have_http_status
(
201
)
expect
(
Time
.
parse
(
json_response
[
'created_at'
])).
to
be_like_time
(
creation_time
)
end
end
context
'the user can only read the issue'
do
it
'cannot create new labels'
do
expect
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
non_member
),
title:
'new issue'
,
labels:
'label, label2'
end
.
not_to
change
{
project
.
labels
.
count
}
end
end
end
describe
'POST /projects/:id/issues with spam filtering'
do
before
do
allow_any_instance_of
(
SpamService
).
to
receive
(
:check_for_spam?
).
and_return
(
true
)
allow_any_instance_of
(
AkismetService
).
to
receive_messages
(
is_spam?:
true
)
end
let
(
:params
)
do
{
title:
'new issue'
,
description:
'content here'
,
labels:
'label, label2'
}
end
it
"does not create a new project issue"
do
expect
{
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues"
,
user
),
params
}.
not_to
change
(
Issue
,
:count
)
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
({
"error"
=>
"Spam detected"
})
spam_logs
=
SpamLog
.
all
expect
(
spam_logs
.
count
).
to
eq
(
1
)
expect
(
spam_logs
[
0
].
title
).
to
eq
(
'new issue'
)
expect
(
spam_logs
[
0
].
description
).
to
eq
(
'content here'
)
expect
(
spam_logs
[
0
].
user
).
to
eq
(
user
)
expect
(
spam_logs
[
0
].
noteable_type
).
to
eq
(
'Issue'
)
end
end
describe
"PUT /projects/:id/issues/:issue_id to update only title"
do
it
"updates a project issue"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
title:
'updated title'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
'updated title'
)
end
it
"returns 404 error if issue id not found"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/44444"
,
user
),
title:
'updated title'
expect
(
response
).
to
have_http_status
(
404
)
end
it
'allows special label names'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
title:
'updated title'
,
labels:
'label, label?, label&foo, ?, &'
expect
(
response
.
status
).
to
eq
(
200
)
expect
(
json_response
[
'labels'
]).
to
include
'label'
expect
(
json_response
[
'labels'
]).
to
include
'label?'
expect
(
json_response
[
'labels'
]).
to
include
'label&foo'
expect
(
json_response
[
'labels'
]).
to
include
'?'
expect
(
json_response
[
'labels'
]).
to
include
'&'
end
context
'confidential issues'
do
it
"returns 403 for non project members"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
non_member
),
title:
'updated title'
expect
(
response
).
to
have_http_status
(
403
)
end
it
"returns 403 for project members with guest role"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
guest
),
title:
'updated title'
expect
(
response
).
to
have_http_status
(
403
)
end
it
"updates a confidential issue for project members"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
user
),
title:
'updated title'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
'updated title'
)
end
it
"updates a confidential issue for author"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
author
),
title:
'updated title'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
'updated title'
)
end
it
"updates a confidential issue for admin"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
admin
),
title:
'updated title'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
'updated title'
)
end
it
'sets an issue to confidential'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
confidential:
true
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'confidential'
]).
to
be_truthy
end
it
'makes a confidential issue public'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
user
),
confidential:
false
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'confidential'
]).
to
be_falsy
end
it
'does not update a confidential issue with wrong confidential flag'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
"
,
user
),
confidential:
'foo'
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'error'
]).
to
eq
(
'confidential is invalid'
)
end
end
end
describe
'PUT /projects/:id/issues/:issue_id to update labels'
do
let!
(
:label
)
{
create
(
:label
,
title:
'dummy'
,
project:
project
)
}
let!
(
:label_link
)
{
create
(
:label_link
,
label:
label
,
target:
issue
)
}
it
'does not update labels if not present'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
title:
'updated title'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'labels'
]).
to
eq
([
label
.
title
])
end
it
"sends notifications for subscribers of newly added labels when issue is updated"
do
label
=
create
(
:label
,
title:
'foo'
,
color:
'#FFAABB'
,
project:
project
)
label
.
toggle_subscription
(
user2
,
project
)
perform_enqueued_jobs
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
title:
'updated title'
,
labels:
label
.
title
end
should_email
(
user2
)
end
it
'removes all labels'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
labels:
''
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'labels'
]).
to
eq
([])
end
it
'updates labels'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
labels:
'foo,bar'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'labels'
]).
to
include
'foo'
expect
(
json_response
[
'labels'
]).
to
include
'bar'
end
it
'allows special label names'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
labels:
'label:foo, label-bar,label_bar,label/bar,label?bar,label&bar,?,&'
expect
(
response
.
status
).
to
eq
(
200
)
expect
(
json_response
[
'labels'
]).
to
include
'label:foo'
expect
(
json_response
[
'labels'
]).
to
include
'label-bar'
expect
(
json_response
[
'labels'
]).
to
include
'label_bar'
expect
(
json_response
[
'labels'
]).
to
include
'label/bar'
expect
(
json_response
[
'labels'
]).
to
include
'label?bar'
expect
(
json_response
[
'labels'
]).
to
include
'label&bar'
expect
(
json_response
[
'labels'
]).
to
include
'?'
expect
(
json_response
[
'labels'
]).
to
include
'&'
end
it
'returns 400 if title is too long'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
title:
'g'
*
256
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
][
'title'
]).
to
eq
([
'is too long (maximum is 255 characters)'
])
end
end
describe
"PUT /projects/:id/issues/:issue_id to update state and label"
do
it
"updates a project issue"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
labels:
'label2'
,
state_event:
"close"
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'labels'
]).
to
include
'label2'
expect
(
json_response
[
'state'
]).
to
eq
"closed"
end
it
'reopens a project isssue'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
closed_issue
.
id
}
"
,
user
),
state_event:
'reopen'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'state'
]).
to
eq
'reopened'
end
context
'when an admin or owner makes the request'
do
it
'accepts the update date to be set'
do
update_time
=
2
.
weeks
.
ago
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
labels:
'label3'
,
state_event:
'close'
,
updated_at:
update_time
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'labels'
]).
to
include
'label3'
expect
(
Time
.
parse
(
json_response
[
'updated_at'
])).
to
be_like_time
(
update_time
)
end
end
end
describe
'PUT /projects/:id/issues/:issue_id to update due date'
do
it
'creates a new project issue'
do
due_date
=
2
.
weeks
.
from_now
.
strftime
(
'%Y-%m-%d'
)
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
due_date:
due_date
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'due_date'
]).
to
eq
(
due_date
)
end
end
describe
"DELETE /projects/:id/issues/:issue_id"
do
it
"rejects a non member from deleting an issue"
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
non_member
)
expect
(
response
).
to
have_http_status
(
403
)
end
it
"rejects a developer from deleting an issue"
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
author
)
expect
(
response
).
to
have_http_status
(
403
)
end
context
"when the user is project owner"
do
let
(
:owner
)
{
create
(
:user
)
}
let
(
:project
)
{
create
(
:empty_project
,
namespace:
owner
.
namespace
)
}
it
"deletes the issue if an admin requests it"
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
owner
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'state'
]).
to
eq
'opened'
end
end
context
'when issue does not exist'
do
it
'returns 404 when trying to move an issue'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/issues/123"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
end
describe
'/projects/:id/issues/:issue_id/move'
do
let!
(
:target_project
)
{
create
(
:empty_project
,
path:
'project2'
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let!
(
:target_project2
)
{
create
(
:empty_project
,
creator_id:
non_member
.
id
,
namespace:
non_member
.
namespace
)
}
it
'moves an issue'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
/move"
,
user
),
to_project_id:
target_project
.
id
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'project_id'
]).
to
eq
(
target_project
.
id
)
end
context
'when source and target projects are the same'
do
it
'returns 400 when trying to move an issue'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
/move"
,
user
),
to_project_id:
project
.
id
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
(
'Cannot move issue to project it originates from!'
)
end
end
context
'when the user does not have the permission to move issues'
do
it
'returns 400 when trying to move an issue'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
/move"
,
user
),
to_project_id:
target_project2
.
id
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
(
'Cannot move issue due to insufficient permissions!'
)
end
end
it
'moves the issue to another namespace if I am admin'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
/move"
,
admin
),
to_project_id:
target_project2
.
id
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'project_id'
]).
to
eq
(
target_project2
.
id
)
end
context
'when issue does not exist'
do
it
'returns 404 when trying to move an issue'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/123/move"
,
user
),
to_project_id:
target_project
.
id
expect
(
response
).
to
have_http_status
(
404
)
expect
(
json_response
[
'message'
]).
to
eq
(
'404 Issue Not Found'
)
end
end
context
'when source project does not exist'
do
it
'returns 404 when trying to move an issue'
do
post
v3_api
(
"/projects/123/issues/
#{
issue
.
id
}
/move"
,
user
),
to_project_id:
target_project
.
id
expect
(
response
).
to
have_http_status
(
404
)
expect
(
json_response
[
'message'
]).
to
eq
(
'404 Project Not Found'
)
end
end
context
'when target project does not exist'
do
it
'returns 404 when trying to move an issue'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
/move"
,
user
),
to_project_id:
123
expect
(
response
).
to
have_http_status
(
404
)
end
end
end
describe
'POST :id/issues/:issue_id/subscription'
do
it
'subscribes to an issue'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
/subscription"
,
user2
)
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'subscribed'
]).
to
eq
(
true
)
end
it
'returns 304 if already subscribed'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
/subscription"
,
user
)
expect
(
response
).
to
have_http_status
(
304
)
end
it
'returns 404 if the issue is not found'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/123/subscription"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
it
'returns 404 if the issue is confidential'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
/subscription"
,
non_member
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
'DELETE :id/issues/:issue_id/subscription'
do
it
'unsubscribes from an issue'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
/subscription"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'subscribed'
]).
to
eq
(
false
)
end
it
'returns 304 if not subscribed'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
/subscription"
,
user2
)
expect
(
response
).
to
have_http_status
(
304
)
end
it
'returns 404 if the issue is not found'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/issues/123/subscription"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
it
'returns 404 if the issue is confidential'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
confidential_issue
.
id
}
/subscription"
,
non_member
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
'time tracking endpoints'
do
let
(
:issuable
)
{
issue
}
include_examples
'time tracking endpoints'
,
'issue'
end
end
spec/requests/api/v3/merge_requests_spec.rb
0 → 100644
View file @
707ce837
require
"spec_helper"
describe
API
::
MergeRequests
,
api:
true
do
include
ApiHelpers
let
(
:base_time
)
{
Time
.
now
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:admin
)
{
create
(
:user
,
:admin
)
}
let
(
:non_member
)
{
create
(
:user
)
}
let!
(
:project
)
{
create
(
:project
,
:public
,
:repository
,
creator:
user
,
namespace:
user
.
namespace
)
}
let!
(
:merge_request
)
{
create
(
:merge_request
,
:simple
,
author:
user
,
assignee:
user
,
source_project:
project
,
title:
"Test"
,
created_at:
base_time
)
}
let!
(
:merge_request_closed
)
{
create
(
:merge_request
,
state:
"closed"
,
author:
user
,
assignee:
user
,
source_project:
project
,
title:
"Closed test"
,
created_at:
base_time
+
1
.
second
)
}
let!
(
:merge_request_merged
)
{
create
(
:merge_request
,
state:
"merged"
,
author:
user
,
assignee:
user
,
source_project:
project
,
title:
"Merged test"
,
created_at:
base_time
+
2
.
seconds
,
merge_commit_sha:
'9999999999999999999999999999999999999999'
)
}
let
(
:milestone
)
{
create
(
:milestone
,
title:
'1.0.0'
,
project:
project
)
}
before
do
project
.
team
<<
[
user
,
:reporter
]
end
describe
"GET /projects/:id/merge_requests"
do
context
"when unauthenticated"
do
it
"returns authentication error"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
)
expect
(
response
).
to
have_http_status
(
401
)
end
end
context
"when authenticated"
do
it
"returns an array of all merge_requests"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
3
)
expect
(
json_response
.
last
[
'title'
]).
to
eq
(
merge_request
.
title
)
expect
(
json_response
.
last
).
to
have_key
(
'web_url'
)
expect
(
json_response
.
last
[
'sha'
]).
to
eq
(
merge_request
.
diff_head_sha
)
expect
(
json_response
.
last
[
'merge_commit_sha'
]).
to
be_nil
expect
(
json_response
.
last
[
'merge_commit_sha'
]).
to
eq
(
merge_request
.
merge_commit_sha
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
merge_request_merged
.
title
)
expect
(
json_response
.
first
[
'sha'
]).
to
eq
(
merge_request_merged
.
diff_head_sha
)
expect
(
json_response
.
first
[
'merge_commit_sha'
]).
not_to
be_nil
expect
(
json_response
.
first
[
'merge_commit_sha'
]).
to
eq
(
merge_request_merged
.
merge_commit_sha
)
end
it
"returns an array of all merge_requests"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests?state"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
3
)
expect
(
json_response
.
last
[
'title'
]).
to
eq
(
merge_request
.
title
)
end
it
"returns an array of open merge_requests"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests?state=opened"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
last
[
'title'
]).
to
eq
(
merge_request
.
title
)
end
it
"returns an array of closed merge_requests"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests?state=closed"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
merge_request_closed
.
title
)
end
it
"returns an array of merged merge_requests"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests?state=merged"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
merge_request_merged
.
title
)
end
context
"with ordering"
do
before
do
@mr_later
=
mr_with_later_created_and_updated_at_time
@mr_earlier
=
mr_with_earlier_created_and_updated_at_time
end
it
"returns an array of merge_requests in ascending order"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests?sort=asc"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
3
)
response_dates
=
json_response
.
map
{
|
merge_request
|
merge_request
[
'created_at'
]
}
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
)
end
it
"returns an array of merge_requests in descending order"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests?sort=desc"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
3
)
response_dates
=
json_response
.
map
{
|
merge_request
|
merge_request
[
'created_at'
]
}
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
.
reverse
)
end
it
"returns an array of merge_requests ordered by updated_at"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests?order_by=updated_at"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
3
)
response_dates
=
json_response
.
map
{
|
merge_request
|
merge_request
[
'updated_at'
]
}
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
.
reverse
)
end
it
"returns an array of merge_requests ordered by created_at"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests?order_by=created_at&sort=asc"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
3
)
response_dates
=
json_response
.
map
{
|
merge_request
|
merge_request
[
'created_at'
]
}
expect
(
response_dates
).
to
eq
(
response_dates
.
sort
)
end
end
end
end
describe
"GET /projects/:id/merge_requests/:merge_request_id"
do
it
'exposes known attributes'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'id'
]).
to
eq
(
merge_request
.
id
)
expect
(
json_response
[
'iid'
]).
to
eq
(
merge_request
.
iid
)
expect
(
json_response
[
'project_id'
]).
to
eq
(
merge_request
.
project
.
id
)
expect
(
json_response
[
'title'
]).
to
eq
(
merge_request
.
title
)
expect
(
json_response
[
'description'
]).
to
eq
(
merge_request
.
description
)
expect
(
json_response
[
'state'
]).
to
eq
(
merge_request
.
state
)
expect
(
json_response
[
'created_at'
]).
to
be_present
expect
(
json_response
[
'updated_at'
]).
to
be_present
expect
(
json_response
[
'labels'
]).
to
eq
(
merge_request
.
label_names
)
expect
(
json_response
[
'milestone'
]).
to
be_nil
expect
(
json_response
[
'assignee'
]).
to
be_a
Hash
expect
(
json_response
[
'author'
]).
to
be_a
Hash
expect
(
json_response
[
'target_branch'
]).
to
eq
(
merge_request
.
target_branch
)
expect
(
json_response
[
'source_branch'
]).
to
eq
(
merge_request
.
source_branch
)
expect
(
json_response
[
'upvotes'
]).
to
eq
(
0
)
expect
(
json_response
[
'downvotes'
]).
to
eq
(
0
)
expect
(
json_response
[
'source_project_id'
]).
to
eq
(
merge_request
.
source_project
.
id
)
expect
(
json_response
[
'target_project_id'
]).
to
eq
(
merge_request
.
target_project
.
id
)
expect
(
json_response
[
'work_in_progress'
]).
to
be_falsy
expect
(
json_response
[
'merge_when_build_succeeds'
]).
to
be_falsy
expect
(
json_response
[
'merge_status'
]).
to
eq
(
'can_be_merged'
)
expect
(
json_response
[
'should_close_merge_request'
]).
to
be_falsy
expect
(
json_response
[
'force_close_merge_request'
]).
to
be_falsy
end
it
"returns merge_request"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
merge_request
.
title
)
expect
(
json_response
[
'iid'
]).
to
eq
(
merge_request
.
iid
)
expect
(
json_response
[
'work_in_progress'
]).
to
eq
(
false
)
expect
(
json_response
[
'merge_status'
]).
to
eq
(
'can_be_merged'
)
expect
(
json_response
[
'should_close_merge_request'
]).
to
be_falsy
expect
(
json_response
[
'force_close_merge_request'
]).
to
be_falsy
end
it
'returns merge_request by iid'
do
url
=
"/projects/
#{
project
.
id
}
/merge_requests?iid=
#{
merge_request
.
iid
}
"
get
v3_api
(
url
,
user
)
expect
(
response
.
status
).
to
eq
200
expect
(
json_response
.
first
[
'title'
]).
to
eq
merge_request
.
title
expect
(
json_response
.
first
[
'id'
]).
to
eq
merge_request
.
id
end
it
'returns merge_request by iid array'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
iid:
[
merge_request
.
iid
,
merge_request_closed
.
iid
]
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
merge_request_closed
.
title
expect
(
json_response
.
first
[
'id'
]).
to
eq
merge_request_closed
.
id
end
it
"returns a 404 error if merge_request_id not found"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/999"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
context
'Work in Progress'
do
let!
(
:merge_request_wip
)
{
create
(
:merge_request
,
author:
user
,
assignee:
user
,
source_project:
project
,
target_project:
project
,
title:
"WIP: Test"
,
created_at:
base_time
+
1
.
second
)
}
it
"returns merge_request"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request_wip
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'work_in_progress'
]).
to
eq
(
true
)
end
end
end
describe
'GET /projects/:id/merge_requests/:merge_request_id/commits'
do
it
'returns a 200 when merge request is valid'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/commits"
,
user
)
commit
=
merge_request
.
commits
.
first
expect
(
response
.
status
).
to
eq
200
expect
(
json_response
.
size
).
to
eq
(
merge_request
.
commits
.
size
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
commit
.
id
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
commit
.
title
)
end
it
'returns a 404 when merge_request_id not found'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/999/commits"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
'GET /projects/:id/merge_requests/:merge_request_id/changes'
do
it
'returns the change information of the merge_request'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/changes"
,
user
)
expect
(
response
.
status
).
to
eq
200
expect
(
json_response
[
'changes'
].
size
).
to
eq
(
merge_request
.
diffs
.
size
)
end
it
'returns a 404 when merge_request_id not found'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/999/changes"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
"POST /projects/:id/merge_requests"
do
context
'between branches projects'
do
it
"returns merge_request"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
title:
'Test merge_request'
,
source_branch:
'feature_conflict'
,
target_branch:
'master'
,
author:
user
,
labels:
'label, label2'
,
milestone_id:
milestone
.
id
,
remove_source_branch:
true
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'title'
]).
to
eq
(
'Test merge_request'
)
expect
(
json_response
[
'labels'
]).
to
eq
([
'label'
,
'label2'
])
expect
(
json_response
[
'milestone'
][
'id'
]).
to
eq
(
milestone
.
id
)
expect
(
json_response
[
'force_remove_source_branch'
]).
to
be_truthy
end
it
"returns 422 when source_branch equals target_branch"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
title:
"Test merge_request"
,
source_branch:
"master"
,
target_branch:
"master"
,
author:
user
expect
(
response
).
to
have_http_status
(
422
)
end
it
"returns 400 when source_branch is missing"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
title:
"Test merge_request"
,
target_branch:
"master"
,
author:
user
expect
(
response
).
to
have_http_status
(
400
)
end
it
"returns 400 when target_branch is missing"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
title:
"Test merge_request"
,
source_branch:
"markdown"
,
author:
user
expect
(
response
).
to
have_http_status
(
400
)
end
it
"returns 400 when title is missing"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
target_branch:
'master'
,
source_branch:
'markdown'
expect
(
response
).
to
have_http_status
(
400
)
end
it
'allows special label names'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
title:
'Test merge_request'
,
source_branch:
'markdown'
,
target_branch:
'master'
,
author:
user
,
labels:
'label, label?, label&foo, ?, &'
expect
(
response
.
status
).
to
eq
(
201
)
expect
(
json_response
[
'labels'
]).
to
include
'label'
expect
(
json_response
[
'labels'
]).
to
include
'label?'
expect
(
json_response
[
'labels'
]).
to
include
'label&foo'
expect
(
json_response
[
'labels'
]).
to
include
'?'
expect
(
json_response
[
'labels'
]).
to
include
'&'
end
context
'with existing MR'
do
before
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
title:
'Test merge_request'
,
source_branch:
'feature_conflict'
,
target_branch:
'master'
,
author:
user
@mr
=
MergeRequest
.
all
.
last
end
it
'returns 409 when MR already exists for source/target'
do
expect
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
title:
'New test merge_request'
,
source_branch:
'feature_conflict'
,
target_branch:
'master'
,
author:
user
end
.
to
change
{
MergeRequest
.
count
}.
by
(
0
)
expect
(
response
).
to
have_http_status
(
409
)
end
end
end
context
'forked projects'
do
let!
(
:user2
)
{
create
(
:user
)
}
let!
(
:fork_project
)
{
create
(
:empty_project
,
forked_from_project:
project
,
namespace:
user2
.
namespace
,
creator_id:
user2
.
id
)
}
let!
(
:unrelated_project
)
{
create
(
:empty_project
,
namespace:
create
(
:user
).
namespace
,
creator_id:
user2
.
id
)
}
before
:each
do
|
each
|
fork_project
.
team
<<
[
user2
,
:reporter
]
end
it
"returns merge_request"
do
post
v3_api
(
"/projects/
#{
fork_project
.
id
}
/merge_requests"
,
user2
),
title:
'Test merge_request'
,
source_branch:
"feature_conflict"
,
target_branch:
"master"
,
author:
user2
,
target_project_id:
project
.
id
,
description:
'Test description for Test merge_request'
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'title'
]).
to
eq
(
'Test merge_request'
)
expect
(
json_response
[
'description'
]).
to
eq
(
'Test description for Test merge_request'
)
end
it
"does not return 422 when source_branch equals target_branch"
do
expect
(
project
.
id
).
not_to
eq
(
fork_project
.
id
)
expect
(
fork_project
.
forked?
).
to
be_truthy
expect
(
fork_project
.
forked_from_project
).
to
eq
(
project
)
post
v3_api
(
"/projects/
#{
fork_project
.
id
}
/merge_requests"
,
user2
),
title:
'Test merge_request'
,
source_branch:
"master"
,
target_branch:
"master"
,
author:
user2
,
target_project_id:
project
.
id
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'title'
]).
to
eq
(
'Test merge_request'
)
end
it
"returns 400 when source_branch is missing"
do
post
v3_api
(
"/projects/
#{
fork_project
.
id
}
/merge_requests"
,
user2
),
title:
'Test merge_request'
,
target_branch:
"master"
,
author:
user2
,
target_project_id:
project
.
id
expect
(
response
).
to
have_http_status
(
400
)
end
it
"returns 400 when target_branch is missing"
do
post
v3_api
(
"/projects/
#{
fork_project
.
id
}
/merge_requests"
,
user2
),
title:
'Test merge_request'
,
target_branch:
"master"
,
author:
user2
,
target_project_id:
project
.
id
expect
(
response
).
to
have_http_status
(
400
)
end
it
"returns 400 when title is missing"
do
post
v3_api
(
"/projects/
#{
fork_project
.
id
}
/merge_requests"
,
user2
),
target_branch:
'master'
,
source_branch:
'markdown'
,
author:
user2
,
target_project_id:
project
.
id
expect
(
response
).
to
have_http_status
(
400
)
end
context
'when target_branch is specified'
do
it
'returns 422 if not a forked project'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests"
,
user
),
title:
'Test merge_request'
,
target_branch:
'master'
,
source_branch:
'markdown'
,
author:
user
,
target_project_id:
fork_project
.
id
expect
(
response
).
to
have_http_status
(
422
)
end
it
'returns 422 if targeting a different fork'
do
post
v3_api
(
"/projects/
#{
fork_project
.
id
}
/merge_requests"
,
user2
),
title:
'Test merge_request'
,
target_branch:
'master'
,
source_branch:
'markdown'
,
author:
user2
,
target_project_id:
unrelated_project
.
id
expect
(
response
).
to
have_http_status
(
422
)
end
end
it
"returns 201 when target_branch is specified and for the same project"
do
post
v3_api
(
"/projects/
#{
fork_project
.
id
}
/merge_requests"
,
user2
),
title:
'Test merge_request'
,
target_branch:
'master'
,
source_branch:
'markdown'
,
author:
user2
,
target_project_id:
fork_project
.
id
expect
(
response
).
to
have_http_status
(
201
)
end
end
end
describe
"DELETE /projects/:id/merge_requests/:merge_request_id"
do
context
"when the user is developer"
do
let
(
:developer
)
{
create
(
:user
)
}
before
do
project
.
team
<<
[
developer
,
:developer
]
end
it
"denies the deletion of the merge request"
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
developer
)
expect
(
response
).
to
have_http_status
(
403
)
end
end
context
"when the user is project owner"
do
it
"destroys the merge request owners can destroy"
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
end
end
end
describe
"PUT /projects/:id/merge_requests/:merge_request_id/merge"
do
let
(
:pipeline
)
{
create
(
:ci_pipeline_without_jobs
)
}
it
"returns merge_request in case of success"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/merge"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
end
it
"returns 406 if branch can't be merged"
do
allow_any_instance_of
(
MergeRequest
).
to
receive
(
:can_be_merged?
).
and_return
(
false
)
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/merge"
,
user
)
expect
(
response
).
to
have_http_status
(
406
)
expect
(
json_response
[
'message'
]).
to
eq
(
'Branch cannot be merged'
)
end
it
"returns 405 if merge_request is not open"
do
merge_request
.
close
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/merge"
,
user
)
expect
(
response
).
to
have_http_status
(
405
)
expect
(
json_response
[
'message'
]).
to
eq
(
'405 Method Not Allowed'
)
end
it
"returns 405 if merge_request is a work in progress"
do
merge_request
.
update_attribute
(
:title
,
"WIP:
#{
merge_request
.
title
}
"
)
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/merge"
,
user
)
expect
(
response
).
to
have_http_status
(
405
)
expect
(
json_response
[
'message'
]).
to
eq
(
'405 Method Not Allowed'
)
end
it
'returns 405 if the build failed for a merge request that requires success'
do
allow_any_instance_of
(
MergeRequest
).
to
receive
(
:mergeable_ci_state?
).
and_return
(
false
)
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/merge"
,
user
)
expect
(
response
).
to
have_http_status
(
405
)
expect
(
json_response
[
'message'
]).
to
eq
(
'405 Method Not Allowed'
)
end
it
"returns 401 if user has no permissions to merge"
do
user2
=
create
(
:user
)
project
.
team
<<
[
user2
,
:reporter
]
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/merge"
,
user2
)
expect
(
response
).
to
have_http_status
(
401
)
expect
(
json_response
[
'message'
]).
to
eq
(
'401 Unauthorized'
)
end
it
"returns 409 if the SHA parameter doesn't match"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/merge"
,
user
),
sha:
merge_request
.
diff_head_sha
.
reverse
expect
(
response
).
to
have_http_status
(
409
)
expect
(
json_response
[
'message'
]).
to
start_with
(
'SHA does not match HEAD of source branch'
)
end
it
"succeeds if the SHA parameter matches"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/merge"
,
user
),
sha:
merge_request
.
diff_head_sha
expect
(
response
).
to
have_http_status
(
200
)
end
it
"enables merge when pipeline succeeds if the pipeline is active"
do
allow_any_instance_of
(
MergeRequest
).
to
receive
(
:head_pipeline
).
and_return
(
pipeline
)
allow
(
pipeline
).
to
receive
(
:active?
).
and_return
(
true
)
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/merge"
,
user
),
merge_when_build_succeeds:
true
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
'Test'
)
expect
(
json_response
[
'merge_when_build_succeeds'
]).
to
eq
(
true
)
end
end
describe
"PUT /projects/:id/merge_requests/:merge_request_id"
do
context
"to close a MR"
do
it
"returns merge_request"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
),
state_event:
"close"
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'state'
]).
to
eq
(
'closed'
)
end
end
it
"updates title and returns merge_request"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
),
title:
"New title"
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
'New title'
)
end
it
"updates description and returns merge_request"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
),
description:
"New description"
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'description'
]).
to
eq
(
'New description'
)
end
it
"updates milestone_id and returns merge_request"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
),
milestone_id:
milestone
.
id
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'milestone'
][
'id'
]).
to
eq
(
milestone
.
id
)
end
it
"returns merge_request with renamed target_branch"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
),
target_branch:
"wiki"
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'target_branch'
]).
to
eq
(
'wiki'
)
end
it
"returns merge_request that removes the source branch"
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
),
remove_source_branch:
true
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'force_remove_source_branch'
]).
to
be_truthy
end
it
'allows special label names'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
),
title:
'new issue'
,
labels:
'label, label?, label&foo, ?, &'
expect
(
response
.
status
).
to
eq
(
200
)
expect
(
json_response
[
'labels'
]).
to
include
'label'
expect
(
json_response
[
'labels'
]).
to
include
'label?'
expect
(
json_response
[
'labels'
]).
to
include
'label&foo'
expect
(
json_response
[
'labels'
]).
to
include
'?'
expect
(
json_response
[
'labels'
]).
to
include
'&'
end
it
'does not update state when title is empty'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
),
state_event:
'close'
,
title:
nil
merge_request
.
reload
expect
(
response
).
to
have_http_status
(
400
)
expect
(
merge_request
.
state
).
to
eq
(
'opened'
)
end
it
'does not update state when target_branch is empty'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
"
,
user
),
state_event:
'close'
,
target_branch:
nil
merge_request
.
reload
expect
(
response
).
to
have_http_status
(
400
)
expect
(
merge_request
.
state
).
to
eq
(
'opened'
)
end
end
describe
"POST /projects/:id/merge_requests/:merge_request_id/comments"
do
it
"returns comment"
do
original_count
=
merge_request
.
notes
.
size
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/comments"
,
user
),
note:
"My comment"
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'note'
]).
to
eq
(
'My comment'
)
expect
(
json_response
[
'author'
][
'name'
]).
to
eq
(
user
.
name
)
expect
(
json_response
[
'author'
][
'username'
]).
to
eq
(
user
.
username
)
expect
(
merge_request
.
reload
.
notes
.
size
).
to
eq
(
original_count
+
1
)
end
it
"returns 400 if note is missing"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/comments"
,
user
)
expect
(
response
).
to
have_http_status
(
400
)
end
it
"returns 404 if note is attached to non existent merge request"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/404/comments"
,
user
),
note:
'My comment'
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
"GET :id/merge_requests/:merge_request_id/comments"
do
let!
(
:note
)
{
create
(
:note_on_merge_request
,
author:
user
,
project:
project
,
noteable:
merge_request
,
note:
"a comment on a MR"
)
}
let!
(
:note2
)
{
create
(
:note_on_merge_request
,
author:
user
,
project:
project
,
noteable:
merge_request
,
note:
"another comment on a MR"
)
}
it
"returns merge_request comments ordered by created_at"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/comments"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
expect
(
json_response
.
first
[
'note'
]).
to
eq
(
"a comment on a MR"
)
expect
(
json_response
.
first
[
'author'
][
'id'
]).
to
eq
(
user
.
id
)
expect
(
json_response
.
last
[
'note'
]).
to
eq
(
"another comment on a MR"
)
end
it
"returns a 404 error if merge_request_id not found"
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/999/comments"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
'GET :id/merge_requests/:merge_request_id/closes_issues'
do
it
'returns the issue that will be closed on merge'
do
issue
=
create
(
:issue
,
project:
project
)
mr
=
merge_request
.
tap
do
|
mr
|
mr
.
update_attribute
(
:description
,
"Closes
#{
issue
.
to_reference
(
mr
.
project
)
}
"
)
end
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
mr
.
id
}
/closes_issues"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
issue
.
id
)
end
it
'returns an empty array when there are no issues to be closed'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/closes_issues"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
0
)
end
it
'handles external issues'
do
jira_project
=
create
(
:jira_project
,
:public
,
name:
'JIR_EXT1'
)
issue
=
ExternalIssue
.
new
(
"
#{
jira_project
.
name
}
-123"
,
jira_project
)
merge_request
=
create
(
:merge_request
,
:simple
,
author:
user
,
assignee:
user
,
source_project:
jira_project
)
merge_request
.
update_attribute
(
:description
,
"Closes
#{
issue
.
to_reference
(
jira_project
)
}
"
)
get
v3_api
(
"/projects/
#{
jira_project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/closes_issues"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
issue
.
title
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
issue
.
id
)
end
it
'returns 403 if the user has no access to the merge request'
do
project
=
create
(
:empty_project
,
:private
)
merge_request
=
create
(
:merge_request
,
:simple
,
source_project:
project
)
guest
=
create
(
:user
)
project
.
team
<<
[
guest
,
:guest
]
get
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/closes_issues"
,
guest
)
expect
(
response
).
to
have_http_status
(
403
)
end
end
describe
'POST :id/merge_requests/:merge_request_id/subscription'
do
it
'subscribes to a merge request'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/subscription"
,
admin
)
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'subscribed'
]).
to
eq
(
true
)
end
it
'returns 304 if already subscribed'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/subscription"
,
user
)
expect
(
response
).
to
have_http_status
(
304
)
end
it
'returns 404 if the merge request is not found'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/123/subscription"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
it
'returns 403 if user has no access to read code'
do
guest
=
create
(
:user
)
project
.
team
<<
[
guest
,
:guest
]
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/subscription"
,
guest
)
expect
(
response
).
to
have_http_status
(
403
)
end
end
describe
'DELETE :id/merge_requests/:merge_request_id/subscription'
do
it
'unsubscribes from a merge request'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/subscription"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'subscribed'
]).
to
eq
(
false
)
end
it
'returns 304 if not subscribed'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/subscription"
,
admin
)
expect
(
response
).
to
have_http_status
(
304
)
end
it
'returns 404 if the merge request is not found'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/123/subscription"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
it
'returns 403 if user has no access to read code'
do
guest
=
create
(
:user
)
project
.
team
<<
[
guest
,
:guest
]
delete
v3_api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
id
}
/subscription"
,
guest
)
expect
(
response
).
to
have_http_status
(
403
)
end
end
describe
'Time tracking'
do
let
(
:issuable
)
{
merge_request
}
include_examples
'time tracking endpoints'
,
'merge_request'
end
def
mr_with_later_created_and_updated_at_time
merge_request
merge_request
.
created_at
+=
1
.
hour
merge_request
.
updated_at
+=
30
.
minutes
merge_request
.
save
merge_request
end
def
mr_with_earlier_created_and_updated_at_time
merge_request_closed
merge_request_closed
.
created_at
-=
1
.
hour
merge_request_closed
.
updated_at
-=
30
.
minutes
merge_request_closed
.
save
merge_request_closed
end
end
spec/services/system_note_service_spec.rb
View file @
707ce837
...
@@ -752,13 +752,13 @@ describe SystemNoteService, services: true do
...
@@ -752,13 +752,13 @@ describe SystemNoteService, services: true do
it
'sets the note text'
do
it
'sets the note text'
do
noteable
.
update_attribute
(
:time_estimate
,
277200
)
noteable
.
update_attribute
(
:time_estimate
,
277200
)
expect
(
subject
.
note
).
to
eq
"
Changed time estimate of this issu
e to 1w 4d 5h"
expect
(
subject
.
note
).
to
eq
"
changed time estimat
e to 1w 4d 5h"
end
end
end
end
context
'without a time estimate'
do
context
'without a time estimate'
do
it
'sets the note text'
do
it
'sets the note text'
do
expect
(
subject
.
note
).
to
eq
"
Removed time estimate on this issu
e"
expect
(
subject
.
note
).
to
eq
"
removed time estimat
e"
end
end
end
end
end
end
...
@@ -782,7 +782,7 @@ describe SystemNoteService, services: true do
...
@@ -782,7 +782,7 @@ describe SystemNoteService, services: true do
it
'sets the note text'
do
it
'sets the note text'
do
spend_time!
(
277200
)
spend_time!
(
277200
)
expect
(
subject
.
note
).
to
eq
"
Added 1w 4d 5h of time spent on this merge reques
t"
expect
(
subject
.
note
).
to
eq
"
added 1w 4d 5h of time spen
t"
end
end
end
end
...
@@ -790,7 +790,7 @@ describe SystemNoteService, services: true do
...
@@ -790,7 +790,7 @@ describe SystemNoteService, services: true do
it
'sets the note text'
do
it
'sets the note text'
do
spend_time!
(
-
277200
)
spend_time!
(
-
277200
)
expect
(
subject
.
note
).
to
eq
"
Subtracted 1w 4d 5h of time spent on this merge reques
t"
expect
(
subject
.
note
).
to
eq
"
subtracted 1w 4d 5h of time spen
t"
end
end
end
end
...
@@ -798,7 +798,7 @@ describe SystemNoteService, services: true do
...
@@ -798,7 +798,7 @@ describe SystemNoteService, services: true do
it
'sets the note text'
do
it
'sets the note text'
do
spend_time!
(
:reset
)
spend_time!
(
:reset
)
expect
(
subject
.
note
).
to
eq
"
Removed time spent on this merge reques
t"
expect
(
subject
.
note
).
to
eq
"
removed time spen
t"
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