octokit 4.15.0 → 4.21.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.
@@ -23,6 +23,18 @@ module Octokit
23
23
  alias :references :refs
24
24
  alias :list_references :refs
25
25
 
26
+ # Fetch matching refs
27
+ #
28
+ # @param repo [Integer, String, Repository, Hash] A GitHub repository
29
+ # @param ref [String] The ref, e.g. <tt>tags/v0.0.3</tt> or <tt>heads/rails-3</tt>
30
+ # @return [Array<Sawyer::Resource>] The reference matching the given repo and the ref id
31
+ # @see https://developer.github.com/v3/git/refs/#list-matching-references
32
+ # @example Fetch refs matching tags/v2 for sferik/rails_admin
33
+ # Octokit.ref("sferik/rails_admin","tags/v2")
34
+ def matching_refs(repo, ref, options = {})
35
+ paginate "#{Repository.path repo}/git/matching-refs/#{ref}", options
36
+ end
37
+
26
38
  # Fetch a given reference
27
39
  #
28
40
  # @param repo [Integer, String, Repository, Hash] A GitHub repository
@@ -60,11 +72,13 @@ module Octokit
60
72
  # @param repo [Integer, String, Repository, Hash] A GitHub repository
61
73
  # @param ref [String] The ref, e.g. <tt>tags/v0.0.3</tt>
62
74
  # @param sha [String] A SHA, e.g. <tt>827efc6d56897b048c772eb4087f854f46256132</tt>
63
- # @param force [Boolean] A flag indicating one wants to force the update to make sure the update is a fast-forward update.
75
+ # @param force [Boolean] A flag indicating whether to force the update or to make sure the update is a fast-forward update.
64
76
  # @return [Array<Sawyer::Resource>] The list of references updated
65
77
  # @see https://developer.github.com/v3/git/refs/#update-a-reference
66
78
  # @example Force update heads/sc/featureA for octocat/Hello-World with sha aa218f56b14c9653891f9e74264a383fa43fefbd
67
79
  # Octokit.update_ref("octocat/Hello-World", "heads/sc/featureA", "aa218f56b14c9653891f9e74264a383fa43fefbd")
80
+ # @example Fast-forward update heads/sc/featureA for octocat/Hello-World with sha aa218f56b14c9653891f9e74264a383fa43fefbd
81
+ # Octokit.update_ref("octocat/Hello-World", "heads/sc/featureA", "aa218f56b14c9653891f9e74264a383fa43fefbd", false)
68
82
  def update_ref(repo, ref, sha, force = true, options = {})
