octokit 4.2.0 → 9.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. checksums.yaml +5 -5
  2. data/CONTRIBUTING.md +14 -13
  3. data/LICENSE.md +1 -1
  4. data/README.md +275 -127
  5. data/Rakefile +20 -14
  6. data/lib/ext/sawyer/relation.rb +12 -0
  7. data/lib/octokit/arguments.rb +3 -3
  8. data/lib/octokit/authentication.rb +20 -14
  9. data/lib/octokit/client/actions_artifacts.rb +71 -0
  10. data/lib/octokit/client/actions_secrets.rb +161 -0
  11. data/lib/octokit/client/actions_workflow_jobs.rb +65 -0
  12. data/lib/octokit/client/actions_workflow_runs.rb +125 -0
  13. data/lib/octokit/client/actions_workflows.rb +68 -0
  14. data/lib/octokit/client/apps.rb +259 -0
  15. data/lib/octokit/client/checks.rb +200 -0
  16. data/lib/octokit/client/code_scanning.rb +190 -0
  17. data/lib/octokit/client/codespaces_secrets.rb +108 -0
  18. data/lib/octokit/client/commit_branches.rb +20 -0
  19. data/lib/octokit/client/commit_comments.rb +8 -8
  20. data/lib/octokit/client/commit_pulls.rb +20 -0
  21. data/lib/octokit/client/commits.rb +32 -35
  22. data/lib/octokit/client/community_profile.rb +21 -0
  23. data/lib/octokit/client/contents.rb +24 -21
  24. data/lib/octokit/client/dependabot_secrets.rb +108 -0
  25. data/lib/octokit/client/deployments.rb +29 -7
  26. data/lib/octokit/client/downloads.rb +5 -6
  27. data/lib/octokit/client/emojis.rb +3 -3
  28. data/lib/octokit/client/environments.rb +58 -0
  29. data/lib/octokit/client/events.rb +4 -4
  30. data/lib/octokit/client/feeds.rb +4 -5
  31. data/lib/octokit/client/gists.rb +36 -8
  32. data/lib/octokit/client/gitignore.rb +3 -3
  33. data/lib/octokit/client/hooks.rb +34 -30
  34. data/lib/octokit/client/issues.rb +97 -14
  35. data/lib/octokit/client/labels.rb +17 -17
  36. data/lib/octokit/client/legacy_search.rb +3 -3
  37. data/lib/octokit/client/licenses.rb +5 -8
  38. data/lib/octokit/client/markdown.rb +3 -3
  39. data/lib/octokit/client/marketplace.rb +56 -0
  40. data/lib/octokit/client/meta.rb +4 -5
  41. data/lib/octokit/client/milestones.rb +14 -14
  42. data/lib/octokit/client/notifications.rb +7 -11
  43. data/lib/octokit/client/oauth_applications.rb +116 -0
  44. data/lib/octokit/client/objects.rb +14 -14
  45. data/lib/octokit/client/organizations.rb +256 -73
  46. data/lib/octokit/client/pages.rb +26 -3
  47. data/lib/octokit/client/projects.rb +294 -0
  48. data/lib/octokit/client/pull_requests.rb +74 -51
  49. data/lib/octokit/client/rate_limit.rb +11 -13
  50. data/lib/octokit/client/reactions.rb +204 -0
  51. data/lib/octokit/client/refs.rb +34 -20
  52. data/lib/octokit/client/releases.rb +16 -13
  53. data/lib/octokit/client/repositories.rb +276 -60
  54. data/lib/octokit/client/repository_invitations.rb +96 -0
  55. data/lib/octokit/client/reviews.rb +227 -0
  56. data/lib/octokit/client/say.rb +4 -5
  57. data/lib/octokit/client/search.rb +46 -17
  58. data/lib/octokit/client/service_status.rb +19 -9
  59. data/lib/octokit/client/source_import.rb +156 -0
  60. data/lib/octokit/client/stats.rb +39 -17
  61. data/lib/octokit/client/statuses.rb +6 -6
  62. data/lib/octokit/client/tokens.rb +31 -0
  63. data/lib/octokit/client/traffic.rb +64 -0
  64. data/lib/octokit/client/users.rb +133 -25
  65. data/lib/octokit/client.rb +85 -19
  66. data/lib/octokit/configurable.rb +60 -32
  67. data/lib/octokit/connection.rb +45 -21
  68. data/lib/octokit/default.rb +82 -35
  69. data/lib/octokit/enterprise_admin_client/admin_stats.rb +14 -15
  70. data/lib/octokit/enterprise_admin_client/license.rb +4 -5
  71. data/lib/octokit/enterprise_admin_client/orgs.rb +7 -6
  72. data/lib/octokit/enterprise_admin_client/search_indexing.rb +8 -9
  73. data/lib/octokit/enterprise_admin_client/users.rb +19 -18
  74. data/lib/octokit/enterprise_admin_client.rb +11 -3
  75. data/lib/octokit/enterprise_management_console_client/management_console.rb +52 -34
  76. data/lib/octokit/enterprise_management_console_client.rb +9 -3
  77. data/lib/octokit/error.rb +144 -26
  78. data/lib/octokit/gist.rb +4 -5
  79. data/lib/octokit/manage_ghes_client/manage_ghes.rb +178 -0
  80. data/lib/octokit/manage_ghes_client.rb +64 -0
  81. data/lib/octokit/middleware/follow_redirects.rb +18 -14
  82. data/lib/octokit/organization.rb +3 -1
  83. data/lib/octokit/rate_limit.rb +11 -9
  84. data/lib/octokit/repo_arguments.rb +3 -4
  85. data/lib/octokit/repository.rb +35 -23
  86. data/lib/octokit/response/base_middleware.rb +10 -0
  87. data/lib/octokit/response/feed_parser.rb +5 -9
  88. data/lib/octokit/response/raise_error.rb +4 -6
  89. data/lib/octokit/user.rb +4 -2
  90. data/lib/octokit/version.rb +3 -1
  91. data/lib/octokit/warnable.rb +4 -5
  92. data/lib/octokit.rb +30 -8
  93. data/octokit.gemspec +12 -10
  94. metadata +47 -24
  95. data/lib/octokit/client/authorizations.rb +0 -256
  96. data/lib/octokit/client/pub_sub_hubbub.rb +0 -111
  97. data/lib/octokit/preview.rb +0 -28
