1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
# frozen_string_literal: true
require 'mime/types'
module API
class Branches < ::API::Base
include PaginationParams
BRANCH_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(branch: API::NO_SLASH_URL_PART_REGEX)
after_validation { content_type "application/json" }
feature_category :source_code_management
before do
require_repository_enabled!
authorize! :download_code, user_project
end
rescue_from Gitlab::Git::Repository::NoRepository do
not_found!
end
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', values: %w[name_asc updated_asc updated_desc]
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
optional :page_token, type: String, desc: 'Name of branch to start the paginaition from'
end
get ':id/repository/branches', urgency: :low do
cache_action([user_project, :branches, current_user, declared_params], expires_in: 30.seconds) do
user_project.preload_protected_branches
repository = user_project.repository
branches_finder = BranchesFinder.new(repository, declared_params(include_missing: false))
branches = Gitlab::Pagination::GitalyKeysetPager.new(self, user_project).paginate(branches_finder)
merged_branch_names = repository.merged_branch_names(branches.map(&:name))
if Feature.enabled?(:api_caching_branches, user_project, type: :development, default_enabled: :yaml)
present_cached(
branches,
with: Entities::Branch,
current_user: current_user,
project: user_project,
merged_branch_names: merged_branch_names,
expires_in: 10.minutes,
cache_context: -> (branch) { [current_user&.cache_key, merged_branch_names.include?(branch.name)] }
)
else
present(
branches,
with: Entities::Branch,
current_user: current_user,
project: user_project,
merged_branch_names: merged_branch_names
)
end
end
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]) ? no_content! : not_found!
end
get '/', urgency: :low 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 = ::Branches::CreateService.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 = ::Branches::DeleteService.new(user_project, current_user)
.execute(params[:branch])
if result.error?
render_api_error!(result.message, result.http_status)
end
end
end
desc 'Delete all merged branches'
delete ':id/repository/merged_branches' do
::Branches::DeleteMergedService.new(user_project, current_user).async_execute
accepted!
end
end
end
end
|