69
83
  parameters = {
70
84
  :sha => sha,
@@ -79,11 +93,13 @@ module Octokit
79
93
  # @param repo [Integer, String, Repository, Hash] A GitHub repository
80
94
  # @param branch [String] The ref, e.g. <tt>feature/new-shiny</tt>
81
95
  # @param sha [String] A SHA, e.g. <tt>827efc6d56897b048c772eb4087f854f46256132</tt>
82
- # @param force [Boolean] A flag indicating one wants to force the update to make sure the update is a fast-forward update.
96
+ # @param force [Boolean] A flag indicating whether to force the update or to make sure the update is a fast-forward update.
83
97
  # @return [Array<Sawyer::Resource>] The list of references updated
84
98
  # @see https://developer.github.com/v3/git/refs/#update-a-reference
85
99
  # @example Force update heads/sc/featureA for octocat/Hello-World with sha aa218f56b14c9653891f9e74264a383fa43fefbd
86
- # Octokit.update_branch("octocat/Hello-World","sc/featureA", "aa218f56b14c9653891f9e74264a383fa43fefbd")
100
+ # Octokit.update_branch("octocat/Hello-World", "sc/featureA", "aa218f56b14c9653891f9e74264a383fa43fefbd")
101
+ # @example Fast-forward update heads/sc/featureA for octocat/Hello-World with sha aa218f56b14c9653891f9e74264a383fa43fefbd
102
+ # Octokit.update_branch("octocat/Hello-World", "sc/featureA", "aa218f56b14c9653891f9e74264a383fa43fefbd", false)
87
103
  def update_branch(repo, branch, sha, force = true, options = {})
88
104
  update_ref repo, "heads/#{branch}", sha, force, options
89
105
  end
@@ -32,7 +32,7 @@ module Octokit
32
32
 
33
33
  # Edit a repository
34
34
  #
35
- # @see https://developer.github.com/v3/repos/#edit
35
+ # @see https://developer.github.com/v3/repos/#update-a-repository
36
36
  # @param repo [String, Hash, Repository] A GitHub repository
37
37
  # @param options [Hash] Repository information to update
38
38
  # @option options [String] :name Name of the repo
@@ -429,7 +429,7 @@ module Octokit
429
429
  # @example List topics for octokit/octokit.rb
430
430
  # Octokit.topics('octokit/octokit.rb')
431
431
  # @example List topics for octokit/octokit.rb
432
- # client.topics('octokit/octokit.rb')
432
+ # client.topics('octokit/octokit.rb')
433
433
  def topics(repo, options = {})
434
434
  opts = ensure_api_media_type(:topics, options)
435
435
  paginate "#{Repository.path repo}/topics", opts
@@ -586,14 +586,14 @@ module Octokit
586
586
  #
587
587
  # @param repo [Integer, String, Hash, Repository] A GitHub repository.
588
588
  # @param branch [String] Branch name
589
- # @option options [Hash] :required_status_checks If not null, the following keys are required:
590
- # <tt>:enforce_admins [boolean] Enforce required status checks for repository administrators.</tt>
591
- # <tt>:strict [boolean] Require branches to be up to date before merging.</tt>
592
- # <tt>:contexts [Array] The list of status checks to require in order to merge into this branch</tt>
589
+ # @option options [Hash] :required_status_checks If not null, the following keys are required:
590
+ # <tt>:enforce_admins [boolean] Enforce required status checks for repository administrators.</tt>
591
+ # <tt>:strict [boolean] Require branches to be up to date before merging.</tt>
592
+ # <tt>:contexts [Array] The list of status checks to require in order to merge into this branch</tt>
593
593
  #
594
594
  # @option options [Hash] :restrictions If not null, the following keys are required:
595
- # <tt>:users [Array] The list of user logins with push access</tt>
596
- # <tt>:teams [Array] The list of team slugs with push access</tt>.
595
+ # <tt>:users [Array] The list of user logins with push access</tt>
596
+ # <tt>:teams [Array] The list of team slugs with push access</tt>.
597
597
  #
598
598
  # Teams and users restrictions are only available for organization-owned repositories.
599
599
  # @return [Sawyer::Resource] The protected branch
@@ -640,6 +640,24 @@ module Octokit
640
640
  boolean_from_response :delete, "#{Repository.path repo}/branches/#{branch}/protection", opts
641
641
  end
642
642
 
643
+ # Rename a single branch from a repository
644
+ #
645
+ # Requires authenticated client
646
+ #
647
+ # @param repo [Integer, String, Hash, Repository] A GitHub repository.
648
+ # @param branch [String] Current branch name
649
+ # @param new_name [String] New branch name
650
+ # @return [Sawyer::Resource] The renamed branch
651
+ # @see https://developer.github.com/v3/repos/#rename-a-branch
652
+ # @example
653
+ # @client.rename_branch('octokit/octokit.rb', 'master', 'main')
654
+ def rename_branch(repo, branch, new_name, options = {})
655
+ params = {
656
+ new_name: new_name,
657
+ }
658
+ post "#{Repository.path repo}/branches/#{branch}/rename", params.merge(options)
659
+ end
660
+
643
661
  # List users available for assigning to issues.
644
662
  #
645
663
  # Requires authenticated client for private repos.
@@ -720,6 +738,62 @@ module Octokit
720
738
  def delete_subscription(repo, options = {})
721
739
  boolean_from_response :delete, "#{Repository.path repo}/subscription", options
722
740
  end
741
+
742
+ # Create a repository dispatch event
743
+ #
744
+ # @param repo [Integer, String, Hash, Repository] A GitHub repository.
745
+ # @param event_type [String] A custom webhook event name.
746
+ # @option options [Hash] :client_payload payload with extra information
747
+ # about the webhook event that your action or worklow may use.
748
+ #
749
+ # @return [Boolean] True if event was dispatched, false otherwise.
750
+ # @see https://developer.github.com/v3/repos/#create-a-repository-dispatch-event
751
+ def dispatch_event(repo, event_type, options = {})
752
+ boolean_from_response :post, "#{Repository.path repo}/dispatches", options.merge({ event_type: event_type })
753
+ end
754
+
755
+ # Check to see if vulnerability alerts are enabled for a repository
756
+ #
757
+ # The authenticated user must have admin access to the repository.
758
+ #
759
+ # @param repo [Integer, String, Hash, Repository] A GitHub repository.
760
+ # @return [Boolean] True if vulnerability alerts are enabled, false otherwise.
761
+ # @see https://docs.github.com/en/rest/reference/repos#check-if-vulnerability-alerts-are-enabled-for-a-repository
762
+ #
763
+ # @example
764
+ # @client.vulnerability_alerts_enabled?("octokit/octokit.rb")
765
+ def vulnerability_alerts_enabled?(repo, options = {})
766
+ opts = ensure_api_media_type(:vulnerability_alerts, options)
767
+ boolean_from_response(:get, "#{Repository.path repo}/vulnerability-alerts", opts)
768
+ end
769
+
770
+ # Enable vulnerability alerts for a repository
771
+ #
772
+ # @param repo [Integer, String, Hash, Repository] A GitHub repository.
773
+ # @param options [Hash]
774
+ #
775
+ # @return [Boolean] True if vulnerability alerts enabled, false otherwise.
776
+ # @see https://docs.github.com/en/rest/reference/repos#enable-vulnerability-alerts
777
+ # @example Enable vulnerability alerts for a repository
778
+ # @client.enable_vulnerability_alerts("octokit/octokit.rb")
779
+ def enable_vulnerability_alerts(repo, options = {})
780
+ opts = ensure_api_media_type(:vulnerability_alerts, options)
781
+ boolean_from_response(:put, "#{Repository.path repo}/vulnerability-alerts", opts)
782
+ end
783
+
784
+ # Disable vulnerability alerts for a repository
785
+ #
786
+ # @param repo [Integer, String, Hash, Repository] A GitHub repository.
787
+ # @param options [Hash]
788
+ #
789
+ # @return [Boolean] True if vulnerability alerts disabled, false otherwise.
790
+ # @see https://docs.github.com/en/rest/reference/repos#disable-vulnerability-alerts
791
+ # @example Disable vulnerability alerts for a repository
792
+ # @client.disable_vulnerability_alerts("octokit/octokit.rb")
793
+ def disable_vulnerability_alerts(repo, options = {})
794
+ opts = ensure_api_media_type(:vulnerability_alerts, options)
795
+ boolean_from_response(:delete, "#{Repository.path repo}/vulnerability-alerts", opts)
796
+ end
723
797
  end
724
798
  end
725
799
  end
@@ -44,7 +44,7 @@ module Octokit
44
44
  # @option options [Integer] :page Page of paginated results
45
45
  # @option options [Integer] :per_page Number of items per page
46
46
  # @return [Sawyer::Resource] Search results object
47
- # @see https://developer.github.com/v3/search/#search-issues
47
+ # @see https://developer.github.com/v3/search/#search-issues-and-pull-requests
48
48
  def search_issues(query, options = {})
49
49
  search "search/issues", query, options
50
50
  end
@@ -340,6 +340,92 @@ module Octokit
340
340
  end
341
341
  alias :watched :subscriptions
342
342
 
343
+ # Initiates the generation of a migration archive.
344
+ #
345
+ # Requires authenticated user.
346
+ #
347
+ # @param repositories [Array<String>] :repositories Repositories for the organization.
348
+ # @option options [Boolean, optional] :lock_repositories Indicates whether repositories should be locked during migration
349
+ # @option options [Boolean, optional] :exclude_attachments Exclude attachments fro the migration data
350
+ # @return [Sawyer::Resource] Hash representing the new migration.
351
+ # @example
352
+ # @client.start_migration(['octocat/hello-world'])
353
+ # @see https://docs.github.com/en/rest/reference/migrations#start-a-user-migration
354
+ def start_user_migration(repositories, options = {})
355
+ options = ensure_api_media_type(:migrations, options)
356
+ options[:repositories] = repositories
357
+ post "user/migrations", options
358
+ end
359
+
360
+ # Lists the most recent migrations.
361
+ #
362
+ # Requires authenticated user.
363
+ #
364
+ # @return [Array<Sawyer::Resource>] Array of migration resources.
365
+ # @see https://docs.github.com/en/rest/reference/migrations#list-user-migrations
366
+ def user_migrations(options = {})
367
+ options = ensure_api_media_type(:migrations, options)
368
+ paginate "user/migrations", options
369
+ end
370
+
371
+ # Fetches the status of a migration.
372
+ #
373
+ # Requires authenticated user.
374
+ #
375
+ # @param id [Integer] ID number of the migration.
376
+ # @see https://docs.github.com/en/rest/reference/migrations#get-a-user-migration-status
377
+ def user_migration_status(id, options = {})
378
+ options = ensure_api_media_type(:migrations, options)
379
+ get "user/migrations/#{id}", options
380
+ end
381
+
382
+ # Fetches the URL to a migration archive.
383
+ #
384
+ # Requires authenticated user.
385
+ #
386
+ # @param id [Integer] ID number of the migration.
387
+ # @see https://docs.github.com/en/rest/reference/migrations#download-a-user-migration-archive
388
+ def user_migration_archive_url(id, options = {})
389
+ options = ensure_api_media_type(:migrations, options)
390
+ url = "user/migrations/#{id}/archive"
391
+
392
+ response = client_without_redirects(options).get(url)
393
+ response.headers['location']
394
+ end
395
+
396
+ # Deletes a previous migration archive.
397
+ #
398
+ # Requires authenticated user.
399
+ #
400
+ # @param id [Integer] ID number of the migration.
401
+ # @see https://docs.github.com/en/rest/reference/migrations#delete-a-user-migration-archive
402
+ def delete_user_migration_archive(id, options = {})
403
+ options = ensure_api_media_type(:migrations, options)
404
+ delete "user/migrations/#{id}/archive", options
405
+ end
406
+
407
+ # List repositories for a user migration.
408
+ #
409
+ # Requires authenticated user.
410
+ #
411
+ # @param id [Integer] ID number of the migration.
412
+ # @see https://docs.github.com/en/rest/reference/migrations#list-repositories-for-a-user-migration
413
+ def user_migration_repositories(id, options = {})
414
+ options = ensure_api_media_type(:migrations, options)
415
+ get "user/migrations/#{id}/repositories", options
416
+ end
417
+
418
+ # Unlock a user repository which has been locked by a migration.
419
+ #
420
+ # Requires authenticated user.
421
+ #
422
+ # @param id [Integer] ID number of the migration.
423
+ # @param repo [String] Name of the repository.
424
+ # @see https://docs.github.com/en/rest/reference/migrations#unlock-a-user-repository
425
+ def unlock_user_repository(id, repo, options = {})
426
+ options = ensure_api_media_type(:migrations, options)
427
+ delete "user/migrations/#{id}/repos/#{repo}/lock", options
428
+ end
343
429
  end
344
430
 
345
431
  private
@@ -113,7 +113,7 @@ module Octokit
113
113
  elsif bearer_authenticated?
114
114
  http.authorization 'Bearer', @bearer_token
115
115
  elsif application_authenticated?
116
- http.params = http.params.merge application_authentication
116
+ http.basic_auth(@client_id, @client_secret)
117
117
  end
118
118
  end
119
119
  end
@@ -155,6 +155,9 @@ module Octokit
155
155
 
156
156
  @last_response = response = agent.call(method, Addressable::URI.parse(path.to_s).normalize.to_s, data, options)
157
157
  response.data
158
+ rescue Octokit::Error => error
159
+ @last_response = nil
160
+ raise error
158
161
  end
159
162
 
160
163
  # Executes the request, checking if it was successful
@@ -162,7 +165,7 @@ module Octokit
162
165
  # @return [Boolean] True on success, false otherwise
163
166
  def boolean_from_response(method, path, options = {})
164
167
  request(method, path, options)
165
- @last_response.status == 204
168
+ [201, 202, 204].include? @last_response.status
166
169
  rescue Octokit::NotFound
167
170
  false
168
171
  end
@@ -177,12 +180,12 @@ module Octokit
177
180
  conn_opts[:proxy] = @proxy if @proxy
178
181
  if conn_opts[:ssl].nil?
179
182
  conn_opts[:ssl] = { :verify_mode => @ssl_verify_mode } if @ssl_verify_mode
180
- else
181
- if @connection_options[:ssl][:verify] == false
182
- conn_opts[:ssl] = { :verify_mode => 0}
183
- else
184
- conn_opts[:ssl] = { :verify_mode => @ssl_verify_mode }
185
- end
183
+ else
184
+ verify = @connection_options[:ssl][:verify]
185
+ conn_opts[:ssl] = {
186
+ :verify => verify,
187
+ :verify_mode => verify == false ? 0 : @ssl_verify_mode
188
+ }
186
189
  end
187
190
  opts[:faraday] = Faraday.new(conn_opts)
188
191
 
data/lib/octokit/error.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Octokit
2
2
  # Custom error class for rescuing from all GitHub errors
3
3
  class Error < StandardError
4
-
4
+ attr_reader :context
5
5
  # Returns the appropriate Octokit::Error subclass based
6
6
  # on status and response message
7
7
  #
@@ -21,7 +21,7 @@ module Octokit
21
21
  when 406 then Octokit::NotAcceptable
22
22
  when 409 then Octokit::Conflict
23
23
  when 415 then Octokit::UnsupportedMediaType
24
- when 422 then Octokit::UnprocessableEntity
24
+ when 422 then error_for_422(body)
25
25
  when 451 then Octokit::UnavailableForLegalReasons
26
26
  when 400..499 then Octokit::ClientError
27
27
  when 500 then Octokit::InternalServerError
@@ -34,9 +34,16 @@ module Octokit
34
34
  end
35
35
  end
36
36
 
37
+ def build_error_context
38
+ if RATE_LIMITED_ERRORS.include?(self.class)
39
+ @context = Octokit::RateLimit.from_response(@response)
40
+ end
41
+ end
42
+
37
43
  def initialize(response=nil)
38
44
  @response = response
39
45
  super(build_error_message)
46
+ build_error_context
40
47
  end
41
48
 
42
49
  # Documentation URL returned by the API for some errors
@@ -77,6 +84,8 @@ module Octokit
77
84
  Octokit::BillingIssue
78
85
  elsif body =~ /Resource protected by organization SAML enforcement/i
79
86
  Octokit::SAMLProtected
87
+ elsif body =~ /suspended your access|This installation has been suspended/i
88
+ Octokit::InstallationSuspended
80
89
  else
81
90
  Octokit::Forbidden
82
91
  end
@@ -92,6 +101,18 @@ module Octokit
92
101
  end
93
102
  end
94
103
 
104
+ # Return most appropriate error for 422 HTTP status code
105
+ # @private
106
+ def self.error_for_422(body)
107
+ if body =~ /PullRequestReviewComment/i && body =~ /(commit_id|end_commit_oid) is not part of the pull request/i
108
+ Octokit::CommitIsNotPartOfPullRequest
109
+ elsif body =~ /Path diff too large/i
110
+ Octokit::PathDiffTooLarge
111
+ else
112
+ Octokit::UnprocessableEntity
113
+ end
114
+ end
115
+
95
116
  # Array of validation errors
96
117
  # @return [Array<Hash>] Error info
97
118
  def errors
@@ -265,6 +286,10 @@ module Octokit
265
286
  # and body matches 'Resource protected by organization SAML enforcement'
266
287
  class SAMLProtected < Forbidden; end
267
288
 
289
+ # Raised when GitHub returns a 403 HTTP status code
290
+ # and body matches 'suspended your access'
291
+ class InstallationSuspended < Forbidden; end
292
+
268
293
  # Raised when GitHub returns a 404 HTTP status code
269
294
  class NotFound < ClientError; end
270
295
 
@@ -287,6 +312,14 @@ module Octokit
287
312
  # Raised when GitHub returns a 422 HTTP status code
288
313
  class UnprocessableEntity < ClientError; end
289
314
 
315
+ # Raised when GitHub returns a 422 HTTP status code
316
+ # and body matches 'PullRequestReviewComment' and 'commit_id (or end_commit_oid) is not part of the pull request'
317
+ class CommitIsNotPartOfPullRequest < UnprocessableEntity; end
318
+
319
+ # Raised when GitHub returns a 422 HTTP status code and body matches 'Path diff too large'.
320
+ # It could occur when attempting to post review comments on a "too large" file.
321
+ class PathDiffTooLarge < UnprocessableEntity; end
322
+
290
323
  # Raised when GitHub returns a 451 HTTP status code
291
324
  class UnavailableForLegalReasons < ClientError; end
292
325
 
@@ -315,4 +348,5 @@ module Octokit
315
348
  # Raised when a repository is created with an invalid format
316
349
  class InvalidRepository < ArgumentError; end
317
350
 
351
+ RATE_LIMITED_ERRORS = [Octokit::TooManyRequests, Octokit::AbuseDetected]
318
352
  end
@@ -4,10 +4,11 @@ module Octokit
4
4
  module Preview
5
5
 
6
6
  PREVIEW_TYPES = {
7
+ :applications_api => 'application/vnd.github.doctor-strange-preview+json'.freeze,
7
8
  :branch_protection => 'application/vnd.github.luke-cage-preview+json'.freeze,
8
- :checks => 'application/vnd.github.antiope-preview+json'.freeze,
9
9
  :commit_search => 'application/vnd.github.cloak-preview+json'.freeze,
10
10
  :commit_pulls => 'application/vnd.github.groot-preview+json'.freeze,
11
+ :commit_branches => 'application/vnd.github.groot-preview+json'.freeze,
11
12
  :migrations => 'application/vnd.github.wyandotte-preview+json'.freeze,
12
13
  :licenses => 'application/vnd.github.drax-preview+json'.freeze,
13
14
  :source_imports => 'application/vnd.github.barred-rock-preview'.freeze,
@@ -18,13 +19,12 @@ module Octokit
18
19
  :pages => 'application/vnd.github.mister-fantastic-preview+json'.freeze,
19
20
  :projects => 'application/vnd.github.inertia-preview+json'.freeze,
20
21
  :traffic => 'application/vnd.github.spiderman-preview'.freeze,
21
- :integrations => 'application/vnd.github.machine-man-preview+json'.freeze,
22
22
  :topics => 'application/vnd.github.mercy-preview+json'.freeze,
23
23
  :community_profile => 'application/vnd.github.black-panther-preview+json'.freeze,
24
24
  :strict_validation => 'application/vnd.github.speedy-preview+json'.freeze,
25
- :drafts => 'application/vnd.github.shadow-cat-preview'.freeze,
26
25
  :template_repositories => 'application/vnd.github.baptiste-preview+json'.freeze,
27
- :uninstall_github_app => 'application/vnd.github.gambit-preview+json'.freeze,
26
+ :project_card_events => 'application/vnd.github.starfox-preview+json'.freeze,
27
+ :vulnerability_alerts => 'application/vnd.github.dorian-preview+json'.freeze,
28
28
  }
29
29
 
30
30
  def ensure_api_media_type(type, options)
@@ -20,7 +20,7 @@ module Octokit
20
20
  # @return [RateLimit]
21
21
  def self.from_response(response)
22
22
  info = new
23
- if response && !response.headers.nil?
23
+ if response && response.respond_to?(:headers) && !response.headers.nil?
24
24
  info.limit = (response.headers['X-RateLimit-Limit'] || 1).to_i
25
25
  info.remaining = (response.headers['X-RateLimit-Remaining'] || 1).to_i
26
26
  info.resets_at = Time.at((response.headers['X-RateLimit-Reset'] || Time.now).to_i)