Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
c2d64d67
Commit
c2d64d67
authored
Jan 25, 2017
by
Oswaldo Ferreira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove deprecated MR and Issue endpoints and preserve V3 namespace
parent
999edc5c
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
2647 additions
and
184 deletions
+2647
-184
changelogs/unreleased/9-0-api-changes.yml
changelogs/unreleased/9-0-api-changes.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
No files found.
changelogs/unreleased/9-0-api-changes.yml
0 → 100644
View file @
c2d64d67
---
title
:
Remove deprecated MR and Issue endpoints and preserve V3 namespace
merge_request
:
8967
author
:
doc/api/issues.md
View file @
c2d64d67
...
@@ -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 @
c2d64d67
...
@@ -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 @
c2d64d67
...
@@ -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 @
c2d64d67
...
@@ -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 @
c2d64d67
...
@@ -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 @
c2d64d67
...
@@ -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 @
c2d64d67
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 @
c2d64d67
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 @
c2d64d67
...
@@ -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 @
c2d64d67
...
@@ -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 @
c2d64d67
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 @
c2d64d67
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
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