Grapify the projects API
This commit is contained in:
parent
c54827961a
commit
7c607a55ab
4 changed files with 292 additions and 362 deletions
|
@ -626,6 +626,7 @@ Parameters:
|
||||||
| `path` | string | no | Custom repository name for new project. By default generated based on name |
|
| `path` | string | no | Custom repository name for new project. By default generated based on name |
|
||||||
| `default_branch` | string | no | `master` by default |
|
| `default_branch` | string | no | `master` by default |
|
||||||
| `namespace_id` | integer | no | Namespace for the new project (defaults to the current user's namespace) |
|
| `namespace_id` | integer | no | Namespace for the new project (defaults to the current user's namespace) |
|
||||||
|
| `default_branch` | string | no | `master` by default |
|
||||||
| `description` | string | no | Short project description |
|
| `description` | string | no | Short project description |
|
||||||
| `issues_enabled` | boolean | no | Enable issues for this project |
|
| `issues_enabled` | boolean | no | Enable issues for this project |
|
||||||
| `merge_requests_enabled` | boolean | no | Enable merge requests for this project |
|
| `merge_requests_enabled` | boolean | no | Enable merge requests for this project |
|
||||||
|
|
|
@ -324,11 +324,6 @@ module API
|
||||||
# Projects helpers
|
# Projects helpers
|
||||||
|
|
||||||
def filter_projects(projects)
|
def filter_projects(projects)
|
||||||
# If the archived parameter is passed, limit results accordingly
|
|
||||||
if params[:archived].present?
|
|
||||||
projects = projects.where(archived: to_boolean(params[:archived]))
|
|
||||||
end
|
|
||||||
|
|
||||||
if params[:search].present?
|
if params[:search].present?
|
||||||
projects = projects.search(params[:search])
|
projects = projects.search(params[:search])
|
||||||
end
|
end
|
||||||
|
@ -337,25 +332,8 @@ module API
|
||||||
projects = projects.search_by_visibility(params[:visibility])
|
projects = projects.search_by_visibility(params[:visibility])
|
||||||
end
|
end
|
||||||
|
|
||||||
projects.reorder(project_order_by => project_sort)
|
projects = projects.where(archived: params[:archived])
|
||||||
end
|
projects.reorder(params[:order_by] => params[:sort])
|
||||||
|
|
||||||
def project_order_by
|
|
||||||
order_fields = %w(id name path created_at updated_at last_activity_at)
|
|
||||||
|
|
||||||
if order_fields.include?(params['order_by'])
|
|
||||||
params['order_by']
|
|
||||||
else
|
|
||||||
'created_at'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def project_sort
|
|
||||||
if params["sort"] == 'asc'
|
|
||||||
:asc
|
|
||||||
else
|
|
||||||
:desc
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# file helpers
|
# file helpers
|
||||||
|
|
|
@ -1,293 +1,287 @@
|
||||||
module API
|
module API
|
||||||
# Projects API
|
# Projects API
|
||||||
class Projects < Grape::API
|
class Projects < Grape::API
|
||||||
|
include PaginationParams
|
||||||
|
|
||||||
before { authenticate! }
|
before { authenticate! }
|
||||||
|
|
||||||
resource :projects, requirements: { id: /[^\/]+/ } do
|
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
|
helpers do
|
||||||
def map_public_to_visibility_level(attrs)
|
params :sort_params do
|
||||||
publik = attrs.delete(:public)
|
optional :order_by, type: String, values: %w[id name path created_at updated_at last_activity_at],
|
||||||
if publik.present? && !attrs[:visibility_level].present?
|
default: 'created_at', desc: 'Return projects ordered by field'
|
||||||
publik = to_boolean(publik)
|
optional :sort, type: String, values: %w[asc desc], default: 'desc',
|
||||||
# Since setting the public attribute to private could mean either
|
desc: 'Return projects sorted in ascending and descending order'
|
||||||
# private or internal, use the more conservative option, private.
|
end
|
||||||
attrs[:visibility_level] = (publik == true) ? Gitlab::VisibilityLevel::PUBLIC : Gitlab::VisibilityLevel::PRIVATE
|
|
||||||
end
|
params :filter_params do
|
||||||
attrs
|
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'
|
||||||
|
use :sort_params
|
||||||
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get a projects list for authenticated user
|
desc 'Get a projects list for authenticated user' do
|
||||||
#
|
success Entities::BasicProjectDetails
|
||||||
# Example Request:
|
end
|
||||||
# GET /projects
|
params do
|
||||||
|
optional :simple, type: Boolean, default: false,
|
||||||
|
desc: 'Return only the ID, URL, name, and path of each project'
|
||||||
|
use :filter_params
|
||||||
|
use :pagination
|
||||||
|
end
|
||||||
get do
|
get do
|
||||||
projects = current_user.authorized_projects
|
projects = current_user.authorized_projects
|
||||||
projects = filter_projects(projects)
|
projects = filter_projects(projects)
|
||||||
projects = paginate projects
|
|
||||||
entity = params[:simple] ? Entities::BasicProjectDetails : Entities::ProjectWithAccess
|
entity = params[:simple] ? Entities::BasicProjectDetails : Entities::ProjectWithAccess
|
||||||
|
|
||||||
present projects, with: entity, user: current_user
|
present paginate(projects), with: entity, user: current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get a list of visible projects for authenticated user
|
desc 'Get a list of visible projects for authenticated user' do
|
||||||
#
|
success Entities::BasicProjectDetails
|
||||||
# Example Request:
|
end
|
||||||
# GET /projects/visible
|
params do
|
||||||
|
optional :simple, type: Boolean, default: false,
|
||||||
|
desc: 'Return only the ID, URL, name, and path of each project'
|
||||||
|
use :filter_params
|
||||||
|
use :pagination
|
||||||
|
end
|
||||||
get '/visible' do
|
get '/visible' do
|
||||||
projects = ProjectsFinder.new.execute(current_user)
|
projects = ProjectsFinder.new.execute(current_user)
|
||||||
projects = filter_projects(projects)
|
projects = filter_projects(projects)
|
||||||
projects = paginate projects
|
|
||||||
entity = params[:simple] ? Entities::BasicProjectDetails : Entities::ProjectWithAccess
|
entity = params[:simple] ? Entities::BasicProjectDetails : Entities::ProjectWithAccess
|
||||||
|
|
||||||
present projects, with: entity, user: current_user
|
present paginate(projects), with: entity, user: current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get an owned projects list for authenticated user
|
desc 'Get an owned projects list for authenticated user' do
|
||||||
#
|
success Entities::BasicProjectDetails
|
||||||
# Example Request:
|
end
|
||||||
# GET /projects/owned
|
params do
|
||||||
|
use :filter_params
|
||||||
|
use :pagination
|
||||||
|
end
|
||||||
get '/owned' do
|
get '/owned' do
|
||||||
projects = current_user.owned_projects
|
projects = current_user.owned_projects
|
||||||
projects = filter_projects(projects)
|
projects = filter_projects(projects)
|
||||||
projects = paginate projects
|
|
||||||
present projects, with: Entities::ProjectWithAccess, user: current_user
|
present paginate(projects), with: Entities::ProjectWithAccess, user: current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
# Gets starred project for the authenticated user
|
desc 'Gets starred project for the authenticated user' do
|
||||||
#
|
success Entities::BasicProjectDetails
|
||||||
# Example Request:
|
end
|
||||||
# GET /projects/starred
|
params do
|
||||||
|
use :filter_params
|
||||||
|
use :pagination
|
||||||
|
end
|
||||||
get '/starred' do
|
get '/starred' do
|
||||||
projects = current_user.viewable_starred_projects
|
projects = current_user.viewable_starred_projects
|
||||||
projects = filter_projects(projects)
|
projects = filter_projects(projects)
|
||||||
projects = paginate projects
|
|
||||||
present projects, with: Entities::Project, user: current_user
|
present paginate(projects), with: Entities::Project, user: current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get all projects for admin user
|
desc 'Get all projects for admin user' do
|
||||||
#
|
success Entities::BasicProjectDetails
|
||||||
# Example Request:
|
end
|
||||||
# GET /projects/all
|
params do
|
||||||
|
use :filter_params
|
||||||
|
use :pagination
|
||||||
|
end
|
||||||
get '/all' do
|
get '/all' do
|
||||||
authenticated_as_admin!
|
authenticated_as_admin!
|
||||||
projects = Project.all
|
projects = Project.all
|
||||||
projects = filter_projects(projects)
|
projects = filter_projects(projects)
|
||||||
projects = paginate projects
|
|
||||||
present projects, with: Entities::ProjectWithAccess, user: current_user
|
present paginate(projects), with: Entities::ProjectWithAccess, user: current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get a single project
|
desc 'Search for projects the current user has access to' do
|
||||||
#
|
success Entities::Project
|
||||||
# Parameters:
|
end
|
||||||
# id (required) - The ID of a project
|
params do
|
||||||
# Example Request:
|
requires :query, type: String, desc: 'The project name to be searched'
|
||||||
# GET /projects/:id
|
use :sort_params
|
||||||
|
use :pagination
|
||||||
|
end
|
||||||
|
get "/search/: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
|
get ":id" do
|
||||||
present user_project, with: Entities::ProjectWithAccess, user: current_user,
|
present user_project, with: Entities::ProjectWithAccess, user: current_user,
|
||||||
user_can_admin_project: can?(current_user, :admin_project, user_project)
|
user_can_admin_project: can?(current_user, :admin_project, user_project)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get events for a single project
|
desc 'Get events for a single project' do
|
||||||
#
|
success Entities::Event
|
||||||
# Parameters:
|
end
|
||||||
# id (required) - The ID of a project
|
params do
|
||||||
# Example Request:
|
use :pagination
|
||||||
# GET /projects/:id/events
|
end
|
||||||
get ":id/events" do
|
get ":id/events" do
|
||||||
events = paginate user_project.events.recent
|
present paginate(user_project.events.recent), with: Entities::Event
|
||||||
present events, with: Entities::Event
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create new project
|
desc 'Fork new project for the current user or provided namespace.' do
|
||||||
#
|
success Entities::Project
|
||||||
# Parameters:
|
|
||||||
# name (required) - name for new project
|
|
||||||
# description (optional) - short project description
|
|
||||||
# issues_enabled (optional)
|
|
||||||
# merge_requests_enabled (optional)
|
|
||||||
# builds_enabled (optional)
|
|
||||||
# wiki_enabled (optional)
|
|
||||||
# snippets_enabled (optional)
|
|
||||||
# container_registry_enabled (optional)
|
|
||||||
# shared_runners_enabled (optional)
|
|
||||||
# namespace_id (optional) - defaults to user namespace
|
|
||||||
# public (optional) - if true same as setting visibility_level = 20
|
|
||||||
# visibility_level (optional) - 0 by default
|
|
||||||
# import_url (optional)
|
|
||||||
# public_builds (optional)
|
|
||||||
# lfs_enabled (optional)
|
|
||||||
# request_access_enabled (optional) - Allow users to request member access
|
|
||||||
# Example Request
|
|
||||||
# POST /projects
|
|
||||||
post do
|
|
||||||
required_attributes! [:name]
|
|
||||||
attrs = attributes_for_keys [:builds_enabled,
|
|
||||||
:container_registry_enabled,
|
|
||||||
:description,
|
|
||||||
:import_url,
|
|
||||||
:issues_enabled,
|
|
||||||
:lfs_enabled,
|
|
||||||
:merge_requests_enabled,
|
|
||||||
:name,
|
|
||||||
:namespace_id,
|
|
||||||
:only_allow_merge_if_build_succeeds,
|
|
||||||
:path,
|
|
||||||
:public,
|
|
||||||
:public_builds,
|
|
||||||
:request_access_enabled,
|
|
||||||
:shared_runners_enabled,
|
|
||||||
:snippets_enabled,
|
|
||||||
:visibility_level,
|
|
||||||
:wiki_enabled,
|
|
||||||
:only_allow_merge_if_all_discussions_are_resolved]
|
|
||||||
attrs = map_public_to_visibility_level(attrs)
|
|
||||||
@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
|
end
|
||||||
|
params do
|
||||||
# Create new project for a specified user. Only available to admin users.
|
optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be forked into'
|
||||||
#
|
|
||||||
# Parameters:
|
|
||||||
# user_id (required) - The ID of a user
|
|
||||||
# name (required) - name for new project
|
|
||||||
# description (optional) - short project description
|
|
||||||
# default_branch (optional) - 'master' by default
|
|
||||||
# issues_enabled (optional)
|
|
||||||
# merge_requests_enabled (optional)
|
|
||||||
# builds_enabled (optional)
|
|
||||||
# wiki_enabled (optional)
|
|
||||||
# snippets_enabled (optional)
|
|
||||||
# container_registry_enabled (optional)
|
|
||||||
# shared_runners_enabled (optional)
|
|
||||||
# public (optional) - if true same as setting visibility_level = 20
|
|
||||||
# visibility_level (optional)
|
|
||||||
# import_url (optional)
|
|
||||||
# public_builds (optional)
|
|
||||||
# lfs_enabled (optional)
|
|
||||||
# request_access_enabled (optional) - Allow users to request member access
|
|
||||||
# Example Request
|
|
||||||
# POST /projects/user/:user_id
|
|
||||||
post "user/:user_id" do
|
|
||||||
authenticated_as_admin!
|
|
||||||
user = User.find(params[:user_id])
|
|
||||||
attrs = attributes_for_keys [:builds_enabled,
|
|
||||||
:default_branch,
|
|
||||||
:description,
|
|
||||||
:import_url,
|
|
||||||
:issues_enabled,
|
|
||||||
:lfs_enabled,
|
|
||||||
:merge_requests_enabled,
|
|
||||||
:name,
|
|
||||||
:only_allow_merge_if_build_succeeds,
|
|
||||||
:public,
|
|
||||||
:public_builds,
|
|
||||||
:request_access_enabled,
|
|
||||||
:shared_runners_enabled,
|
|
||||||
:snippets_enabled,
|
|
||||||
:visibility_level,
|
|
||||||
:wiki_enabled,
|
|
||||||
:only_allow_merge_if_all_discussions_are_resolved]
|
|
||||||
attrs = map_public_to_visibility_level(attrs)
|
|
||||||
@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
|
||||||
|
|
||||||
# Fork new project for the current user or provided namespace.
|
|
||||||
#
|
|
||||||
# Parameters:
|
|
||||||
# id (required) - The ID of a project
|
|
||||||
# namespace (optional) - The ID or name of the namespace that the project will be forked into.
|
|
||||||
# Example Request
|
|
||||||
# POST /projects/fork/:id
|
|
||||||
post 'fork/:id' do
|
post 'fork/:id' do
|
||||||
attrs = {}
|
fork_params = declared_params(include_missing: false)
|
||||||
namespace_id = params[:namespace]
|
namespace_id = fork_params[:namespace]
|
||||||
|
|
||||||
if namespace_id.present?
|
if namespace_id.present?
|
||||||
namespace = Namespace.find_by(id: namespace_id) || Namespace.find_by_path_or_name(namespace_id)
|
fork_params[:namespace] = if namespace_id =~ /^\d+$/
|
||||||
|
Namespace.find_by(id: namespace_id)
|
||||||
|
else
|
||||||
|
Namespace.find_by_path_or_name(namespace_id)
|
||||||
|
end
|
||||||
|
|
||||||
unless namespace && can?(current_user, :create_projects, namespace)
|
unless fork_params[:namespace] && can?(current_user, :create_projects, fork_params[:namespace])
|
||||||
not_found!('Target Namespace')
|
not_found!('Target Namespace')
|
||||||
end
|
end
|
||||||
|
|
||||||
attrs[:namespace] = namespace
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@forked_project =
|
forked_project = ::Projects::ForkService.new(user_project, current_user, fork_params).execute
|
||||||
::Projects::ForkService.new(user_project,
|
|
||||||
current_user,
|
|
||||||
attrs).execute
|
|
||||||
|
|
||||||
if @forked_project.errors.any?
|
if forked_project.errors.any?
|
||||||
conflict!(@forked_project.errors.messages)
|
conflict!(forked_project.errors.messages)
|
||||||
else
|
else
|
||||||
present @forked_project, with: Entities::Project,
|
present forked_project, with: Entities::Project,
|
||||||
user_can_admin_project: can?(current_user, :admin_project, @forked_project)
|
user_can_admin_project: can?(current_user, :admin_project, forked_project)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Update an existing project
|
desc 'Update an existing project' do
|
||||||
#
|
success Entities::Project
|
||||||
# Parameters:
|
end
|
||||||
# id (required) - the id of a project
|
params do
|
||||||
# name (optional) - name of a project
|
optional :name, type: String, desc: 'The name of the project'
|
||||||
# path (optional) - path of a project
|
optional :default_branch, type: String, desc: 'The default branch of the project'
|
||||||
# description (optional) - short project description
|
optional :path, type: String, desc: 'The path of the repository'
|
||||||
# issues_enabled (optional)
|
use :optional_params
|
||||||
# merge_requests_enabled (optional)
|
at_least_one_of :name, :description, :issues_enabled, :merge_requests_enabled,
|
||||||
# builds_enabled (optional)
|
:wiki_enabled, :builds_enabled, :snippets_enabled,
|
||||||
# wiki_enabled (optional)
|
:shared_runners_enabled, :container_registry_enabled,
|
||||||
# snippets_enabled (optional)
|
:lfs_enabled, :public, :visibility_level, :public_builds,
|
||||||
# container_registry_enabled (optional)
|
:request_access_enabled, :only_allow_merge_if_build_succeeds,
|
||||||
# shared_runners_enabled (optional)
|
:only_allow_merge_if_all_discussions_are_resolved, :path,
|
||||||
# public (optional) - if true same as setting visibility_level = 20
|
:default_branch
|
||||||
# visibility_level (optional) - visibility level of a project
|
end
|
||||||
# public_builds (optional)
|
|
||||||
# lfs_enabled (optional)
|
|
||||||
# Example Request
|
|
||||||
# PUT /projects/:id
|
|
||||||
put ':id' do
|
put ':id' do
|
||||||
attrs = attributes_for_keys [:builds_enabled,
|
|
||||||
:container_registry_enabled,
|
|
||||||
:default_branch,
|
|
||||||
:description,
|
|
||||||
:issues_enabled,
|
|
||||||
:lfs_enabled,
|
|
||||||
:merge_requests_enabled,
|
|
||||||
:name,
|
|
||||||
:only_allow_merge_if_build_succeeds,
|
|
||||||
:path,
|
|
||||||
:public,
|
|
||||||
:public_builds,
|
|
||||||
:request_access_enabled,
|
|
||||||
:shared_runners_enabled,
|
|
||||||
:snippets_enabled,
|
|
||||||
:visibility_level,
|
|
||||||
:wiki_enabled,
|
|
||||||
:only_allow_merge_if_all_discussions_are_resolved]
|
|
||||||
attrs = map_public_to_visibility_level(attrs)
|
|
||||||
authorize_admin_project
|
authorize_admin_project
|
||||||
|
attrs = map_public_to_visibility_level(declared_params(include_missing: false))
|
||||||
authorize! :rename_project, user_project if attrs[:name].present?
|
authorize! :rename_project, user_project if attrs[:name].present?
|
||||||
if attrs[:visibility_level].present?
|
authorize! :change_visibility_level, user_project if attrs[:visibility_level].present?
|
||||||
authorize! :change_visibility_level, user_project
|
|
||||||
end
|
|
||||||
|
|
||||||
::Projects::UpdateService.new(user_project,
|
::Projects::UpdateService.new(user_project, current_user, attrs).execute
|
||||||
current_user, attrs).execute
|
|
||||||
|
|
||||||
if user_project.errors.any?
|
if user_project.errors.any?
|
||||||
render_validation_error!(user_project)
|
render_validation_error!(user_project)
|
||||||
|
@ -297,12 +291,9 @@ module API
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Archive project
|
desc 'Archive a project' do
|
||||||
#
|
success Entities::Project
|
||||||
# Parameters:
|
end
|
||||||
# id (required) - The ID of a project
|
|
||||||
# Example Request:
|
|
||||||
# PUT /projects/:id/archive
|
|
||||||
post ':id/archive' do
|
post ':id/archive' do
|
||||||
authorize!(:archive_project, user_project)
|
authorize!(:archive_project, user_project)
|
||||||
|
|
||||||
|
@ -311,12 +302,9 @@ module API
|
||||||
present user_project, with: Entities::Project
|
present user_project, with: Entities::Project
|
||||||
end
|
end
|
||||||
|
|
||||||
# Unarchive project
|
desc 'Unarchive a project' do
|
||||||
#
|
success Entities::Project
|
||||||
# Parameters:
|
end
|
||||||
# id (required) - The ID of a project
|
|
||||||
# Example Request:
|
|
||||||
# PUT /projects/:id/unarchive
|
|
||||||
post ':id/unarchive' do
|
post ':id/unarchive' do
|
||||||
authorize!(:archive_project, user_project)
|
authorize!(:archive_project, user_project)
|
||||||
|
|
||||||
|
@ -325,12 +313,9 @@ module API
|
||||||
present user_project, with: Entities::Project
|
present user_project, with: Entities::Project
|
||||||
end
|
end
|
||||||
|
|
||||||
# Star project
|
desc 'Star a project' do
|
||||||
#
|
success Entities::Project
|
||||||
# Parameters:
|
end
|
||||||
# id (required) - The ID of a project
|
|
||||||
# Example Request:
|
|
||||||
# POST /projects/:id/star
|
|
||||||
post ':id/star' do
|
post ':id/star' do
|
||||||
if current_user.starred?(user_project)
|
if current_user.starred?(user_project)
|
||||||
not_modified!
|
not_modified!
|
||||||
|
@ -342,12 +327,9 @@ module API
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Unstar project
|
desc 'Unstar a project' do
|
||||||
#
|
success Entities::Project
|
||||||
# Parameters:
|
end
|
||||||
# id (required) - The ID of a project
|
|
||||||
# Example Request:
|
|
||||||
# DELETE /projects/:id/star
|
|
||||||
delete ':id/star' do
|
delete ':id/star' do
|
||||||
if current_user.starred?(user_project)
|
if current_user.starred?(user_project)
|
||||||
current_user.toggle_star(user_project)
|
current_user.toggle_star(user_project)
|
||||||
|
@ -359,67 +341,51 @@ module API
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove project
|
desc 'Remove a project'
|
||||||
#
|
|
||||||
# Parameters:
|
|
||||||
# id (required) - The ID of a project
|
|
||||||
# Example Request:
|
|
||||||
# DELETE /projects/:id
|
|
||||||
delete ":id" do
|
delete ":id" do
|
||||||
authorize! :remove_project, user_project
|
authorize! :remove_project, user_project
|
||||||
::Projects::DestroyService.new(user_project, current_user, {}).async_execute
|
::Projects::DestroyService.new(user_project, current_user, {}).async_execute
|
||||||
end
|
end
|
||||||
|
|
||||||
# Mark this project as forked from another
|
desc 'Mark this project as forked from another'
|
||||||
#
|
params do
|
||||||
# Parameters:
|
requires :forked_from_id, type: String, desc: 'The ID of the project it was forked from'
|
||||||
# id: (required) - The ID of the project being marked as a fork
|
end
|
||||||
# forked_from_id: (required) - The ID of the project it was forked from
|
|
||||||
# Example Request:
|
|
||||||
# POST /projects/:id/fork/:forked_from_id
|
|
||||||
post ":id/fork/:forked_from_id" do
|
post ":id/fork/:forked_from_id" do
|
||||||
authenticated_as_admin!
|
authenticated_as_admin!
|
||||||
|
|
||||||
forked_from_project = find_project!(params[:forked_from_id])
|
forked_from_project = find_project!(params[:forked_from_id])
|
||||||
unless forked_from_project.nil?
|
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)
|
if user_project.forked_from_project.nil?
|
||||||
else
|
user_project.create_forked_project_link(forked_to_project_id: user_project.id, forked_from_project_id: forked_from_project.id)
|
||||||
render_api_error!("Project already forked", 409)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
not_found!("Source Project")
|
render_api_error!("Project already forked", 409)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove a forked_from relationship
|
desc 'Remove a forked_from relationship'
|
||||||
#
|
|
||||||
# Parameters:
|
|
||||||
# id: (required) - The ID of the project being marked as a fork
|
|
||||||
# Example Request:
|
|
||||||
# DELETE /projects/:id/fork
|
|
||||||
delete ":id/fork" do
|
delete ":id/fork" do
|
||||||
authorize! :remove_fork_project, user_project
|
authorize! :remove_fork_project, user_project
|
||||||
|
|
||||||
if user_project.forked?
|
if user_project.forked?
|
||||||
user_project.forked_project_link.destroy
|
user_project.forked_project_link.destroy
|
||||||
|
else
|
||||||
|
not_modified!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Share project with group
|
desc 'Share the project with a group' do
|
||||||
#
|
success Entities::ProjectGroupLink
|
||||||
# Parameters:
|
end
|
||||||
# id (required) - The ID of a project
|
params do
|
||||||
# group_id (required) - The ID of a group
|
requires :group_id, type: Integer, desc: 'The ID of a group'
|
||||||
# group_access (required) - Level of permissions for sharing
|
requires :group_access, type: Integer, values: Gitlab::Access.values, desc: 'The group access level'
|
||||||
# expires_at (optional) - Share expiration date
|
optional :expires_at, type: Date, desc: 'Share expiration date'
|
||||||
#
|
end
|
||||||
# Example Request:
|
|
||||||
# POST /projects/:id/share
|
|
||||||
post ":id/share" do
|
post ":id/share" do
|
||||||
authorize! :admin_project, user_project
|
authorize! :admin_project, user_project
|
||||||
required_attributes! [:group_id, :group_access]
|
group = Group.find_by_id(params[:group_id])
|
||||||
attrs = attributes_for_keys [:group_id, :group_access, :expires_at]
|
|
||||||
|
|
||||||
group = Group.find_by_id(attrs[:group_id])
|
|
||||||
|
|
||||||
unless group && can?(current_user, :read_group, group)
|
unless group && can?(current_user, :read_group, group)
|
||||||
not_found!('Group')
|
not_found!('Group')
|
||||||
|
@ -429,7 +395,7 @@ module API
|
||||||
return render_api_error!("The project sharing with group is disabled", 400)
|
return render_api_error!("The project sharing with group is disabled", 400)
|
||||||
end
|
end
|
||||||
|
|
||||||
link = user_project.project_group_links.new(attrs)
|
link = user_project.project_group_links.new(declared_params(include_missing: false))
|
||||||
|
|
||||||
if link.save
|
if link.save
|
||||||
present link, with: Entities::ProjectGroupLink
|
present link, with: Entities::ProjectGroupLink
|
||||||
|
@ -451,40 +417,26 @@ module API
|
||||||
no_content!
|
no_content!
|
||||||
end
|
end
|
||||||
|
|
||||||
# Upload a file
|
desc 'Upload a file'
|
||||||
#
|
params do
|
||||||
# Parameters:
|
requires :file, type: File, desc: 'The file to be uploaded'
|
||||||
# id: (required) - The ID of the project
|
end
|
||||||
# file: (required) - The file to be uploaded
|
|
||||||
post ":id/uploads" do
|
post ":id/uploads" do
|
||||||
::Projects::UploadService.new(user_project, params[:file]).execute
|
::Projects::UploadService.new(user_project, params[:file]).execute
|
||||||
end
|
end
|
||||||
|
|
||||||
# search for projects current_user has access to
|
desc 'Get the users list of a project' do
|
||||||
#
|
success Entities::UserBasic
|
||||||
# Parameters:
|
end
|
||||||
# query (required) - A string contained in the project name
|
params do
|
||||||
# per_page (optional) - number of projects to return per page
|
optional :search, type: String, desc: 'Return list of users matching the search criteria'
|
||||||
# page (optional) - the page to retrieve
|
use :pagination
|
||||||
# Example Request:
|
|
||||||
# GET /projects/search/:query
|
|
||||||
get "/search/:query" do
|
|
||||||
search_service = Search::GlobalService.new(current_user, search: params[:query]).execute
|
|
||||||
projects = search_service.objects('projects', params[:page])
|
|
||||||
projects = projects.reorder(project_order_by => project_sort)
|
|
||||||
|
|
||||||
present paginate(projects), with: Entities::Project
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get a users list
|
|
||||||
#
|
|
||||||
# Example Request:
|
|
||||||
# GET /users
|
|
||||||
get ':id/users' do
|
get ':id/users' do
|
||||||
@users = User.where(id: user_project.team.users.map(&:id))
|
users = User.where(id: user_project.team.users.map(&:id))
|
||||||
@users = @users.search(params[:search]) if params[:search].present?
|
users = users.search(params[:search]) if params[:search].present?
|
||||||
@users = paginate @users
|
|
||||||
present @users, with: Entities::UserBasic
|
present paginate(users), with: Entities::UserBasic
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -415,16 +415,7 @@ describe API::API, api: true do
|
||||||
not_to change { Project.count }
|
not_to change { Project.count }
|
||||||
|
|
||||||
expect(response).to have_http_status(400)
|
expect(response).to have_http_status(400)
|
||||||
expect(json_response['message']['name']).to eq([
|
expect(json_response['error']).to eq('name is missing')
|
||||||
'can\'t be blank',
|
|
||||||
'is too short (minimum is 0 characters)',
|
|
||||||
Gitlab::Regex.project_name_regex_message
|
|
||||||
])
|
|
||||||
expect(json_response['message']['path']).to eq([
|
|
||||||
'can\'t be blank',
|
|
||||||
'is too short (minimum is 0 characters)',
|
|
||||||
Gitlab::Regex.send(:project_path_regex_message)
|
|
||||||
])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'assigns attributes to project' do
|
it 'assigns attributes to project' do
|
||||||
|
@ -438,6 +429,7 @@ describe API::API, api: true do
|
||||||
|
|
||||||
post api("/projects/user/#{user.id}", admin), project
|
post api("/projects/user/#{user.id}", admin), project
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
project.each_pair do |k, v|
|
project.each_pair do |k, v|
|
||||||
next if %i[has_external_issue_tracker path].include?(k)
|
next if %i[has_external_issue_tracker path].include?(k)
|
||||||
expect(json_response[k.to_s]).to eq(v)
|
expect(json_response[k.to_s]).to eq(v)
|
||||||
|
@ -447,6 +439,8 @@ describe API::API, api: true do
|
||||||
it 'sets a project as public' do
|
it 'sets a project as public' do
|
||||||
project = attributes_for(:project, :public)
|
project = attributes_for(:project, :public)
|
||||||
post api("/projects/user/#{user.id}", admin), project
|
post api("/projects/user/#{user.id}", admin), project
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
expect(json_response['public']).to be_truthy
|
expect(json_response['public']).to be_truthy
|
||||||
expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
|
expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
|
||||||
end
|
end
|
||||||
|
@ -454,6 +448,8 @@ describe API::API, api: true do
|
||||||
it 'sets a project as public using :public' do
|
it 'sets a project as public using :public' do
|
||||||
project = attributes_for(:project, { public: true })
|
project = attributes_for(:project, { public: true })
|
||||||
post api("/projects/user/#{user.id}", admin), project
|
post api("/projects/user/#{user.id}", admin), project
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
expect(json_response['public']).to be_truthy
|
expect(json_response['public']).to be_truthy
|
||||||
expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
|
expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
|
||||||
end
|
end
|
||||||
|
@ -461,6 +457,8 @@ describe API::API, api: true do
|
||||||
it 'sets a project as internal' do
|
it 'sets a project as internal' do
|
||||||
project = attributes_for(:project, :internal)
|
project = attributes_for(:project, :internal)
|
||||||
post api("/projects/user/#{user.id}", admin), project
|
post api("/projects/user/#{user.id}", admin), project
|
||||||
|
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
expect(json_response['public']).to be_falsey
|
expect(json_response['public']).to be_falsey
|
||||||
expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
|
expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
|
||||||
end
|
end
|
||||||
|
@ -468,6 +466,7 @@ describe API::API, api: true do
|
||||||
it 'sets a project as internal overriding :public' do
|
it 'sets a project as internal overriding :public' do
|
||||||
project = attributes_for(:project, :internal, { public: true })
|
project = attributes_for(:project, :internal, { public: true })
|
||||||
post api("/projects/user/#{user.id}", admin), project
|
post api("/projects/user/#{user.id}", admin), project
|
||||||
|
expect(response).to have_http_status(201)
|
||||||
expect(json_response['public']).to be_falsey
|
expect(json_response['public']).to be_falsey
|
||||||
expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
|
expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
|
||||||
end
|
end
|
||||||
|
@ -848,7 +847,7 @@ describe API::API, api: true do
|
||||||
it 'is idempotent if not forked' do
|
it 'is idempotent if not forked' do
|
||||||
expect(project_fork_target.forked_from_project).to be_nil
|
expect(project_fork_target.forked_from_project).to be_nil
|
||||||
delete api("/projects/#{project_fork_target.id}/fork", admin)
|
delete api("/projects/#{project_fork_target.id}/fork", admin)
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(304)
|
||||||
expect(project_fork_target.reload.forked_from_project).to be_nil
|
expect(project_fork_target.reload.forked_from_project).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -865,7 +864,7 @@ describe API::API, api: true do
|
||||||
post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: Gitlab::Access::DEVELOPER, expires_at: expires_at
|
post 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)
|
end.to change { ProjectGroupLink.count }.by(1)
|
||||||
|
|
||||||
expect(response.status).to eq 201
|
expect(response).to have_http_status(201)
|
||||||
expect(json_response['group_id']).to eq(group.id)
|
expect(json_response['group_id']).to eq(group.id)
|
||||||
expect(json_response['group_access']).to eq(Gitlab::Access::DEVELOPER)
|
expect(json_response['group_access']).to eq(Gitlab::Access::DEVELOPER)
|
||||||
expect(json_response['expires_at']).to eq(expires_at.to_s)
|
expect(json_response['expires_at']).to eq(expires_at.to_s)
|
||||||
|
@ -873,18 +872,18 @@ describe API::API, api: true do
|
||||||
|
|
||||||
it "returns a 400 error when group id is not given" do
|
it "returns a 400 error when group id is not given" do
|
||||||
post api("/projects/#{project.id}/share", user), group_access: Gitlab::Access::DEVELOPER
|
post api("/projects/#{project.id}/share", user), group_access: Gitlab::Access::DEVELOPER
|
||||||
expect(response.status).to eq 400
|
expect(response).to have_http_status(400)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns a 400 error when access level is not given" do
|
it "returns a 400 error when access level is not given" do
|
||||||
post api("/projects/#{project.id}/share", user), group_id: group.id
|
post api("/projects/#{project.id}/share", user), group_id: group.id
|
||||||
expect(response.status).to eq 400
|
expect(response).to have_http_status(400)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns a 400 error when sharing is disabled" do
|
it "returns a 400 error when sharing is disabled" do
|
||||||
project.namespace.update(share_with_group_lock: true)
|
project.namespace.update(share_with_group_lock: true)
|
||||||
post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: Gitlab::Access::DEVELOPER
|
post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: Gitlab::Access::DEVELOPER
|
||||||
expect(response.status).to eq 400
|
expect(response).to have_http_status(400)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a 404 error when user cannot read group' do
|
it 'returns a 404 error when user cannot read group' do
|
||||||
|
@ -892,19 +891,20 @@ describe API::API, api: true do
|
||||||
|
|
||||||
post api("/projects/#{project.id}/share", user), group_id: private_group.id, group_access: Gitlab::Access::DEVELOPER
|
post api("/projects/#{project.id}/share", user), group_id: private_group.id, group_access: Gitlab::Access::DEVELOPER
|
||||||
|
|
||||||
expect(response.status).to eq 404
|
expect(response).to have_http_status(404)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a 404 error when group does not exist' do
|
it 'returns a 404 error when group does not exist' do
|
||||||
post api("/projects/#{project.id}/share", user), group_id: 1234, group_access: Gitlab::Access::DEVELOPER
|
post api("/projects/#{project.id}/share", user), group_id: 1234, group_access: Gitlab::Access::DEVELOPER
|
||||||
|
|
||||||
expect(response.status).to eq 404
|
expect(response).to have_http_status(404)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns a 409 error when wrong params passed" do
|
it "returns a 400 error when wrong params passed" do
|
||||||
post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: 1234
|
post api("/projects/#{project.id}/share", user), group_id: group.id, group_access: 1234
|
||||||
expect(response.status).to eq 409
|
|
||||||
expect(json_response['message']).to eq 'Group access is not included in the list'
|
expect(response).to have_http_status(400)
|
||||||
|
expect(json_response['error']).to eq 'group_access does not have a valid value'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1017,7 +1017,6 @@ describe API::API, api: true do
|
||||||
|
|
||||||
it 'updates visibility_level from public to private' do
|
it 'updates visibility_level from public to private' do
|
||||||
project3.update_attributes({ visibility_level: Gitlab::VisibilityLevel::PUBLIC })
|
project3.update_attributes({ visibility_level: Gitlab::VisibilityLevel::PUBLIC })
|
||||||
|
|
||||||
project_param = { public: false }
|
project_param = { public: false }
|
||||||
put api("/projects/#{project3.id}", user), project_param
|
put api("/projects/#{project3.id}", user), project_param
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
|
|
Loading…
Reference in a new issue