octokit 8.0.0 → 9.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9f2dca26c45a1b912572448c2fe16e78f37b7bb5fc7dc885488847c6eb19315
4
- data.tar.gz: 11a332c8d3ad5f92ac0ed01ccd03e6a699f852d31946e6e4acc43e75ea3b2d00
3
+ metadata.gz: ff098c16b9a72f52713782145e415ca2658ae2f7f48bd1c64f908507f26eb4cc
4
+ data.tar.gz: 06610fe737e7bf1c9b56447828fd5c5ab19e343832b34573f4ad0c02eec41c62
5
5
  SHA512:
6
- metadata.gz: 4790f888c01d7094b822ba72fc1ac576efa0803c6433982b53373787649b9b398842ee2986e43af6000677cda62a81e9072936b1d46c516a441a8256de10a1ae
7
- data.tar.gz: 135c6ab374669d1db0fd18172670f79856adb627ef3e8cf015e0af93dacedf110f6f022df2be04907fdf11d4db68d7c382569e56f792d4c5eac2db7f65f8bbec
6
+ metadata.gz: f236b59523559b762dd8c58718d0ff58d8181877740b7c2c5e10851f7be8f490e959bbf4f0b457e641c1931b562a6f5a4aa4f6d0f2b56bb63251a7cc3691faa1
7
+ data.tar.gz: f7b50ad0662923a499628fd914ba6aa36df8370c1e111d3fd16582f027eeef358fa8f25502376fac9e744848dbf55e5ddc781a5a5ca1ae7638cf4acbb6545b9e
data/README.md CHANGED
@@ -81,7 +81,7 @@ Install via Rubygems
81
81
 
82
82
  ... or add to your Gemfile
83
83
 
84
- gem "octokit", "~> 5.0"
84
+ gem "octokit"
85
85
 
86
86
  Access the library in Ruby:
87
87
 
@@ -709,6 +709,9 @@ Octokit:
709
709
  | `OCTOKIT_TEST_GITHUB_ENTERPRISE_MANAGEMENT_CONSOLE_PASSWORD` | GitHub Enterprise management console password. |
710
710
  | `OCTOKIT_TEST_GITHUB_ENTERPRISE_ENDPOINT` | GitHub Enterprise hostname. |
711
711
  | `OCTOKIT_TEST_GITHUB_ENTERPRISE_MANAGEMENT_CONSOLE_ENDPOINT` | GitHub Enterprise Management Console endpoint. |