data/lib/octokit/error.rb CHANGED
@@ -1,12 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Octokit
2
4
  # Custom error class for rescuing from all GitHub errors
3
5
  class Error < StandardError
6
+ attr_reader :context
4
7
 
5
8
  # Returns the appropriate Octokit::Error subclass based
6
9
  # on status and response message
7
10
  #
8
11
  # @param [Hash] response HTTP response
9
12
  # @return [Octokit::Error]
13
+ # rubocop:disable Metrics/CyclomaticComplexity
10
14
  def self.from_response(response)
11
15
  status = response[:status].to_i
12
16
  body = response[:body].to_s
@@ -16,12 +20,14 @@ module Octokit
16
20
  when 400 then Octokit::BadRequest
17
21
  when 401 then error_for_401(headers)
18
22
  when 403 then error_for_403(body)
19
- when 404 then Octokit::NotFound
23
+ when 404 then error_for_404(body)
20
24
  when 405 then Octokit::MethodNotAllowed
21
25
  when 406 then Octokit::NotAcceptable
22
26
  when 409 then Octokit::Conflict
27
+ when 410 then Octokit::Deprecated
23
28
  when 415 then Octokit::UnsupportedMediaType
24
- when 422 then Octokit::UnprocessableEntity
29
+ when 422 then error_for_422(body)
30
+ when 451 then Octokit::UnavailableForLegalReasons
25
31
  when 400..499 then Octokit::ClientError
26
32
  when 500 then Octokit::InternalServerError
27
33
  when 501 then Octokit::NotImplemented
@@ -32,10 +38,18 @@ module Octokit
32
38
  klass.new(response)
33
39
  end
34
40
  end
41
+ # rubocop:enable Metrics/CyclomaticComplexity
42
+
43
+ def build_error_context
44
+ if RATE_LIMITED_ERRORS.include?(self.class)
45
+ @context = Octokit::RateLimit.from_response(@response)
46
+ end
47
+ end
35
48
 
36
- def initialize(response=nil)
49
+ def initialize(response = nil)
37
50
  @response = response
38
51
  super(build_error_message)
