Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Tatuya Kamada
gitlab-ce
Commits
cadef802
Commit
cadef802
authored
Jan 30, 2017
by
Oswaldo Ferreira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remain V3 endpoint unchanged
parent
cc24682b
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1895 additions
and
3 deletions
+1895
-3
lib/api/api.rb
lib/api/api.rb
+6
-1
lib/api/v3/projects.rb
lib/api/v3/projects.rb
+458
-0
spec/requests/api/v3/projects_spec.rb
spec/requests/api/v3/projects_spec.rb
+1424
-0
spec/support/api_helpers.rb
spec/support/api_helpers.rb
+7
-2
No files found.
lib/api/api.rb
View file @
cadef802
module
API
class
API
<
Grape
::
API
include
APIGuard
version
'v3'
,
using: :path
version
%w(v3 v4)
,
using: :path
version
'v3'
,
using: :path
do
mount
::
API
::
V3
::
Projects
end
before
{
allow_access_with_scope
:api
}
...
...
lib/api/v3/projects.rb
0 → 100644
View file @
cadef802
module
API
module
V3
class
Projects
<
Grape
::
API
include
PaginationParams
before
{
authenticate_non_get!
}
helpers
do
params
:optional_params
do
optional
:description
,
type:
String
,
desc:
'The description of the project'
optional
:issues_enabled
,
type:
Boolean
,
desc:
'Flag indication if the issue tracker is enabled'
optional
:merge_requests_enabled
,
type:
Boolean
,
desc:
'Flag indication if merge requests are enabled'
optional
:wiki_enabled
,
type:
Boolean
,
desc:
'Flag indication if the wiki is enabled'
optional
:builds_enabled
,
type:
Boolean
,
desc:
'Flag indication if builds are enabled'
optional
:snippets_enabled
,
type:
Boolean
,
desc:
'Flag indication if snippets are enabled'
optional
:shared_runners_enabled
,
type:
Boolean
,
desc:
'Flag indication if shared runners are enabled for that project'
optional
:container_registry_enabled
,
type:
Boolean
,
desc:
'Flag indication if the container registry is enabled for that project'
optional
:lfs_enabled
,
type:
Boolean
,
desc:
'Flag indication if Git LFS is enabled for that project'
optional
:public
,
type:
Boolean
,
desc:
'Create a public project. The same as visibility_level = 20.'
optional
:visibility_level
,
type:
Integer
,
values:
[
Gitlab
::
VisibilityLevel
::
PRIVATE
,
Gitlab
::
VisibilityLevel
::
INTERNAL
,
Gitlab
::
VisibilityLevel
::
PUBLIC
],
desc:
'Create a public project. The same as visibility_level = 20.'
optional
:public_builds
,
type:
Boolean
,
desc:
'Perform public builds'
optional
:request_access_enabled
,
type:
Boolean
,
desc:
'Allow users to request member access'
optional
:only_allow_merge_if_build_succeeds
,
type:
Boolean
,
desc:
'Only allow to merge if builds succeed'
optional
:only_allow_merge_if_all_discussions_are_resolved
,
type:
Boolean
,
desc:
'Only allow to merge if all discussions are resolved'
end
def
map_public_to_visibility_level
(
attrs
)
publik
=
attrs
.
delete
(
:public
)
if
!
publik
.
nil?
&&
!
attrs
[
:visibility_level
].
present?
# Since setting the public attribute to private could mean either
# private or internal, use the more conservative option, private.
attrs
[
:visibility_level
]
=
(
publik
==
true
)
?
Gitlab
::
VisibilityLevel
::
PUBLIC
:
Gitlab
::
VisibilityLevel
::
PRIVATE
end
attrs
end
end
resource
:projects
do
helpers
do
params
:collection_params
do
use
:sort_params
use
:filter_params
use
:pagination
optional
:simple
,
type:
Boolean
,
default:
false
,
desc:
'Return only the ID, URL, name, and path of each project'
end
params
:sort_params
do
optional
:order_by
,
type:
String
,
values:
%w[id name path created_at updated_at last_activity_at]
,
default:
'created_at'
,
desc:
'Return projects ordered by field'
optional
:sort
,
type:
String
,
values:
%w[asc desc]
,
default:
'desc'
,
desc:
'Return projects sorted in ascending and descending order'
end
params
:filter_params
do
optional
:archived
,
type:
Boolean
,
default:
false
,
desc:
'Limit by archived status'
optional
:visibility
,
type:
String
,
values:
%w[public internal private]
,
desc:
'Limit by visibility'
optional
:search
,
type:
String
,
desc:
'Return list of authorized projects matching the search criteria'
end
params
:statistics_params
do
optional
:statistics
,
type:
Boolean
,
default:
false
,
desc:
'Include project statistics'
end
params
:create_params
do
optional
:namespace_id
,
type:
Integer
,
desc:
'Namespace ID for the new project. Default to the user namespace.'
optional
:import_url
,
type:
String
,
desc:
'URL from which the project is imported'
end
def
present_projects
(
projects
,
options
=
{})
options
=
options
.
reverse_merge
(
with:
Entities
::
Project
,
current_user:
current_user
,
simple:
params
[
:simple
],
)
projects
=
filter_projects
(
projects
)
projects
=
projects
.
with_statistics
if
options
[
:statistics
]
options
[
:with
]
=
Entities
::
BasicProjectDetails
if
options
[
:simple
]
present
paginate
(
projects
),
options
end
end
desc
'Get a list of visible projects for authenticated user'
do
success
Entities
::
BasicProjectDetails
end
params
do
use
:collection_params
end
get
'/visible'
do
entity
=
current_user
?
Entities
::
ProjectWithAccess
:
Entities
::
BasicProjectDetails
present_projects
ProjectsFinder
.
new
.
execute
(
current_user
),
with:
entity
end
desc
'Get a projects list for authenticated user'
do
success
Entities
::
BasicProjectDetails
end
params
do
use
:collection_params
end
get
do
authenticate!
present_projects
current_user
.
authorized_projects
,
with:
Entities
::
ProjectWithAccess
end
desc
'Get an owned projects list for authenticated user'
do
success
Entities
::
BasicProjectDetails
end
params
do
use
:collection_params
use
:statistics_params
end
get
'/owned'
do
authenticate!
present_projects
current_user
.
owned_projects
,
with:
Entities
::
ProjectWithAccess
,
statistics:
params
[
:statistics
]
end
desc
'Gets starred project for the authenticated user'
do
success
Entities
::
BasicProjectDetails
end
params
do
use
:collection_params
end
get
'/starred'
do
authenticate!
present_projects
current_user
.
viewable_starred_projects
end
desc
'Get all projects for admin user'
do
success
Entities
::
BasicProjectDetails
end
params
do
use
:collection_params
use
:statistics_params
end
get
'/all'
do
authenticated_as_admin!
present_projects
Project
.
all
,
with:
Entities
::
ProjectWithAccess
,
statistics:
params
[
:statistics
]
end
desc
'Search for projects the current user has access to'
do
success
Entities
::
Project
end
params
do
requires
:query
,
type:
String
,
desc:
'The project name to be searched'
use
:sort_params
use
:pagination
end
get
"/search/:query"
,
requirements:
{
query:
/[^\/]+/
}
do
search_service
=
Search
::
GlobalService
.
new
(
current_user
,
search:
params
[
:query
]).
execute
projects
=
search_service
.
objects
(
'projects'
,
params
[
:page
])
projects
=
projects
.
reorder
(
params
[
:order_by
]
=>
params
[
:sort
])
present
paginate
(
projects
),
with:
Entities
::
Project
end
desc
'Create new project'
do
success
Entities
::
Project
end
params
do
requires
:name
,
type:
String
,
desc:
'The name of the project'
optional
:path
,
type:
String
,
desc:
'The path of the repository'
use
:optional_params
use
:create_params
end
post
do
attrs
=
map_public_to_visibility_level
(
declared_params
(
include_missing:
false
))
project
=
::
Projects
::
CreateService
.
new
(
current_user
,
attrs
).
execute
if
project
.
saved?
present
project
,
with:
Entities
::
Project
,
user_can_admin_project:
can?
(
current_user
,
:admin_project
,
project
)
else
if
project
.
errors
[
:limit_reached
].
present?
error!
(
project
.
errors
[
:limit_reached
],
403
)
end
render_validation_error!
(
project
)
end
end
desc
'Create new project for a specified user. Only available to admin users.'
do
success
Entities
::
Project
end
params
do
requires
:name
,
type:
String
,
desc:
'The name of the project'
requires
:user_id
,
type:
Integer
,
desc:
'The ID of a user'
optional
:default_branch
,
type:
String
,
desc:
'The default branch of the project'
use
:optional_params
use
:create_params
end
post
"user/:user_id"
do
authenticated_as_admin!
user
=
User
.
find_by
(
id:
params
.
delete
(
:user_id
))
not_found!
(
'User'
)
unless
user
attrs
=
map_public_to_visibility_level
(
declared_params
(
include_missing:
false
))
project
=
::
Projects
::
CreateService
.
new
(
user
,
attrs
).
execute
if
project
.
saved?
present
project
,
with:
Entities
::
Project
,
user_can_admin_project:
can?
(
current_user
,
:admin_project
,
project
)
else
render_validation_error!
(
project
)
end
end
end
params
do
requires
:id
,
type:
String
,
desc:
'The ID of a project'
end
resource
:projects
,
requirements:
{
id:
/[^\/]+/
}
do
desc
'Get a single project'
do
success
Entities
::
ProjectWithAccess
end
get
":id"
do
entity
=
current_user
?
Entities
::
ProjectWithAccess
:
Entities
::
BasicProjectDetails
present
user_project
,
with:
entity
,
current_user:
current_user
,
user_can_admin_project:
can?
(
current_user
,
:admin_project
,
user_project
)
end
desc
'Get events for a single project'
do
success
Entities
::
Event
end
params
do
use
:pagination
end
get
":id/events"
do
present
paginate
(
user_project
.
events
.
recent
),
with:
Entities
::
Event
end
desc
'Fork new project for the current user or provided namespace.'
do
success
Entities
::
Project
end
params
do
optional
:namespace
,
type:
String
,
desc:
'The ID or name of the namespace that the project will be forked into'
end
post
'fork/:id'
do
fork_params
=
declared_params
(
include_missing:
false
)
namespace_id
=
fork_params
[
:namespace
]
if
namespace_id
.
present?
fork_params
[
:namespace
]
=
if
namespace_id
=~
/^\d+$/
Namespace
.
find_by
(
id:
namespace_id
)
else
Namespace
.
find_by_path_or_name
(
namespace_id
)
end
unless
fork_params
[
:namespace
]
&&
can?
(
current_user
,
:create_projects
,
fork_params
[
:namespace
])
not_found!
(
'Target Namespace'
)
end
end
forked_project
=
::
Projects
::
ForkService
.
new
(
user_project
,
current_user
,
fork_params
).
execute
if
forked_project
.
errors
.
any?
conflict!
(
forked_project
.
errors
.
messages
)
else
present
forked_project
,
with:
Entities
::
Project
,
user_can_admin_project:
can?
(
current_user
,
:admin_project
,
forked_project
)
end
end
desc
'Update an existing project'
do
success
Entities
::
Project
end
params
do
optional
:name
,
type:
String
,
desc:
'The name of the project'
optional
:default_branch
,
type:
String
,
desc:
'The default branch of the project'
optional
:path
,
type:
String
,
desc:
'The path of the repository'
use
:optional_params
at_least_one_of
:name
,
:description
,
:issues_enabled
,
:merge_requests_enabled
,
:wiki_enabled
,
:builds_enabled
,
:snippets_enabled
,
:shared_runners_enabled
,
:container_registry_enabled
,
:lfs_enabled
,
:public
,
:visibility_level
,
:public_builds
,
:request_access_enabled
,
:only_allow_merge_if_build_succeeds
,
:only_allow_merge_if_all_discussions_are_resolved
,
:path
,
:default_branch
end
put
':id'
do
authorize_admin_project
attrs
=
map_public_to_visibility_level
(
declared_params
(
include_missing:
false
))
authorize!
:rename_project
,
user_project
if
attrs
[
:name
].
present?
authorize!
:change_visibility_level
,
user_project
if
attrs
[
:visibility_level
].
present?
result
=
::
Projects
::
UpdateService
.
new
(
user_project
,
current_user
,
attrs
).
execute
if
result
[
:status
]
==
:success
present
user_project
,
with:
Entities
::
Project
,
user_can_admin_project:
can?
(
current_user
,
:admin_project
,
user_project
)
else
render_validation_error!
(
user_project
)
end
end
desc
'Archive a project'
do
success
Entities
::
Project
end
post
':id/archive'
do
authorize!
(
:archive_project
,
user_project
)
user_project
.
archive!
present
user_project
,
with:
Entities
::
Project
end
desc
'Unarchive a project'
do
success
Entities
::
Project
end
post
':id/unarchive'
do
authorize!
(
:archive_project
,
user_project
)
user_project
.
unarchive!
present
user_project
,
with:
Entities
::
Project
end
desc
'Star a project'
do
success
Entities
::
Project
end
post
':id/star'
do
if
current_user
.
starred?
(
user_project
)
not_modified!
else
current_user
.
toggle_star
(
user_project
)
user_project
.
reload
present
user_project
,
with:
Entities
::
Project
end
end
desc
'Unstar a project'
do
success
Entities
::
Project
end
delete
':id/star'
do
if
current_user
.
starred?
(
user_project
)
current_user
.
toggle_star
(
user_project
)
user_project
.
reload
present
user_project
,
with:
Entities
::
Project
else
not_modified!
end
end
desc
'Remove a project'
delete
":id"
do
authorize!
:remove_project
,
user_project
::
Projects
::
DestroyService
.
new
(
user_project
,
current_user
,
{}).
async_execute
end
desc
'Mark this project as forked from another'
params
do
requires
:forked_from_id
,
type:
String
,
desc:
'The ID of the project it was forked from'
end
post
":id/fork/:forked_from_id"
do
authenticated_as_admin!
forked_from_project
=
find_project!
(
params
[
:forked_from_id
])
not_found!
(
"Source Project"
)
unless
forked_from_project
if
user_project
.
forked_from_project
.
nil?
user_project
.
create_forked_project_link
(
forked_to_project_id:
user_project
.
id
,
forked_from_project_id:
forked_from_project
.
id
)
else
render_api_error!
(
"Project already forked"
,
409
)
end
end
desc
'Remove a forked_from relationship'
delete
":id/fork"
do
authorize!
:remove_fork_project
,
user_project
if
user_project
.
forked?
user_project
.
forked_project_link
.
destroy
else
not_modified!
end
end
desc
'Share the project with a group'
do
success
Entities
::
ProjectGroupLink
end
params
do
requires
:group_id
,
type:
Integer
,
desc:
'The ID of a group'
requires
:group_access
,
type:
Integer
,
values:
Gitlab
::
Access
.
values
,
desc:
'The group access level'
optional
:expires_at
,
type:
Date
,
desc:
'Share expiration date'
end
post
":id/share"
do
authorize!
:admin_project
,
user_project
group
=
Group
.
find_by_id
(
params
[
:group_id
])
unless
group
&&
can?
(
current_user
,
:read_group
,
group
)
not_found!
(
'Group'
)
end
unless
user_project
.
allowed_to_share_with_group?
return
render_api_error!
(
"The project sharing with group is disabled"
,
400
)
end
link
=
user_project
.
project_group_links
.
new
(
declared_params
(
include_missing:
false
))
if
link
.
save
present
link
,
with:
Entities
::
ProjectGroupLink
else
render_api_error!
(
link
.
errors
.
full_messages
.
first
,
409
)
end
end
params
do
requires
:group_id
,
type:
Integer
,
desc:
'The ID of the group'
end
delete
":id/share/:group_id"
do
authorize!
:admin_project
,
user_project
link
=
user_project
.
project_group_links
.
find_by
(
group_id:
params
[
:group_id
])
not_found!
(
'Group Link'
)
unless
link
link
.
destroy
no_content!
end
desc
'Upload a file'
params
do
requires
:file
,
type:
File
,
desc:
'The file to be uploaded'
end
post
":id/uploads"
do
::
Projects
::
UploadService
.
new
(
user_project
,
params
[
:file
]).
execute
end
desc
'Get the users list of a project'
do
success
Entities
::
UserBasic
end
params
do
optional
:search
,
type:
String
,
desc:
'Return list of users matching the search criteria'
use
:pagination
end
get
':id/users'
do
users
=
user_project
.
team
.
users
users
=
users
.
search
(
params
[
:search
])
if
params
[
:search
].
present?
present
paginate
(
users
),
with:
Entities
::
UserBasic
end
end
end
end
end
spec/requests/api/v3/projects_spec.rb
0 → 100644
View file @
cadef802
require
'spec_helper'
describe
API
::
V3
::
Projects
,
v3_api:
true
do
include
ApiHelpers
include
Gitlab
::
CurrentSettings
let
(
:user
)
{
create
(
:user
)
}
let
(
:user2
)
{
create
(
:user
)
}
let
(
:user3
)
{
create
(
:user
)
}
let
(
:admin
)
{
create
(
:admin
)
}
let
(
:project
)
{
create
(
:empty_project
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let
(
:project2
)
{
create
(
:empty_project
,
path:
'project2'
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let
(
:snippet
)
{
create
(
:project_snippet
,
:public
,
author:
user
,
project:
project
,
title:
'example'
)
}
let
(
:project_member
)
{
create
(
:project_member
,
:master
,
user:
user
,
project:
project
)
}
let
(
:project_member2
)
{
create
(
:project_member
,
:developer
,
user:
user3
,
project:
project
)
}
let
(
:user4
)
{
create
(
:user
)
}
let
(
:project3
)
do
create
(
:project
,
:private
,
:repository
,
name:
'second_project'
,
path:
'second_project'
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
,
merge_requests_enabled:
false
,
issues_enabled:
false
,
wiki_enabled:
false
,
snippets_enabled:
false
)
end
let
(
:project_member3
)
do
create
(
:project_member
,
user:
user4
,
project:
project3
,
access_level:
ProjectMember
::
MASTER
)
end
let
(
:project4
)
do
create
(
:empty_project
,
name:
'third_project'
,
path:
'third_project'
,
creator_id:
user4
.
id
,
namespace:
user4
.
namespace
)
end
describe
'GET /projects'
do
before
{
project
}
context
'when unauthenticated'
do
it
'returns authentication error'
do
get
v3_api
(
'/projects'
)
expect
(
response
).
to
have_http_status
(
401
)
end
end
context
'when authenticated as regular user'
do
it
'returns an array of projects'
do
get
v3_api
(
'/projects'
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
[
'name'
]).
to
eq
(
project
.
name
)
expect
(
json_response
.
first
[
'owner'
][
'username'
]).
to
eq
(
user
.
username
)
end
it
'includes the project labels as the tag_list'
do
get
v3_api
(
'/projects'
,
user
)
expect
(
response
.
status
).
to
eq
200
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
.
keys
).
to
include
(
'tag_list'
)
end
it
'includes open_issues_count'
do
get
v3_api
(
'/projects'
,
user
)
expect
(
response
.
status
).
to
eq
200
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
.
keys
).
to
include
(
'open_issues_count'
)
end
it
'does not include open_issues_count'
do
project
.
project_feature
.
update_attribute
(
:issues_access_level
,
ProjectFeature
::
DISABLED
)
get
v3_api
(
'/projects'
,
user
)
expect
(
response
.
status
).
to
eq
200
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
.
keys
).
not_to
include
(
'open_issues_count'
)
end
context
'GET /projects?simple=true'
do
it
'returns a simplified version of all the projects'
do
expected_keys
=
[
"id"
,
"http_url_to_repo"
,
"web_url"
,
"name"
,
"name_with_namespace"
,
"path"
,
"path_with_namespace"
]
get
v3_api
(
'/projects?simple=true'
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
.
keys
).
to
match_array
expected_keys
end
end
context
'and using search'
do
it
'returns searched project'
do
get
v3_api
(
'/projects'
,
user
),
{
search:
project
.
name
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
end
end
context
'and using the visibility filter'
do
it
'filters based on private visibility param'
do
get
v3_api
(
'/projects'
,
user
),
{
visibility:
'private'
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
user
.
namespace
.
projects
.
where
(
visibility_level:
Gitlab
::
VisibilityLevel
::
PRIVATE
).
count
)
end
it
'filters based on internal visibility param'
do
get
v3_api
(
'/projects'
,
user
),
{
visibility:
'internal'
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
user
.
namespace
.
projects
.
where
(
visibility_level:
Gitlab
::
VisibilityLevel
::
INTERNAL
).
count
)
end
it
'filters based on public visibility param'
do
get
v3_api
(
'/projects'
,
user
),
{
visibility:
'public'
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
user
.
namespace
.
projects
.
where
(
visibility_level:
Gitlab
::
VisibilityLevel
::
PUBLIC
).
count
)
end
end
context
'and using sorting'
do
before
do
project2
project3
end
it
'returns the correct order when sorted by id'
do
get
v3_api
(
'/projects'
,
user
),
{
order_by:
'id'
,
sort:
'desc'
}
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
project3
.
id
)
end
end
end
end
describe
'GET /projects/all'
do
before
{
project
}
context
'when unauthenticated'
do
it
'returns authentication error'
do
get
v3_api
(
'/projects/all'
)
expect
(
response
).
to
have_http_status
(
401
)
end
end
context
'when authenticated as regular user'
do
it
'returns authentication error'
do
get
v3_api
(
'/projects/all'
,
user
)
expect
(
response
).
to
have_http_status
(
403
)
end
end
context
'when authenticated as admin'
do
it
'returns an array of all projects'
do
get
v3_api
(
'/projects/all'
,
admin
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
).
to
satisfy
do
|
response
|
response
.
one?
do
|
entry
|
entry
.
has_key?
(
'permissions'
)
&&
entry
[
'name'
]
==
project
.
name
&&
entry
[
'owner'
][
'username'
]
==
user
.
username
end
end
end
it
"does not include statistics by default"
do
get
v3_api
(
'/projects/all'
,
admin
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
).
not_to
include
(
'statistics'
)
end
it
"includes statistics if requested"
do
get
v3_api
(
'/projects/all'
,
admin
),
statistics:
true
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
).
to
include
'statistics'
end
end
end
describe
'GET /projects/owned'
do
before
do
project3
project4
end
context
'when unauthenticated'
do
it
'returns authentication error'
do
get
v3_api
(
'/projects/owned'
)
expect
(
response
).
to
have_http_status
(
401
)
end
end
context
'when authenticated as project owner'
do
it
'returns an array of projects the user owns'
do
get
v3_api
(
'/projects/owned'
,
user4
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
[
'name'
]).
to
eq
(
project4
.
name
)
expect
(
json_response
.
first
[
'owner'
][
'username'
]).
to
eq
(
user4
.
username
)
end
it
"does not include statistics by default"
do
get
v3_api
(
'/projects/owned'
,
user4
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
).
not_to
include
(
'statistics'
)
end
it
"includes statistics if requested"
do
attributes
=
{
commit_count:
23
,
storage_size:
702
,
repository_size:
123
,
lfs_objects_size:
234
,
build_artifacts_size:
345
,
}
project4
.
statistics
.
update!
(
attributes
)
get
v3_api
(
'/projects/owned'
,
user4
),
statistics:
true
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
[
'statistics'
]).
to
eq
attributes
.
stringify_keys
end
end
end
describe
'GET /projects/visible'
do
shared_examples_for
'visible projects response'
do
it
'returns the visible projects'
do
get
v3_api
(
'/projects/visible'
,
current_user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
map
{
|
p
|
p
[
'id'
]
}).
to
contain_exactly
(
*
projects
.
map
(
&
:id
))
end
end
let!
(
:public_project
)
{
create
(
:empty_project
,
:public
)
}
before
do
project
project2
project3
project4
end
context
'when unauthenticated'
do
it_behaves_like
'visible projects response'
do
let
(
:current_user
)
{
nil
}
let
(
:projects
)
{
[
public_project
]
}
end
end
context
'when authenticated'
do
it_behaves_like
'visible projects response'
do
let
(
:current_user
)
{
user
}
let
(
:projects
)
{
[
public_project
,
project
,
project2
,
project3
]
}
end
end
context
'when authenticated as a different user'
do
it_behaves_like
'visible projects response'
do
let
(
:current_user
)
{
user2
}
let
(
:projects
)
{
[
public_project
]
}
end
end
end
describe
'GET /projects/starred'
do
let
(
:public_project
)
{
create
(
:empty_project
,
:public
)
}
before
do
project_member2
user3
.
update_attributes
(
starred_projects:
[
project
,
project2
,
project3
,
public_project
])
end
it
'returns the starred projects viewable by the user'
do
get
v3_api
(
'/projects/starred'
,
user3
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
map
{
|
project
|
project
[
'id'
]
}).
to
contain_exactly
(
project
.
id
,
public_project
.
id
)
end
end
describe
'POST /projects'
do
context
'maximum number of projects reached'
do
it
'does not create new project and respond with 403'
do
allow_any_instance_of
(
User
).
to
receive
(
:projects_limit_left
).
and_return
(
0
)
expect
{
post
v3_api
(
'/projects'
,
user2
),
name:
'foo'
}.
to
change
{
Project
.
count
}.
by
(
0
)
expect
(
response
).
to
have_http_status
(
403
)
end
end
it
'creates new project without path and return 201'
do
expect
{
post
v3_api
(
'/projects'
,
user
),
name:
'foo'
}.
to
change
{
Project
.
count
}.
by
(
1
)
expect
(
response
).
to
have_http_status
(
201
)
end
it
'creates last project before reaching project limit'
do
allow_any_instance_of
(
User
).
to
receive
(
:projects_limit_left
).
and_return
(
1
)
post
v3_api
(
'/projects'
,
user2
),
name:
'foo'
expect
(
response
).
to
have_http_status
(
201
)
end
it
'does not create new project without name and return 400'
do
expect
{
post
v3_api
(
'/projects'
,
user
)
}.
not_to
change
{
Project
.
count
}
expect
(
response
).
to
have_http_status
(
400
)
end
it
"assigns attributes to project"
do
project
=
attributes_for
(
:project
,
{
path:
'camelCasePath'
,
description:
FFaker
::
Lorem
.
sentence
,
issues_enabled:
false
,
merge_requests_enabled:
false
,
wiki_enabled:
false
,
only_allow_merge_if_build_succeeds:
false
,
request_access_enabled:
true
,
only_allow_merge_if_all_discussions_are_resolved:
false
})
post
v3_api
(
'/projects'
,
user
),
project
project
.
each_pair
do
|
k
,
v
|
next
if
%i[has_external_issue_tracker issues_enabled merge_requests_enabled wiki_enabled]
.
include?
(
k
)
expect
(
json_response
[
k
.
to_s
]).
to
eq
(
v
)
end
# Check feature permissions attributes
project
=
Project
.
find_by_path
(
project
[
:path
])
expect
(
project
.
project_feature
.
issues_access_level
).
to
eq
(
ProjectFeature
::
DISABLED
)
expect
(
project
.
project_feature
.
merge_requests_access_level
).
to
eq
(
ProjectFeature
::
DISABLED
)
expect
(
project
.
project_feature
.
wiki_access_level
).
to
eq
(
ProjectFeature
::
DISABLED
)
end
it
'sets a project as public'
do
project
=
attributes_for
(
:project
,
:public
)
post
v3_api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'public'
]).
to
be_truthy
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PUBLIC
)
end
it
'sets a project as public using :public'
do
project
=
attributes_for
(
:project
,
{
public:
true
})
post
v3_api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'public'
]).
to
be_truthy
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PUBLIC
)
end
it
'sets a project as internal'
do
project
=
attributes_for
(
:project
,
:internal
)
post
v3_api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
INTERNAL
)
end
it
'sets a project as internal overriding :public'
do
project
=
attributes_for
(
:project
,
:internal
,
{
public:
true
})
post
v3_api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
INTERNAL
)
end
it
'sets a project as private'
do
project
=
attributes_for
(
:project
,
:private
)
post
v3_api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PRIVATE
)
end
it
'sets a project as private using :public'
do
project
=
attributes_for
(
:project
,
{
public:
false
})
post
v3_api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PRIVATE
)
end
it
'sets a project as allowing merge even if build fails'
do
project
=
attributes_for
(
:project
,
{
only_allow_merge_if_build_succeeds:
false
})
post
v3_api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'only_allow_merge_if_build_succeeds'
]).
to
be_falsey
end
it
'sets a project as allowing merge only if build succeeds'
do
project
=
attributes_for
(
:project
,
{
only_allow_merge_if_build_succeeds:
true
})
post
v3_api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'only_allow_merge_if_build_succeeds'
]).
to
be_truthy
end
it
'sets a project as allowing merge even if discussions are unresolved'
do
project
=
attributes_for
(
:project
,
{
only_allow_merge_if_all_discussions_are_resolved:
false
})
post
v3_api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'only_allow_merge_if_all_discussions_are_resolved'
]).
to
be_falsey
end
it
'sets a project as allowing merge if only_allow_merge_if_all_discussions_are_resolved is nil'
do
project
=
attributes_for
(
:project
,
only_allow_merge_if_all_discussions_are_resolved:
nil
)
post
v3_api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'only_allow_merge_if_all_discussions_are_resolved'
]).
to
be_falsey
end
it
'sets a project as allowing merge only if all discussions are resolved'
do
project
=
attributes_for
(
:project
,
{
only_allow_merge_if_all_discussions_are_resolved:
true
})
post
v3_api
(
'/projects'
,
user
),
project
expect
(
json_response
[
'only_allow_merge_if_all_discussions_are_resolved'
]).
to
be_truthy
end
context
'when a visibility level is restricted'
do
before
do
@project
=
attributes_for
(
:project
,
{
public:
true
})
stub_application_setting
(
restricted_visibility_levels:
[
Gitlab
::
VisibilityLevel
::
PUBLIC
])
end
it
'does not allow a non-admin to use a restricted visibility level'
do
post
v3_api
(
'/projects'
,
user
),
@project
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
][
'visibility_level'
].
first
).
to
(
match
(
'restricted by your GitLab administrator'
)
)
end
it
'allows an admin to override restricted visibility settings'
do
post
v3_api
(
'/projects'
,
admin
),
@project
expect
(
json_response
[
'public'
]).
to
be_truthy
expect
(
json_response
[
'visibility_level'
]).
to
(
eq
(
Gitlab
::
VisibilityLevel
::
PUBLIC
)
)
end
end
end
describe
'POST /projects/user/:id'
do
before
{
project
}
before
{
admin
}
it
'should create new project without path and return 201'
do
expect
{
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
name:
'foo'
}.
to
change
{
Project
.
count
}.
by
(
1
)
expect
(
response
).
to
have_http_status
(
201
)
end
it
'responds with 400 on failure and not project'
do
expect
{
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
)
}.
not_to
change
{
Project
.
count
}
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'error'
]).
to
eq
(
'name is missing'
)
end
it
'assigns attributes to project'
do
project
=
attributes_for
(
:project
,
{
description:
FFaker
::
Lorem
.
sentence
,
issues_enabled:
false
,
merge_requests_enabled:
false
,
wiki_enabled:
false
,
request_access_enabled:
true
})
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
response
).
to
have_http_status
(
201
)
project
.
each_pair
do
|
k
,
v
|
next
if
%i[has_external_issue_tracker path]
.
include?
(
k
)
expect
(
json_response
[
k
.
to_s
]).
to
eq
(
v
)
end
end
it
'sets a project as public'
do
project
=
attributes_for
(
:project
,
:public
)
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'public'
]).
to
be_truthy
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PUBLIC
)
end
it
'sets a project as public using :public'
do
project
=
attributes_for
(
:project
,
{
public:
true
})
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'public'
]).
to
be_truthy
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PUBLIC
)
end
it
'sets a project as internal'
do
project
=
attributes_for
(
:project
,
:internal
)
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
INTERNAL
)
end
it
'sets a project as internal overriding :public'
do
project
=
attributes_for
(
:project
,
:internal
,
{
public:
true
})
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
INTERNAL
)
end
it
'sets a project as private'
do
project
=
attributes_for
(
:project
,
:private
)
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PRIVATE
)
end
it
'sets a project as private using :public'
do
project
=
attributes_for
(
:project
,
{
public:
false
})
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PRIVATE
)
end
it
'sets a project as allowing merge even if build fails'
do
project
=
attributes_for
(
:project
,
{
only_allow_merge_if_build_succeeds:
false
})
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
json_response
[
'only_allow_merge_if_build_succeeds'
]).
to
be_falsey
end
it
'sets a project as allowing merge only if build succeeds'
do
project
=
attributes_for
(
:project
,
{
only_allow_merge_if_build_succeeds:
true
})
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
json_response
[
'only_allow_merge_if_build_succeeds'
]).
to
be_truthy
end
it
'sets a project as allowing merge even if discussions are unresolved'
do
project
=
attributes_for
(
:project
,
{
only_allow_merge_if_all_discussions_are_resolved:
false
})
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
json_response
[
'only_allow_merge_if_all_discussions_are_resolved'
]).
to
be_falsey
end
it
'sets a project as allowing merge only if all discussions are resolved'
do
project
=
attributes_for
(
:project
,
{
only_allow_merge_if_all_discussions_are_resolved:
true
})
post
v3_api
(
"/projects/user/
#{
user
.
id
}
"
,
admin
),
project
expect
(
json_response
[
'only_allow_merge_if_all_discussions_are_resolved'
]).
to
be_truthy
end
end
describe
"POST /projects/:id/uploads"
do
before
{
project
}
it
"uploads the file and returns its info"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/uploads"
,
user
),
file:
fixture_file_upload
(
Rails
.
root
+
"spec/fixtures/dk.png"
,
"image/png"
)
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'alt'
]).
to
eq
(
"dk"
)
expect
(
json_response
[
'url'
]).
to
start_with
(
"/uploads/"
)
expect
(
json_response
[
'url'
]).
to
end_with
(
"/dk.png"
)
end
end
describe
'GET /projects/:id'
do
context
'when unauthenticated'
do
it
'returns the public projects'
do
public_project
=
create
(
:empty_project
,
:public
)
get
v3_api
(
"/projects/
#{
public_project
.
id
}
"
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'id'
]).
to
eq
(
public_project
.
id
)
expect
(
json_response
[
'description'
]).
to
eq
(
public_project
.
description
)
expect
(
json_response
.
keys
).
not_to
include
(
'permissions'
)
end
end
context
'when authenticated'
do
before
do
project
project_member
end
it
'returns a project by id'
do
group
=
create
(
:group
)
link
=
create
(
:project_group_link
,
project:
project
,
group:
group
)
get
v3_api
(
"/projects/
#{
project
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'id'
]).
to
eq
(
project
.
id
)
expect
(
json_response
[
'description'
]).
to
eq
(
project
.
description
)
expect
(
json_response
[
'default_branch'
]).
to
eq
(
project
.
default_branch
)
expect
(
json_response
[
'tag_list'
]).
to
be_an
Array
expect
(
json_response
[
'public'
]).
to
be_falsey
expect
(
json_response
[
'archived'
]).
to
be_falsey
expect
(
json_response
[
'visibility_level'
]).
to
be_present
expect
(
json_response
[
'ssh_url_to_repo'
]).
to
be_present
expect
(
json_response
[
'http_url_to_repo'
]).
to
be_present
expect
(
json_response
[
'web_url'
]).
to
be_present
expect
(
json_response
[
'owner'
]).
to
be_a
Hash
expect
(
json_response
[
'owner'
]).
to
be_a
Hash
expect
(
json_response
[
'name'
]).
to
eq
(
project
.
name
)
expect
(
json_response
[
'path'
]).
to
be_present
expect
(
json_response
[
'issues_enabled'
]).
to
be_present
expect
(
json_response
[
'merge_requests_enabled'
]).
to
be_present
expect
(
json_response
[
'wiki_enabled'
]).
to
be_present
expect
(
json_response
[
'builds_enabled'
]).
to
be_present
expect
(
json_response
[
'snippets_enabled'
]).
to
be_present
expect
(
json_response
[
'container_registry_enabled'
]).
to
be_present
expect
(
json_response
[
'created_at'
]).
to
be_present
expect
(
json_response
[
'last_activity_at'
]).
to
be_present
expect
(
json_response
[
'shared_runners_enabled'
]).
to
be_present
expect
(
json_response
[
'creator_id'
]).
to
be_present
expect
(
json_response
[
'namespace'
]).
to
be_present
expect
(
json_response
[
'avatar_url'
]).
to
be_nil
expect
(
json_response
[
'star_count'
]).
to
be_present
expect
(
json_response
[
'forks_count'
]).
to
be_present
expect
(
json_response
[
'public_builds'
]).
to
be_present
expect
(
json_response
[
'shared_with_groups'
]).
to
be_an
Array
expect
(
json_response
[
'shared_with_groups'
].
length
).
to
eq
(
1
)
expect
(
json_response
[
'shared_with_groups'
][
0
][
'group_id'
]).
to
eq
(
group
.
id
)
expect
(
json_response
[
'shared_with_groups'
][
0
][
'group_name'
]).
to
eq
(
group
.
name
)
expect
(
json_response
[
'shared_with_groups'
][
0
][
'group_access_level'
]).
to
eq
(
link
.
group_access
)
expect
(
json_response
[
'only_allow_merge_if_build_succeeds'
]).
to
eq
(
project
.
only_allow_merge_if_build_succeeds
)
expect
(
json_response
[
'only_allow_merge_if_all_discussions_are_resolved'
]).
to
eq
(
project
.
only_allow_merge_if_all_discussions_are_resolved
)
end
it
'returns a project by path name'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'name'
]).
to
eq
(
project
.
name
)
end
it
'returns a 404 error if not found'
do
get
v3_api
(
'/projects/42'
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
expect
(
json_response
[
'message'
]).
to
eq
(
'404 Project Not Found'
)
end
it
'returns a 404 error if user is not a member'
do
other_user
=
create
(
:user
)
get
v3_api
(
"/projects/
#{
project
.
id
}
"
,
other_user
)
expect
(
response
).
to
have_http_status
(
404
)
end
it
'handles users with dots'
do
dot_user
=
create
(
:user
,
username:
'dot.user'
)
project
=
create
(
:empty_project
,
creator_id:
dot_user
.
id
,
namespace:
dot_user
.
namespace
)
get
v3_api
(
"/projects/
#{
dot_user
.
namespace
.
name
}
%2F
#{
project
.
path
}
"
,
dot_user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'name'
]).
to
eq
(
project
.
name
)
end
it
'exposes namespace fields'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'namespace'
]).
to
eq
({
'id'
=>
user
.
namespace
.
id
,
'name'
=>
user
.
namespace
.
name
,
'path'
=>
user
.
namespace
.
path
,
'kind'
=>
user
.
namespace
.
kind
,
})
end
describe
'permissions'
do
context
'all projects'
do
before
{
project
.
team
<<
[
user
,
:master
]
}
it
'contains permission information'
do
get
v3_api
(
"/projects"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
.
first
[
'permissions'
][
'project_access'
][
'access_level'
]).
to
eq
(
Gitlab
::
Access
::
MASTER
)
expect
(
json_response
.
first
[
'permissions'
][
'group_access'
]).
to
be_nil
end
end
context
'personal project'
do
it
'sets project access and returns 200'
do
project
.
team
<<
[
user
,
:master
]
get
v3_api
(
"/projects/
#{
project
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'permissions'
][
'project_access'
][
'access_level'
]).
to
eq
(
Gitlab
::
Access
::
MASTER
)
expect
(
json_response
[
'permissions'
][
'group_access'
]).
to
be_nil
end
end
context
'group project'
do
let
(
:project2
)
{
create
(
:empty_project
,
group:
create
(
:group
))
}
before
{
project2
.
group
.
add_owner
(
user
)
}
it
'sets the owner and return 200'
do
get
v3_api
(
"/projects/
#{
project2
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'permissions'
][
'project_access'
]).
to
be_nil
expect
(
json_response
[
'permissions'
][
'group_access'
][
'access_level'
]).
to
eq
(
Gitlab
::
Access
::
OWNER
)
end
end
end
end
end
describe
'GET /projects/:id/events'
do
shared_examples_for
'project events response'
do
it
'returns the project events'
do
member
=
create
(
:user
)
create
(
:project_member
,
:developer
,
user:
member
,
project:
project
)
note
=
create
(
:note_on_issue
,
note:
'What an awesome day!'
,
project:
project
)
EventCreateService
.
new
.
leave_note
(
note
,
note
.
author
)
get
v3_api
(
"/projects/
#{
project
.
id
}
/events"
,
current_user
)
expect
(
response
).
to
have_http_status
(
200
)
first_event
=
json_response
.
first
expect
(
first_event
[
'action_name'
]).
to
eq
(
'commented on'
)
expect
(
first_event
[
'note'
][
'body'
]).
to
eq
(
'What an awesome day!'
)
last_event
=
json_response
.
last
expect
(
last_event
[
'action_name'
]).
to
eq
(
'joined'
)
expect
(
last_event
[
'project_id'
].
to_i
).
to
eq
(
project
.
id
)
expect
(
last_event
[
'author_username'
]).
to
eq
(
member
.
username
)
expect
(
last_event
[
'author'
][
'name'
]).
to
eq
(
member
.
name
)
end
end
context
'when unauthenticated'
do
it_behaves_like
'project events response'
do
let
(
:project
)
{
create
(
:empty_project
,
:public
)
}
let
(
:current_user
)
{
nil
}
end
end
context
'when authenticated'
do
context
'valid request'
do
it_behaves_like
'project events response'
do
let
(
:current_user
)
{
user
}
end
end
it
'returns a 404 error if not found'
do
get
v3_api
(
'/projects/42/events'
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
expect
(
json_response
[
'message'
]).
to
eq
(
'404 Project Not Found'
)
end
it
'returns a 404 error if user is not a member'
do
other_user
=
create
(
:user
)
get
v3_api
(
"/projects/
#{
project
.
id
}
/events"
,
other_user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
end
describe
'GET /projects/:id/users'
do
shared_examples_for
'project users response'
do
it
'returns the project users'
do
member
=
create
(
:user
)
create
(
:project_member
,
:developer
,
user:
member
,
project:
project
)
get
v3_api
(
"/projects/
#{
project
.
id
}
/users"
,
current_user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
size
).
to
eq
(
1
)
first_user
=
json_response
.
first
expect
(
first_user
[
'username'
]).
to
eq
(
member
.
username
)
expect
(
first_user
[
'name'
]).
to
eq
(
member
.
name
)
expect
(
first_user
.
keys
).
to
contain_exactly
(
*
%w[name username id state avatar_url web_url]
)
end
end
context
'when unauthenticated'
do
it_behaves_like
'project users response'
do
let
(
:project
)
{
create
(
:empty_project
,
:public
)
}
let
(
:current_user
)
{
nil
}
end
end
context
'when authenticated'
do
context
'valid request'
do
it_behaves_like
'project users response'
do
let
(
:current_user
)
{
user
}
end
end
it
'returns a 404 error if not found'
do
get
v3_api
(
'/projects/42/users'
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
expect
(
json_response
[
'message'
]).
to
eq
(
'404 Project Not Found'
)
end
it
'returns a 404 error if user is not a member'
do
other_user
=
create
(
:user
)
get
v3_api
(
"/projects/
#{
project
.
id
}
/users"
,
other_user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
end
describe
'GET /projects/:id/snippets'
do
before
{
snippet
}
it
'returns an array of project snippets'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/snippets"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
first
[
'title'
]).
to
eq
(
snippet
.
title
)
end
end
describe
'GET /projects/:id/snippets/:snippet_id'
do
it
'returns a project snippet'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/snippets/
#{
snippet
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
snippet
.
title
)
end
it
'returns a 404 error if snippet id not found'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/snippets/1234"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
'POST /projects/:id/snippets'
do
it
'creates a new project snippet'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/snippets"
,
user
),
title:
'v3_api test'
,
file_name:
'sample.rb'
,
code:
'test'
,
visibility_level:
'0'
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'title'
]).
to
eq
(
'v3_api test'
)
end
it
'returns a 400 error if invalid snippet is given'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/snippets"
,
user
)
expect
(
status
).
to
eq
(
400
)
end
end
describe
'PUT /projects/:id/snippets/:snippet_id'
do
it
'updates an existing project snippet'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/snippets/
#{
snippet
.
id
}
"
,
user
),
code:
'updated code'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
'example'
)
expect
(
snippet
.
reload
.
content
).
to
eq
(
'updated code'
)
end
it
'updates an existing project snippet with new title'
do
put
v3_api
(
"/projects/
#{
project
.
id
}
/snippets/
#{
snippet
.
id
}
"
,
user
),
title:
'other v3_api test'
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'title'
]).
to
eq
(
'other v3_api test'
)
end
end
describe
'DELETE /projects/:id/snippets/:snippet_id'
do
before
{
snippet
}
it
'deletes existing project snippet'
do
expect
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/snippets/
#{
snippet
.
id
}
"
,
user
)
end
.
to
change
{
Snippet
.
count
}.
by
(
-
1
)
expect
(
response
).
to
have_http_status
(
200
)
end
it
'returns 404 when deleting unknown snippet id'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/snippets/1234"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
'GET /projects/:id/snippets/:snippet_id/raw'
do
it
'gets a raw project snippet'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/snippets/
#{
snippet
.
id
}
/raw"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
end
it
'returns a 404 error if raw project snippet not found'
do
get
v3_api
(
"/projects/
#{
project
.
id
}
/snippets/5555/raw"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
:fork_admin
do
let
(
:project_fork_target
)
{
create
(
:empty_project
)
}
let
(
:project_fork_source
)
{
create
(
:empty_project
,
:public
)
}
describe
'POST /projects/:id/fork/:forked_from_id'
do
let
(
:new_project_fork_source
)
{
create
(
:empty_project
,
:public
)
}
it
"is not available for non admin users"
do
post
v3_api
(
"/projects/
#{
project_fork_target
.
id
}
/fork/
#{
project_fork_source
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
403
)
end
it
'allows project to be forked from an existing project'
do
expect
(
project_fork_target
.
forked?
).
not_to
be_truthy
post
v3_api
(
"/projects/
#{
project_fork_target
.
id
}
/fork/
#{
project_fork_source
.
id
}
"
,
admin
)
expect
(
response
).
to
have_http_status
(
201
)
project_fork_target
.
reload
expect
(
project_fork_target
.
forked_from_project
.
id
).
to
eq
(
project_fork_source
.
id
)
expect
(
project_fork_target
.
forked_project_link
).
not_to
be_nil
expect
(
project_fork_target
.
forked?
).
to
be_truthy
end
it
'fails if forked_from project which does not exist'
do
post
v3_api
(
"/projects/
#{
project_fork_target
.
id
}
/fork/9999"
,
admin
)
expect
(
response
).
to
have_http_status
(
404
)
end
it
'fails with 409 if already forked'
do
post
v3_api
(
"/projects/
#{
project_fork_target
.
id
}
/fork/
#{
project_fork_source
.
id
}
"
,
admin
)
project_fork_target
.
reload
expect
(
project_fork_target
.
forked_from_project
.
id
).
to
eq
(
project_fork_source
.
id
)
post
v3_api
(
"/projects/
#{
project_fork_target
.
id
}
/fork/
#{
new_project_fork_source
.
id
}
"
,
admin
)
expect
(
response
).
to
have_http_status
(
409
)
project_fork_target
.
reload
expect
(
project_fork_target
.
forked_from_project
.
id
).
to
eq
(
project_fork_source
.
id
)
expect
(
project_fork_target
.
forked?
).
to
be_truthy
end
end
describe
'DELETE /projects/:id/fork'
do
it
"is not visible to users outside group"
do
delete
v3_api
(
"/projects/
#{
project_fork_target
.
id
}
/fork"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
context
'when users belong to project group'
do
let
(
:project_fork_target
)
{
create
(
:empty_project
,
group:
create
(
:group
))
}
before
do
project_fork_target
.
group
.
add_owner
user
project_fork_target
.
group
.
add_developer
user2
end
it
'is forbidden to non-owner users'
do
delete
v3_api
(
"/projects/
#{
project_fork_target
.
id
}
/fork"
,
user2
)
expect
(
response
).
to
have_http_status
(
403
)
end
it
'makes forked project unforked'
do
post
v3_api
(
"/projects/
#{
project_fork_target
.
id
}
/fork/
#{
project_fork_source
.
id
}
"
,
admin
)
project_fork_target
.
reload
expect
(
project_fork_target
.
forked_from_project
).
not_to
be_nil
expect
(
project_fork_target
.
forked?
).
to
be_truthy
delete
v3_api
(
"/projects/
#{
project_fork_target
.
id
}
/fork"
,
admin
)
expect
(
response
).
to
have_http_status
(
200
)
project_fork_target
.
reload
expect
(
project_fork_target
.
forked_from_project
).
to
be_nil
expect
(
project_fork_target
.
forked?
).
not_to
be_truthy
end
it
'is idempotent if not forked'
do
expect
(
project_fork_target
.
forked_from_project
).
to
be_nil
delete
v3_api
(
"/projects/
#{
project_fork_target
.
id
}
/fork"
,
admin
)
expect
(
response
).
to
have_http_status
(
304
)
expect
(
project_fork_target
.
reload
.
forked_from_project
).
to
be_nil
end
end
end
end
describe
"POST /projects/:id/share"
do
let
(
:group
)
{
create
(
:group
)
}
it
"shares project with group"
do
expires_at
=
10
.
days
.
from_now
.
to_date
expect
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/share"
,
user
),
group_id:
group
.
id
,
group_access:
Gitlab
::
Access
::
DEVELOPER
,
expires_at:
expires_at
end
.
to
change
{
ProjectGroupLink
.
count
}.
by
(
1
)
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'group_id'
]).
to
eq
(
group
.
id
)
expect
(
json_response
[
'group_access'
]).
to
eq
(
Gitlab
::
Access
::
DEVELOPER
)
expect
(
json_response
[
'expires_at'
]).
to
eq
(
expires_at
.
to_s
)
end
it
"returns a 400 error when group id is not given"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/share"
,
user
),
group_access:
Gitlab
::
Access
::
DEVELOPER
expect
(
response
).
to
have_http_status
(
400
)
end
it
"returns a 400 error when access level is not given"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/share"
,
user
),
group_id:
group
.
id
expect
(
response
).
to
have_http_status
(
400
)
end
it
"returns a 400 error when sharing is disabled"
do
project
.
namespace
.
update
(
share_with_group_lock:
true
)
post
v3_api
(
"/projects/
#{
project
.
id
}
/share"
,
user
),
group_id:
group
.
id
,
group_access:
Gitlab
::
Access
::
DEVELOPER
expect
(
response
).
to
have_http_status
(
400
)
end
it
'returns a 404 error when user cannot read group'
do
private_group
=
create
(
:group
,
:private
)
post
v3_api
(
"/projects/
#{
project
.
id
}
/share"
,
user
),
group_id:
private_group
.
id
,
group_access:
Gitlab
::
Access
::
DEVELOPER
expect
(
response
).
to
have_http_status
(
404
)
end
it
'returns a 404 error when group does not exist'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/share"
,
user
),
group_id:
1234
,
group_access:
Gitlab
::
Access
::
DEVELOPER
expect
(
response
).
to
have_http_status
(
404
)
end
it
"returns a 400 error when wrong params passed"
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/share"
,
user
),
group_id:
group
.
id
,
group_access:
1234
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'error'
]).
to
eq
'group_access does not have a valid value'
end
end
describe
'DELETE /projects/:id/share/:group_id'
do
it
'returns 204 when deleting a group share'
do
group
=
create
(
:group
,
:public
)
create
(
:project_group_link
,
group:
group
,
project:
project
)
delete
v3_api
(
"/projects/
#{
project
.
id
}
/share/
#{
group
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
204
)
expect
(
project
.
project_group_links
).
to
be_empty
end
it
'returns a 400 when group id is not an integer'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/share/foo"
,
user
)
expect
(
response
).
to
have_http_status
(
400
)
end
it
'returns a 404 error when group link does not exist'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
/share/1234"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
it
'returns a 404 error when project does not exist'
do
delete
v3_api
(
"/projects/123/share/1234"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
'GET /projects/search/:query'
do
let!
(
:query
)
{
'query'
}
let!
(
:search
)
{
create
(
:empty_project
,
name:
query
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let!
(
:pre
)
{
create
(
:empty_project
,
name:
"pre_
#{
query
}
"
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let!
(
:post
)
{
create
(
:empty_project
,
name:
"
#{
query
}
_post"
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let!
(
:pre_post
)
{
create
(
:empty_project
,
name:
"pre_
#{
query
}
_post"
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let!
(
:unfound
)
{
create
(
:empty_project
,
name:
'unfound'
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let!
(
:internal
)
{
create
(
:empty_project
,
:internal
,
name:
"internal
#{
query
}
"
)
}
let!
(
:unfound_internal
)
{
create
(
:empty_project
,
:internal
,
name:
'unfound internal'
)
}
let!
(
:public
)
{
create
(
:empty_project
,
:public
,
name:
"public
#{
query
}
"
)
}
let!
(
:unfound_public
)
{
create
(
:empty_project
,
:public
,
name:
'unfound public'
)
}
let!
(
:one_dot_two
)
{
create
(
:empty_project
,
:public
,
name:
"one.dot.two"
)
}
shared_examples_for
'project search response'
do
|
args
=
{}
|
it
'returns project search responses'
do
get
v3_api
(
"/projects/search/
#{
args
[
:query
]
}
"
,
current_user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
size
).
to
eq
(
args
[
:results
])
json_response
.
each
{
|
project
|
expect
(
project
[
'name'
]).
to
match
(
args
[
:match_regex
]
||
/.*
#{
args
[
:query
]
}
.*/
)
}
end
end
context
'when unauthenticated'
do
it_behaves_like
'project search response'
,
query:
'query'
,
results:
1
do
let
(
:current_user
)
{
nil
}
end
end
context
'when authenticated'
do
it_behaves_like
'project search response'
,
query:
'query'
,
results:
6
do
let
(
:current_user
)
{
user
}
end
it_behaves_like
'project search response'
,
query:
'one.dot.two'
,
results:
1
do
let
(
:current_user
)
{
user
}
end
end
context
'when authenticated as a different user'
do
it_behaves_like
'project search response'
,
query:
'query'
,
results:
2
,
match_regex:
/(internal|public) query/
do
let
(
:current_user
)
{
user2
}
end
end
end
describe
'PUT /projects/:id'
do
before
{
project
}
before
{
user
}
before
{
user3
}
before
{
user4
}
before
{
project3
}
before
{
project4
}
before
{
project_member3
}
before
{
project_member2
}
context
'when unauthenticated'
do
it
'returns authentication error'
do
project_param
=
{
name:
'bar'
}
put
v3_api
(
"/projects/
#{
project
.
id
}
"
),
project_param
expect
(
response
).
to
have_http_status
(
401
)
end
end
context
'when authenticated as project owner'
do
it
'updates name'
do
project_param
=
{
name:
'bar'
}
put
v3_api
(
"/projects/
#{
project
.
id
}
"
,
user
),
project_param
expect
(
response
).
to
have_http_status
(
200
)
project_param
.
each_pair
do
|
k
,
v
|
expect
(
json_response
[
k
.
to_s
]).
to
eq
(
v
)
end
end
it
'updates visibility_level'
do
project_param
=
{
visibility_level:
20
}
put
v3_api
(
"/projects/
#{
project3
.
id
}
"
,
user
),
project_param
expect
(
response
).
to
have_http_status
(
200
)
project_param
.
each_pair
do
|
k
,
v
|
expect
(
json_response
[
k
.
to_s
]).
to
eq
(
v
)
end
end
it
'updates visibility_level from public to private'
do
project3
.
update_attributes
({
visibility_level:
Gitlab
::
VisibilityLevel
::
PUBLIC
})
project_param
=
{
public:
false
}
put
v3_api
(
"/projects/
#{
project3
.
id
}
"
,
user
),
project_param
expect
(
response
).
to
have_http_status
(
200
)
project_param
.
each_pair
do
|
k
,
v
|
expect
(
json_response
[
k
.
to_s
]).
to
eq
(
v
)
end
expect
(
json_response
[
'visibility_level'
]).
to
eq
(
Gitlab
::
VisibilityLevel
::
PRIVATE
)
end
it
'does not update name to existing name'
do
project_param
=
{
name:
project3
.
name
}
put
v3_api
(
"/projects/
#{
project
.
id
}
"
,
user
),
project_param
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
][
'name'
]).
to
eq
([
'has already been taken'
])
end
it
'updates request_access_enabled'
do
project_param
=
{
request_access_enabled:
false
}
put
v3_api
(
"/projects/
#{
project
.
id
}
"
,
user
),
project_param
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'request_access_enabled'
]).
to
eq
(
false
)
end
it
'updates path & name to existing path & name in different namespace'
do
project_param
=
{
path:
project4
.
path
,
name:
project4
.
name
}
put
v3_api
(
"/projects/
#{
project3
.
id
}
"
,
user
),
project_param
expect
(
response
).
to
have_http_status
(
200
)
project_param
.
each_pair
do
|
k
,
v
|
expect
(
json_response
[
k
.
to_s
]).
to
eq
(
v
)
end
end
end
context
'when authenticated as project master'
do
it
'updates path'
do
project_param
=
{
path:
'bar'
}
put
v3_api
(
"/projects/
#{
project3
.
id
}
"
,
user4
),
project_param
expect
(
response
).
to
have_http_status
(
200
)
project_param
.
each_pair
do
|
k
,
v
|
expect
(
json_response
[
k
.
to_s
]).
to
eq
(
v
)
end
end
it
'updates other attributes'
do
project_param
=
{
issues_enabled:
true
,
wiki_enabled:
true
,
snippets_enabled:
true
,
merge_requests_enabled:
true
,
description:
'new description'
}
put
v3_api
(
"/projects/
#{
project3
.
id
}
"
,
user4
),
project_param
expect
(
response
).
to
have_http_status
(
200
)
project_param
.
each_pair
do
|
k
,
v
|
expect
(
json_response
[
k
.
to_s
]).
to
eq
(
v
)
end
end
it
'does not update path to existing path'
do
project_param
=
{
path:
project
.
path
}
put
v3_api
(
"/projects/
#{
project3
.
id
}
"
,
user4
),
project_param
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
][
'path'
]).
to
eq
([
'has already been taken'
])
end
it
'does not update name'
do
project_param
=
{
name:
'bar'
}
put
v3_api
(
"/projects/
#{
project3
.
id
}
"
,
user4
),
project_param
expect
(
response
).
to
have_http_status
(
403
)
end
it
'does not update visibility_level'
do
project_param
=
{
visibility_level:
20
}
put
v3_api
(
"/projects/
#{
project3
.
id
}
"
,
user4
),
project_param
expect
(
response
).
to
have_http_status
(
403
)
end
end
context
'when authenticated as project developer'
do
it
'does not update other attributes'
do
project_param
=
{
path:
'bar'
,
issues_enabled:
true
,
wiki_enabled:
true
,
snippets_enabled:
true
,
merge_requests_enabled:
true
,
description:
'new description'
,
request_access_enabled:
true
}
put
v3_api
(
"/projects/
#{
project
.
id
}
"
,
user3
),
project_param
expect
(
response
).
to
have_http_status
(
403
)
end
end
end
describe
'POST /projects/:id/archive'
do
context
'on an unarchived project'
do
it
'archives the project'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/archive"
,
user
)
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'archived'
]).
to
be_truthy
end
end
context
'on an archived project'
do
before
do
project
.
archive!
end
it
'remains archived'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/archive"
,
user
)
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'archived'
]).
to
be_truthy
end
end
context
'user without archiving rights to the project'
do
before
do
project
.
team
<<
[
user3
,
:developer
]
end
it
'rejects the action'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/archive"
,
user3
)
expect
(
response
).
to
have_http_status
(
403
)
end
end
end
describe
'POST /projects/:id/unarchive'
do
context
'on an unarchived project'
do
it
'remains unarchived'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/unarchive"
,
user
)
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'archived'
]).
to
be_falsey
end
end
context
'on an archived project'
do
before
do
project
.
archive!
end
it
'unarchives the project'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/unarchive"
,
user
)
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'archived'
]).
to
be_falsey
end
end
context
'user without archiving rights to the project'
do
before
do
project
.
team
<<
[
user3
,
:developer
]
end
it
'rejects the action'
do
post
v3_api
(
"/projects/
#{
project
.
id
}
/unarchive"
,
user3
)
expect
(
response
).
to
have_http_status
(
403
)
end
end
end
describe
'POST /projects/:id/star'
do
context
'on an unstarred project'
do
it
'stars the project'
do
expect
{
post
v3_api
(
"/projects/
#{
project
.
id
}
/star"
,
user
)
}.
to
change
{
project
.
reload
.
star_count
}.
by
(
1
)
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'star_count'
]).
to
eq
(
1
)
end
end
context
'on a starred project'
do
before
do
user
.
toggle_star
(
project
)
project
.
reload
end
it
'does not modify the star count'
do
expect
{
post
v3_api
(
"/projects/
#{
project
.
id
}
/star"
,
user
)
}.
not_to
change
{
project
.
reload
.
star_count
}
expect
(
response
).
to
have_http_status
(
304
)
end
end
end
describe
'DELETE /projects/:id/star'
do
context
'on a starred project'
do
before
do
user
.
toggle_star
(
project
)
project
.
reload
end
it
'unstars the project'
do
expect
{
delete
v3_api
(
"/projects/
#{
project
.
id
}
/star"
,
user
)
}.
to
change
{
project
.
reload
.
star_count
}.
by
(
-
1
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'star_count'
]).
to
eq
(
0
)
end
end
context
'on an unstarred project'
do
it
'does not modify the star count'
do
expect
{
delete
v3_api
(
"/projects/
#{
project
.
id
}
/star"
,
user
)
}.
not_to
change
{
project
.
reload
.
star_count
}
expect
(
response
).
to
have_http_status
(
304
)
end
end
end
describe
'DELETE /projects/:id'
do
context
'when authenticated as user'
do
it
'removes project'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
end
it
'does not remove a project if not an owner'
do
user3
=
create
(
:user
)
project
.
team
<<
[
user3
,
:developer
]
delete
v3_api
(
"/projects/
#{
project
.
id
}
"
,
user3
)
expect
(
response
).
to
have_http_status
(
403
)
end
it
'does not remove a non existing project'
do
delete
v3_api
(
'/projects/1328'
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
it
'does not remove a project not attached to user'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
"
,
user2
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
context
'when authenticated as admin'
do
it
'removes any existing project'
do
delete
v3_api
(
"/projects/
#{
project
.
id
}
"
,
admin
)
expect
(
response
).
to
have_http_status
(
200
)
end
it
'does not remove a non existing project'
do
delete
v3_api
(
'/projects/1328'
,
admin
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
end
end
spec/support/api_helpers.rb
View file @
cadef802
...
...
@@ -17,8 +17,8 @@ module ApiHelpers
# => "/api/v2/issues?foo=bar&private_token=..."
#
# Returns the relative path to the requested API resource
def
api
(
path
,
user
=
nil
)
"/api/
#{
API
::
API
.
version
}#{
path
}
"
+
def
api
(
path
,
user
=
nil
,
version:
API
::
API
.
version
)
"/api/
#{
version
}#{
path
}
"
+
# Normalize query string
(
path
.
index
(
'?'
)
?
''
:
'?'
)
+
...
...
@@ -31,6 +31,11 @@ module ApiHelpers
end
end
# Temporary helper method for simplifying V3 exclusive API specs
def
v3_api
(
path
,
user
=
nil
)
api
(
path
,
user
,
version:
'v3'
)
end
def
ci_api
(
path
,
user
=
nil
)
"/ci/api/v1/
#{
path
}
"
+
...
...
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