712
+ | `OCTOKIT_TEST_GITHUB_MANAGE_GHES_ENDPOINT` | GitHub Enterprise Server GHES Manage Endpoint. |
713
+ | `OCTOKIT_TEST_GITHUB_MANAGE_GHES_USERNAME` | GitHub Enterprise Server GHES Manage Username. |
714
+ | `OCTOKIT_TEST_GITHUB_MANAGE_GHES_PASSWORD` | GitHub Enterprise Server GHES Manage Password. |
712
715
  | `OCTOKIT_TEST_GITHUB_INTEGRATION` | [GitHub Integration](https://developer.github.com/early-access/integrations/) owned by your test organization. |
713
716
  | `OCTOKIT_TEST_GITHUB_INTEGRATION_INSTALLATION` | Installation of the GitHub Integration specified above. |
714
717
  | `OCTOKIT_TEST_INTEGRATION_PEM_KEY` | File path to the private key generated from your integration. |
@@ -738,6 +741,7 @@ implementations:
738
741
  * Ruby 3.0
739
742
  * Ruby 3.1
740
743
  * Ruby 3.2
744
+ * Ruby 3.3
741
745
 
742
746
  If something doesn't work on one of these Ruby versions, it's a bug.
743
747
 
@@ -8,7 +8,7 @@ module Octokit
8
8
 
9
9
  def initialize(args)
10
10
  @options = args.last.is_a?(::Hash) ? args.pop : {}
11
- super(args)
11
+ super
12
12
  end
13
13
  end
14
14
  end
@@ -15,6 +15,15 @@ module Octokit
15
15
  get "#{Repository.path repo}/actions/secrets/public-key"
16
16
  end
17
17
 
18
+ # Get public key for secrets encryption
19
+ #
20
+ # @param org [String] A GitHub organization
21
+ # @return [Hash] key_id and key
22
+ # @see https://developer.github.com/v3/actions/secrets/#get-your-public-key
23
+ def get_org_actions_public_key(org)
24
+ get "#{Organization.path org}/actions/secrets/public-key"
25
+ end
26
+
18
27
  # List secrets
19
28
  #
20
29
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -26,6 +35,17 @@ module Octokit
26
35
  end
27
36
  end
28
37
 
38
+ # List org secrets
39
+ #
40
+ # @param org [String] A GitHub organization
41
+ # @return [Hash] total_count and list of secrets (each item is hash with name, created_at and updated_at)
42
+ # @see https://developer.github.com/v3/actions/secrets/#list-organization-secrets
43
+ def list_org_actions_secrets(org)
44
+ paginate "#{Organization.path org}/actions/secrets" do |data, last_response|
45
+ data.secrets.concat last_response.data.secrets
46
+ end
47
+ end
48
+
29
49
  # Get a secret
30
50
  #
31
51
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -36,6 +56,16 @@ module Octokit
36
56
  get "#{Repository.path repo}/actions/secrets/#{name}"
37
57
  end
38
58
 
59
+ # Get an org secret
60
+ #
61
+ # @param org [String] A GitHub organization
62
+ # @param name [String] Name of secret
63
+ # @return [Hash] name, created_at and updated_at
64
+ # @see https://developer.github.com/v3/actions/secrets/#get-a-secret
65
+ def get_org_actions_secret(org, name)
66
+ get "#{Organization.path org}/actions/secrets/#{name}"
67
+ end
68
+
39
69
  # Create or update secrets
40
70
  #
41
71
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -46,6 +76,16 @@ module Octokit
46
76
  put "#{Repository.path repo}/actions/secrets/#{name}", options
47
77
  end
48
78
 
79
+ # Create or update org secrets
80
+ #
81
+ # @param org [String] A GitHub organization
82
+ # @param name [String] Name of secret
83
+ # @param options [Hash] encrypted_value and key_id
84
+ # @see https://developer.github.com/v3/actions/secrets/#create-or-update-a-secret
85
+ def create_or_update_org_actions_secret(org, name, options)
86
+ put "#{Organization.path org}/actions/secrets/#{name}", options
87
+ end
88
+
49
89
  # Delete a secret
50
90
  #
51
91
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -55,6 +95,15 @@ module Octokit
55
95
  boolean_from_response :delete, "#{Repository.path repo}/actions/secrets/#{name}"
56
96
  end
57
97
 
98
+ # Delete an org secret
99
+ #
100
+ # @param org [String] A GitHub organization
101
+ # @param name [String] Name of secret
102
+ # @see https://developer.github.com/v3/actions/secrets/#delete-a-secret
103
+ def delete_org_actions_secret(org, name)
104
+ boolean_from_response :delete, "#{Organization.path org}/actions/secrets/#{name}"
105
+ end
106
+
58
107
  # Get environment public key for secrets encryption
59
108
  #
60
109
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -231,6 +231,18 @@ module Octokit
231
231
  end
232
232
  end
233
233
 
234
+ # Returns a delivery for the webhook configured for a GitHub App.
235
+ #
236
+ # @param delivery_id [String] The id of a GitHub App Hook Delivery
237
+ # @param options [Hash] A customizable set of options
238
+ #
239
+ # @see https://docs.github.com/en/rest/apps/webhooks#get-a-delivery-for-an-app-webhook
240
+ #
241
+ # @return [<Sawyer::Resource>] The webhook delivery
242
+ def app_hook_delivery(delivery_id, options = {})
243
+ get "/app/hook/deliveries/#{delivery_id}", options
244
+ end
245
+
234
246
  # Redeliver a delivery for the webhook configured for a GitHub App.
235
247
  #
236
248
  # @param delivery_id [Integer] The id of a GitHub App Hook Delivery
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'base64'
4
3
  require 'tempfile'
5
4
  require 'zlib'
6
5
 
@@ -45,7 +44,7 @@ module Octokit
45
44
  Zlib::GzipWriter.open(tempfile) do |gz_file|
46
45
  gz_file.write File.binread(file)
47
46
  end
48
- Base64.strict_encode64(tempfile.read)
47
+ [tempfile.read].pack('m0') # Base64.strict_encode64
49
48
  end
50
49
  end
51
50
  end
@@ -15,6 +15,15 @@ module Octokit
15
15
  get "#{Repository.path repo}/codespaces/secrets/public-key"
16
16
  end
17
17
 
18
+ # Get public key for secrets encryption
19
+ #
20
+ # @param org [String] A GitHub organization
21
+ # @return [Hash] key_id and key
22
+ # @see https://docs.github.com/en/rest/codespaces/organization-secrets?apiVersion=2022-11-28#get-an-organization-public-key
23
+ def get_org_codespaces_public_key(org)
24
+ get "#{Organization.path org}/codespaces/secrets/public-key"
25
+ end
26
+
18
27
  # List secrets
19
28
  #
20
29
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -26,6 +35,17 @@ module Octokit
26
35
  end
27
36
  end
28
37
 
38
+ # List org secrets
39
+ #
40
+ # @param org [String] A GitHub organization
41
+ # @return [Hash] total_count and list of secrets (each item is hash with name, created_at and updated_at)
42
+ # @see https://docs.github.com/en/rest/codespaces/organization-secrets?apiVersion=2022-11-28#list-organization-secrets
43
+ def list_org_codespaces_secrets(org)
44
+ paginate "#{Organization.path org}/codespaces/secrets" do |data, last_response|
45
+ data.secrets.concat last_response.data.secrets
46
+ end
47
+ end
48
+
29
49
  # Get a secret
30
50
  #
31
51
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -36,6 +56,16 @@ module Octokit
36
56
  get "#{Repository.path repo}/codespaces/secrets/#{name}"
37
57
  end
38
58
 
59
+ # Get an org secret
60
+ #
61
+ # @param org [String] A GitHub organization
62
+ # @param name [String] Name of secret
63
+ # @return [Hash] name, created_at, updated_at, and visibility
64
+ # @see https://docs.github.com/en/rest/codespaces/organization-secrets?apiVersion=2022-11-28#get-an-organization-secret
65
+ def get_org_codespaces_secret(org, name)
66
+ get "#{Organization.path org}/codespaces/secrets/#{name}"
67
+ end
68
+
39
69
  # Create or update secrets
40
70
  #
41
71
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -46,6 +76,16 @@ module Octokit
46
76
  put "#{Repository.path repo}/codespaces/secrets/#{name}", options
47
77
  end
48
78
 
79
+ # Create or update org secrets
80
+ #
81
+ # @param org [String] A GitHub organization
82
+ # @param name [String] Name of secret
83
+ # @param options [Hash] encrypted_value and key_id
84
+ # @see https://docs.github.com/en/rest/codespaces/organization-secrets?apiVersion=2022-11-28#create-or-update-an-organization-secret
85
+ def create_or_update_org_codespaces_secret(org, name, options)
86
+ put "#{Organization.path org}/codespaces/secrets/#{name}", options
87
+ end
88
+
49
89
  # Delete a secret
50
90
  #
51
91
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -54,6 +94,15 @@ module Octokit
54
94
  def delete_codespaces_secret(repo, name)
55
95
  boolean_from_response :delete, "#{Repository.path repo}/codespaces/secrets/#{name}"
56
96
  end
97
+
98
+ # Delete an org secret
99
+ #
100
+ # @param org [String] A GitHub organization
101
+ # @param name [String] Name of secret
102
+ # @see https://docs.github.com/en/rest/codespaces/organization-secrets?apiVersion=2022-11-28#delete-an-organization-secret
103
+ def delete_org_codespaces_secret(org, name)
104
+ boolean_from_response :delete, "#{Organization.path org}/codespaces/secrets/#{name}"
105
+ end
57
106
  end
58
107
  end
59
108
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'base64'
4
-
5
3
  module Octokit
6
4
  class Client
7
5
  # Methods for the Repo Contents API
@@ -80,7 +78,7 @@ module Octokit
80
78
  end
81
79
  raise ArgumentError, 'content or :file option required' if content.nil?
82
80
 
83
- options[:content] = Base64.strict_encode64(content)
81
+ options[:content] = [content].pack('m0') # Base64.strict_encode64
84
82
  options[:message] = message
85
83
  url = "#{Repository.path repo}/contents/#{path}"
86
84
  put url, options
@@ -15,6 +15,15 @@ module Octokit
15
15
  get "#{Repository.path repo}/dependabot/secrets/public-key"
16
16
  end
17
17
 
18
+ # Get public key for secrets encryption
19
+ #
20
+ # @param org [String] A GitHub organization
21
+ # @return [Hash] key_id and key
22
+ # @see https://docs.github.com/en/rest/dependabot/organization-secrets?apiVersion=2022-11-28#get-an-organization-public-key
23
+ def get_org_dependabot_public_key(org)
24
+ get "#{Organization.path org}/dependabot/secrets/public-key"
25
+ end
26
+
18
27
  # List secrets
19
28
  #
20
29
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -26,6 +35,17 @@ module Octokit
26
35
  end
27
36
  end
28
37
 
38
+ # List org secrets
39
+ #
40
+ # @param org [String] A GitHub organization
41
+ # @return [Hash] total_count and list of secrets (each item is hash with name, created_at and updated_at)
42
+ # @see https://docs.github.com/en/rest/dependabot/organization-secrets?apiVersion=2022-11-28#list-organization-secrets
43
+ def list_org_dependabot_secrets(org)
44
+ paginate "#{Organization.path org}/dependabot/secrets" do |data, last_response|
45
+ data.secrets.concat last_response.data.secrets
46
+ end
47
+ end
48
+
29
49
  # Get a secret
30
50
  #
31
51
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -36,6 +56,16 @@ module Octokit
36
56
  get "#{Repository.path repo}/dependabot/secrets/#{name}"
37
57
  end
38
58
 
59
+ # Get an org secret
60
+ #
61
+ # @param org [String] A GitHub organization
62
+ # @param name [String] Name of secret
63
+ # @return [Hash] name, created_at, updated_at, and visibility
64
+ # @see https://docs.github.com/en/rest/dependabot/organization-secrets?apiVersion=2022-11-28#get-an-organization-secret
65
+ def get_org_dependabot_secret(org, name)
66
+ get "#{Organization.path org}/dependabot/secrets/#{name}"
67
+ end
68
+
39
69
  # Create or update secrets
40
70
  #
41
71
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -46,6 +76,16 @@ module Octokit
46
76
  put "#{Repository.path repo}/dependabot/secrets/#{name}", options
47
77
  end
48
78
 
79
+ # Create or update org secrets
80
+ #
81
+ # @param org [String] A GitHub organization
82
+ # @param name [String] Name of secret
83
+ # @param options [Hash] encrypted_value and key_id
84
+ # @see https://docs.github.com/en/rest/dependabot/organization-secrets?apiVersion=2022-11-28#create-or-update-an-organization-secret
85
+ def create_or_update_org_dependabot_secret(org, name, options)
86
+ put "#{Organization.path org}/dependabot/secrets/#{name}", options
87
+ end
88
+
49
89
  # Delete a secret
50
90
  #
51
91
  # @param repo [Integer, String, Hash, Repository] A GitHub repository
@@ -54,6 +94,15 @@ module Octokit
54
94
  def delete_dependabot_secret(repo, name)
55
95
  boolean_from_response :delete, "#{Repository.path repo}/dependabot/secrets/#{name}"
56
96
  end
97
+
98
+ # Delete an org secret
99
+ #
100
+ # @param org [String] A GitHub organization
101
+ # @param name [String] Name of secret
102
+ # @see https://docs.github.com/en/rest/dependabot/organization-secrets?apiVersion=2022-11-28#delete-an-organization-secret
103
+ def delete_org_dependabot_secret(org, name)
104
+ boolean_from_response :delete, "#{Organization.path org}/dependabot/secrets/#{name}"
105
+ end
57
106
  end
58
107
  end
59
108
  end
@@ -22,7 +22,7 @@ module Octokit
22
22
  # @return [Array<Sawyer::Resource>] A list of deployments
23
23
  # @see https://developer.github.com/v3/repos/deployments/#list-deployments
24
24
  def deployments(repo, options = {})
25
- get("#{Repository.path repo}/deployments", options)
25
+ paginate("#{Repository.path repo}/deployments", options)
26
26
  end
27
27
  alias list_deployments deployments
28
28
 
@@ -60,7 +60,7 @@ module Octokit
60
60
  # @see https://developer.github.com/v3/repos/deployments/#list-deployment-statuses
61
61
  def deployment_statuses(deployment_url, options = {})
62
62
  deployment = get(deployment_url, accept: options[:accept])
63
- get(deployment.rels[:statuses].href, options)
63
+ paginate(deployment.rels[:statuses].href, options)
64
64
  end
65
65
  alias list_deployment_statuses deployment_statuses
66
66
 
@@ -24,7 +24,10 @@ module Octokit
24
24
  # @return [Sawyer::Resource] Total count of environments and list of environments
25
25
  # @see https://docs.github.com/en/rest/deployments/environments#list-environments
26
26
  def environments(repo, options = {})
27
- get("#{Repository.path repo}/environments", options)
27
+ paginate("#{Repository.path repo}/environments", options) do |data, last_response|
28
+ data.environments.concat last_response.data.environments
29
+ data.total_count += last_response.data.total_count
30
+ end
28
31
  end
29
32
  alias list_environments environments
30
33
 
@@ -65,7 +65,7 @@ module Octokit
65
65
  #
66
66
  # @example
67
67
  # client = Octokit::Client.new(:client_id => 'abcdefg12345', :client_secret => 'secret')
68
- # client.delete_token('deadbeef1234567890deadbeef987654321')
68
+ # client.delete_app_token('deadbeef1234567890deadbeef987654321')
69
69
  def delete_app_token(access_token, options = {})
70
70
  options[:access_token] = access_token
71
71
 
@@ -57,6 +57,33 @@ module Octokit
57
57
  post "#{web_endpoint}login/oauth/access_token", options
58
58
  end
59
59
 
60
+ # Refresh a user's access token with a refresh token.
61
+ #
62
+ # Applications can refresh an access token without requiring a user to re-authorize using refresh access token.
63
+ #
64
+ # @param code [String] 40 character GitHub OAuth refresh access token
65
+ #
66
+ # @return [Sawyer::Resource]
67
+ # @see https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens#refreshing-a-user-access-token-with-a-refresh-token
68
+ #
69
+ # @example
70
+ # client = Octokit::Client.new(:client_id => 'abcdefg12345', :client_secret => 'secret')
71
+ # client.refresh_access_token('40-character-refresh-token')
72
+ def refresh_access_token(code, app_id = client_id, app_secret = client_secret, options = {})
73
+ options = options.merge({
74
+ refresh_token: code,
75
+ client_id: app_id,
76
+ client_secret: app_secret,
77
+ grant_type: 'refresh_token',
78
+ headers: {
79
+ content_type: 'application/json',
80
+ accept: 'application/json'
81
+ }
82
+ })
83
+
84
+ post "#{web_endpoint}login/oauth/access_token", options
85
+ end
86
+
60
87
  # Validate user username and password
61
88
  #
62
89
  # @param options [Hash] User credentials
@@ -50,7 +50,6 @@ require 'octokit/client/objects'
50
50
  require 'octokit/client/organizations'
51
51
  require 'octokit/client/pages'
52
52
  require 'octokit/client/projects'
53
- require 'octokit/client/pub_sub_hubbub'
54
53
  require 'octokit/client/pull_requests'
55
54
  require 'octokit/client/rate_limit'
56
55
  require 'octokit/client/reactions'
@@ -118,7 +117,6 @@ module Octokit
118
117
  include Octokit::Client::Organizations
119
118
  include Octokit::Client::Pages
120
119
  include Octokit::Client::Projects
121
- include Octokit::Client::PubSubHubbub
122
120
  include Octokit::Client::PullRequests
123
121
  include Octokit::Client::RateLimit
124
122
  include Octokit::Client::Reactions
@@ -32,6 +32,12 @@ module Octokit
32
32
  # @return [String] An admin password set up for your GitHub Enterprise management console
33
33
  # @!attribute management_console_endpoint
34
34
  # @return [String] Base URL for API requests to the GitHub Enterprise management console
35
+ # @!attribute manage_ghes_endpoint
36
+ # @return [String] Base URL for API requests to the GitHub Enterprise Server Manage API
37
+ # @!attribute manage_ghes_username
38
+ # @return [String] API username for requests to the GitHub Enterprise Server Manage API
39
+ # @!attribute manage_ghes_password
40
+ # @return [String] API user password for requests to the GitHub Enterprise Server Manage API
35
41
  # @!attribute middleware
36
42
  # @see https://github.com/lostisland/faraday
37
43
  # @return [Faraday::Builder or Faraday::RackBuilder] Configure middleware for Faraday
@@ -59,7 +65,10 @@ module Octokit
59
65
  :middleware, :netrc, :netrc_file,
60
66
  :per_page, :proxy, :ssl_verify_mode, :user_agent
61
67
  attr_writer :password, :web_endpoint, :api_endpoint, :login,
62
- :management_console_endpoint, :management_console_password
68
+ :management_console_endpoint, :management_console_password,
69
+ :manage_ghes_endpoint,
70
+ :manage_ghes_username,
71
+ :manage_ghes_password
63
72
 
64
73
  class << self
65
74
  # List of configurable keys for {Octokit::Client}
@@ -77,6 +86,9 @@ module Octokit
77
86
  login
78
87
  management_console_endpoint
79
88
  management_console_password
89
+ manage_ghes_endpoint
90
+ manage_ghes_username
91
+ manage_ghes_password
80
92
  middleware
81
93
  netrc
82
94
  netrc_file
@@ -126,6 +138,10 @@ module Octokit
126
138
  File.join(@management_console_endpoint, '')
127
139
  end
128
140
 
141
+ def manage_ghes_endpoint
142
+ File.join(@manage_ghes_endpoint, '')
143
+ end
144
+
129
145
  # Base URL for generated web URLs
130
146
  #
131
147
  # @return [String] Default: https://github.com/
@@ -12,6 +12,11 @@ if Gem::Version.new(Faraday::VERSION) >= Gem::Version.new('2.0')
12
12
  rescue LoadError
13
13
  Octokit::Warnable.octokit_warn 'To use retry middleware with Faraday v2.0+, install `faraday-retry` gem'
14
14
  end
15
+ begin
16
+ require 'faraday/multipart'
17
+ rescue LoadError
18
+ Octokit::Warnable.octokit_warn 'To use multipart middleware with Faraday v2.0+, install `faraday-multipart` gem; note: this is used by the ManageGHES client for uploading licenses'
19
+ end
15
20
  end
16
21
 
17
22
  module Octokit
@@ -102,6 +107,24 @@ module Octokit
102
107
  ENV.fetch('OCTOKIT_ENTERPRISE_MANAGEMENT_CONSOLE_ENDPOINT', nil)
103
108
  end
104
109
 
110
+ # Default GHES Manage API endpoint from ENV
111
+ # @return [String]
112
+ def manage_ghes_endpoint
113
+ ENV.fetch('OCTOKIT_MANAGE_GHES_ENDPOINT', nil)
114
+ end
115
+
116
+ # Default GHES Manage API username from ENV
117
+ # @return [String]
118
+ def manage_ghes_username
119
+ ENV.fetch('OCTOKIT_MANAGE_GHES_USERNAME', nil)
120
+ end
121
+
122
+ # Default GHES Manage API password from ENV
123
+ # @return [String]
124
+ def manage_ghes_password
125
+ ENV.fetch('OCTOKIT_MANAGE_GHES_PASSWORD', nil)
126
+ end
127
+
105
128
  # Default options for Faraday::Connection
106
129
  # @return [Hash]
107
130
  def connection_options
@@ -14,6 +14,7 @@ module Octokit
14
14
  # @see https://docs.github.com/en/enterprise-server@3.4/rest/enterprise-admin/management-console#create-a-github-license
15
15
  # @return nil
16
16
  def upload_license(license, settings = nil)
17
+ octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.')
17
18
  conn = faraday_configuration
18
19
 
19
20
  params = {}
@@ -28,6 +29,7 @@ module Octokit
28
29
  #
29
30
  # @return nil
30
31
  def start_configuration
32
+ octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.')
31
33
  post '/setup/api/configure', password_hash
32
34
  end
33
35
 
@@ -37,6 +39,7 @@ module Octokit
37
39
  #
38
40
  # @return nil
39
41
  def upgrade(license)
42
+ octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.')
40
43
  conn = faraday_configuration
41
44
 
42
45
  params = {}
@@ -49,6 +52,7 @@ module Octokit
49
52
  #
50
53
  # @return [Sawyer::Resource] The installation information
51
54
  def config_status
55
+ octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.')
52
56
  get '/setup/api/configcheck', password_hash
53
57
  end
54
58
  alias config_check config_status
@@ -57,6 +61,7 @@ module Octokit
57
61
  #
58
62
  # @return [Sawyer::Resource] The settings
59
63
  def settings
64
+ octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.')
60
65
  get '/setup/api/settings', password_hash
61
66
  end
62
67
  alias get_settings settings
@@ -67,6 +72,7 @@ module Octokit
67
72
  #
68
73
  # @return [nil]
69
74
  def edit_settings(settings)
75
+ octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.')
70
76
  queries = password_hash
71
77
  queries[:query][:settings] = settings.to_json.to_s
72
78
  put '/setup/api/settings', queries
@@ -76,6 +82,7 @@ module Octokit
76
82
  #
77
83
  # @return [Sawyer::Resource] The maintenance status
78
84
  def maintenance_status
85
+ octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.')
79
86
  get '/setup/api/maintenance', password_hash
80
87
  end
81
88
  alias get_maintenance_status maintenance_status
@@ -85,6 +92,7 @@ module Octokit
85
92
  # @param maintenance [Hash] A hash configuration of the maintenance settings
86
93
  # @return [nil]
87
94
  def set_maintenance_status(maintenance)
95
+ octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.')
88
96
  queries = password_hash
89
97
  queries[:query][:maintenance] = maintenance.to_json.to_s
90
98
  post '/setup/api/maintenance', queries
@@ -95,6 +103,7 @@ module Octokit
95
103
  #
96
104
  # @return [Sawyer::Resource] An array of authorized SSH keys
97
105
  def authorized_keys
106
+ octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.')
98
107
  get '/setup/api/settings/authorized-keys', password_hash
99
108
  end
100
109
  alias get_authorized_keys authorized_keys
@@ -104,6 +113,7 @@ module Octokit
104
113
  # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself
105
114
  # @return [Sawyer::Resource] An array of authorized SSH keys
106
115
  def add_authorized_key(key)
116
+ octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.')
107
117
  queries = password_hash
108
118
  case key
109
119
  when String
@@ -128,6 +138,7 @@ module Octokit
128
138
  # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself
129
139
  # @return [Sawyer::Resource] An array of authorized SSH keys
130
140
  def remove_authorized_key(key)
141
+ octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.')
131
142
  queries = password_hash
132
143
  case key
133
144
  when String
data/lib/octokit/error.rb CHANGED
@@ -10,6 +10,7 @@ module Octokit
10
10
  #
11
11
  # @param [Hash] response HTTP response
12
12
  # @return [Octokit::Error]
13
+ # rubocop:disable Metrics/CyclomaticComplexity
13
14
  def self.from_response(response)
14
15
  status = response[:status].to_i
15
16
  body = response[:body].to_s
@@ -23,6 +24,7 @@ module Octokit
23
24
  when 405 then Octokit::MethodNotAllowed
24
25
  when 406 then Octokit::NotAcceptable
25
26
  when 409 then Octokit::Conflict
27
+ when 410 then Octokit::Deprecated
26
28
  when 415 then Octokit::UnsupportedMediaType
27
29
  when 422 then error_for_422(body)
28
30
  when 451 then Octokit::UnavailableForLegalReasons
@@ -36,6 +38,7 @@ module Octokit
36
38
  klass.new(response)
37
39
  end
38
40
  end
41
+ # rubocop:enable Metrics/CyclomaticComplexity
39
42
 
40
43
  def build_error_context
41
44
  if RATE_LIMITED_ERRORS.include?(self.class)
@@ -317,6 +320,9 @@ module Octokit
317
320
  # Raised when GitHub returns a 409 HTTP status code
318
321
  class Conflict < ClientError; end
319
322
 
323
+ # Raised when GHES Manage return a 410 HTTP status code
324
+ class Deprecated < ClientError; end
325
+
320
326
  # Raised when GitHub returns a 414 HTTP status code
321
327
  class UnsupportedMediaType < ClientError; end
322
328
 
@@ -0,0 +1,171 @@
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
+ conn.request :multipart
40
+ params = {}
41
+ params[:license] = Faraday::FilePart.new(license, 'binary')
42
+ params[:password] = @manage_ghes_password
43
+ @last_response = conn.post('/manage/v1/config/init', params, { 'Content-Type' => 'multipart/form-data' })
44
+ end
45
+
46
+ # Start a configuration process.
47
+ #
48
+ # @return [nil]
49
+ def start_configuration
50
+ conn = authenticated_client
51
+ @last_response = conn.post('/manage/v1/config/apply')
52
+ end
53
+
54
+ # Get information about the Enterprise installation
55
+ #
56
+ # @return [nil]
57
+ def config_status
58
+ conn = authenticated_client
59
+ @last_response = conn.get('/manage/v1/config/apply')
60
+ end
61
+ alias config_check config_status
62
+
63
+ # Get information about the Enterprise installation
64
+ #
65
+ # @return [nil]
66
+ def settings
67
+ conn = authenticated_client
68
+ @last_response = conn.get('/manage/v1/config/settings')
69
+ end
70
+ alias get_settings settings
71
+
72
+ # Modify the Enterprise settings
73
+ #
74
+ # @param settings [Hash] A hash configuration of the new settings
75
+ #
76
+ # @return [nil]
77
+ def edit_settings(settings)
78
+ conn = authenticated_client
79
+ @last_response = conn.put('/manage/v1/config/settings', settings.to_json.to_s)
80
+ end
81
+
82
+ def authorized_keys
83
+ conn = authenticated_client
84
+ @last_response = conn.get('/manage/v1/access/ssh')
85
+ end
86
+ alias get_authorized_keys authorized_keys
87
+
88
+ # Add an authorized SSH keys on the Enterprise install
89
+ #
90
+ # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself
91
+ # @return [nil]
92
+ def add_authorized_key(key)
93
+ conn = authenticated_client
94
+ case key
95
+ when String
96
+ if File.exist?(key)
97
+ key = File.open(key, 'r')
98
+ content = key.read.strip
99
+ key.close
100
+ else
101
+ content = key
102
+ end
103
+ when File
104
+ content = key.read.strip
105
+ key.close
106
+ end
107
+
108
+ queries = {}
109
+ queries[:key] = content
110
+ @last_response = conn.post('/manage/v1/access/ssh', queries)
111
+ end
112
+
113
+ # Removes an authorized SSH keys from the Enterprise install
114
+ #
115
+ # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself
116
+ # @return [nil]
117
+ def remove_authorized_key(key)
118
+ conn = authenticated_client
119
+ case key
120
+ when String
121
+ if File.exist?(key)
122
+ key = File.open(key, 'r')
123
+ content = key.read.strip
124
+ key.close
125
+ else
126
+ content = key
127
+ end
128
+ when File
129
+ content = key.read.strip
130
+ key.close
131
+ end
132
+
133
+ queries = {}
134
+ queries[:key] = content
135
+ @last_response = conn.run_request(:delete, '/manage/v1/access/ssh', queries, nil)
136
+ end
137
+ alias delete_authorized_key remove_authorized_key
138
+
139
+ private
140
+
141
+ def basic_authenticated?
142
+ !!(@manage_ghes_username && @manage_ghes_password)
143
+ end
144
+
145
+ # If no username is provided, we assume root site admin should be used
146
+ def root_site_admin_assumed?
147
+ !@manage_ghes_username
148
+ end
149
+
150
+ def authenticated_client
151
+ @authenticated_client ||= Faraday.new(url: @manage_ghes_endpoint) do |c|
152
+ c.headers[:user_agent] = user_agent
153
+ c.request :json
154
+ c.response :json
155
+ c.adapter Faraday.default_adapter
156
+
157
+ if root_site_admin_assumed?
158
+ username = 'api_key'
159
+ elsif basic_authenticated?
160
+ username = @manage_ghes_username
161
+ end
162
+ c.request(*FARADAY_BASIC_AUTH_KEYS, username, @manage_ghes_password)
163
+
164
+ # Disabling SSL is essential for certain self-hosted Enterprise instances
165
+ c.ssl[:verify] = false if connection_options[:ssl] && !connection_options[:ssl][:verify]
166
+
167
+ c.use Octokit::Response::RaiseError
168
+ end
169
+ end
170
+ end
171
+ 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
@@ -15,7 +15,7 @@ module Octokit
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
@@ -9,7 +9,7 @@ module Octokit
9
9
  attr_reader :repo
10
10
 
11
11
  def initialize(args)
12
- arguments = super(args)
12
+ arguments = super
13
13
  @repo = arguments.shift
14
14
 
15
15
  arguments
@@ -3,7 +3,7 @@
3
3
  module Octokit
4
4
  # Current major release.
5
5
  # @return [Integer]
6
- MAJOR = 8
6
+ MAJOR = 9
7
7
 
8
8
  # Current minor release.
9
9
  # @return [Integer]
data/lib/octokit.rb CHANGED
@@ -4,6 +4,7 @@ require 'octokit/default'
4
4
  require 'octokit/client'
5
5
  require 'octokit/enterprise_admin_client'
6
6
  require 'octokit/enterprise_management_console_client'
7
+ require 'octokit/manage_ghes_client'
7
8
 
8
9
  # Ruby toolkit for the GitHub API
9
10
  module Octokit
@@ -41,12 +42,24 @@ module Octokit
41
42
  @enterprise_management_console_client = Octokit::EnterpriseManagementConsoleClient.new(options)
42
43
  end
43
44
 
45
+ # ManageGHESClient client based on configured options {Configurable}
46
+ #
47
+ # @return [Octokit::ManageGHESClient] API wrapper
48
+ def manage_ghes_client
49
+ if defined?(@manage_ghes_client) && @manage_ghes_client.same_options?(options)
50
+ return @manage_ghes_client
51
+ end
52
+
53
+ @manage_ghes_client = Octokit::ManageGHESClient.new(options)
54
+ end
55
+
44
56
  private
45
57
 
46
58
  def respond_to_missing?(method_name, include_private = false)
47
59
  client.respond_to?(method_name, include_private) ||
48
60
  enterprise_admin_client.respond_to?(method_name, include_private) ||
49
- enterprise_management_console_client.respond_to?(method_name, include_private)
61
+ enterprise_management_console_client.respond_to?(method_name, include_private) ||
62
+ manage_ghes_client.respond_to?(method_name, include_private)
50
63
  end
51
64
 
52
65
  def method_missing(method_name, *args, &block)
@@ -56,6 +69,8 @@ module Octokit
56
69
  return enterprise_admin_client.send(method_name, *args, &block)
57
70
  elsif enterprise_management_console_client.respond_to?(method_name)
58
71
  return enterprise_management_console_client.send(method_name, *args, &block)
72
+ elsif manage_ghes_client.respond_to?(method_name)
73
+ return manage_ghes_client.send(method_name, *args, &block)
59
74
  end
60
75
 
61
76
  super
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: octokit
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.0
4
+ version: 9.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wynn Netherland
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-10-30 00:00:00.000000000 Z
13
+ date: 2024-06-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: faraday
@@ -104,7 +104,6 @@ files:
104
104
  - lib/octokit/client/organizations.rb
105
105
  - lib/octokit/client/pages.rb
106
106
  - lib/octokit/client/projects.rb
107
- - lib/octokit/client/pub_sub_hubbub.rb
108
107
  - lib/octokit/client/pull_requests.rb
109
108
  - lib/octokit/client/rate_limit.rb
110
109
  - lib/octokit/client/reactions.rb
@@ -135,6 +134,8 @@ files:
135
134
  - lib/octokit/enterprise_management_console_client/management_console.rb
136
135
  - lib/octokit/error.rb
137
136
  - lib/octokit/gist.rb
137
+ - lib/octokit/manage_ghes_client.rb
138
+ - lib/octokit/manage_ghes_client/manage_ghes.rb
138
139
  - lib/octokit/middleware/follow_redirects.rb
139
140
  - lib/octokit/organization.rb
140
141
  - lib/octokit/rate_limit.rb
@@ -167,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
168
  - !ruby/object:Gem::Version
168
169
  version: 1.3.5
169
170
  requirements: []
170
- rubygems_version: 3.4.0.dev
171
+ rubygems_version: 3.4.20
171
172
  signing_key:
172
173
  specification_version: 4
173
174
  summary: Ruby toolkit for working with the GitHub API
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Octokit
4
- class Client
5
- # Methods for the PubSubHubbub API
6
- #
7
- # @see https://developer.github.com/v3/repos/hooks/#pubsubhubbub
8
- module PubSubHubbub
9
- # Subscribe to a pubsub topic
10
- #
11
- # @param topic [String] A recoginized and supported pubsub topic
12
- # @param callback [String] A callback url to be posted to when the topic event is fired
13
- # @param secret [String] An optional shared secret used to generate a SHA1 HMAC of the outgoing body content
14
- # @return [Boolean] true if the subscribe was successful, otherwise an error is raised
15
- # @see https://developer.github.com/v3/repos/hooks/#subscribing
16
- # @example Subscribe to push events from one of your repositories, having an email sent when fired
17
- # client = Octokit::Client.new(:oauth_token = "token")
18
- # client.subscribe("https://github.com/joshk/devise_imapable/events/push", "github://Email?address=josh.kalderimis@gmail.com")
19
- def subscribe(topic, callback, secret = nil)
20
- options = {
21
- 'hub.callback': callback,
22
- 'hub.mode': 'subscribe',
23
- 'hub.topic': topic
24
- }
25
- options.merge!('hub.secret': secret) unless secret.nil?
26
-
27
- response = pub_sub_hubbub_request(options)
28
-
29
- response.status == 204
30
- end
31
-
32
- # Unsubscribe from a pubsub topic
33
- #
34
- # @param topic [String] A recoginized pubsub topic
35
- # @param callback [String] A callback url to be unsubscribed from
36
- # @return [Boolean] true if the unsubscribe was successful, otherwise an error is raised
37
- # @see https://developer.github.com/v3/repos/hooks/#subscribing
38
- # @example Unsubscribe to push events from one of your repositories, no longer having an email sent when fired
39
- # client = Octokit::Client.new(:oauth_token = "token")
40
- # client.unsubscribe("https://github.com/joshk/devise_imapable/events/push", "github://Email?address=josh.kalderimis@gmail.com")
41
- def unsubscribe(topic, callback)
42
- options = {
43
- 'hub.callback': callback,
44
- 'hub.mode': 'unsubscribe',
45
- 'hub.topic': topic
46
- }
47
- response = pub_sub_hubbub_request(options)
48
-
49
- response.status == 204
50
- end
51
-
52
- # Subscribe to a repository through pubsub
53
- #
54
- # @param repo [String, Repository, Hash] A GitHub repository
55
- # @param service_name [String] service name owner
56
- # @param service_arguments [Hash] params that will be passed by subscribed hook.
57
- # List of services is available @ https://github.com/github/github-services/tree/master/docs.
58
- # Please refer Data node for complete list of arguments.
59
- # @param secret [String] An optional shared secret used to generate a SHA1 HMAC of the outgoing body content
60
- # @return [Boolean] True if subscription successful, false otherwise
61
- # @see https://developer.github.com/v3/repos/hooks/#subscribing
62
- # @example Subscribe to push events to one of your repositories to Travis-CI
63
- # client = Octokit::Client.new(:oauth_token = "token")
64
- # client.subscribe_service_hook('joshk/device_imapable', 'Travis', { :token => "test", :domain => "domain", :user => "user" })
65
- def subscribe_service_hook(repo, service_name, service_arguments = {}, secret = nil)
66
- topic = "#{Octokit.web_endpoint}#{Repository.new(repo)}/events/push"
67
- callback = "github://#{service_name}?#{service_arguments.collect { |k, v| [k, v].map { |p| URI.encode_www_form_component(p) }.join('=') }.join('&')}"
68
- subscribe(topic, callback, secret)
69
- end
70
-
71
- # Unsubscribe repository through pubsub
72
- #
73
- # @param repo [String, Repository, Hash] A GitHub repository
74
- # @param service_name [String] service name owner
75
- # List of services is available @ https://github.com/github/github-services/tree/master/docs.
76
- # @see https://developer.github.com/v3/repos/hooks/#subscribing
77
- # @example Subscribe to push events to one of your repositories to Travis-CI
78
- # client = Octokit::Client.new(:oauth_token = "token")
79
- # client.unsubscribe_service_hook('joshk/device_imapable', 'Travis')
80
- def unsubscribe_service_hook(repo, service_name)
81
- topic = "#{Octokit.web_endpoint}#{Repository.new(repo)}/events/push"
82
- callback = "github://#{service_name}"
83
- unsubscribe(topic, callback)
84
- end
85
-
86
- private
87
-
88
- def pub_sub_hubbub_request(options = {})
89
- # This method is janky, bypass normal stack so we don't
90
- # serialize request as JSON
91
- conn = Faraday.new(url: @api_endpoint) do |http|
92
- http.headers[:user_agent] = user_agent
93
- if basic_authenticated?
94
- http.request(*FARADAY_BASIC_AUTH_KEYS, @login, @password)
95
- elsif token_authenticated?
96
- http.request :authorization, 'token', @access_token
97
- end
98
- http.request :url_encoded
99
- http.use Octokit::Response::RaiseError
100
- http.adapter Faraday.default_adapter
101
- end
102
-
103
- conn.post do |req|
104
- req.url 'hub'
105
- req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
106
- req.body = options
107
- end
108
- end
109
- end
110
- end
111
- end