52
+ build_error_context
39
53
  end
40
54
 
41
55
  # Documentation URL returned by the API for some errors
@@ -47,7 +61,9 @@ module Octokit
47
61
 
48
62
  # Returns most appropriate error for 401 HTTP status code
49
63
  # @private
64
+ # rubocop:disable Naming/VariableNumber
50
65
  def self.error_for_401(headers)
66
+ # rubocop:enbale Naming/VariableNumber
51
67
  if Octokit::OneTimePasswordRequired.required_header(headers)
52
68
  Octokit::OneTimePasswordRequired
53
69
  else
@@ -58,46 +74,103 @@ module Octokit
58
74
  # Returns most appropriate error for 403 HTTP status code
59
75
  # @private
60
76
  def self.error_for_403(body)
61
- if body =~ /rate limit exceeded/i
77
+ # rubocop:enable Naming/VariableNumber
78
+ case body
79
+ when /rate limit exceeded/i, /exceeded a secondary rate limit/i
62
80
  Octokit::TooManyRequests
63
- elsif body =~ /login attempts exceeded/i
81
+ when /login attempts exceeded/i
64
82
  Octokit::TooManyLoginAttempts
65
- elsif body =~ /abuse/i
83
+ when /(returns|for) blobs (up to|between) [0-9-]+ MB/i
84
+ Octokit::TooLargeContent
85
+ when /abuse/i
66
86
  Octokit::AbuseDetected
67
- elsif body =~ /repository access blocked/i
87
+ when /repository access blocked/i
68
88
  Octokit::RepositoryUnavailable
69
- elsif body =~ /email address must be verified/i
89
+ when /email address must be verified/i
70
90
  Octokit::UnverifiedEmail
91
+ when /account was suspended/i
92
+ Octokit::AccountSuspended
93
+ when /billing issue/i
94
+ Octokit::BillingIssue
95
+ when /Resource protected by organization SAML enforcement/i
96
+ Octokit::SAMLProtected
97
+ when /suspended your access|This installation has been suspended/i
98
+ Octokit::InstallationSuspended
71
99
  else
72
100
  Octokit::Forbidden
73
101
  end
74
102
  end
75
103
 
104
+ # Return most appropriate error for 404 HTTP status code
105
+ # @private
106
+ # rubocop:disable Naming/VariableNumber
107
+ def self.error_for_404(body)
108
+ # rubocop:enable Naming/VariableNumber
109
+ if body =~ /Branch not protected/i
110
+ Octokit::BranchNotProtected
111
+ else
112
+ Octokit::NotFound
113
+ end
114
+ end
115
+
116
+ # Return most appropriate error for 422 HTTP status code
117
+ # @private
118
+ # rubocop:disable Naming/VariableNumber
119
+ def self.error_for_422(body)
120
+ # rubocop:enable Naming/VariableNumber
121
+ if body =~ /PullRequestReviewComment/i && body =~ /(commit_id|end_commit_oid) is not part of the pull request/i
122
+ Octokit::CommitIsNotPartOfPullRequest
123
+ elsif body =~ /Path diff too large/i
124
+ Octokit::PathDiffTooLarge
125
+ else
126
+ Octokit::UnprocessableEntity
127
+ end
128
+ end
129
+
76
130
  # Array of validation errors
77
131
  # @return [Array<Hash>] Error info
78
132
  def errors
79
- if data && data.is_a?(Hash)
133
+ if data.is_a?(Hash)
80
134
  data[:errors] || []
81
135
  else
82
136
  []
83
137
  end
84
138
  end
85
139
 
140
+ # Status code returned by the GitHub server.
141
+ #
142
+ # @return [Integer]
143
+ def response_status
144
+ @response[:status]
145
+ end
146
+
147
+ # Headers returned by the GitHub server.
148
+ #
149
+ # @return [Hash]
150
+ def response_headers
151
+ @response[:response_headers]
152
+ end
153
+
154
+ # Body returned by the GitHub server.
155
+ #
156
+ # @return [String]
157
+ def response_body
158
+ @response[:body]
159
+ end
160
+
86
161
  private
87
162
 
88
163
  def data
89
164
  @data ||=
90
165
  if (body = @response[:body]) && !body.empty?
