summaryrefslogtreecommitdiff
path: root/lib/api
diff options
context:
space:
mode:
Diffstat (limited to 'lib/api')
-rw-r--r--lib/api/api.rb4
-rw-r--r--lib/api/commit_statuses.rb2
-rw-r--r--lib/api/entities.rb74
-rw-r--r--lib/api/files.rb6
-rw-r--r--lib/api/groups.rb12
-rw-r--r--lib/api/helpers.rb57
-rw-r--r--lib/api/merge_requests.rb80
-rw-r--r--lib/api/project_hooks.rb2
-rw-r--r--lib/api/projects.rb37
-rw-r--r--lib/api/repositories.rb35
-rw-r--r--lib/api/tags.rb86
-rw-r--r--lib/api/triggers.rb48
-rw-r--r--lib/api/users.rb16
13 files changed, 350 insertions, 109 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb
index afc0402f9e1..7834262d612 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -25,7 +25,7 @@ module API
format :json
content_type :txt, "text/plain"
- helpers APIHelpers
+ helpers Helpers
mount Groups
mount GroupMembers
@@ -52,5 +52,7 @@ module API
mount Labels
mount Settings
mount Keys
+ mount Tags
+ mount Triggers
end
end
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 2c0596c9dfb..1162271f5fc 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -53,7 +53,7 @@ module API
name = params[:name] || params[:context]
status = GenericCommitStatus.running_or_pending.find_by(commit: ci_commit, name: name, ref: params[:ref])
- status ||= GenericCommitStatus.new(commit: ci_commit, user: current_user)
+ status ||= GenericCommitStatus.new(project: @project, commit: ci_commit, user: current_user)
status.update(attrs)
case params[:state].to_s
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 883a5e14b17..26e7c956e8f 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -45,7 +45,8 @@ module API
class ProjectHook < Hook
expose :project_id, :push_events
- expose :issues_events, :merge_requests_events, :tag_push_events, :note_events, :enable_ssl_verification
+ expose :issues_events, :merge_requests_events, :tag_push_events, :note_events, :build_events
+ expose :enable_ssl_verification
end
class ForkedFromProject < Grape::Entity
@@ -62,12 +63,14 @@ module API
expose :owner, using: Entities::UserBasic, unless: ->(project, options) { project.group }
expose :name, :name_with_namespace
expose :path, :path_with_namespace
- expose :issues_enabled, :merge_requests_enabled, :wiki_enabled, :snippets_enabled, :created_at, :last_activity_at
+ expose :issues_enabled, :merge_requests_enabled, :wiki_enabled, :builds_enabled, :snippets_enabled, :created_at, :last_activity_at
+ expose :shared_runners_enabled
expose :creator_id
expose :namespace
- expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ | project, options | project.forked? }
+ expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ |project, options| project.forked? }
expose :avatar_url
expose :star_count, :forks_count
+ expose :open_issues_count, if: lambda { |project, options| project.issues_enabled? && project.default_issues_tracker? }
end
class ProjectMember < UserBasic
@@ -95,25 +98,6 @@ module API
end
end
- class RepoTag < Grape::Entity
- expose :name
- expose :message do |repo_obj, _options|
- if repo_obj.respond_to?(:message)
- repo_obj.message
- else
- nil
- end
- end
-
- expose :commit do |repo_obj, options|
- if repo_obj.respond_to?(:commit)
- repo_obj.commit
- elsif options[:project]
- options[:project].repository.commit(repo_obj.target)
- end
- end
- end
-
class RepoObject < Grape::Entity
expose :name
@@ -181,13 +165,15 @@ module API
end
class MergeRequest < ProjectEntity
- expose :target_branch, :source_branch, :upvotes, :downvotes
+ expose :target_branch, :source_branch
+ expose :upvotes, :downvotes
expose :author, :assignee, using: Entities::UserBasic
expose :source_project_id, :target_project_id
expose :label_names, as: :labels
expose :description
expose :work_in_progress?, as: :work_in_progress
expose :milestone, using: Entities::Milestone
+ expose :merge_when_build_succeeds
end
class MergeRequestChanges < MergeRequest
@@ -211,6 +197,8 @@ module API
expose :author, using: Entities::UserBasic
expose :created_at
expose :system?, as: :system
+ expose :noteable_id, :noteable_type
+ # upvote? and downvote? are deprecated, always return false
expose :upvote?, as: :upvote
expose :downvote?, as: :downvote
end
@@ -231,7 +219,7 @@ module API
class CommitStatus < Grape::Entity
expose :id, :sha, :ref, :status, :name, :target_url, :description,
- :created_at, :started_at, :finished_at
+ :created_at, :started_at, :finished_at, :allow_failure
expose :author, using: Entities::UserBasic
end
@@ -240,6 +228,8 @@ module API
expose :target_id, :target_type, :author_id
expose :data, :target_title
expose :created_at
+ expose :note, using: Entities::Note, if: ->(event, options) { event.note? }
+ expose :author, using: Entities::UserBasic, if: ->(event, options) { event.author }
expose :author_username do |event, options|
if event.author
@@ -264,7 +254,7 @@ module API
class ProjectService < Grape::Entity
expose :id, :title, :created_at, :updated_at, :active
- expose :push_events, :issues_events, :merge_requests_events, :tag_push_events, :note_events
+ expose :push_events, :issues_events, :merge_requests_events, :tag_push_events, :note_events, :build_events
# Expose serialized properties
expose :properties do |service, options|
field_names = service.fields.
@@ -341,5 +331,39 @@ module API
expose :user_oauth_applications
expose :after_sign_out_path
end
+
+ class Release < Grape::Entity
+ expose :tag, as: :tag_name
+ expose :description
+ end
+
+ class RepoTag < Grape::Entity
+ expose :name
+ expose :message do |repo_obj, _options|
+ if repo_obj.respond_to?(:message)
+ repo_obj.message
+ else
+ nil
+ end
+ end
+
+ expose :commit do |repo_obj, options|
+ if repo_obj.respond_to?(:commit)
+ repo_obj.commit
+ elsif options[:project]
+ options[:project].repository.commit(repo_obj.target)
+ end
+ end
+
+ expose :release, using: Entities::Release do |repo_obj, options|
+ if options[:project]
+ options[:project].releases.find_by(tag: repo_obj.name)
+ end
+ end
+ end
+
+ class TriggerRequest < Grape::Entity
+ expose :id, :variables
+ end
end
end
diff --git a/lib/api/files.rb b/lib/api/files.rb
index 308c84dd135..8ad2c1883c7 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -7,7 +7,7 @@ module API
def commit_params(attrs)
{
file_path: attrs[:file_path],
- current_branch: attrs[:branch_name],
+ source_branch: attrs[:branch_name],
target_branch: attrs[:branch_name],
commit_message: attrs[:commit_message],
file_content: attrs[:content],
@@ -43,7 +43,8 @@ module API
# "content": "IyA9PSBTY2hlbWEgSW5mb3...",
# "ref": "master",
# "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83",
- # "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50"
+ # "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50",
+ # "last_commit_id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
# }
#
get ":id/repository/files" do
@@ -71,6 +72,7 @@ module API
ref: ref,
blob_id: blob.id,
commit_id: commit.id,
+ last_commit_id: user_project.repository.last_commit_for_path(commit.sha, file_path).id
}
else
not_found! 'File'
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 024aeec2e14..1a14d870a4a 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -65,6 +65,18 @@ module API
DestroyGroupService.new(group, current_user).execute
end
+ # Get a list of projects in this group
+ #
+ # Example Request:
+ # GET /groups/:id/projects
+ get ":id/projects" do
+ group = find_group(params[:id])
+ projects = group.projects
+ projects = filter_projects(projects)
+ projects = paginate projects
+ present projects, with: Entities::Project
+ end
+
# Transfer a project to the Group namespace
#
# Parameters:
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 549b1f9e9a7..a4df810e755 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -1,5 +1,5 @@
module API
- module APIHelpers
+ module Helpers
PRIVATE_TOKEN_HEADER = "HTTP_PRIVATE_TOKEN"
PRIVATE_TOKEN_PARAM = :private_token
SUDO_HEADER ="HTTP_SUDO"
@@ -133,6 +133,12 @@ module API
authorize! :admin_project, user_project
end
+ def require_gitlab_workhorse!
+ unless env['HTTP_GITLAB_WORKHORSE'].present?
+ forbidden!('Request should be executed via GitLab Workhorse')
+ end
+ end
+
def can?(object, action, subject)
abilities.allowed?(object, action, subject)
end
@@ -234,6 +240,10 @@ module API
render_api_error!(message || '409 Conflict', 409)
end
+ def file_to_large!
+ render_api_error!('413 Request Entity Too Large', 413)
+ end
+
def render_validation_error!(model)
if model.errors.any?
render_api_error!(model.errors.messages || '400 Bad Request', 400)
@@ -256,12 +266,7 @@ module API
projects = projects.search(params[:search])
end
- if params[:ci_enabled_first].present?
- projects.includes(:gitlab_ci_service).
- reorder("services.active DESC, projects.#{project_order_by} #{project_sort}")
- else
- projects.reorder(project_order_by => project_sort)
- end
+ projects.reorder(project_order_by => project_sort)
end
def project_order_by
@@ -282,6 +287,44 @@ module API
end
end
+ # file helpers
+
+ def uploaded_file!(field, uploads_path)
+ if params[field]
+ bad_request!("#{field} is not a file") unless params[field].respond_to?(:filename)
+ return params[field]
+ end
+
+ # sanitize file paths
+ # this requires all paths to exist
+ required_attributes! %W(#{field}.path)
+ uploads_path = File.realpath(uploads_path)
+ file_path = File.realpath(params["#{field}.path"])
+ bad_request!('Bad file path') unless file_path.start_with?(uploads_path)
+
+ UploadedFile.new(
+ file_path,
+ params["#{field}.name"],
+ params["#{field}.type"] || 'application/octet-stream',
+ )
+ end
+
+ def present_file!(path, filename, content_type = 'application/octet-stream')
+ filename ||= File.basename(path)
+ header['Content-Disposition'] = "attachment; filename=#{filename}"
+ header['Content-Transfer-Encoding'] = 'binary'
+ content_type content_type
+
+ # Support download acceleration
+ case headers['X-Sendfile-Type']
+ when 'X-Sendfile'
+ header['X-Sendfile'] = path
+ body
+ else
+ file FileStreamer.new(path)
+ end
+ end
+
private
def add_pagination_headers(paginated, per_page)
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 6eb84baf9cb..3c1c6bda260 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -76,6 +76,22 @@ module API
present merge_request, with: Entities::MergeRequest
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_request/:merge_request_id/commits
+ #
+ get ':id/merge_request/:merge_request_id/commits' do
+ 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:
@@ -179,46 +195,54 @@ module API
# 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
+ # 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
# Example:
# PUT /projects/:id/merge_request/:merge_request_id/merge
#
put ":id/merge_request/:merge_request_id/merge" do
merge_request = user_project.merge_requests.find(params[:merge_request_id])
- allowed = ::Gitlab::GitAccess.new(current_user, user_project).
- can_push_to_branch?(merge_request.target_branch)
+ # Merge request can not be merged
+ # because user dont have permissions to push into target branch
+ unauthorized! unless merge_request.can_be_merged_by?(current_user)
+ not_allowed! if !merge_request.open? || merge_request.work_in_progress?
- if allowed
- if merge_request.unchecked?
- merge_request.check_if_can_be_merged
- end
+ merge_request.check_if_can_be_merged if merge_request.unchecked?
- if merge_request.open? && !merge_request.work_in_progress?
- if merge_request.can_be_merged?
- commit_message = params[:merge_commit_message] || merge_request.merge_commit_message
-
- ::MergeRequests::MergeService.new(merge_request.target_project, current_user).
- execute(merge_request, commit_message)
-
- present merge_request, with: Entities::MergeRequest
- else
- render_api_error!('Branch cannot be merged', 405)
- end
- else
- # Merge request can not be merged
- # because it is already closed/merged or marked as WIP
- not_allowed!
- end
+ render_api_error!('Branch cannot be merged', 406) unless merge_request.can_be_merged?
+
+ merge_params = {
+ commit_message: params[:merge_commit_message],
+ should_remove_source_branch: params[:should_remove_source_branch]
+ }
+
+ if parse_boolean(params[:merge_when_build_succeeds]) && merge_request.ci_commit && merge_request.ci_commit.active?
+ ::MergeRequests::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params).
+ execute(merge_request)
else
- # Merge request can not be merged
- # because user dont have permissions to push into target branch
- unauthorized!
+ ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params).
+ execute(merge_request)
end
+
+ present merge_request, with: Entities::MergeRequest
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
+ #
+ post ":id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds" do
+ merge_request = user_project.merge_requests.find(params[:merge_request_id])
+
+ unauthorized! unless merge_request.can_cancel_merge_when_build_succeeds?(current_user)
+
+ ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user).cancel(merge_request)
+ end
# Get a merge request's comments
#
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index 882d1a083ad..cf9938d25a7 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -45,6 +45,7 @@ module API
:merge_requests_events,
:tag_push_events,
:note_events,
+ :build_events,
:enable_ssl_verification
]
@hook = user_project.hooks.new(attrs)
@@ -77,6 +78,7 @@ module API
:merge_requests_events,
:tag_push_events,
:note_events,
+ :build_events,
:enable_ssl_verification
]
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 67ee66a2058..0781236cf6d 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -3,12 +3,16 @@ module API
class Projects < Grape::API
before { authenticate! }
- resource :projects do
+ resource :projects, requirements: { id: /[^\/]+/ } do
helpers do
def map_public_to_visibility_level(attrs)
publik = attrs.delete(:public)
- publik = parse_boolean(publik)
- attrs[:visibility_level] = Gitlab::VisibilityLevel::PUBLIC if !attrs[:visibility_level].present? && publik == true
+ if publik.present? && !attrs[:visibility_level].present?
+ publik = parse_boolean(publik)
+ # 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
@@ -21,7 +25,7 @@ module API
@projects = current_user.authorized_projects
@projects = filter_projects(@projects)
@projects = paginate @projects
- present @projects, with: Entities::Project
+ present @projects, with: Entities::ProjectWithAccess, user: current_user
end
# Get an owned projects list for authenticated user
@@ -32,6 +36,17 @@ module API
@projects = current_user.owned_projects
@projects = filter_projects(@projects)
@projects = paginate @projects
+ present @projects, with: Entities::ProjectWithAccess, user: current_user
+ end
+
+ # Gets starred project for the authenticated user
+ #
+ # Example Request:
+ # GET /projects/starred
+ get '/starred' do
+ @projects = current_user.starred_projects
+ @projects = filter_projects(@projects)
+ @projects = paginate @projects
present @projects, with: Entities::Project
end
@@ -44,7 +59,7 @@ module API
@projects = Project.all
@projects = filter_projects(@projects)
@projects = paginate @projects
- present @projects, with: Entities::Project
+ present @projects, with: Entities::ProjectWithAccess, user: current_user
end
# Get a single project
@@ -75,8 +90,10 @@ module API
# description (optional) - short project description
# issues_enabled (optional)
# merge_requests_enabled (optional)
+ # builds_enabled (optional)
# wiki_enabled (optional)
# snippets_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
@@ -90,8 +107,10 @@ module API
:description,
:issues_enabled,
:merge_requests_enabled,
+ :builds_enabled,
:wiki_enabled,
:snippets_enabled,
+ :shared_runners_enabled,
:namespace_id,
:public,
:visibility_level,
@@ -117,8 +136,10 @@ module API
# default_branch (optional) - 'master' by default
# issues_enabled (optional)
# merge_requests_enabled (optional)
+ # builds_enabled (optional)
# wiki_enabled (optional)
# snippets_enabled (optional)
+ # shared_runners_enabled (optional)
# public (optional) - if true same as setting visibility_level = 20
# visibility_level (optional)
# import_url (optional)
@@ -132,8 +153,10 @@ module API
:default_branch,
:issues_enabled,
:merge_requests_enabled,
+ :builds_enabled,
:wiki_enabled,
:snippets_enabled,
+ :shared_runners_enabled,
:public,
:visibility_level,
:import_url]
@@ -172,8 +195,10 @@ module API
# description (optional) - short project description
# issues_enabled (optional)
# merge_requests_enabled (optional)
+ # builds_enabled (optional)
# wiki_enabled (optional)
# snippets_enabled (optional)
+ # shared_runners_enabled (optional)
# public (optional) - if true same as setting visibility_level = 20
# visibility_level (optional) - visibility level of a project
# Example Request
@@ -185,8 +210,10 @@ module API
:default_branch,
:issues_enabled,
:merge_requests_enabled,
+ :builds_enabled,
:wiki_enabled,
:snippets_enabled,
+ :shared_runners_enabled,
:public,
:visibility_level]
attrs = map_public_to_visibility_level(attrs)
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 20d568cf462..d7c48639eba 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -16,41 +16,6 @@ module API
end
end
- # Get a project repository tags
- #
- # Parameters:
- # id (required) - The ID of a project
- # Example Request:
- # GET /projects/:id/repository/tags
- get ":id/repository/tags" do
- present user_project.repo.tags.sort_by(&:name).reverse,
- with: Entities::RepoTag, project: user_project
- end
-
- # Create tag
- #
- # Parameters:
- # id (required) - The ID of a project
- # tag_name (required) - The name of the tag
- # ref (required) - Create tag from commit sha or branch
- # message (optional) - Specifying a message creates an annotated tag.
- # Example Request:
- # POST /projects/:id/repository/tags
- post ':id/repository/tags' do
- authorize_push_project
- message = params[:message] || nil
- result = CreateTagService.new(user_project, current_user).
- execute(params[:tag_name], params[:ref], message)
-
- if result[:status] == :success
- present result[:tag],
- with: Entities::RepoTag,
- project: user_project
- else
- render_api_error!(result[:message], 400)
- end
- end
-
# Get a project repository tree
#
# Parameters:
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
new file mode 100644
index 00000000000..47621f443e6
--- /dev/null
+++ b/lib/api/tags.rb
@@ -0,0 +1,86 @@
+module API
+ # Git Tags API
+ class Tags < Grape::API
+ before { authenticate! }
+ before { authorize! :download_code, user_project }
+
+ resource :projects do
+ # Get a project repository tags
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # Example Request:
+ # GET /projects/:id/repository/tags
+ get ":id/repository/tags" do
+ present user_project.repo.tags.sort_by(&:name).reverse,
+ with: Entities::RepoTag, project: user_project
+ end
+
+ # Create tag
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # tag_name (required) - The name of the tag
+ # ref (required) - Create tag from commit sha or branch
+ # message (optional) - Specifying a message creates an annotated tag.
+ # Example Request:
+ # POST /projects/:id/repository/tags
+ post ':id/repository/tags' do
+ authorize_push_project
+ message = params[:message] || nil
+ result = CreateTagService.new(user_project, current_user).
+ execute(params[:tag_name], params[:ref], message, params[:release_description])
+
+ if result[:status] == :success
+ present result[:tag],
+ with: Entities::RepoTag,
+ project: user_project
+ else
+ render_api_error!(result[:message], 400)
+ end
+ end
+
+ # Add release notes to tag
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # tag_name (required) - The name of the tag
+ # description (required) - Release notes with markdown support
+ # Example Request:
+ # POST /projects/:id/repository/tags/:tag_name/release
+ post ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.*/ } do
+ authorize_push_project
+ required_attributes! [:description]
+ result = CreateReleaseService.new(user_project, current_user).
+ execute(params[:tag_name], params[:description])
+
+ if result[:status] == :success
+ present result[:release], with: Entities::Release
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+
+ # Updates a release notes of a tag
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # tag_name (required) - The name of the tag
+ # description (required) - Release notes with markdown support
+ # Example Request:
+ # PUT /projects/:id/repository/tags/:tag_name/release
+ put ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.*/ } do
+ authorize_push_project
+ required_attributes! [:description]
+ result = UpdateReleaseService.new(user_project, current_user).
+ execute(params[:tag_name], params[:description])
+
+ if result[:status] == :success
+ present result[:release], with: Entities::Release
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb
new file mode 100644
index 00000000000..2781f1cf191
--- /dev/null
+++ b/lib/api/triggers.rb
@@ -0,0 +1,48 @@
+module API
+ # Triggers API
+ class Triggers < Grape::API
+ resource :projects do
+ # Trigger a GitLab project build
+ #
+ # Parameters:
+ # id (required) - The ID of a CI project
+ # ref (required) - The name of project's branch or tag
+ # token (required) - The uniq token of trigger
+ # variables (optional) - The list of variables to be injected into build
+ # Example Request:
+ # POST /projects/:id/trigger/builds
+ post ":id/trigger/builds" do
+ required_attributes! [:ref, :token]
+
+ 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
+ unauthorized! unless trigger.project == project
+
+ # validate variables
+ variables = params[:variables]
+ if variables
+ unless variables.is_a?(Hash)
+ render_api_error!('variables needs to be a hash', 400)
+ end
+
+ unless variables.all? { |key, value| key.is_a?(String) && value.is_a?(String) }
+ render_api_error!('variables needs to be a map of key-valued strings', 400)
+ end
+
+ # convert variables from Mash to Hash
+ variables = variables.to_h
+ end
+
+ # create request and trigger builds
+ trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref].to_s, variables)
+ if trigger_request
+ present trigger_request, with: Entities::TriggerRequest
+ else
+ errors = 'No builds created'
+ render_api_error!(errors, 400)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index a98d668e02d..0d7813428e2 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -8,11 +8,17 @@ module API
#
# Example Request:
# GET /users
+ # GET /users?search=Admin
+ # GET /users?username=root
get do
- @users = User.all
- @users = @users.active if params[:active].present?
- @users = @users.search(params[:search]) if params[:search].present?
- @users = paginate @users
+ if params[:username].present?
+ @users = User.where(username: params[:username])
+ else
+ @users = User.all
+ @users = @users.active if params[:active].present?
+ @users = @users.search(params[:search]) if params[:search].present?
+ @users = paginate @users
+ end
if current_user.is_admin?
present @users, with: Entities::UserFull
@@ -33,7 +39,7 @@ module API
if current_user.is_admin?
present @user, with: Entities::UserFull
else
- present @user, with: Entities::UserBasic
+ present @user, with: Entities::User
end
end