e7bd824484
47d4890d
changed the order of pagination so that the full list of
branches would be passed to Gitaly to determine which ones had been
merged, but this operation can timeout for large repositories with
many branches. We only need to determine whether the found branches have
been merged, so limit the scan to those.
Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/55724
179 lines
6.5 KiB
Ruby
179 lines
6.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'mime/types'
|
|
|
|
module API
|
|
class Branches < Grape::API
|
|
include PaginationParams
|
|
|
|
BRANCH_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(branch: API::NO_SLASH_URL_PART_REGEX)
|
|
|
|
before { authorize! :download_code, user_project }
|
|
|
|
helpers do
|
|
params :filter_params do
|
|
optional :search, type: String, desc: 'Return list of branches matching the search criteria'
|
|
optional :sort, type: String, desc: 'Return list of branches sorted by the given field'
|
|
end
|
|
end
|
|
|
|
params do
|
|
requires :id, type: String, desc: 'The ID of a project'
|
|
end
|
|
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
|
|
desc 'Get a project repository branches' do
|
|
success Entities::Branch
|
|
end
|
|
params do
|
|
use :pagination
|
|
use :filter_params
|
|
end
|
|
get ':id/repository/branches' do
|
|
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42329')
|
|
|
|
repository = user_project.repository
|
|
|
|
branches = BranchesFinder.new(repository, declared_params(include_missing: false)).execute
|
|
branches = ::Kaminari.paginate_array(branches)
|
|
merged_branch_names = repository.merged_branch_names(branches.map(&:name))
|
|
|
|
present(
|
|
paginate(branches),
|
|
with: Entities::Branch,
|
|
current_user: current_user,
|
|
project: user_project,
|
|
merged_branch_names: merged_branch_names
|
|
)
|
|
end
|
|
|
|
resource ':id/repository/branches/:branch', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
|
|
desc 'Get a single branch' do
|
|
success Entities::Branch
|
|
end
|
|
params do
|
|
requires :branch, type: String, desc: 'The name of the branch'
|
|
end
|
|
head do
|
|
user_project.repository.branch_exists?(params[:branch]) ? status(204) : status(404)
|
|
end
|
|
get do
|
|
branch = find_branch!(params[:branch])
|
|
|
|
present branch, with: Entities::Branch, current_user: current_user, project: user_project
|
|
end
|
|
end
|
|
|
|
# Note: This API will be deprecated in favor of the protected branches API.
|
|
# Note: The internal data model moved from `developers_can_{merge,push}` to `allowed_to_{merge,push}`
|
|
# in `gitlab-org/gitlab-ce!5081`. The API interface has not been changed (to maintain compatibility),
|
|
# but it works with the changed data model to infer `developers_can_merge` and `developers_can_push`.
|
|
desc 'Protect a single branch' do
|
|
success Entities::Branch
|
|
end
|
|
params do
|
|
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
|
|
optional :developers_can_push, type: Boolean, desc: 'Flag if developers can push to that branch'
|
|
optional :developers_can_merge, type: Boolean, desc: 'Flag if developers can merge to that branch'
|
|
end
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
put ':id/repository/branches/:branch/protect', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
|
|
authorize_admin_project
|
|
|
|
branch = find_branch!(params[:branch])
|
|
|
|
protected_branch = user_project.protected_branches.find_by(name: branch.name)
|
|
|
|
protected_branch_params = {
|
|
name: branch.name,
|
|
developers_can_push: params[:developers_can_push],
|
|
developers_can_merge: params[:developers_can_merge]
|
|
}
|
|
|
|
service_args = [user_project, current_user, protected_branch_params]
|
|
|
|
protected_branch = if protected_branch
|
|
::ProtectedBranches::LegacyApiUpdateService.new(*service_args).execute(protected_branch)
|
|
else
|
|
::ProtectedBranches::LegacyApiCreateService.new(*service_args).execute
|
|
end
|
|
|
|
if protected_branch.valid?
|
|
present branch, with: Entities::Branch, current_user: current_user, project: user_project
|
|
else
|
|
render_api_error!(protected_branch.errors.full_messages, 422)
|
|
end
|
|
end
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
|
|
|
# Note: This API will be deprecated in favor of the protected branches API.
|
|
desc 'Unprotect a single branch' do
|
|
success Entities::Branch
|
|
end
|
|
params do
|
|
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
|
|
end
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
put ':id/repository/branches/:branch/unprotect', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
|
|
authorize_admin_project
|
|
|
|
branch = find_branch!(params[:branch])
|
|
protected_branch = user_project.protected_branches.find_by(name: branch.name)
|
|
protected_branch&.destroy
|
|
|
|
present branch, with: Entities::Branch, current_user: current_user, project: user_project
|
|
end
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
|
|
|
desc 'Create branch' do
|
|
success Entities::Branch
|
|
end
|
|
params do
|
|
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
|
|
requires :ref, type: String, desc: 'Create branch from commit sha or existing branch', allow_blank: false
|
|
end
|
|
post ':id/repository/branches' do
|
|
authorize_push_project
|
|
|
|
result = CreateBranchService.new(user_project, current_user)
|
|
.execute(params[:branch], params[:ref])
|
|
|
|
if result[:status] == :success
|
|
present result[:branch],
|
|
with: Entities::Branch,
|
|
current_user: current_user,
|
|
project: user_project
|
|
else
|
|
render_api_error!(result[:message], 400)
|
|
end
|
|
end
|
|
|
|
desc 'Delete a branch'
|
|
params do
|
|
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
|
|
end
|
|
delete ':id/repository/branches/:branch', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
|
|
authorize_push_project
|
|
|
|
branch = find_branch!(params[:branch])
|
|
|
|
commit = user_project.repository.commit(branch.dereferenced_target)
|
|
|
|
destroy_conditionally!(commit, last_updated: commit.authored_date) do
|
|
result = DeleteBranchService.new(user_project, current_user)
|
|
.execute(params[:branch])
|
|
|
|
if result[:status] != :success
|
|
render_api_error!(result[:message], result[:return_code])
|
|
end
|
|
end
|
|
end
|
|
|
|
desc 'Delete all merged branches'
|
|
delete ':id/repository/merged_branches' do
|
|
DeleteMergedBranchesService.new(user_project, current_user).async_execute
|
|
|
|
accepted!
|
|
end
|
|
end
|
|
end
|
|
end
|