Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib/api
diff options
context:
space:
mode:
Diffstat (limited to 'lib/api')
-rw-r--r--lib/api/access_requests.rb2
-rw-r--r--lib/api/branches.rb12
-rw-r--r--lib/api/broadcast_messages.rb6
-rw-r--r--lib/api/commits.rb2
-rw-r--r--lib/api/deploy_keys.rb2
-rw-r--r--lib/api/entities.rb21
-rw-r--r--lib/api/environments.rb7
-rw-r--r--lib/api/groups.rb160
-rw-r--r--lib/api/helpers.rb19
-rw-r--r--lib/api/helpers/internal_helpers.rb57
-rw-r--r--lib/api/internal.rb38
-rw-r--r--lib/api/issues.rb10
-rw-r--r--lib/api/labels.rb11
-rw-r--r--lib/api/members.rb2
-rw-r--r--lib/api/merge_requests.rb282
-rw-r--r--lib/api/milestones.rb2
-rw-r--r--lib/api/notes.rb124
-rw-r--r--lib/api/notification_settings.rb7
-rw-r--r--lib/api/pipelines.rb21
-rw-r--r--lib/api/project_hooks.rb10
-rw-r--r--lib/api/repositories.rb95
-rw-r--r--lib/api/services.rb29
-rw-r--r--lib/api/subscriptions.rb12
-rw-r--r--lib/api/system_hooks.rb2
-rw-r--r--lib/api/tags.rb3
-rw-r--r--lib/api/triggers.rb2
26 files changed, 457 insertions, 481 deletions
diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb
index 87915b19480..ed723b94cfd 100644
--- a/lib/api/access_requests.rb
+++ b/lib/api/access_requests.rb
@@ -48,7 +48,7 @@ module API
put ':id/access_requests/:user_id/approve' do
source = find_source(source_type, params[:id])
- member = ::Members::ApproveAccessRequestService.new(source, current_user, declared(params)).execute
+ member = ::Members::ApproveAccessRequestService.new(source, current_user, declared_params).execute
status :created
present member.user, with: Entities::Member, member: member
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 21a106387f0..73aed624ea7 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -128,6 +128,18 @@ module API
render_api_error!(result[:message], result[:return_code])
end
end
+
+ # Delete all merged branches
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # Example Request:
+ # DELETE /projects/:id/repository/branches/delete_merged
+ delete ":id/repository/merged_branches" do
+ DeleteMergedBranchesService.new(user_project, current_user).async_execute
+
+ status(200)
+ end
end
end
end
diff --git a/lib/api/broadcast_messages.rb b/lib/api/broadcast_messages.rb
index fb2a4148011..b6281a7f0ac 100644
--- a/lib/api/broadcast_messages.rb
+++ b/lib/api/broadcast_messages.rb
@@ -36,8 +36,7 @@ module API
optional :font, type: String, desc: 'Foreground color'
end
post do
- create_params = declared(params, include_missing: false).to_h
- message = BroadcastMessage.create(create_params)
+ message = BroadcastMessage.create(declared_params(include_missing: false))
if message.persisted?
present message, with: Entities::BroadcastMessage
@@ -73,9 +72,8 @@ module API
end
put ':id' do
message = find_message
- update_params = declared(params, include_missing: false).to_h
- if message.update(update_params)
+ if message.update(declared_params(include_missing: false))
present message, with: Entities::BroadcastMessage
else
render_validation_error!(message)
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index 2f2cf769481..f412e1da1bf 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -53,7 +53,7 @@ module API
post ":id/repository/commits" do
authorize! :push_code, user_project
- attrs = declared(params)
+ attrs = declared_params
attrs[:source_branch] = attrs[:branch_name]
attrs[:target_branch] = attrs[:branch_name]
attrs[:actions].map! do |action|
diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb
index 425df2c176a..85360730841 100644
--- a/lib/api/deploy_keys.rb
+++ b/lib/api/deploy_keys.rb
@@ -82,7 +82,7 @@ module API
end
post ":id/#{path}/:key_id/enable" do
key = ::Projects::EnableDeployKeyService.new(user_project,
- current_user, declared(params)).execute
+ current_user, declared_params).execute
if key
present key, with: Entities::SSHKey
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 1942aeea656..33cb6fd3704 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -159,7 +159,7 @@ module API
end
class RepoTreeObject < Grape::Entity
- expose :id, :name, :type
+ expose :id, :name, :type, :path
expose :mode do |obj, options|
filemode = obj.mode.to_s(8)
@@ -218,7 +218,7 @@ module API
expose :assignee, :author, using: Entities::UserBasic
expose :subscribed do |issue, options|
- issue.subscribed?(options[:current_user])
+ issue.subscribed?(options[:current_user], options[:project] || issue.project)
end
expose :user_notes_count
expose :upvotes, :downvotes
@@ -248,7 +248,7 @@ module API
expose :diff_head_sha, as: :sha
expose :merge_commit_sha
expose :subscribed do |merge_request, options|
- merge_request.subscribed?(options[:current_user])
+ merge_request.subscribed?(options[:current_user], options[:project])
end
expose :user_notes_count
expose :should_remove_source_branch?, as: :should_remove_source_branch
@@ -437,13 +437,24 @@ module API
end
class Label < LabelBasic
- expose :open_issues_count, :closed_issues_count, :open_merge_requests_count
+ expose :open_issues_count do |label, options|
+ label.open_issues_count(options[:current_user])
+ end
+
+ expose :closed_issues_count do |label, options|
+ label.closed_issues_count(options[:current_user])
+ end
+
+ expose :open_merge_requests_count do |label, options|
+ label.open_merge_requests_count(options[:current_user])
+ end
+
expose :priority do |label, options|
label.priority(options[:project])
end
expose :subscribed do |label, options|
- label.subscribed?(options[:current_user])
+ label.subscribed?(options[:current_user], options[:project])
end
end
diff --git a/lib/api/environments.rb b/lib/api/environments.rb
index 819f80d8365..00c901937b1 100644
--- a/lib/api/environments.rb
+++ b/lib/api/environments.rb
@@ -32,8 +32,7 @@ module API
post ':id/environments' do
authorize! :create_environment, user_project
- create_params = declared(params, include_parent_namespaces: false).to_h
- environment = user_project.environments.create(create_params)
+ environment = user_project.environments.create(declared_params)
if environment.persisted?
present environment, with: Entities::Environment
@@ -55,8 +54,8 @@ module API
authorize! :update_environment, user_project
environment = user_project.environments.find(params[:environment_id])
-
- update_params = declared(params, include_missing: false).extract!(:name, :external_url).to_h
+
+ update_params = declared_params(include_missing: false).extract!(:name, :external_url)
if environment.update(update_params)
present environment, with: Entities::Environment
else
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 40644fc2adf..48ad3b80ae0 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -1,118 +1,115 @@
module API
- # groups API
class Groups < Grape::API
before { authenticate! }
+ helpers do
+ params :optional_params do
+ optional :description, type: String, desc: 'The description of the group'
+ optional :visibility_level, type: Integer, desc: 'The visibility level of the group'
+ optional :lfs_enabled, type: Boolean, desc: 'Enable/disable LFS for the projects in this group'
+ optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access'
+ end
+ end
+
resource :groups do
- # Get a groups list
- #
- # Parameters:
- # skip_groups (optional) - Array of group ids to exclude from list
- # all_available (optional, boolean) - Show all group that you have access to
- # Example Request:
- # GET /groups
+ desc 'Get a groups list' do
+ success Entities::Group
+ end
+ params do
+ optional :skip_groups, type: Array[Integer], desc: 'Array of group ids to exclude from list'
+ optional :all_available, type: Boolean, desc: 'Show all group that you have access to'
+ optional :search, type: String, desc: 'Search for a specific group'
+ optional :order_by, type: String, values: %w[name path], default: 'name', desc: 'Order by name or path'
+ optional :sort, type: String, values: %w[asc desc], default: 'asc', desc: 'Sort by asc (ascending) or desc (descending)'
+ end
get do
- @groups = if current_user.admin
- Group.all
- elsif params[:all_available]
- GroupsFinder.new.execute(current_user)
- else
- current_user.groups
- end
+ groups = if current_user.admin
+ Group.all
+ elsif params[:all_available]
+ GroupsFinder.new.execute(current_user)
+ else
+ current_user.groups
+ end
- @groups = @groups.search(params[:search]) if params[:search].present?
- @groups = @groups.where.not(id: params[:skip_groups]) if params[:skip_groups].present?
- @groups = paginate @groups
- present @groups, with: Entities::Group
+ groups = groups.search(params[:search]) if params[:search].present?
+ groups = groups.where.not(id: params[:skip_groups]) if params[:skip_groups].present?
+ groups = groups.reorder(params[:order_by] => params[:sort].to_sym)
+
+ present paginate(groups), with: Entities::Group
end
- # Get list of owned groups for authenticated user
- #
- # Example Request:
- # GET /groups/owned
+ desc 'Get list of owned groups for authenticated user' do
+ success Entities::Group
+ end
get '/owned' do
- @groups = current_user.owned_groups
- @groups = paginate @groups
- present @groups, with: Entities::Group, user: current_user
+ groups = current_user.owned_groups
+ present paginate(groups), with: Entities::Group, user: current_user
end
- # Create group. Available only for users who can create groups.
- #
- # Parameters:
- # name (required) - The name of the group
- # path (required) - The path of the group
- # description (optional) - The description of the group
- # visibility_level (optional) - The visibility level of the group
- # lfs_enabled (optional) - Enable/disable LFS for the projects in this group
- # request_access_enabled (optional) - Allow users to request member access
- # Example Request:
- # POST /groups
+ desc 'Create a group. Available only for users who can create groups.' do
+ success Entities::Group
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the group'
+ requires :path, type: String, desc: 'The path of the group'
+ use :optional_params
+ end
post do
authorize! :create_group
- required_attributes! [:name, :path]
- attrs = attributes_for_keys [:name, :path, :description, :visibility_level, :lfs_enabled, :request_access_enabled]
- @group = Group.new(attrs)
+ group = ::Groups::CreateService.new(current_user, declared_params(include_missing: false)).execute
- if @group.save
- @group.add_owner(current_user)
- present @group, with: Entities::Group
+ if group.persisted?
+ present group, with: Entities::Group
else
- render_api_error!("Failed to save group #{@group.errors.messages}", 400)
+ render_api_error!("Failed to save group #{group.errors.messages}", 400)
end
end
+ end
- # Update group. Available only for users who can administrate groups.
- #
- # Parameters:
- # id (required) - The ID of a group
- # path (optional) - The path of the group
- # description (optional) - The description of the group
- # visibility_level (optional) - The visibility level of the group
- # lfs_enabled (optional) - Enable/disable LFS for the projects in this group
- # request_access_enabled (optional) - Allow users to request member access
- # Example Request:
- # PUT /groups/:id
+ params do
+ requires :id, type: String, desc: 'The ID of a group'
+ end
+ resource :groups do
+ desc 'Update a group. Available only for users who can administrate groups.' do
+ success Entities::Group
+ end
+ params do
+ optional :name, type: String, desc: 'The name of the group'
+ optional :path, type: String, desc: 'The path of the group'
+ use :optional_params
+ at_least_one_of :name, :path, :description, :visibility_level,
+ :lfs_enabled, :request_access_enabled
+ end
put ':id' do
group = find_group(params[:id])
authorize! :admin_group, group
- attrs = attributes_for_keys [:name, :path, :description, :visibility_level, :lfs_enabled, :request_access_enabled]
-
- if ::Groups::UpdateService.new(group, current_user, attrs).execute
+ if ::Groups::UpdateService.new(group, current_user, declared_params(include_missing: false)).execute
present group, with: Entities::GroupDetail
else
render_validation_error!(group)
end
end
- # Get a single group, with containing projects
- #
- # Parameters:
- # id (required) - The ID of a group
- # Example Request:
- # GET /groups/:id
+ desc 'Get a single group, with containing projects.' do
+ success Entities::GroupDetail
+ end
get ":id" do
group = find_group(params[:id])
present group, with: Entities::GroupDetail
end
- # Remove group
- #
- # Parameters:
- # id (required) - The ID of a group
- # Example Request:
- # DELETE /groups/:id
+ desc 'Remove a group.'
delete ":id" do
group = find_group(params[:id])
authorize! :admin_group, group
DestroyGroupService.new(group, current_user).execute
end
- # Get a list of projects in this group
- #
- # Example Request:
- # GET /groups/:id/projects
+ desc 'Get a list of projects in this group.' do
+ success Entities::Project
+ end
get ":id/projects" do
group = find_group(params[:id])
projects = GroupProjectsFinder.new(group).execute(current_user)
@@ -120,13 +117,12 @@ module API
present projects, with: Entities::Project, user: current_user
end
- # Transfer a project to the Group namespace
- #
- # Parameters:
- # id - group id
- # project_id - project id
- # Example Request:
- # POST /groups/:id/projects/:project_id
+ desc 'Transfer a project to the group namespace. Available only for admin.' do
+ success Entities::GroupDetail
+ end
+ params do
+ requires :project_id, type: String, desc: 'The ID of the project'
+ end
post ":id/projects/:project_id" do
authenticated_as_admin!
group = Group.find_by(id: params[:id])
@@ -134,7 +130,7 @@ module API
result = ::Projects::TransferService.new(project, current_user).execute(group)
if result
- present group
+ present group, with: Entities::GroupDetail
else
render_api_error!("Failed to transfer project #{project.errors.messages}", 400)
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 6998b6dc039..2c593dbb4ea 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -85,26 +85,11 @@ module API
end
end
- def project_service
- @project_service ||= begin
- underscored_service = params[:service_slug].underscore
-
- if Service.available_services_names.include?(underscored_service)
- user_project.build_missing_services
-
- service_method = "#{underscored_service}_service"
-
- send_service(service_method)
- end
- end
-
+ def project_service(project = user_project)
+ @project_service ||= project.find_or_initialize_service(params[:service_slug].underscore)
@project_service || not_found!("Service")
end
- def send_service(service_method)
- user_project.send(service_method)
- end
-
def service_attributes
@service_attributes ||= project_service.fields.inject([]) do |arr, hash|
arr << hash[:name].to_sym
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
new file mode 100644
index 00000000000..eb223c1101d
--- /dev/null
+++ b/lib/api/helpers/internal_helpers.rb
@@ -0,0 +1,57 @@
+module API
+ module Helpers
+ module InternalHelpers
+ # Project paths may be any of the following:
+ # * /repository/storage/path/namespace/project
+ # * /namespace/project
+ # * namespace/project
+ #
+ # In addition, they may have a '.git' extension and multiple namespaces
+ #
+ # Transform all these cases to 'namespace/project'
+ def clean_project_path(project_path, storage_paths = Repository.storages.values)
+ project_path = project_path.sub(/\.git\z/, '')
+
+ storage_paths.each do |storage_path|
+ storage_path = File.expand_path(storage_path)
+
+ if project_path.start_with?(storage_path)
+ project_path = project_path.sub(storage_path, '')
+ break
+ end
+ end
+
+ project_path.sub(/\A\//, '')
+ end
+
+ def project_path
+ @project_path ||= clean_project_path(params[:project])
+ end
+
+ def wiki?
+ @wiki ||= project_path.end_with?('.wiki') &&
+ !Project.find_with_namespace(project_path)
+ end
+
+ def project
+ @project ||= begin
+ # Check for *.wiki repositories.
+ # Strip out the .wiki from the pathname before finding the
+ # project. This applies the correct project permissions to
+ # the wiki repository as well.
+ project_path.chomp!('.wiki') if wiki?
+
+ Project.find_with_namespace(project_path)
+ end
+ end
+
+ def ssh_authentication_abilities
+ [
+ :read_project,
+ :download_code,
+ :push_code
+ ]
+ end
+ end
+ end
+end
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index ccf181402f9..7087ce11401 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -3,6 +3,8 @@ module API
class Internal < Grape::API
before { authenticate_by_gitlab_shell_token! }
+ helpers ::API::Helpers::InternalHelpers
+
namespace 'internal' do
# Check if git command is allowed to project
#
@@ -14,42 +16,6 @@ module API
# ref - branch name
# forced_push - forced_push
# protocol - Git access protocol being used, e.g. HTTP or SSH
- #
-
- helpers do
- def project_path
- @project_path ||= begin
- project_path = params[:project].sub(/\.git\z/, '')
- Repository.remove_storage_from_path(project_path)
- end
- end
-
- def wiki?
- @wiki ||= project_path.end_with?('.wiki') &&
- !Project.find_with_namespace(project_path)
- end
-
- def project
- @project ||= begin
- # Check for *.wiki repositories.
- # Strip out the .wiki from the pathname before finding the
- # project. This applies the correct project permissions to
- # the wiki repository as well.
- project_path.chomp!('.wiki') if wiki?
-
- Project.find_with_namespace(project_path)
- end
- end
-
- def ssh_authentication_abilities
- [
- :read_project,
- :download_code,
- :push_code
- ]
- end
- end
-
post "/allowed" do
status 200
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index c9689e6f8ef..eea5b91d4f9 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -120,7 +120,7 @@ module API
issues = issues.reorder(issuable_order_by => issuable_sort)
- present paginate(issues), with: Entities::Issue, current_user: current_user
+ present paginate(issues), with: Entities::Issue, current_user: current_user, project: user_project
end
# Get a single project issue
@@ -132,7 +132,7 @@ module API
# GET /projects/:id/issues/:issue_id
get ":id/issues/:issue_id" do
@issue = find_project_issue(params[:issue_id])
- present @issue, with: Entities::Issue, current_user: current_user
+ present @issue, with: Entities::Issue, current_user: current_user, project: user_project
end
# Create a new project issue
@@ -174,7 +174,7 @@ module API
end
if issue.valid?
- present issue, with: Entities::Issue, current_user: current_user
+ present issue, with: Entities::Issue, current_user: current_user, project: user_project
else
render_validation_error!(issue)
end
@@ -217,7 +217,7 @@ module API
issue = ::Issues::UpdateService.new(user_project, current_user, attrs).execute(issue)
if issue.valid?
- present issue, with: Entities::Issue, current_user: current_user
+ present issue, with: Entities::Issue, current_user: current_user, project: user_project
else
render_validation_error!(issue)
end
@@ -239,7 +239,7 @@ module API
begin
issue = ::Issues::MoveService.new(user_project, current_user).execute(issue, new_project)
- present issue, with: Entities::Issue, current_user: current_user
+ present issue, with: Entities::Issue, current_user: current_user, project: user_project
rescue ::Issues::MoveService::MoveError => error
render_api_error!(error.message, 400)
end
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index 97218054f37..652786d4e3e 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -30,10 +30,7 @@ module API
conflict!('Label already exists') if label
priority = params.delete(:priority)
- label_params = declared(params,
- include_parent_namespaces: false,
- include_missing: false).to_h
- label = user_project.labels.create(label_params)
+ label = user_project.labels.create(declared_params(include_missing: false))
if label.valid?
label.prioritize!(user_project, priority) if priority
@@ -77,11 +74,9 @@ module API
update_priority = params.key?(:priority)
priority = params.delete(:priority)
- label_params = declared(params,
- include_parent_namespaces: false,
- include_missing: false).to_h
+ label_params = declared_params(include_missing: false)
# Rename new name to the actual label attribute name
- label_params[:name] = label_params.delete('new_name') if label_params.key?('new_name')
+ label_params[:name] = label_params.delete(:new_name) if label_params.key?(:new_name)
render_validation_error!(label) unless label.update(label_params)
diff --git a/lib/api/members.rb b/lib/api/members.rb
index b80818f0eb6..2d4d5cedf20 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -120,7 +120,7 @@ module API
if member.nil?
{ message: "Access revoked", id: params[:user_id].to_i }
else
- ::Members::DestroyService.new(source, current_user, declared(params)).execute
+ ::Members::DestroyService.new(source, current_user, declared_params).execute
present member.user, with: Entities::Member, member: member
end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index bf8504e1101..4176c7eec06 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -1,8 +1,12 @@
module API
- # MergeRequest API
class MergeRequests < Grape::API
+ DEPRECATION_MESSAGE = 'This endpoint is deprecated and will be removed in GitLab 9.0.'.freeze
+
before { authenticate! }
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
resource :projects do
helpers do
def handle_merge_request_errors!(errors)
@@ -18,27 +22,27 @@ module API
render_api_error!(errors, 400)
end
+
+ params :optional_params do
+ optional :description, type: String, desc: 'The description of the merge request'
+ optional :assignee_id, type: Integer, desc: 'The ID of a user to assign the merge request'
+ optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign the merge request'
+ optional :labels, type: String, desc: 'Comma-separated list of label names'
+ end
end
- # List merge requests
- #
- # Parameters:
- # id (required) - The ID of a project
- # iid (optional) - Return the project MR having the given `iid`
- # state (optional) - Return requests "merged", "opened" or "closed"
- # order_by (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at`
- # sort (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc`
- #
- # Example:
- # GET /projects/:id/merge_requests
- # GET /projects/:id/merge_requests?state=opened
- # GET /projects/:id/merge_requests?state=closed
- # GET /projects/:id/merge_requests?order_by=created_at
- # GET /projects/:id/merge_requests?order_by=updated_at
- # GET /projects/:id/merge_requests?sort=desc
- # GET /projects/:id/merge_requests?sort=asc
- # GET /projects/:id/merge_requests?iid=42
- #
+ desc 'List merge requests' do
+ success Entities::MergeRequest
+ end
+ params do
+ optional :state, type: String, values: %w[opened closed merged all], default: 'all',
+ desc: 'Return opened, closed, merged, or all merge requests'
+ optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at',
+ desc: 'Return merge requests ordered by `created_at` or `updated_at` fields.'
+ optional :sort, type: String, values: %w[asc desc], default: 'desc',
+ desc: 'Return merge requests sorted in `asc` or `desc` order.'
+ optional :iid, type: Integer, desc: 'The IID of the merge requests'
+ end
get ":id/merge_requests" do
authorize! :read_merge_request, user_project
merge_requests = user_project.merge_requests.inc_notes_with_associations
@@ -48,60 +52,51 @@ module API
end
merge_requests =
- case params["state"]
- when "opened" then merge_requests.opened
- when "closed" then merge_requests.closed
- when "merged" then merge_requests.merged
+ case params[:state]
+ when 'opened' then merge_requests.opened
+ when 'closed' then merge_requests.closed
+ when 'merged' then merge_requests.merged
else merge_requests
end
merge_requests = merge_requests.reorder(issuable_order_by => issuable_sort)
- present paginate(merge_requests), with: Entities::MergeRequest, current_user: current_user
+ present paginate(merge_requests), with: Entities::MergeRequest, current_user: current_user, project: user_project
end
- # Create MR
- #
- # Parameters:
- #
- # id (required) - The ID of a project - this will be the source of the merge request
- # source_branch (required) - The source branch
- # target_branch (required) - The target branch
- # target_project_id - The target project of the merge request defaults to the :id of the project
- # assignee_id - Assignee user ID
- # title (required) - Title of MR
- # description - Description of MR
- # labels (optional) - Labels for MR as a comma-separated list
- # milestone_id (optional) - Milestone ID
- #
- # Example:
- # POST /projects/:id/merge_requests
- #
+ desc 'Create a merge request' do
+ success Entities::MergeRequest
+ end
+ params do
+ requires :title, type: String, desc: 'The title of the merge request'
+ requires :source_branch, type: String, desc: 'The source branch'
+ requires :target_branch, type: String, desc: 'The target branch'
+ optional :target_project_id, type: Integer,
+ desc: 'The target project of the merge request defaults to the :id of the project'
+ use :optional_params
+ end
post ":id/merge_requests" do
authorize! :create_merge_request, user_project
- required_attributes! [:source_branch, :target_branch, :title]
- attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :target_project_id, :description, :milestone_id]
+
+ mr_params = declared_params
# Validate label names in advance
- if (errors = validate_label_params(params)).any?
+ if (errors = validate_label_params(mr_params)).any?
render_api_error!({ labels: errors }, 400)
end
- attrs[:labels] = params[:labels] if params[:labels]
-
- merge_request = ::MergeRequests::CreateService.new(user_project, current_user, attrs).execute
+ merge_request = ::MergeRequests::CreateService.new(user_project, current_user, mr_params).execute
if merge_request.valid?
- present merge_request, with: Entities::MergeRequest, current_user: current_user
+ present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project
else
handle_merge_request_errors! merge_request.errors
end
end
- # Delete a MR
- #
- # Parameters:
- # id (required) - The ID of the project
- # merge_request_id (required) - The MR id
+ desc 'Delete a merge request'
+ params do
+ requires :merge_request_id, type: Integer, desc: 'The ID of a merge request'
+ end
delete ":id/merge_requests/:merge_request_id" do
merge_request = user_project.merge_requests.find_by(id: params[:merge_request_id])
@@ -112,109 +107,83 @@ module API
# Routing "merge_request/:merge_request_id/..." is DEPRECATED and WILL BE REMOVED in version 9.0
# Use "merge_requests/:merge_request_id/..." instead.
#
- [":id/merge_request/:merge_request_id", ":id/merge_requests/:merge_request_id"].each do |path|
- # Show MR
- #
- # Parameters:
- # id (required) - The ID of a project
- # merge_request_id (required) - The ID of MR
- #
- # Example:
- # GET /projects/:id/merge_requests/:merge_request_id
- #
+ params do
+ requires :merge_request_id, type: Integer, desc: 'The ID of a merge request'
+ end
+ { ":id/merge_request/:merge_request_id" => :deprecated, ":id/merge_requests/:merge_request_id" => :ok }.each do |path, status|
+ desc 'Get a single merge request' do
+ if status == :deprecated
+ detail DEPRECATION_MESSAGE
+ end
+ success Entities::MergeRequest
+ end
get path do
merge_request = user_project.merge_requests.find(params[:merge_request_id])
-
authorize! :read_merge_request, merge_request
-
- present merge_request, with: Entities::MergeRequest, current_user: current_user
+ present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project
end
- # Show MR commits
- #
- # Parameters:
- # id (required) - The ID of a project
- # merge_request_id (required) - The ID of MR
- #
- # Example:
- # GET /projects/:id/merge_requests/:merge_request_id/commits
- #
+ desc 'Get the commits of a merge request' do
+ success Entities::RepoCommit
+ end
get "#{path}/commits" do
- merge_request = user_project.merge_requests.
- find(params[:merge_request_id])
+ merge_request = user_project.merge_requests.find(params[:merge_request_id])
authorize! :read_merge_request, merge_request
present merge_request.commits, with: Entities::RepoCommit
end
- # Show MR changes
- #
- # Parameters:
- # id (required) - The ID of a project
- # merge_request_id (required) - The ID of MR
- #
- # Example:
- # GET /projects/:id/merge_requests/:merge_request_id/changes
- #
+ desc 'Show the merge request changes' do
+ success Entities::MergeRequestChanges
+ end
get "#{path}/changes" do
- merge_request = user_project.merge_requests.
- find(params[:merge_request_id])
+ merge_request = user_project.merge_requests.find(params[:merge_request_id])
authorize! :read_merge_request, merge_request
present merge_request, with: Entities::MergeRequestChanges, current_user: current_user
end
- # Update MR
- #
- # Parameters:
- # id (required) - The ID of a project
- # merge_request_id (required) - ID of MR
- # target_branch - The target branch
- # assignee_id - Assignee user ID
- # title - Title of MR
- # state_event - Status of MR. (close|reopen|merge)
- # description - Description of MR
- # labels (optional) - Labels for a MR as a comma-separated list
- # milestone_id (optional) - Milestone ID
- # Example:
- # PUT /projects/:id/merge_requests/:merge_request_id
- #
+ desc 'Update a merge request' do
+ success Entities::MergeRequest
+ end
+ params do
+ optional :title, type: String, desc: 'The title of the merge request'
+ optional :target_branch, type: String, desc: 'The target branch'
+ optional :state_event, type: String, values: %w[close reopen merge],
+ desc: 'Status of the merge request'
+ use :optional_params
+ at_least_one_of :title, :target_branch, :description, :assignee_id,
+ :milestone_id, :labels, :state_event
+ end
put path do
- attrs = attributes_for_keys [:target_branch, :assignee_id, :title, :state_event, :description, :milestone_id]
- merge_request = user_project.merge_requests.find(params[:merge_request_id])
+ merge_request = user_project.merge_requests.find(params.delete(:merge_request_id))
authorize! :update_merge_request, merge_request
- # Ensure source_branch is not specified
- if params[:source_branch].present?
- render_api_error!('Source branch cannot be changed', 400)
- end
+ mr_params = declared_params(include_missing: false)
# Validate label names in advance
- if (errors = validate_label_params(params)).any?
+ if (errors = validate_label_params(mr_params)).any?
render_api_error!({ labels: errors }, 400)
end
- attrs[:labels] = params[:labels] if params[:labels]
-
- merge_request = ::MergeRequests::UpdateService.new(user_project, current_user, attrs).execute(merge_request)
+ merge_request = ::MergeRequests::UpdateService.new(user_project, current_user, mr_params).execute(merge_request)
if merge_request.valid?
- present merge_request, with: Entities::MergeRequest, current_user: current_user
+ present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project
else
handle_merge_request_errors! merge_request.errors
end
end
- # Merge MR
- #
- # Parameters:
- # id (required) - The ID of a project
- # merge_request_id (required) - ID of MR
- # merge_commit_message (optional) - Custom merge commit message
- # should_remove_source_branch (optional) - When true, the source branch will be deleted if possible
- # merge_when_build_succeeds (optional) - When true, this MR will be merged when the build succeeds
- # sha (optional) - When present, must have the HEAD SHA of the source branch
- # Example:
- # PUT /projects/:id/merge_requests/:merge_request_id/merge
- #
+ desc 'Merge a merge request' do
+ success Entities::MergeRequest
+ end
+ params do
+ optional :merge_commit_message, type: String, desc: 'Custom merge commit message'
+ optional :should_remove_source_branch, type: Boolean,
+ desc: 'When true, the source branch will be deleted if possible'
+ optional :merge_when_build_succeeds, type: Boolean,
+ desc: 'When true, this merge request will be merged when the build succeeds'
+ optional :sha, type: String, desc: 'When present, must have the HEAD SHA of the source branch'
+ end
put "#{path}/merge" do
merge_request = user_project.merge_requests.find(params[:merge_request_id])
@@ -235,7 +204,7 @@ module API
should_remove_source_branch: params[:should_remove_source_branch]
}
- if to_boolean(params[:merge_when_build_succeeds]) && merge_request.pipeline && merge_request.pipeline.active?
+ if params[:merge_when_build_succeeds] && merge_request.pipeline && merge_request.pipeline.active?
::MergeRequests::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params).
execute(merge_request)
else
@@ -243,14 +212,12 @@ module API
execute(merge_request)
end
- present merge_request, with: Entities::MergeRequest, current_user: current_user
+ present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project
end
- # Cancel Merge if Merge When build succeeds is enabled
- # Parameters:
- # id (required) - The ID of a project
- # merge_request_id (required) - ID of MR
- #
+ desc 'Cancel merge if "Merge when build succeeds" is enabled' do
+ success Entities::MergeRequest
+ end
post "#{path}/cancel_merge_when_build_succeeds" do
merge_request = user_project.merge_requests.find(params[:merge_request_id])
@@ -259,17 +226,10 @@ module API
::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user).cancel(merge_request)
end
- # Duplicate. DEPRECATED and WILL BE REMOVED in 9.0.
- # Use GET "/projects/:id/merge_requests/:merge_request_id/notes" instead
- #
- # Get a merge request's comments
- #
- # Parameters:
- # id (required) - The ID of a project
- # merge_request_id (required) - ID of MR
- # Examples:
- # GET /projects/:id/merge_requests/:merge_request_id/comments
- #
+ desc 'Get the comments of a merge request' do
+ detail 'Duplicate. DEPRECATED and WILL BE REMOVED in 9.0'
+ success Entities::MRNote
+ end
get "#{path}/comments" do
merge_request = user_project.merge_requests.find(params[:merge_request_id])
@@ -278,23 +238,15 @@ module API
present paginate(merge_request.notes.fresh), with: Entities::MRNote
end
- # Duplicate. DEPRECATED and WILL BE REMOVED in 9.0.
- # Use POST "/projects/:id/merge_requests/:merge_request_id/notes" instead
- #
- # Post comment to merge request
- #
- # Parameters:
- # id (required) - The ID of a project
- # merge_request_id (required) - ID of MR
- # note (required) - Text of comment
- # Examples:
- # POST /projects/:id/merge_requests/:merge_request_id/comments
- #
+ desc 'Post a comment to a merge request' do
+ detail 'Duplicate. DEPRECATED and WILL BE REMOVED in 9.0'
+ success Entities::MRNote
+ end
+ params do
+ requires :note, type: String, desc: 'The text of the comment'
+ end
post "#{path}/comments" do
- required_attributes! [:note]
-
merge_request = user_project.merge_requests.find(params[:merge_request_id])
-
authorize! :create_note, merge_request
opts = {
@@ -312,13 +264,9 @@ module API
end
end
- # List issues that will close on merge
- #
- # Parameters:
- # id (required) - The ID of a project
- # merge_request_id (required) - ID of MR
- # Examples:
- # GET /projects/:id/merge_requests/:merge_request_id/closes_issues
+ desc 'List issues that will be closed on merge' do
+ success Entities::MRNote
+ end
get "#{path}/closes_issues" do
merge_request = user_project.merge_requests.find(params[:merge_request_id])
issues = ::Kaminari.paginate_array(merge_request.closes_issues(current_user))
diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb
index ba4a84275bc..937c118779d 100644
--- a/lib/api/milestones.rb
+++ b/lib/api/milestones.rb
@@ -114,7 +114,7 @@ module API
}
issues = IssuesFinder.new(current_user, finder_params).execute
- present paginate(issues), with: Entities::Issue, current_user: current_user
+ present paginate(issues), with: Entities::Issue, current_user: current_user, project: user_project
end
end
end
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index c5c214d4d13..b255b47742b 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -5,23 +5,23 @@ module API
NOTEABLE_TYPES = [Issue, MergeRequest, Snippet]
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
resource :projects do
NOTEABLE_TYPES.each do |noteable_type|
noteables_str = noteable_type.to_s.underscore.pluralize
- noteable_id_str = "#{noteable_type.to_s.underscore}_id"
-
- # Get a list of project +noteable+ notes
- #
- # Parameters:
- # id (required) - The ID of a project
- # noteable_id (required) - The ID of an issue or snippet
- # Example Request:
- # GET /projects/:id/issues/:noteable_id/notes
- # GET /projects/:id/snippets/:noteable_id/notes
- get ":id/#{noteables_str}/:#{noteable_id_str}/notes" do
- @noteable = user_project.send(noteables_str.to_sym).find(params[noteable_id_str.to_sym])
-
- if can?(current_user, noteable_read_ability_name(@noteable), @noteable)
+
+ desc 'Get a list of project +noteable+ notes' do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ end
+ get ":id/#{noteables_str}/:noteable_id/notes" do
+ noteable = user_project.send(noteables_str.to_sym).find(params[:noteable_id])
+
+ if can?(current_user, noteable_read_ability_name(noteable), noteable)
# We exclude notes that are cross-references and that cannot be viewed
# by the current user. By doing this exclusion at this level and not
# at the DB query level (which we cannot in that case), the current
@@ -31,7 +31,7 @@ module API
# paginate() only works with a relation. This could lead to a
# mismatch between the pagination headers info and the actual notes
# array returned, but this is really a edge-case.
- paginate(@noteable.notes).
+ paginate(noteable.notes).
reject { |n| n.cross_reference_not_visible_for?(current_user) }
present notes, with: Entities::Note
else
@@ -39,44 +39,40 @@ module API
end
end
- # Get a single +noteable+ note
- #
- # Parameters:
- # id (required) - The ID of a project
- # noteable_id (required) - The ID of an issue or snippet
- # note_id (required) - The ID of a note
- # Example Request:
- # GET /projects/:id/issues/:noteable_id/notes/:note_id
- # GET /projects/:id/snippets/:noteable_id/notes/:note_id
- get ":id/#{noteables_str}/:#{noteable_id_str}/notes/:note_id" do
- @noteable = user_project.send(noteables_str.to_sym).find(params[noteable_id_str.to_sym])
- @note = @noteable.notes.find(params[:note_id])
- can_read_note = can?(current_user, noteable_read_ability_name(@noteable), @noteable) && !@note.cross_reference_not_visible_for?(current_user)
+ desc 'Get a single +noteable+ note' do
+ success Entities::Note
+ end
+ params do
+ requires :note_id, type: Integer, desc: 'The ID of a note'
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ end
+ get ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
+ noteable = user_project.send(noteables_str.to_sym).find(params[:noteable_id])
+ note = noteable.notes.find(params[:note_id])
+ can_read_note = can?(current_user, noteable_read_ability_name(noteable), noteable) && !note.cross_reference_not_visible_for?(current_user)
if can_read_note
- present @note, with: Entities::Note
+ present note, with: Entities::Note
else
not_found!("Note")
end
end
- # Create a new +noteable+ note
- #
- # Parameters:
- # id (required) - The ID of a project
- # noteable_id (required) - The ID of an issue or snippet
- # body (required) - The content of a note
- # created_at (optional) - The date
- # Example Request:
- # POST /projects/:id/issues/:noteable_id/notes
- # POST /projects/:id/snippets/:noteable_id/notes
- post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do
+ desc 'Create a new +noteable+ note' do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :body, type: String, desc: 'The content of a note'
+ optional :created_at, type: String, desc: 'The creation date of the note'
+ end
+ post ":id/#{noteables_str}/:noteable_id/notes" do
required_attributes! [:body]
opts = {
note: params[:body],
noteable_type: noteables_str.classify,
- noteable_id: params[noteable_id_str]
+ noteable_id: params[:noteable_id]
}
if params[:created_at] && (current_user.is_admin? || user_project.owner == current_user)
@@ -92,19 +88,15 @@ module API
end
end
- # Modify existing +noteable+ note
- #
- # Parameters:
- # id (required) - The ID of a project
- # noteable_id (required) - The ID of an issue or snippet
- # node_id (required) - The ID of a note
- # body (required) - New content of a note
- # Example Request:
- # PUT /projects/:id/issues/:noteable_id/notes/:note_id
- # PUT /projects/:id/snippets/:noteable_id/notes/:node_id
- put ":id/#{noteables_str}/:#{noteable_id_str}/notes/:note_id" do
- required_attributes! [:body]
-
+ desc 'Update an existing +noteable+ note' do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :note_id, type: Integer, desc: 'The ID of a note'
+ requires :body, type: String, desc: 'The content of a note'
+ end
+ put ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
note = user_project.notes.find(params[:note_id])
authorize! :admin_note, note
@@ -113,25 +105,23 @@ module API
note: params[:body]
}
- @note = ::Notes::UpdateService.new(user_project, current_user, opts).execute(note)
+ note = ::Notes::UpdateService.new(user_project, current_user, opts).execute(note)
- if @note.valid?
- present @note, with: Entities::Note
+ if note.valid?
+ present note, with: Entities::Note
else
render_api_error!("Failed to save note #{note.errors.messages}", 400)
end
end
- # Delete a +noteable+ note
- #
- # Parameters:
- # id (required) - The ID of a project
- # noteable_id (required) - The ID of an issue, MR, or snippet
- # node_id (required) - The ID of a note
- # Example Request:
- # DELETE /projects/:id/issues/:noteable_id/notes/:note_id
- # DELETE /projects/:id/snippets/:noteable_id/notes/:node_id
- delete ":id/#{noteables_str}/:#{noteable_id_str}/notes/:note_id" do
+ desc 'Delete a +noteable+ note' do
+ success Entities::Note
+ end
+ params do
+ requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ requires :note_id, type: Integer, desc: 'The ID of a note'
+ end
+ delete ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
note = user_project.notes.find(params[:note_id])
authorize! :admin_note, note
diff --git a/lib/api/notification_settings.rb b/lib/api/notification_settings.rb
index a70a7e71073..c5e9b3ad69b 100644
--- a/lib/api/notification_settings.rb
+++ b/lib/api/notification_settings.rb
@@ -33,10 +33,9 @@ module API
begin
notification_setting.transaction do
new_notification_email = params.delete(:notification_email)
- declared_params = declared(params, include_missing: false).to_h
current_user.update(notification_email: new_notification_email) if new_notification_email
- notification_setting.update(declared_params)
+ notification_setting.update(declared_params(include_missing: false))
end
rescue ArgumentError => e # catch level enum error
render_api_error! e.to_s, 400
@@ -81,9 +80,7 @@ module API
notification_setting = current_user.notification_settings_for(source)
begin
- declared_params = declared(params, include_missing: false).to_h
-
- notification_setting.update(declared_params)
+ notification_setting.update(declared_params(include_missing: false))
rescue ArgumentError => e # catch level enum error
render_api_error! e.to_s, 400
end
diff --git a/lib/api/pipelines.rb b/lib/api/pipelines.rb
index 2a0c8e1f2c0..e69b0569612 100644
--- a/lib/api/pipelines.rb
+++ b/lib/api/pipelines.rb
@@ -22,6 +22,27 @@ module API
pipelines = PipelinesFinder.new(user_project).execute(scope: params[:scope])
present paginate(pipelines), with: Entities::Pipeline
end
+
+ desc 'Create a new pipeline' do
+ detail 'This feature was introduced in GitLab 8.14'
+ success Entities::Pipeline
+ end
+ params do
+ requires :ref, type: String, desc: 'Reference'
+ end
+ post ':id/pipeline' do
+ authorize! :create_pipeline, user_project
+
+ new_pipeline = Ci::CreatePipelineService.new(user_project,
+ current_user,
+ declared_params(include_missing: false))
+ .execute(ignore_skip_ci: true, save_on_errors: false)
+ if new_pipeline.persisted?
+ present new_pipeline, with: Entities::Pipeline
+ else
+ render_validation_error!(new_pipeline)
+ end
+ end
desc 'Gets a specific pipeline for the project' do
detail 'This feature was introduced in GitLab 8.11'
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index eef343c2ac6..2b36ef7c426 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -51,8 +51,7 @@ module API
use :project_hook_properties
end
post ":id/hooks" do
- new_hook_params = declared(params, include_missing: false, include_parent_namespaces: false).to_h
- hook = user_project.hooks.new(new_hook_params)
+ hook = user_project.hooks.new(declared_params(include_missing: false))
if hook.save
present hook, with: Entities::ProjectHook
@@ -71,12 +70,9 @@ module API
use :project_hook_properties
end
put ":id/hooks/:hook_id" do
- hook = user_project.hooks.find(params[:hook_id])
-
- new_params = declared(params, include_missing: false, include_parent_namespaces: false).to_h
- new_params.delete('hook_id')
+ hook = user_project.hooks.find(params.delete(:hook_id))
- if hook.update_attributes(new_params)
+ if hook.update_attributes(declared_params(include_missing: false))
present hook, with: Entities::ProjectHook
else
error!("Invalid url given", 422) if hook.errors[:url].present?
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index f55aceed92c..c287ee34a68 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -1,11 +1,13 @@
require 'mime/types'
module API
- # Projects API
class Repositories < Grape::API
before { authenticate! }
before { authorize! :download_code, user_project }
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
resource :projects do
helpers do
def handle_project_member_errors(errors)
@@ -16,13 +18,14 @@ module API
end
end
- # Get a project repository tree
- #
- # Parameters:
- # id (required) - The ID of a project
- # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used
- # Example Request:
- # GET /projects/:id/repository/tree
+ desc 'Get a project repository tree' do
+ success Entities::RepoTreeObject
+ end
+ params do
+ optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
+ optional :path, type: String, desc: 'The path of the tree'
+ optional :recursive, type: Boolean, default: false, desc: 'Used to get a recursive tree'
+ end
get ':id/repository/tree' do
ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
path = params[:path] || nil
@@ -30,27 +33,20 @@ module API
commit = user_project.commit(ref)
not_found!('Tree') unless commit
- tree = user_project.repository.tree(commit.id, path)
+ tree = user_project.repository.tree(commit.id, path, recursive: params[:recursive])
present tree.sorted_entries, with: Entities::RepoTreeObject
end
- # Get a raw file contents
- #
- # Parameters:
- # id (required) - The ID of a project
- # sha (required) - The commit or branch name
- # filepath (required) - The path to the file to display
- # Example Request:
- # GET /projects/:id/repository/blobs/:sha
+ desc 'Get a raw file contents'
+ params do
+ requires :sha, type: String, desc: 'The commit, branch name, or tag name'
+ requires :filepath, type: String, desc: 'The path to the file to display'
+ end
get [ ":id/repository/blobs/:sha", ":id/repository/commits/:sha/blob" ] do
- required_attributes! [:filepath]
-
- ref = params[:sha]
-
repo = user_project.repository
- commit = repo.commit(ref)
+ commit = repo.commit(params[:sha])
not_found! "Commit" unless commit
blob = Gitlab::Git::Blob.find(repo, commit.id, params[:filepath])
@@ -59,20 +55,15 @@ module API
send_git_blob repo, blob
end
- # Get a raw blob contents by blob sha
- #
- # Parameters:
- # id (required) - The ID of a project
- # sha (required) - The blob's sha
- # Example Request:
- # GET /projects/:id/repository/raw_blobs/:sha
+ desc 'Get a raw blob contents by blob sha'
+ params do
+ requires :sha, type: String, desc: 'The commit, branch name, or tag name'
+ end
get ':id/repository/raw_blobs/:sha' do
- ref = params[:sha]
-
repo = user_project.repository
begin
- blob = Gitlab::Git::Blob.raw(repo, ref)
+ blob = Gitlab::Git::Blob.raw(repo, params[:sha])
rescue
not_found! 'Blob'
end
@@ -82,15 +73,12 @@ module API
send_git_blob repo, blob
end
- # Get a an archive of the repository
- #
- # Parameters:
- # id (required) - The ID of a project
- # sha (optional) - the commit sha to download defaults to the tip of the default branch
- # Example Request:
- # GET /projects/:id/repository/archive
- get ':id/repository/archive',
- requirements: { format: Gitlab::Regex.archive_formats_regex } do
+ desc 'Get an archive of the repository'
+ params do
+ optional :sha, type: String, desc: 'The commit sha of the archive to be downloaded'
+ optional :format, type: String, desc: 'The archive format'
+ end
+ get ':id/repository/archive', requirements: { format: Gitlab::Regex.archive_formats_regex } do
authorize! :download_code, user_project
begin
@@ -100,27 +88,22 @@ module API
end
end
- # Compare two branches, tags or commits
- #
- # Parameters:
- # id (required) - The ID of a project
- # from (required) - the commit sha or branch name
- # to (required) - the commit sha or branch name
- # Example Request:
- # GET /projects/:id/repository/compare?from=master&to=feature
+ desc 'Compare two branches, tags, or commits' do
+ success Entities::Compare
+ end
+ params do
+ requires :from, type: String, desc: 'The commit, branch name, or tag name to start comparison'
+ requires :to, type: String, desc: 'The commit, branch name, or tag name to stop comparison'
+ end
get ':id/repository/compare' do
authorize! :download_code, user_project
- required_attributes! [:from, :to]
compare = Gitlab::Git::Compare.new(user_project.repository.raw_repository, params[:from], params[:to])
present compare, with: Entities::Compare
end
- # Get repository contributors
- #
- # Parameters:
- # id (required) - The ID of a project
- # Example Request:
- # GET /projects/:id/repository/contributors
+ desc 'Get repository contributors' do
+ success Entities::Contributor
+ end
get ':id/repository/contributors' do
authorize! :download_code, user_project
diff --git a/lib/api/services.rb b/lib/api/services.rb
index fc8598daa32..4d23499aa39 100644
--- a/lib/api/services.rb
+++ b/lib/api/services.rb
@@ -1,10 +1,10 @@
module API
# Projects API
class Services < Grape::API
- before { authenticate! }
- before { authorize_admin_project }
-
resource :projects do
+ before { authenticate! }
+ before { authorize_admin_project }
+
# Set <service_slug> service for project
#
# Example Request:
@@ -59,5 +59,28 @@ module API
present project_service, with: Entities::ProjectService, include_passwords: current_user.is_admin?
end
end
+
+ resource :projects do
+ desc 'Trigger a slash command' do
+ detail 'Added in GitLab 8.13'
+ end
+ post ':id/services/:service_slug/trigger' do
+ project = Project.find_with_namespace(params[:id]) || Project.find_by(id: params[:id])
+
+ # This is not accurate, but done to prevent leakage of the project names
+ not_found!('Service') unless project
+
+ service = project_service(project)
+
+ result = service.try(:active?) && service.try(:trigger, params)
+
+ if result
+ status result[:status] || 200
+ present result
+ else
+ not_found!('Service')
+ end
+ end
+ end
end
end
diff --git a/lib/api/subscriptions.rb b/lib/api/subscriptions.rb
index 00a79c24f96..10749b34004 100644
--- a/lib/api/subscriptions.rb
+++ b/lib/api/subscriptions.rb
@@ -24,11 +24,11 @@ module API
post ":id/#{type}/:subscribable_id/subscription" do
resource = instance_exec(params[:subscribable_id], &finder)
- if resource.subscribed?(current_user)
+ if resource.subscribed?(current_user, user_project)
not_modified!
else
- resource.subscribe(current_user)
- present resource, with: entity_class, current_user: current_user
+ resource.subscribe(current_user, user_project)
+ present resource, with: entity_class, current_user: current_user, project: user_project
end
end
@@ -38,11 +38,11 @@ module API
delete ":id/#{type}/:subscribable_id/subscription" do
resource = instance_exec(params[:subscribable_id], &finder)
- if !resource.subscribed?(current_user)
+ if !resource.subscribed?(current_user, user_project)
not_modified!
else
- resource.unsubscribe(current_user)
- present resource, with: entity_class, current_user: current_user
+ resource.unsubscribe(current_user, user_project)
+ present resource, with: entity_class, current_user: current_user, project: user_project
end
end
end
diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb
index b6bfff9f20f..708ec8cfe70 100644
--- a/lib/api/system_hooks.rb
+++ b/lib/api/system_hooks.rb
@@ -27,7 +27,7 @@ module API
optional :enable_ssl_verification, type: Boolean, desc: "Do SSL verification when triggering the hook"
end
post do
- hook = SystemHook.new declared(params, include_missing: false).to_h
+ hook = SystemHook.new(declared_params(include_missing: false))
if hook.save
present hook, with: Entities::Hook
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index bf2a199ce21..cd33f9a9903 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -40,10 +40,9 @@ module API
end
post ':id/repository/tags' do
authorize_push_project
- create_params = declared(params)
result = CreateTagService.new(user_project, current_user).
- execute(create_params[:tag_name], create_params[:ref], create_params[:message], create_params[:release_description])
+ execute(params[:tag_name], params[:ref], params[:message], params[:release_description])
if result[:status] == :success
present result[:tag],
diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb
index 9a4f1cd342f..569598fbd2c 100644
--- a/lib/api/triggers.rb
+++ b/lib/api/triggers.rb
@@ -12,7 +12,7 @@ module API
requires :token, type: String, desc: 'The unique token of trigger'
optional :variables, type: Hash, desc: 'The list of variables to be injected into build'
end
- post ":id/trigger/builds" do
+ post ":id/(ref/:ref/)trigger/builds" do
project = Project.find_with_namespace(params[:id]) || Project.find_by(id: params[:id])
trigger = Ci::Trigger.find_by_token(params[:token].to_s)
not_found! unless project && trigger