91
166
  if body.is_a?(String) &&
92
- @response[:response_headers] &&
93
- @response[:response_headers][:content_type] =~ /json/
167
+ @response[:response_headers] &&
168
+ @response[:response_headers][:content_type] =~ /json/
94
169
 
95
170
  Sawyer::Agent.serializer.decode(body)
96
171
  else
97
172
  body
98
173
  end
99
- else
100
- nil
101
174
  end
102
175
  end
103
176
 
@@ -117,9 +190,13 @@ module Octokit
117
190
  def response_error_summary
118
191
  return nil unless data.is_a?(Hash) && !Array(data[:errors]).empty?
119
192
 
120
- summary = "\nError summary:\n"
121
- summary << data[:errors].map do |hash|
122
- hash.map { |k,v| " #{k}: #{v}" }
193
+ summary = +"\nError summary:\n"
194
+ summary << data[:errors].map do |error|
195
+ if error.is_a? Hash
196
+ error.map { |k, v| " #{k}: #{v}" }
197
+ else
198
+ " #{error}"
199
+ end
123
200
  end.join("\n")
124
201
 
125
202
  summary
@@ -128,19 +205,21 @@ module Octokit
128
205
  def build_error_message
129
206
  return nil if @response.nil?
130
207
 
131
- message = "#{@response[:method].to_s.upcase} "
132
- message << redact_url(@response[:url].to_s) + ": "
208
+ message = +"#{@response[:method].to_s.upcase} "
209
+ message << "#{redact_url(@response[:url].to_s.dup)}: "
133
210
  message << "#{@response[:status]} - "
134
- message << "#{response_message}" unless response_message.nil?
135
- message << "#{response_error}" unless response_error.nil?
136
- message << "#{response_error_summary}" unless response_error_summary.nil?
211
+ message << response_message.to_s unless response_message.nil?
212
+ message << response_error.to_s unless response_error.nil?
213
+ message << response_error_summary.to_s unless response_error_summary.nil?
137
214
  message << " // See: #{documentation_url}" unless documentation_url.nil?
138
215
  message
139
216
  end
140
217
 
141
218
  def redact_url(url_string)
