/lib/api/branches.rb

https://gitlab.com/solidnerd/gitlab-ce · Ruby · 179 lines · 137 code · 32 blank · 10 comment · 6 complexity · bab1b03d3b1620a04db32df6be061ff1 MD5 · raw file

  1. # frozen_string_literal: true
  2. require 'mime/types'
  3. module API
  4. class Branches < Grape::API
  5. include PaginationParams
  6. BRANCH_ENDPOINT_REQUIREMENTS = API::PROJECT_ENDPOINT_REQUIREMENTS.merge(branch: API::NO_SLASH_URL_PART_REGEX)
  7. before { authorize! :download_code, user_project }
  8. helpers do
  9. params :filter_params do
  10. optional :search, type: String, desc: 'Return list of branches matching the search criteria'
  11. optional :sort, type: String, desc: 'Return list of branches sorted by the given field'
  12. end
  13. end
  14. params do
  15. requires :id, type: String, desc: 'The ID of a project'
  16. end
  17. resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
  18. desc 'Get a project repository branches' do
  19. success Entities::Branch
  20. end
  21. params do
  22. use :pagination
  23. use :filter_params
  24. end
  25. get ':id/repository/branches' do
  26. Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42329')
  27. repository = user_project.repository
  28. branches = BranchesFinder.new(repository, declared_params(include_missing: false)).execute
  29. merged_branch_names = repository.merged_branch_names(branches.map(&:name))
  30. present(
  31. paginate(::Kaminari.paginate_array(branches)),
  32. with: Entities::Branch,
  33. current_user: current_user,
  34. project: user_project,
  35. merged_branch_names: merged_branch_names
  36. )
  37. end
  38. resource ':id/repository/branches/:branch', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
  39. desc 'Get a single branch' do
  40. success Entities::Branch
  41. end
  42. params do
  43. requires :branch, type: String, desc: 'The name of the branch'
  44. end
  45. head do
  46. user_project.repository.branch_exists?(params[:branch]) ? status(204) : status(404)
  47. end
  48. get do
  49. branch = find_branch!(params[:branch])
  50. present branch, with: Entities::Branch, current_user: current_user, project: user_project
  51. end
  52. end
  53. # Note: This API will be deprecated in favor of the protected branches API.
  54. # Note: The internal data model moved from `developers_can_{merge,push}` to `allowed_to_{merge,push}`
  55. # in `gitlab-org/gitlab-ce!5081`. The API interface has not been changed (to maintain compatibility),
  56. # but it works with the changed data model to infer `developers_can_merge` and `developers_can_push`.
  57. desc 'Protect a single branch' do
  58. success Entities::Branch
  59. end
  60. params do
  61. requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
  62. optional :developers_can_push, type: Boolean, desc: 'Flag if developers can push to that branch'
  63. optional :developers_can_merge, type: Boolean, desc: 'Flag if developers can merge to that branch'
  64. end
  65. # rubocop: disable CodeReuse/ActiveRecord
  66. put ':id/repository/branches/:branch/protect', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
  67. authorize_admin_project
  68. branch = find_branch!(params[:branch])
  69. protected_branch = user_project.protected_branches.find_by(name: branch.name)
  70. protected_branch_params = {
  71. name: branch.name,
  72. developers_can_push: params[:developers_can_push],
  73. developers_can_merge: params[:developers_can_merge]
  74. }
  75. service_args = [user_project, current_user, protected_branch_params]
  76. protected_branch = if protected_branch
  77. ::ProtectedBranches::LegacyApiUpdateService.new(*service_args).execute(protected_branch)
  78. else
  79. ::ProtectedBranches::LegacyApiCreateService.new(*service_args).execute
  80. end
  81. if protected_branch.valid?
  82. present branch, with: Entities::Branch, current_user: current_user, project: user_project
  83. else
  84. render_api_error!(protected_branch.errors.full_messages, 422)
  85. end
  86. end
  87. # rubocop: enable CodeReuse/ActiveRecord
  88. # Note: This API will be deprecated in favor of the protected branches API.
  89. desc 'Unprotect a single branch' do
  90. success Entities::Branch
  91. end
  92. params do
  93. requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
  94. end
  95. # rubocop: disable CodeReuse/ActiveRecord
  96. put ':id/repository/branches/:branch/unprotect', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
  97. authorize_admin_project
  98. branch = find_branch!(params[:branch])
  99. protected_branch = user_project.protected_branches.find_by(name: branch.name)
  100. protected_branch&.destroy
  101. present branch, with: Entities::Branch, current_user: current_user, project: user_project
  102. end
  103. # rubocop: enable CodeReuse/ActiveRecord
  104. desc 'Create branch' do
  105. success Entities::Branch
  106. end
  107. params do
  108. requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
  109. requires :ref, type: String, desc: 'Create branch from commit sha or existing branch', allow_blank: false
  110. end
  111. post ':id/repository/branches' do
  112. authorize_push_project
  113. result = CreateBranchService.new(user_project, current_user)
  114. .execute(params[:branch], params[:ref])
  115. if result[:status] == :success
  116. present result[:branch],
  117. with: Entities::Branch,
  118. current_user: current_user,
  119. project: user_project
  120. else
  121. render_api_error!(result[:message], 400)
  122. end
  123. end
  124. desc 'Delete a branch'
  125. params do
  126. requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
  127. end
  128. delete ':id/repository/branches/:branch', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
  129. authorize_push_project
  130. branch = find_branch!(params[:branch])
  131. commit = user_project.repository.commit(branch.dereferenced_target)
  132. destroy_conditionally!(commit, last_updated: commit.authored_date) do
  133. result = DeleteBranchService.new(user_project, current_user)
  134. .execute(params[:branch])
  135. if result[:status] != :success
  136. render_api_error!(result[:message], result[:return_code])
  137. end
  138. end
  139. end
  140. desc 'Delete all merged branches'
  141. delete ':id/repository/merged_branches' do
  142. DeleteMergedBranchesService.new(user_project, current_user).async_execute
  143. accepted!
  144. end
  145. end
  146. end
  147. end