gitlab 4.19.0 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +0 -267
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/lib/gitlab/cli_helpers.rb +1 -1
- data/lib/gitlab/client/groups.rb +149 -0
- data/lib/gitlab/client/issues.rb +11 -0
- data/lib/gitlab/client/merge_requests.rb +28 -2
- data/lib/gitlab/client/merge_trains.rb +55 -0
- data/lib/gitlab/client/pipeline_schedules.rb +12 -0
- data/lib/gitlab/client/pipelines.rb +25 -0
- data/lib/gitlab/client/project_exports.rb +54 -0
- data/lib/gitlab/client/project_releases.rb +11 -0
- data/lib/gitlab/client/projects.rb +81 -1
- data/lib/gitlab/client/runners.rb +67 -0
- data/lib/gitlab/client/users.rb +125 -1
- data/lib/gitlab/client.rb +10 -1
- data/lib/gitlab/configuration.rb +2 -1
- data/lib/gitlab/headers/page_links.rb +37 -0
- data/lib/gitlab/headers/total.rb +29 -0
- data/lib/gitlab/paginated_response.rb +6 -1
- data/lib/gitlab/request.rb +13 -4
- data/lib/gitlab/version.rb +1 -1
- data/lib/gitlab.rb +5 -2
- metadata +22 -5
- data/lib/gitlab/page_links.rb +0 -35
@@ -43,6 +43,18 @@ class Gitlab::Client
|
|
43
43
|
get("/projects/#{url_encode project}/pipelines/#{id}/test_report")
|
44
44
|
end
|
45
45
|
|
46
|
+
# Gets a single pipeline's variables.
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
# Gitlab.pipeline_variables(5, 36)
|
50
|
+
#
|
51
|
+
# @param [Integer, String] project The ID or name of a project.
|
52
|
+
# @param [Integer] id The ID of a pipeline.
|
53
|
+
# @return [Array<Gitlab::ObjectifiedHash>]
|
54
|
+
def pipeline_variables(project, id)
|
55
|
+
get("/projects/#{url_encode project}/pipelines/#{id}/variables")
|
56
|
+
end
|
57
|
+
|
46
58
|
# Create a pipeline.
|
47
59
|
#
|
48
60
|
# @example
|
@@ -101,5 +113,18 @@ class Gitlab::Client
|
|
101
113
|
def delete_pipeline(project, id)
|
102
114
|
delete("/projects/#{url_encode project}/pipelines/#{id}")
|
103
115
|
end
|
116
|
+
|
117
|
+
# Update a pipeline metadata
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
# Gitlab.update_pipeline_metadata(5, 1, name: 'new name')
|
121
|
+
#
|
122
|
+
# @param [Integer, String] project The ID or name of a project.
|
123
|
+
# @param [Integer] id The ID of a pipeline.
|
124
|
+
# @option options [String] :name The new name of the pipeline.
|
125
|
+
# @return [Gitlab::ObjectifiedHash]
|
126
|
+
def update_pipeline_metadata(project, id, options = {})
|
127
|
+
put("/projects/#{url_encode project}/pipelines/#{id}/metadata", body: options)
|
128
|
+
end
|
104
129
|
end
|
105
130
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Gitlab::Client
|
4
|
+
# Defines methods related to project exports.
|
5
|
+
# @see https://docs.gitlab.com/ce/api/project_import_export.html
|
6
|
+
module ProjectExports
|
7
|
+
# Start a new export
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# Gitlab.export_project(2)
|
11
|
+
#
|
12
|
+
# @param [Integer, String] id The ID or path of a project.
|
13
|
+
# @param [Hash] options A customizable set of options.
|
14
|
+
# @option options [String] description(optional) Overrides the project description
|
15
|
+
# @option options [hash] upload(optional) Hash that contains the information to upload the exported project to a web server
|
16
|
+
# @option options [String] upload[url] TThe URL to upload the project
|
17
|
+
# @option options [String] upload[http_method](optional) The HTTP method to upload the exported project. Only PUT and POST methods allowed. Default is PUT
|
18
|
+
# @return [Gitlab::ObjectifiedHash]
|
19
|
+
def export_project(id, options = {})
|
20
|
+
post("/projects/#{url_encode id}/export", body: options)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get the status of export
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# Gitlab.export_project_status(2)
|
27
|
+
#
|
28
|
+
# @param [Integer, String] id The ID or path of a project.
|
29
|
+
# @return [Gitlab::ObjectifiedHash]
|
30
|
+
def export_project_status(id)
|
31
|
+
get("/projects/#{url_encode id}/export")
|
32
|
+
end
|
33
|
+
|
34
|
+
# Download the finished export
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# Gitlab.exported_project_download(2)
|
38
|
+
#
|
39
|
+
# @param [Integer, String] id The ID or path of a project.
|
40
|
+
# @return [Gitlab::FileResponse]
|
41
|
+
def exported_project_download(id)
|
42
|
+
get("/projects/#{url_encode id}/export/download",
|
43
|
+
format: nil,
|
44
|
+
headers: { Accept: 'application/octet-stream' },
|
45
|
+
parser: proc { |body, _|
|
46
|
+
if body.encoding == Encoding::ASCII_8BIT # binary response
|
47
|
+
::Gitlab::FileResponse.new StringIO.new(body, 'rb+')
|
48
|
+
else # error with json response
|
49
|
+
::Gitlab::Request.parse(body)
|
50
|
+
end
|
51
|
+
})
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -75,5 +75,16 @@ class Gitlab::Client
|
|
75
75
|
def delete_project_release(project, tag_name)
|
76
76
|
delete("/projects/#{url_encode project}/releases/#{tag_name}")
|
77
77
|
end
|
78
|
+
|
79
|
+
# Gets Latest Release
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# Gitlab.project_latest_release(5)
|
83
|
+
#
|
84
|
+
# @param [Integer, String] project The ID or name of a project
|
85
|
+
# @return [Gitlab::ObjectifiedHash] Information about the release
|
86
|
+
def project_latest_release(project)
|
87
|
+
get("/projects/#{url_encode project}/releases/permalink/latest")
|
88
|
+
end
|
78
89
|
end
|
79
90
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
class Gitlab::Client
|
4
4
|
# Defines methods related to projects.
|
5
5
|
# @see https://docs.gitlab.com/ce/api/projects.html
|
6
|
-
module Projects
|
6
|
+
module Projects # rubocop:disable Metrics/ModuleLength
|
7
7
|
# Gets a list of projects owned by the authenticated user.
|
8
8
|
#
|
9
9
|
# @example
|
@@ -704,5 +704,85 @@ class Gitlab::Client
|
|
704
704
|
def project_deploy_tokens(project, options = {})
|
705
705
|
get("/projects/#{url_encode project}/deploy_tokens", query: options)
|
706
706
|
end
|
707
|
+
|
708
|
+
# Get languages used with percentage value
|
709
|
+
#
|
710
|
+
# @example
|
711
|
+
# Gitlab.project_languages(42)
|
712
|
+
#
|
713
|
+
# @param [Integer, String] id The ID or path of a project.
|
714
|
+
# @return [Gitlab::ObjectifiedHash]
|
715
|
+
def project_languages(project)
|
716
|
+
get("/projects/#{url_encode project}/languages")
|
717
|
+
end
|
718
|
+
|
719
|
+
# List all project access tokens.
|
720
|
+
#
|
721
|
+
# @example
|
722
|
+
# Gitlab.project_access_tokens(42)
|
723
|
+
#
|
724
|
+
# @param [Integer, String] project The ID or path of a project.
|
725
|
+
# @option options [String] :state Limit by active/inactive state. Optional.
|
726
|
+
#
|
727
|
+
# @return [Array<Gitlab::ObjectifiedHash>]
|
728
|
+
def project_access_tokens(project, options = {})
|
729
|
+
get("/projects/#{url_encode project}/access_tokens", query: options)
|
730
|
+
end
|
731
|
+
|
732
|
+
# Get a specific project access token.
|
733
|
+
#
|
734
|
+
# @example
|
735
|
+
# Gitlab.project_access_token(42, 1234)
|
736
|
+
#
|
737
|
+
# @param [Integer, String] project The ID or path of a project.
|
738
|
+
# @param [Integer] token_id The ID of the project access token.
|
739
|
+
#
|
740
|
+
# @return [Gitlab::ObjectifiedHash] Information about the specified project access token.
|
741
|
+
def project_access_token(project, token_id)
|
742
|
+
get("/projects/#{url_encode project}/access_tokens/#{token_id}")
|
743
|
+
end
|
744
|
+
|
745
|
+
# Creates a new project access token.
|
746
|
+
#
|
747
|
+
# @example
|
748
|
+
# Gitlab.create_project_access_token(42, 'My Token', ['api'], '2024-12-12', access_level: 40)
|
749
|
+
#
|
750
|
+
# @param [Integer, String] project The ID or path of a project.
|
751
|
+
# @param [String] name The name of the project access token.
|
752
|
+
# @param [Array] scopes List of scopes of the project access token.
|
753
|
+
# @param [String] expires_at A date string in the format YYYY-MM-DD.
|
754
|
+
# @option options [Integer] :access_level Access level. Optional. Defaults to 40.
|
755
|
+
#
|
756
|
+
# @return [Gitlab::ObjectifiedHash] Information about the created project access token.
|
757
|
+
def create_project_access_token(project, name, scopes, expires_at, options = {})
|
758
|
+
post("/projects/#{url_encode project}/access_tokens", body: { name: name, scopes: scopes, expires_at: expires_at }.merge(options))
|
759
|
+
end
|
760
|
+
|
761
|
+
# Rotate a project access token.
|
762
|
+
#
|
763
|
+
# @example
|
764
|
+
# Gitlab.rotate_project_access_token(42, 1234)
|
765
|
+
#
|
766
|
+
# @param [Integer, String] project The ID or path of a project.
|
767
|
+
# @param [Integer] token_id The ID of the project access token.
|
768
|
+
# @option options [String] :expires_at A date string in the format YEAR-MONTH-DAY.
|
769
|
+
#
|
770
|
+
# @return [Gitlab::ObjectifiedHash] Information about the specified project access token.
|
771
|
+
def rotate_project_access_token(project, token_id, options = {})
|
772
|
+
post("/projects/#{url_encode project}/access_tokens/#{token_id}/rotate", query: options)
|
773
|
+
end
|
774
|
+
|
775
|
+
# Revoke a project access token.
|
776
|
+
#
|
777
|
+
# @example
|
778
|
+
# Gitlab.revoke_project_access_token(42, 1234)
|
779
|
+
#
|
780
|
+
# @param [Integer, String] project The ID or path of a project.
|
781
|
+
# @param [Integer] token_id The ID of the project access token.
|
782
|
+
#
|
783
|
+
# @return [Gitlab::ObjectifiedHash]
|
784
|
+
def revoke_project_access_token(project, token_id)
|
785
|
+
delete("/projects/#{url_encode project}/access_tokens/#{token_id}")
|
786
|
+
end
|
707
787
|
end
|
708
788
|
end
|
@@ -207,5 +207,72 @@ class Gitlab::Client
|
|
207
207
|
body = { token: token }
|
208
208
|
post('/runners/verify', body: body)
|
209
209
|
end
|
210
|
+
|
211
|
+
# Creates a new group runner with the new Gitlab approach (v16.0+) and returns the id/token information
|
212
|
+
# https://docs.gitlab.com/ee/api/users.html#create-a-runner
|
213
|
+
# You must use an access token with the create_runner scope
|
214
|
+
#
|
215
|
+
# @example
|
216
|
+
# Gitlab.create_group_runner(9, tag_list: ['one', 'two'])
|
217
|
+
# Gitlab.create_group_runner(9, paused: false, description: 'A note', run_untagged: true)
|
218
|
+
#
|
219
|
+
# @param [String] group(required) Group ID.
|
220
|
+
# @param [Hash] options A customizable set of options.
|
221
|
+
# @return <Gitlab::ObjectifiedHash> Response against runner registration
|
222
|
+
def create_group_runner(group, options = {})
|
223
|
+
create_runner({ runner_type: 'group_type', group_id: group }.merge(options))
|
224
|
+
end
|
225
|
+
|
226
|
+
# Creates a new project runner with the new Gitlab approach (v16.0+) and returns the id/token information
|
227
|
+
# https://docs.gitlab.com/ee/api/users.html#create-a-runner
|
228
|
+
# You must use an access token with the create_runner scope
|
229
|
+
#
|
230
|
+
# @example
|
231
|
+
# Gitlab.create_project_runner(12, tag_list: ['one', 'two'])
|
232
|
+
# Gitlab.create_project_runner(12, paused: false, description: 'A note', run_untagged: true)
|
233
|
+
#
|
234
|
+
# @param [String] project(required) Project ID.
|
235
|
+
# @param [Hash] options A customizable set of options.
|
236
|
+
# @return <Gitlab::ObjectifiedHash> Response against runner registration
|
237
|
+
def create_project_runner(project, options = {})
|
238
|
+
create_runner({ runner_type: 'project_type', project_id: project }.merge(options))
|
239
|
+
end
|
240
|
+
|
241
|
+
# Creates a new instance runner with the new Gitlab approach (v16.0+) and returns the id/token information
|
242
|
+
# You must be an administrator of the GitLab instance
|
243
|
+
# You must use an access token with the create_runner scope
|
244
|
+
# https://docs.gitlab.com/ee/api/users.html#create-a-runner
|
245
|
+
#
|
246
|
+
# @example
|
247
|
+
# Gitlab.create_instance_runner(tag_list: ['one', 'two'])
|
248
|
+
# Gitlab.create_instance_runner(paused: false, description: 'A note', run_untagged: true)
|
249
|
+
#
|
250
|
+
# @param [String] group(required) Project ID.
|
251
|
+
# @param [Hash] options A customizable set of options.
|
252
|
+
# @return <Gitlab::ObjectifiedHash> Response against runner registration
|
253
|
+
def create_instance_runner(options = {})
|
254
|
+
create_runner({ runner_type: 'instance_type' }.merge(options))
|
255
|
+
end
|
256
|
+
|
257
|
+
private
|
258
|
+
|
259
|
+
# Creates a runner linked to the current user.
|
260
|
+
# You must use an access token with the create_runner scope
|
261
|
+
# https://docs.gitlab.com/ee/api/users.html#create-a-runner
|
262
|
+
#
|
263
|
+
# @param [Hash] options(required) A customizable set of options.
|
264
|
+
# @option options [String] :description(optional) Runner description.
|
265
|
+
# @option options [Hash] :info(optional) Runner metadata.
|
266
|
+
# @option options [Boolean] :paused(optional) Whether the Runner ignores new jobs.
|
267
|
+
# @option options [Boolean] :locked(optional) Whether the Runner should be locked for current project.
|
268
|
+
# @option options [Boolean] :run_untagged(optional) Whether the Runner should handle untagged jobs.
|
269
|
+
# @option options [Array<String>] :tag_list(optional) List of Runner tags.
|
270
|
+
# @option options [String] :access_level(optional) Access level of the runner; not_protected or ref_protected.
|
271
|
+
# @option options [Integer] :maximum_timeout(optional) Maximum timeout set when this Runner will handle the job.
|
272
|
+
# @option options [String] :maintenance_note(optional) Free-form maintenance notes for the runner (1024 characters).
|
273
|
+
# @return <Gitlab::ObjectifiedHash> Response against runner registration {"id": 1, "token": foo "token_expires_at": null}
|
274
|
+
def create_runner(options)
|
275
|
+
post('/user/runners', body: options)
|
276
|
+
end
|
210
277
|
end
|
211
278
|
end
|
data/lib/gitlab/client/users.rb
CHANGED
@@ -58,6 +58,22 @@ class Gitlab::Client
|
|
58
58
|
post('/users', body: body)
|
59
59
|
end
|
60
60
|
|
61
|
+
# Creates a service account.
|
62
|
+
# Requires authentication from an admin account.
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
# Gitlab.create_service_account('service_account_6018816a18e515214e0c34c2b33523fc', 'Service account user')
|
66
|
+
#
|
67
|
+
# @param [String] name (required) The email of the service account.
|
68
|
+
# @param [String] username (required) The username of the service account.
|
69
|
+
# @return [Gitlab::ObjectifiedHash] Information about created service account.
|
70
|
+
def create_service_account(*args)
|
71
|
+
raise ArgumentError, 'Missing required parameters' unless args[1]
|
72
|
+
|
73
|
+
body = { name: args[0], username: args[1] }
|
74
|
+
post('/service_accounts', body: body)
|
75
|
+
end
|
76
|
+
|
61
77
|
# Updates a user.
|
62
78
|
#
|
63
79
|
# @example
|
@@ -110,6 +126,28 @@ class Gitlab::Client
|
|
110
126
|
post("/users/#{user_id}/unblock")
|
111
127
|
end
|
112
128
|
|
129
|
+
# Deactivates the specified user. Available only for admin.
|
130
|
+
#
|
131
|
+
# @example
|
132
|
+
# Gitlab.deactivate_user(15)
|
133
|
+
#
|
134
|
+
# @param [Integer] user_id The Id of user
|
135
|
+
# @return [Boolean] success or not
|
136
|
+
def deactivate_user(user_id)
|
137
|
+
post("/users/#{user_id}/deactivate")
|
138
|
+
end
|
139
|
+
|
140
|
+
# Activate the specified user. Available only for admin.
|
141
|
+
#
|
142
|
+
# @example
|
143
|
+
# Gitlab.activate_user(15)
|
144
|
+
#
|
145
|
+
# @param [Integer] user_id The Id of user
|
146
|
+
# @return [Boolean] success or not
|
147
|
+
def activate_user(user_id)
|
148
|
+
post("/users/#{user_id}/activate")
|
149
|
+
end
|
150
|
+
|
113
151
|
# Approves the specified user. Available only for admin.
|
114
152
|
#
|
115
153
|
# @example
|
@@ -276,7 +314,7 @@ class Gitlab::Client
|
|
276
314
|
delete(url)
|
277
315
|
end
|
278
316
|
|
279
|
-
# Search for
|
317
|
+
# Search for users by name
|
280
318
|
#
|
281
319
|
# @example
|
282
320
|
# Gitlab.user_search('gitlab')
|
@@ -291,6 +329,19 @@ class Gitlab::Client
|
|
291
329
|
get('/users', query: options)
|
292
330
|
end
|
293
331
|
|
332
|
+
# Get user by username
|
333
|
+
#
|
334
|
+
# @example
|
335
|
+
# Gitlab.user_by_username('gitlab')
|
336
|
+
#
|
337
|
+
# @param [String] username A username to get.
|
338
|
+
# @param [Hash] options A customizable set of options.
|
339
|
+
# @return [Array<Gitlab::ObjectifiedHash>]
|
340
|
+
def user_by_username(username, options = {})
|
341
|
+
options[:username] = username
|
342
|
+
get('/users', query: options)
|
343
|
+
end
|
344
|
+
|
294
345
|
# Gets user custom_attributes.
|
295
346
|
#
|
296
347
|
# @example
|
@@ -382,6 +433,47 @@ class Gitlab::Client
|
|
382
433
|
post("/users/#{user_id}/impersonation_tokens", body: body)
|
383
434
|
end
|
384
435
|
|
436
|
+
# Get all personal access tokens for a user
|
437
|
+
#
|
438
|
+
# @example
|
439
|
+
# Gitlab.user_personal_access_tokens(1)
|
440
|
+
#
|
441
|
+
# @param [Integer] user_id The ID of the user.
|
442
|
+
# @return [Array<Gitlab::ObjectifiedHash>]
|
443
|
+
def user_personal_access_tokens(user_id)
|
444
|
+
get("/personal_access_tokens?user_id=#{user_id}")
|
445
|
+
end
|
446
|
+
|
447
|
+
# Create personal access token
|
448
|
+
#
|
449
|
+
# @example
|
450
|
+
# Gitlab.create_personal_access_token(2, "token", ["api", "read_user"])
|
451
|
+
# Gitlab.create_personal_access_token(2, "token", ["api", "read_user"], "1970-01-01")
|
452
|
+
#
|
453
|
+
# @param [Integer] user_id The ID of the user.
|
454
|
+
# @param [String] name Name of the personal access token.
|
455
|
+
# @param [Array<String>] scopes Array of scopes for the impersonation token
|
456
|
+
# @param [String] expires_at Date for impersonation token expiration in ISO format.
|
457
|
+
# @return [Gitlab::ObjectifiedHash]
|
458
|
+
def create_personal_access_token(user_id, name, scopes, expires_at = nil)
|
459
|
+
body = { name: name, scopes: scopes }
|
460
|
+
body[:expires_at] = expires_at if expires_at
|
461
|
+
post("/users/#{user_id}/personal_access_tokens", body: body)
|
462
|
+
end
|
463
|
+
|
464
|
+
# Rotate a personal access token
|
465
|
+
#
|
466
|
+
# @example
|
467
|
+
# Gitlab.rotate_personal_access_token(1)
|
468
|
+
#
|
469
|
+
# @param [Integer] personal_access_token_id ID of the personal access token.
|
470
|
+
# @return [Gitlab::ObjectifiedHash]
|
471
|
+
def rotate_personal_access_token(personal_access_token_id, expires_at = nil)
|
472
|
+
body = {}
|
473
|
+
body[:expires_at] = expires_at if expires_at
|
474
|
+
post("/personal_access_tokens/#{personal_access_token_id}/rotate", body: body)
|
475
|
+
end
|
476
|
+
|
385
477
|
# Revoke an impersonation token
|
386
478
|
#
|
387
479
|
# @example
|
@@ -393,5 +485,37 @@ class Gitlab::Client
|
|
393
485
|
def revoke_user_impersonation_token(user_id, impersonation_token_id)
|
394
486
|
delete("/users/#{user_id}/impersonation_tokens/#{impersonation_token_id}")
|
395
487
|
end
|
488
|
+
|
489
|
+
# Lists all projects and groups a user is a member of
|
490
|
+
#
|
491
|
+
# @example
|
492
|
+
# Gitlab.memberships(2)
|
493
|
+
#
|
494
|
+
# @param [Integer] user_id The ID of the user.
|
495
|
+
def memberships(user_id)
|
496
|
+
get("/users/#{user_id}/memberships")
|
497
|
+
end
|
498
|
+
|
499
|
+
# Revoke a personal access token
|
500
|
+
#
|
501
|
+
# @example
|
502
|
+
# Gitlab.revoke_personal_access_token(1)
|
503
|
+
#
|
504
|
+
# @param [Integer] personal_access_token_id ID of the personal access token.
|
505
|
+
# @return [Gitlab::ObjectifiedHash]
|
506
|
+
def revoke_personal_access_token(personal_access_token_id)
|
507
|
+
delete("/personal_access_tokens/#{personal_access_token_id}")
|
508
|
+
end
|
509
|
+
|
510
|
+
# Disables two factor authentication (2FA) for the specified user.
|
511
|
+
#
|
512
|
+
# @example
|
513
|
+
# Gitlab.disable_two_factor(1)
|
514
|
+
#
|
515
|
+
# @param [Integer] id The ID of a user.
|
516
|
+
# @return [Gitlab::ObjectifiedHash]
|
517
|
+
def disable_two_factor(user_id)
|
518
|
+
patch("/users/#{user_id}/disable_two_factor")
|
519
|
+
end
|
396
520
|
end
|
397
521
|
end
|
data/lib/gitlab/client.rb
CHANGED
@@ -37,6 +37,7 @@ module Gitlab
|
|
37
37
|
include Markdown
|
38
38
|
include MergeRequestApprovals
|
39
39
|
include MergeRequests
|
40
|
+
include MergeTrains
|
40
41
|
include Milestones
|
41
42
|
include Namespaces
|
42
43
|
include Notes
|
@@ -46,6 +47,7 @@ module Gitlab
|
|
46
47
|
include Pipelines
|
47
48
|
include ProjectBadges
|
48
49
|
include ProjectClusters
|
50
|
+
include ProjectExports
|
49
51
|
include ProjectReleaseLinks
|
50
52
|
include ProjectReleases
|
51
53
|
include Projects
|
@@ -75,7 +77,7 @@ module Gitlab
|
|
75
77
|
# @return [String]
|
76
78
|
def inspect
|
77
79
|
inspected = super
|
78
|
-
inspected
|
80
|
+
inspected = redact_private_token(inspected, @private_token) if @private_token
|
79
81
|
inspected
|
80
82
|
end
|
81
83
|
|
@@ -89,7 +91,14 @@ module Gitlab
|
|
89
91
|
|
90
92
|
private
|
91
93
|
|
94
|
+
def redact_private_token(inspected, private_token)
|
95
|
+
redacted = only_show_last_four_chars(private_token)
|
96
|
+
inspected.sub %(@private_token="#{private_token}"), %(@private_token="#{redacted}")
|
97
|
+
end
|
98
|
+
|
92
99
|
def only_show_last_four_chars(token)
|
100
|
+
return '****' if token.size <= 4
|
101
|
+
|
93
102
|
"#{'*' * (token.size - 4)}#{token[-4..]}"
|
94
103
|
end
|
95
104
|
end
|
data/lib/gitlab/configuration.rb
CHANGED
@@ -5,7 +5,7 @@ module Gitlab
|
|
5
5
|
# Defines constants and methods related to configuration.
|
6
6
|
module Configuration
|
7
7
|
# An array of valid keys in the options hash when configuring a Gitlab::API.
|
8
|
-
VALID_OPTIONS_KEYS = %i[endpoint private_token user_agent sudo httparty].freeze
|
8
|
+
VALID_OPTIONS_KEYS = %i[endpoint private_token user_agent sudo httparty pat_prefix].freeze
|
9
9
|
|
10
10
|
# The user agent that will be sent to the API endpoint if none is set.
|
11
11
|
DEFAULT_USER_AGENT = "Gitlab Ruby Gem #{Gitlab::VERSION}"
|
@@ -37,6 +37,7 @@ module Gitlab
|
|
37
37
|
def reset
|
38
38
|
self.endpoint = ENV['GITLAB_API_ENDPOINT'] || ENV['CI_API_V4_URL']
|
39
39
|
self.private_token = ENV['GITLAB_API_PRIVATE_TOKEN'] || ENV['GITLAB_API_AUTH_TOKEN']
|
40
|
+
self.pat_prefix = nil
|
40
41
|
self.httparty = get_httparty_config(ENV['GITLAB_API_HTTPARTY_OPTIONS'])
|
41
42
|
self.sudo = nil
|
42
43
|
self.user_agent = DEFAULT_USER_AGENT
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module Headers
|
5
|
+
# Parses link header.
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class PageLinks
|
9
|
+
HEADER_LINK = 'Link'
|
10
|
+
DELIM_LINKS = ','
|
11
|
+
LINK_REGEX = /<([^>]+)>; rel="([^"]+)"/
|
12
|
+
METAS = %w[last next first prev].freeze
|
13
|
+
|
14
|
+
attr_accessor(*METAS)
|
15
|
+
|
16
|
+
def initialize(headers)
|
17
|
+
link_header = headers[HEADER_LINK]
|
18
|
+
|
19
|
+
extract_links(link_header) if link_header && link_header =~ /(next|first|last|prev)/
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def extract_links(header)
|
25
|
+
header.split(DELIM_LINKS).each do |link|
|
26
|
+
LINK_REGEX.match(link.strip) do |match|
|
27
|
+
url = match[1]
|
28
|
+
meta = match[2]
|
29
|
+
next if !url || !meta || METAS.index(meta).nil?
|
30
|
+
|
31
|
+
send("#{meta}=", url)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module Headers
|
5
|
+
# Parses total header.
|
6
|
+
#
|
7
|
+
# @private
|
8
|
+
class Total
|
9
|
+
HEADER_TOTAL = 'x-total'
|
10
|
+
TOTAL_REGEX = /^\d+$/
|
11
|
+
|
12
|
+
attr_accessor :total
|
13
|
+
|
14
|
+
def initialize(headers)
|
15
|
+
header_total = headers[HEADER_TOTAL]
|
16
|
+
|
17
|
+
extract_total(header_total) if header_total
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def extract_total(header_total)
|
23
|
+
TOTAL_REGEX.match(header_total.strip) do |match|
|
24
|
+
@total = match[0]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -30,7 +30,8 @@ module Gitlab
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def parse_headers!(headers)
|
33
|
-
@links = PageLinks.new headers
|
33
|
+
@links = Headers::PageLinks.new headers
|
34
|
+
@total = Headers::Total.new headers
|
34
35
|
end
|
35
36
|
|
36
37
|
def each_page
|
@@ -58,6 +59,10 @@ module Gitlab
|
|
58
59
|
lazy_paginate.take(limit).each(&block)
|
59
60
|
end
|
60
61
|
|
62
|
+
def total
|
63
|
+
@total.total
|
64
|
+
end
|
65
|
+
|
61
66
|
def last_page?
|
62
67
|
!(@links.nil? || @links.last.nil?)
|
63
68
|
end
|
data/lib/gitlab/request.rb
CHANGED
@@ -12,7 +12,7 @@ module Gitlab
|
|
12
12
|
headers 'Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded'
|
13
13
|
parser(proc { |body, _| parse(body) })
|
14
14
|
|
15
|
-
attr_accessor :private_token, :endpoint
|
15
|
+
attr_accessor :private_token, :endpoint, :pat_prefix
|
16
16
|
|
17
17
|
# Converts the response body to an ObjectifiedHash.
|
18
18
|
def self.parse(body)
|
@@ -38,7 +38,7 @@ module Gitlab
|
|
38
38
|
raise Error::Parsing, 'The response is not a valid JSON'
|
39
39
|
end
|
40
40
|
|
41
|
-
%w[get post put delete].each do |method|
|
41
|
+
%w[get post put patch delete].each do |method|
|
42
42
|
define_method method do |path, options = {}|
|
43
43
|
params = options.dup
|
44
44
|
|
@@ -93,10 +93,19 @@ module Gitlab
|
|
93
93
|
def authorization_header
|
94
94
|
raise Error::MissingCredentials, 'Please provide a private_token or auth_token for user' unless private_token
|
95
95
|
|
96
|
-
|
96
|
+
# The Personal Access Token prefix can be at most 20 characters, and the
|
97
|
+
# generated part is of length 20 characters. Personal Access Tokens, thus
|
98
|
+
# can have a maximum size of 40 characters. GitLab uses
|
99
|
+
# `Doorkeeper::OAuth::Helpers::UniqueToken.generate` for generating
|
100
|
+
# OAuth2 tokens, and specified `hex` as token generator method. Thus, the
|
101
|
+
# OAuth2 tokens are of length more than 64. If the token length is below
|
102
|
+
# that, it is probably a Personal Access Token or CI_JOB_TOKEN.
|
103
|
+
if private_token.size >= 64
|
104
|
+
{ 'Authorization' => "Bearer #{private_token}" }
|
105
|
+
elsif private_token.start_with?(pat_prefix.to_s)
|
97
106
|
{ 'PRIVATE-TOKEN' => private_token }
|
98
107
|
else
|
99
|
-
{ '
|
108
|
+
{ 'JOB-TOKEN' => private_token }
|
100
109
|
end
|
101
110
|
end
|
102
111
|
|
data/lib/gitlab/version.rb
CHANGED
data/lib/gitlab.rb
CHANGED
@@ -4,7 +4,8 @@ require 'gitlab/version'
|
|
4
4
|
require 'gitlab/objectified_hash'
|
5
5
|
require 'gitlab/configuration'
|
6
6
|
require 'gitlab/error'
|
7
|
-
require 'gitlab/page_links'
|
7
|
+
require 'gitlab/headers/page_links'
|
8
|
+
require 'gitlab/headers/total'
|
8
9
|
require 'gitlab/paginated_response'
|
9
10
|
require 'gitlab/file_response'
|
10
11
|
require 'gitlab/request'
|
@@ -49,8 +50,10 @@ module Gitlab
|
|
49
50
|
#
|
50
51
|
# @return [Array<Symbol>]
|
51
52
|
def self.actions
|
53
|
+
# rubocop:disable Layout/LineLength
|
52
54
|
hidden =
|
53
|
-
/endpoint|private_token|auth_token|user_agent|sudo|get|post|put|\Adelete\z|validate\z|request_defaults|httparty/
|
55
|
+
/endpoint|private_token|auth_token|user_agent|sudo|get|post|put|patch|\Adelete\z|validate\z|request_defaults|httparty/
|
56
|
+
# rubocop:enable Layout/LineLength
|
54
57
|
(Gitlab::Client.instance_methods - Object.methods).reject { |e| e[hidden] }
|
55
58
|
end
|
56
59
|
end
|