142
- %w[client_secret access_token].each do |token|
143
- url_string.gsub!(/#{token}=\S+/, "#{token}=(redacted)") if url_string.include? token
219
+ %w[client_secret access_token api_key].each do |token|
220
+ if url_string.include? token
221
+ url_string.gsub!(/#{token}=\S+/, "#{token}=(redacted)")
222
+ end
144
223
  end
145
224
  url_string
146
225
  end
@@ -158,10 +237,10 @@ module Octokit
158
237
  # Raised when GitHub returns a 401 HTTP status code
159
238
  # and headers include "X-GitHub-OTP"
160
239
  class OneTimePasswordRequired < ClientError
161
- #@private
162
- OTP_DELIVERY_PATTERN = /required; (\w+)/i
240
+ # @private
241
+ OTP_DELIVERY_PATTERN = /required; (\w+)/i.freeze
163
242
 
164
- #@private
243
+ # @private
165
244
  def self.required_header(headers)
166
245
  OTP_DELIVERY_PATTERN.match headers['X-GitHub-OTP'].to_s
167
246
  end
@@ -193,6 +272,10 @@ module Octokit
193
272
  # and body matches 'login attempts exceeded'
194
273
  class TooManyLoginAttempts < Forbidden; end
195
274
 
275
+ # Raised when GitHub returns a 403 HTTP status code
276
+ # and body matches 'returns blobs up to [0-9]+ MB'
277
+ class TooLargeContent < Forbidden; end
278
+
196
279
  # Raised when GitHub returns a 403 HTTP status code
197
280
  # and body matches 'abuse'
198
281
  class AbuseDetected < Forbidden; end
@@ -205,9 +288,29 @@ module Octokit
205
288
  # and body matches 'email address must be verified'
206
289
  class UnverifiedEmail < Forbidden; end
207
290
 
291
+ # Raised when GitHub returns a 403 HTTP status code
292
+ # and body matches 'account was suspended'
293
+ class AccountSuspended < Forbidden; end
294
+
295
+ # Raised when GitHub returns a 403 HTTP status code
296
+ # and body matches 'billing issue'
297
+ class BillingIssue < Forbidden; end
298
+
299
+ # Raised when GitHub returns a 403 HTTP status code
300
+ # and body matches 'Resource protected by organization SAML enforcement'
301
+ class SAMLProtected < Forbidden; end
302
+
303
+ # Raised when GitHub returns a 403 HTTP status code
304
+ # and body matches 'suspended your access'
305
+ class InstallationSuspended < Forbidden; end
306
+
208
307
  # Raised when GitHub returns a 404 HTTP status code
209
308
  class NotFound < ClientError; end
210
309
 
310
+ # Raised when GitHub returns a 404 HTTP status code
311
+ # and body matches 'Branch not protected'
312
+ class BranchNotProtected < ClientError; end
313
+
211
314
  # Raised when GitHub returns a 405 HTTP status code
212
315
  class MethodNotAllowed < ClientError; end
213
316
 
@@ -217,12 +320,26 @@ module Octokit
217
320
  # Raised when GitHub returns a 409 HTTP status code
218
321
  class Conflict < ClientError; end
219
322
 
323
+ # Raised when GHES Manage return a 410 HTTP status code
324
+ class Deprecated < ClientError; end
325
+
220
326
  # Raised when GitHub returns a 414 HTTP status code
221
327
  class UnsupportedMediaType < ClientError; end
222
328
 
223
329
  # Raised when GitHub returns a 422 HTTP status code
224
330
  class UnprocessableEntity < ClientError; end
225
331
 
332
+ # Raised when GitHub returns a 422 HTTP status code
333
+ # and body matches 'PullRequestReviewComment' and 'commit_id (or end_commit_oid) is not part of the pull request'
334
+ class CommitIsNotPartOfPullRequest < UnprocessableEntity; end
335
+
336
+ # Raised when GitHub returns a 422 HTTP status code and body matches 'Path diff too large'.
337
+ # It could occur when attempting to post review comments on a "too large" file.
338
+ class PathDiffTooLarge < UnprocessableEntity; end
339
+
340
+ # Raised when GitHub returns a 451 HTTP status code
341
+ class UnavailableForLegalReasons < ClientError; end
342
+
226
343
  # Raised on errors in the 500-599 range
227
344
  class ServerError < Error; end
228
345
 
@@ -248,4 +365,5 @@ module Octokit
248
365
  # Raised when a repository is created with an invalid format
249
366
  class InvalidRepository < ArgumentError; end
250
367
 
368
+ RATE_LIMITED_ERRORS = [Octokit::TooManyRequests, Octokit::AbuseDetected].freeze
251
369
  end
data/lib/octokit/gist.rb CHANGED
@@ -1,8 +1,8 @@
1
- module Octokit
1
+ # frozen_string_literal: true
2
2
 
3
+ module Octokit
3
4
  # Class to parse and create Gist URLs
4
5
  class Gist
5
-
6
6
  # !@attribute id
7
7
  # @return [String] Gist ID
8
8
  attr_accessor :id
@@ -10,12 +10,12 @@ module Octokit
10
10
  # Instantiate {Gist} object from Gist URL
11
11
  # @ return [Gist]
12
12
  def self.from_url(url)
13
- Gist.new(URI.parse(url).path[1..-1])
13
+ Gist.new(URI.parse(url).path[1..])
14
14
  end
15
15
 
16
16
  def initialize(gist)
17
17
  case gist
18
- when Fixnum, String
18
+ when Integer, String
19
19
  @id = gist.to_s
20
20
  end
21
21
  end
@@ -31,6 +31,5 @@ module Octokit
31
31
  def url
32
32
  "https://gist.github.com/#{@id}"
33
33
  end
34
-
35
34
  end
36
35
  end
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Octokit
4
+ # Client for the Manage GitHub Enterprise Server API
5
+ class ManageGHESClient
6
+ # Methods for the Manage GitHub Enterprise Server API
7
+ #
8
+ # @see https://developer.github.com/v3/enterprise-admin/manage-ghes
9
+ module ManageAPI
10
+ # Get information about the maintenance status of the GHES instance
11
+ #
12
+ # @return [nil]
13
+ def maintenance_mode
14
+ conn = authenticated_client
15
+
16
+ @last_response = conn.get('/manage/v1/maintenance')
17
+ end
18
+
19
+ # Configure the maintenance mode of the GHES instance
20
+ #
21
+ # @param maintenance [Hash] A hash configuration of the maintenance mode status
22
+ # @return [nil]
23
+ def set_maintenance_mode(enabled, options = {})
24
+ conn = authenticated_client
25
+
26
+ options[:enabled] = enabled
27
+ @last_response = conn.post('/manage/v1/maintenance', options)
28
+ end
29
+ alias configure_maintenance_mode set_maintenance_mode
30
+ end
31
+
32
+ # Uploads a license for the first time
33
+ #
34
+ # @param license [String] The path to your .ghl license file.
35
+ #
36
+ # @return [nil]
37
+ def upload_license(license)
38
+ conn = authenticated_client
39
+ begin
40
+ conn.request :multipart
41
+ rescue Faraday::Error
42
+ raise Faraday::Error, <<~ERROR
43
+ The `faraday-multipart` gem is required to upload a license.
44
+ Please add `gem "faraday-multipart"` to your Gemfile.
45
+ ERROR
46
+ end
47
+ params = {}
48
+ params[:license] = Faraday::FilePart.new(license, 'binary')
49
+ params[:password] = @manage_ghes_password
50
+ @last_response = conn.post('/manage/v1/config/init', params, { 'Content-Type' => 'multipart/form-data' })
51
+ end
52
+
53
+ # Start a configuration process.
54
+ #
55
+ # @return [nil]
56
+ def start_configuration
57
+ conn = authenticated_client
58
+ @last_response = conn.post('/manage/v1/config/apply')
59
+ end
60
+
61
+ # Get information about the Enterprise installation
62
+ #
63
+ # @return [nil]
64
+ def config_status
65
+ conn = authenticated_client
66
+ @last_response = conn.get('/manage/v1/config/apply')
67
+ end
68
+ alias config_check config_status
69
+
70
+ # Get information about the Enterprise installation
71
+ #
72
+ # @return [nil]
73
+ def settings
74
+ conn = authenticated_client
75
+ @last_response = conn.get('/manage/v1/config/settings')
76
+ end
77
+ alias get_settings settings
78
+
79
+ # Modify the Enterprise settings
80
+ #
81
+ # @param settings [Hash] A hash configuration of the new settings
82
+ #
83
+ # @return [nil]
84
+ def edit_settings(settings)
85
+ conn = authenticated_client
86
+ @last_response = conn.put('/manage/v1/config/settings', settings.to_json.to_s)
87
+ end
88
+
89
+ def authorized_keys
90
+ conn = authenticated_client
91
+ @last_response = conn.get('/manage/v1/access/ssh')
92
+ end
93
+ alias get_authorized_keys authorized_keys
94
+
95
+ # Add an authorized SSH keys on the Enterprise install
96
+ #
97
+ # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself
98
+ # @return [nil]
99
+ def add_authorized_key(key)
100
+ conn = authenticated_client
101
+ case key
102
+ when String
103
+ if File.exist?(key)
104
+ key = File.open(key, 'r')
105
+ content = key.read.strip
106
+ key.close
107
+ else
108
+ content = key
109
+ end
110
+ when File
111
+ content = key.read.strip
112
+ key.close
113
+ end
114
+
115
+ queries = {}
116
+ queries[:key] = content
117
+ @last_response = conn.post('/manage/v1/access/ssh', queries)
118
+ end
119
+
120
+ # Removes an authorized SSH keys from the Enterprise install
121
+ #
122
+ # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself
123
+ # @return [nil]
124
+ def remove_authorized_key(key)
125
+ conn = authenticated_client
126
+ case key
127
+ when String
128
+ if File.exist?(key)
129
+ key = File.open(key, 'r')
130
+ content = key.read.strip
131
+ key.close
132
+ else
133
+ content = key
134
+ end
135
+ when File
136
+ content = key.read.strip
137
+ key.close
138
+ end
139
+
140
+ queries = {}
141
+ queries[:key] = content
142
+ @last_response = conn.run_request(:delete, '/manage/v1/access/ssh', queries, nil)
143
+ end
144
+ alias delete_authorized_key remove_authorized_key
145
+
146
+ private
147
+
148
+ def basic_authenticated?
149
+ !!(@manage_ghes_username && @manage_ghes_password)
150
+ end
151
+
152
+ # If no username is provided, we assume root site admin should be used
153
+ def root_site_admin_assumed?
154
+ !@manage_ghes_username
155
+ end
156
+
157
+ def authenticated_client
158
+ @authenticated_client ||= Faraday.new(url: @manage_ghes_endpoint) do |c|
159
+ c.headers[:user_agent] = user_agent
160
+ c.request :json
161
+ c.response :json
162
+ c.adapter Faraday.default_adapter
163
+
164
+ if root_site_admin_assumed?
165
+ username = 'api_key'
166
+ elsif basic_authenticated?
167
+ username = @manage_ghes_username
168
+ end
169
+ c.request(*FARADAY_BASIC_AUTH_KEYS, username, @manage_ghes_password)
170
+
171
+ # Disabling SSL is essential for certain self-hosted Enterprise instances
172
+ c.ssl[:verify] = false if connection_options[:ssl] && !connection_options[:ssl][:verify]
173
+
174
+ c.use Octokit::Response::RaiseError
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'octokit/configurable'
4
+ require 'octokit/connection'
5
+ require 'octokit/warnable'
6
+ require 'octokit/manage_ghes_client/manage_ghes'
7
+
8
+ module Octokit
9
+ # ManageGHESClient is only meant to be used by GitHub Enterprise Server (GHES) operators
10
+ # and provides access to the Manage GHES API endpoints.
11
+ #
12
+ # @see Octokit::Client Use Octokit::Client for regular API use for GitHub
13
+ # and GitHub Enterprise.
14
+ # @see https://developer.github.com/v3/enterprise-admin/manage-ghes/
15
+ class ManageGHESClient
16
+ include Octokit::Configurable
17
+ include Octokit::Connection
18
+ include Octokit::Warnable
19
+ include Octokit::ManageGHESClient::ManageAPI
20
+
21
+ def initialize(options = {})
22
+ # Use options passed in, but fall back to module defaults
23
+ # rubocop:disable Style/HashEachMethods
24
+ #
25
+ # This may look like a `.keys.each` which should be replaced with `#each_key`, but
26
+ # this doesn't actually work, since `#keys` is just a method we've defined ourselves.
27
+ # The class doesn't fulfill the whole `Enumerable` contract.
28
+ Octokit::Configurable.keys.each do |key|
29
+ # rubocop:enable Style/HashEachMethods
30
+ instance_variable_set(:"@#{key}", options[key] || Octokit.instance_variable_get(:"@#{key}"))
31
+ end
32
+ end
33
+
34
+ protected
35
+
36
+ def endpoint
37
+ manage_ghes_endpoint
38
+ end
39
+
40
+ # Set Manage GHES API endpoint
41
+ #
42
+ # @param value [String] Manage GHES API endpoint
43
+ def manage_ghes_endpoint=(value)
44
+ reset_agent
45
+ @manage_ghes_endpoint = value
46
+ end
47
+
48
+ # Set Manage GHES API username
49
+ #
50
+ # @param value [String] Manage GHES API username
51
+ def manage_ghes_username=(value)
52
+ reset_agent
53
+ @manage_ghes_username = value
54
+ end
55
+
56
+ # Set Manage GHES API password
57
+ #
58
+ # @param value [String] Manage GHES API password
59
+ def manage_ghes_password=(value)
60
+ reset_agent
61
+ @manage_ghes_password = value
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'faraday'
2
4
  require 'set'
3
5
 
@@ -7,15 +9,13 @@ require 'set'
7
9
  # https://github.com/lostisland/faraday_middleware/blob/138766e/lib/faraday_middleware/response/follow_redirects.rb
8
10
 
9
11
  module Octokit
10
-
11
12
  module Middleware
12
-
13
13
  # Public: Exception thrown when the maximum amount of requests is exceeded.
14
- class RedirectLimitReached < Faraday::Error::ClientError
14
+ class RedirectLimitReached < Faraday::ClientError
15
15
  attr_reader :response
16
16
 
17
17
  def initialize(response)
18
- super "too many redirects; last one to: #{response['location']}"
18
+ super("too many redirects; last one to: #{response['location']}")
19
19
  @response = response
20
20
  end
21
21
  end
@@ -30,13 +30,13 @@ module Octokit
30
30
  # doesn't support parallelism.
31
31
  class FollowRedirects < Faraday::Middleware
32
32
  # HTTP methods for which 30x redirects can be followed
33
- ALLOWED_METHODS = Set.new [:head, :options, :get, :post, :put, :patch, :delete]
33
+ ALLOWED_METHODS = Set.new %i[head options get post put patch delete]
34
34
 
35
35
  # HTTP redirect status codes that this middleware implements
36
36
  REDIRECT_CODES = Set.new [301, 302, 303, 307]
37
37
 
38
38
  # Keys in env hash which will get cleared between requests
39
- ENV_TO_CLEAR = Set.new [:status, :response, :response_headers]
39
+ ENV_TO_CLEAR = Set.new %i[status response response_headers]
40
40
 
41
41
  # Default value for max redirects followed
42
42
  FOLLOW_LIMIT = 3
@@ -44,12 +44,12 @@ module Octokit
44
44
  # Regex that matches characters that need to be escaped in URLs, sans
45
45
  # the "%" character which we assume already represents an escaped
46
46
  # sequence.
47
- URI_UNSAFE = /[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]%]/
47
+ URI_UNSAFE = %r{[^\-_.!~*'()a-zA-Z\d;/?:@&=+$,\[\]%]}.freeze
48
48
 
49
49
  # Public: Initialize the middleware.
50
50
  #
51
51
  # options - An options Hash (default: {}):
52
- # :limit - A Fixnum redirect limit (default: 3).
52
+ # :limit - A Integer redirect limit (default: 3).
53
53
  def initialize(app, options = {})
54
54
  super(app)
55
55
  @options = options
@@ -64,7 +64,7 @@ module Octokit
64
64
  private
65
65
 
66
66
  def convert_to_get?(response)
67
- ![:head, :options].include?(response.env[:method]) &&
67
+ !%i[head options].include?(response.env[:method]) &&
68
68
  @convert_to_get.include?(response.status)
69
69
  end
70
70
 
@@ -75,6 +75,7 @@ module Octokit
75
75
  response.on_complete do |response_env|
76
76
  if follow_redirect?(response_env, response)
77
77
  raise(RedirectLimitReached, response) if follows.zero?
78
+
78
79
  new_request_env = update_env(response_env, request_body, response)
79
80
  response = perform_with_redirection(new_request_env, follows - 1)
80
81
  end
@@ -84,9 +85,12 @@ module Octokit
84
85
 
85
86
  def update_env(env, request_body, response)
86
87
  original_url = env[:url]
87
- env[:url] += safe_escape(response["location"])
88
+ env[:url] += safe_escape(response['location'])
88
89
  unless same_host?(original_url, env[:url])
89
- env[:request_headers].delete("Authorization")
90
+ # HACK: Faraday’s Authorization middlewares don’t touch the request if the `Authorization` header is set.
91
+ # This is a workaround to drop authentication info.
92
+ # See https://github.com/octokit/octokit.rb/pull/1359#issuecomment-925609697
93
+ env[:request_headers]['Authorization'] = 'dummy'
90
94
  end
91
95
 
92
96
  if convert_to_get?(response)
@@ -122,9 +126,9 @@ module Octokit
122
126
  # URI:HTTP using the `+` operator. Doesn't escape "%" characters so to not
123
127
  # risk double-escaping.
124
128
  def safe_escape(uri)
125
- uri.to_s.gsub(URI_UNSAFE) { |match|
126
- "%" + match.unpack("H2" * match.bytesize).join("%").upcase
127
- }
129
+ uri.to_s.gsub(URI_UNSAFE) do |match|
130
+ "%#{match.unpack('H2' * match.bytesize).join('%').upcase}"
131
+ end
128
132
  end
129
133
  end
130
134
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Octokit
2
4
  # GitHub organization class to generate API path urls
3
5
  class Organization
@@ -5,7 +7,7 @@ module Octokit
5
7
  #
6
8
  # @param org [String, Integer] GitHub organization login or id
7
9
  # @return [String] Organization Api path
8
- def self.path org
10
+ def self.path(org)
9
11
  case org
10
12
  when String
11
13
  "orgs/#{org}"