octokit 2.0.0 → 2.1.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.
- data/README.md +3 -2
- data/lib/octokit/client/authorizations.rb +15 -1
- data/lib/octokit/client/users.rb +5 -1
- data/lib/octokit/configurable.rb +5 -0
- data/lib/octokit/error.rb +23 -3
- data/lib/octokit/version.rb +1 -1
- data/spec/cassettes/Octokit_Client_Authorizations/_create_authorization/with_idempotent_true/creates_a_new_authorization_with_options.json +1 -0
- data/spec/cassettes/Octokit_Client_Authorizations/_create_authorization/with_idempotent_true/returns_an_existing_API_authorization_if_one_already_exists.json +1 -0
- data/spec/cassettes/Octokit_Client_Authorizations/_create_authorization/without_idempotent_true/creates_a_new_API_authorization_each_time.json +1 -0
- data/spec/cassettes/Octokit_Client_Authorizations/_create_authorization/{creates_a_new_authorization_with_options.json → without_idempotent_true/creates_a_new_authorization_with_options.json} +0 -0
- data/spec/cassettes/Octokit_Client_Authorizations/_create_authorization/{creates_an_API_authorization.json → without_idempotent_true/creates_an_API_authorization.json} +0 -0
- data/spec/helper.rb +14 -0
- data/spec/octokit/client/authorizations_spec.rb +47 -11
- data/spec/octokit/client/users_spec.rb +7 -4
- data/spec/octokit/client_spec.rb +30 -0
- metadata +12 -6
data/README.md
CHANGED
@@ -43,8 +43,8 @@ configuration) or as client instance methods.
|
|
43
43
|
```ruby
|
44
44
|
# Provide authentication credentials
|
45
45
|
Octokit.configure do |c|
|
46
|
-
c.login 'defunkt'
|
47
|
-
c.password 'c0d3b4ssssss!'
|
46
|
+
c.login = 'defunkt'
|
47
|
+
c.password = 'c0d3b4ssssss!'
|
48
48
|
end
|
49
49
|
|
50
50
|
# Fetch the current user
|
@@ -297,6 +297,7 @@ client instances based on unique configuration options. Breaking changes also
|
|
297
297
|
include:
|
298
298
|
|
299
299
|
* `:oauth_token` is now `:access_token`
|
300
|
+
* `:auto_traversal` is now `:auto_paginate`
|
300
301
|
* `Hashie::Mash` has been removed. Responses now return a `Sawyer::Resource`
|
301
302
|
object. This new type behaves mostly like a Ruby `Hash`, but does not fully
|
302
303
|
support the `Hashie::Mash` API.
|
@@ -45,6 +45,9 @@ module Octokit
|
|
45
45
|
# @option options [Array] :scopes A list of scopes that this authorization is in.
|
46
46
|
# @option options [String] :note A note to remind you what the OAuth token is for.
|
47
47
|
# @option options [String] :note_url A URL to remind you what app the OAuth token is for.
|
48
|
+
# @option options [Boolean] :idempotent If true, will return an existing authorization if one has already been created.
|
49
|
+
# @option options [String] :client_id Client Id we received when our application was registered with GitHub.
|
50
|
+
# @option options [String] :client_id Client Secret we received when our application was registered with GitHub.
|
48
51
|
#
|
49
52
|
# @return [Sawyer::Resource] A single authorization for the authenticated user
|
50
53
|
# @see http://developer.github.com/v3/oauth/#scopes Available scopes
|
@@ -52,10 +55,21 @@ module Octokit
|
|
52
55
|
# @example Create a new authorization for user ctshryock's project Zoidberg
|
53
56
|
# client = Octokit::Client.new(:login => 'ctshryock', :password => 'secret')
|
54
57
|
# client.create_authorization({:scopes => ["public_repo","gist"], :note => "Why not Zoidberg?", :note_url=> "https://en.wikipedia.org/wiki/Zoidberg"})
|
58
|
+
# @example Create a new OR return an existing authorization to be used by a specific client for user ctshryock's project Zoidberg
|
59
|
+
# client = Octokit::Client.new(:login => 'ctshryock', :password => 'secret')
|
60
|
+
# client.create_authorization({:idempotent => true, :client_id => 'xxxx', :client_secret => 'yyyy', :scopes => ["user"]})
|
55
61
|
def create_authorization(options = {})
|
56
62
|
# Techincally we can omit scopes as GitHub has a default, however the
|
57
63
|
# API will reject us if we send a POST request with an empty body.
|
58
|
-
|
64
|
+
|
65
|
+
if options.delete :idempotent
|
66
|
+
client_id, client_secret = fetch_client_id_and_secret(options)
|
67
|
+
raise ArgumentError.new("Client ID and Secret required for idempotent authorizations") unless client_id && client_secret
|
68
|
+
|
69
|
+
put "authorizations/clients/#{client_id}", options.merge(:client_secret => client_secret)
|
70
|
+
else
|
71
|
+
post 'authorizations', options
|
72
|
+
end
|
59
73
|
end
|
60
74
|
|
61
75
|
# Update an authorization for the authenticated user.
|
data/lib/octokit/client/users.rb
CHANGED
@@ -50,7 +50,11 @@ module Octokit
|
|
50
50
|
options.merge!({
|
51
51
|
:code => code,
|
52
52
|
:client_id => app_id,
|
53
|
-
:client_secret => app_secret
|
53
|
+
:client_secret => app_secret,
|
54
|
+
:headers => {
|
55
|
+
:content_type => 'application/json',
|
56
|
+
:accept => 'application/json'
|
57
|
+
}
|
54
58
|
})
|
55
59
|
post "#{web_endpoint}login/oauth/access_token", options
|
56
60
|
end
|
data/lib/octokit/configurable.rb
CHANGED
@@ -115,5 +115,10 @@ module Octokit
|
|
115
115
|
def options
|
116
116
|
Hash[Octokit::Configurable.keys.map{|key| [key, instance_variable_get(:"@#{key}")]}]
|
117
117
|
end
|
118
|
+
|
119
|
+
def fetch_client_id_and_secret(overrides = {})
|
120
|
+
opts = options.merge(overrides)
|
121
|
+
opts.values_at :client_id, :client_secret
|
122
|
+
end
|
118
123
|
end
|
119
124
|
end
|
data/lib/octokit/error.rb
CHANGED
@@ -8,12 +8,18 @@ module Octokit
|
|
8
8
|
# @param [Hash] response HTTP response
|
9
9
|
# @return [Octokit::Error]
|
10
10
|
def self.from_response(response)
|
11
|
-
status
|
12
|
-
body
|
11
|
+
status = response[:status].to_i
|
12
|
+
body = response[:body].to_s
|
13
|
+
headers = response[:response_headers]
|
13
14
|
|
14
15
|
if klass = case status
|
15
16
|
when 400 then Octokit::BadRequest
|
16
|
-
when 401
|
17
|
+
when 401
|
18
|
+
if Octokit::OneTimePasswordRequired.required_header(headers)
|
19
|
+
Octokit::OneTimePasswordRequired
|
20
|
+
else
|
21
|
+
Octokit::Unauthorized
|
22
|
+
end
|
17
23
|
when 403
|
18
24
|
if body =~ /rate limit exceeded/i
|
19
25
|
Octokit::TooManyRequests
|
@@ -100,6 +106,20 @@ module Octokit
|
|
100
106
|
# Raised when GitHub returns a 401 HTTP status code
|
101
107
|
class Unauthorized < Error; end
|
102
108
|
|
109
|
+
# Raised when GitHub returns a 401 HTTP status code
|
110
|
+
# and headers include "X-GitHub-OTP"
|
111
|
+
class OneTimePasswordRequired < Error
|
112
|
+
HEADER = /required; (?<delivery>\w+)/i
|
113
|
+
|
114
|
+
def self.required_header(headers)
|
115
|
+
HEADER.match headers['X-GitHub-OTP'].to_s
|
116
|
+
end
|
117
|
+
|
118
|
+
def password_delivery
|
119
|
+
@password_delivery ||= self.class.required_header(@response[:response_headers])[:delivery]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
103
123
|
# Raised when GitHub returns a 403 HTTP status code
|
104
124
|
class Forbidden < Error; end
|
105
125
|
|
data/lib/octokit/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
{"http_interactions":[{"request":{"method":"put","uri":"https://<GITHUB_LOGIN>:<GITHUB_PASSWORD>@api.github.com/authorizations/clients/<GITHUB_CLIENT_ID>","body":{"encoding":"UTF-8","base64_string":"eyJjbGllbnRfaWQiOiI8R0lUSFVCX0NMSUVOVF9JRD4iLCJjbGllbnRfc2Vj\ncmV0IjoiPEdJVEhVQl9DTElFTlRfU0VDUkVUPiIsInNjb3BlcyI6WyJnaXN0\nIl19\n"},"headers":{"Accept":["application/vnd.github.beta+json"],"User-Agent":["Octokit Ruby Gem 2.0.0"]}},"response":{"status":{"code":201,"message":"Created"},"headers":{"Server":["GitHub.com"],"Date":["Thu, 29 Aug 2013 19:36:24 GMT"],"Content-Type":["application/json; charset=utf-8"],"Status":["201 Created"],"X-Ratelimit-Limit":["5000"],"X-Ratelimit-Remaining":["4991"],"X-Ratelimit-Reset":["1377808149"],"Location":["https://api.github.com/authorizations/3459491"],"X-Github-Media-Type":["github.beta; format=json"],"X-Content-Type-Options":["nosniff"],"Content-Length":["336"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Expose-Headers":["ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes"],"Access-Control-Allow-Origin":["*"],"Etag":["\"123a8d275487ebdcf01ff056e6a7e178\""],"Cache-Control":["max-age=0, private, must-revalidate"],"X-Github-Request-Id":["0eac2c58-1f44-4ee3-b754-12409a31bad8"]},"body":{"encoding":"US-ASCII","base64_string":"eyJpZCI6MzQ1OTQ5MSwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9h\ndXRob3JpemF0aW9ucy8zNDU5NDkxIiwiYXBwIjp7Im5hbWUiOiJPY3Rva2l0\nIERldmVsb3BtZW50IiwidXJsIjoiaHR0cDovL29jdG9raXQuZGV2IiwiY2xp\nZW50X2lkIjoiPEdJVEhVQl9DTElFTlRfSUQ+In0sInRva2VuIjoiNjFhZmNi\nZDM0YmY2NTIyOWU5MDJiMTBiNGYwNGE0NWRkMGJhODI1NSIsIm5vdGUiOm51\nbGwsIm5vdGVfdXJsIjpudWxsLCJjcmVhdGVkX2F0IjoiMjAxMy0wOC0yOVQx\nOTozNjoyNFoiLCJ1cGRhdGVkX2F0IjoiMjAxMy0wOC0yOVQxOTozNjoyNFoi\nLCJzY29wZXMiOlsiZ2lzdCJdfQ==\n"},"http_version":null},"recorded_at":"Thu, 29 Aug 2013 19:36:24 GMT"}],"recorded_with":"VCR 2.4.0"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"http_interactions":[{"request":{"method":"put","uri":"https://<GITHUB_LOGIN>:<GITHUB_PASSWORD>@api.github.com/authorizations/clients/<GITHUB_CLIENT_ID>","body":{"encoding":"UTF-8","base64_string":"eyJjbGllbnRfaWQiOiI8R0lUSFVCX0NMSUVOVF9JRD4iLCJjbGllbnRfc2Vj\ncmV0IjoiPEdJVEhVQl9DTElFTlRfU0VDUkVUPiJ9\n"},"headers":{"Accept":["application/vnd.github.beta+json"],"User-Agent":["Octokit Ruby Gem 2.0.0"]}},"response":{"status":{"code":200,"message":"OK"},"headers":{"Server":["GitHub.com"],"Date":["Thu, 29 Aug 2013 19:36:24 GMT"],"Content-Type":["application/json; charset=utf-8"],"Status":["200 OK"],"X-Ratelimit-Limit":["5000"],"X-Ratelimit-Remaining":["4990"],"X-Ratelimit-Reset":["1377808149"],"X-Github-Media-Type":["github.beta; format=json"],"X-Content-Type-Options":["nosniff"],"Content-Length":["336"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Expose-Headers":["ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes"],"Access-Control-Allow-Origin":["*"],"Etag":["\"123a8d275487ebdcf01ff056e6a7e178\""],"Cache-Control":["max-age=0, private, must-revalidate"],"X-Github-Request-Id":["9e4afd9a-8f33-47a8-a0cd-8601d1779724"],"Vary":["Accept-Encoding"]},"body":{"encoding":"US-ASCII","base64_string":"eyJpZCI6MzQ1OTQ5MSwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9h\ndXRob3JpemF0aW9ucy8zNDU5NDkxIiwiYXBwIjp7Im5hbWUiOiJPY3Rva2l0\nIERldmVsb3BtZW50IiwidXJsIjoiaHR0cDovL29jdG9raXQuZGV2IiwiY2xp\nZW50X2lkIjoiPEdJVEhVQl9DTElFTlRfSUQ+In0sInRva2VuIjoiNjFhZmNi\nZDM0YmY2NTIyOWU5MDJiMTBiNGYwNGE0NWRkMGJhODI1NSIsIm5vdGUiOm51\nbGwsIm5vdGVfdXJsIjpudWxsLCJjcmVhdGVkX2F0IjoiMjAxMy0wOC0yOVQx\nOTozNjoyNFoiLCJ1cGRhdGVkX2F0IjoiMjAxMy0wOC0yOVQxOTozNjoyNFoi\nLCJzY29wZXMiOlsiZ2lzdCJdfQ==\n"},"http_version":null},"recorded_at":"Thu, 29 Aug 2013 19:36:24 GMT"},{"request":{"method":"put","uri":"https://<GITHUB_LOGIN>:<GITHUB_PASSWORD>@api.github.com/authorizations/clients/<GITHUB_CLIENT_ID>","body":{"encoding":"UTF-8","base64_string":"eyJjbGllbnRfaWQiOiI8R0lUSFVCX0NMSUVOVF9JRD4iLCJjbGllbnRfc2Vj\ncmV0IjoiPEdJVEhVQl9DTElFTlRfU0VDUkVUPiJ9\n"},"headers":{"Accept":["application/vnd.github.beta+json"],"User-Agent":["Octokit Ruby Gem 2.0.0"]}},"response":{"status":{"code":200,"message":"OK"},"headers":{"Server":["GitHub.com"],"Date":["Thu, 29 Aug 2013 19:36:24 GMT"],"Content-Type":["application/json; charset=utf-8"],"Status":["200 OK"],"X-Ratelimit-Limit":["5000"],"X-Ratelimit-Remaining":["4989"],"X-Ratelimit-Reset":["1377808149"],"X-Github-Media-Type":["github.beta; format=json"],"X-Content-Type-Options":["nosniff"],"Content-Length":["336"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Expose-Headers":["ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes"],"Access-Control-Allow-Origin":["*"],"Etag":["\"123a8d275487ebdcf01ff056e6a7e178\""],"Cache-Control":["max-age=0, private, must-revalidate"],"X-Github-Request-Id":["0132512e-b1c7-41f0-b662-e3cdb67abd92"],"Vary":["Accept-Encoding"]},"body":{"encoding":"US-ASCII","base64_string":"eyJpZCI6MzQ1OTQ5MSwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9h\ndXRob3JpemF0aW9ucy8zNDU5NDkxIiwiYXBwIjp7Im5hbWUiOiJPY3Rva2l0\nIERldmVsb3BtZW50IiwidXJsIjoiaHR0cDovL29jdG9raXQuZGV2IiwiY2xp\nZW50X2lkIjoiPEdJVEhVQl9DTElFTlRfSUQ+In0sInRva2VuIjoiNjFhZmNi\nZDM0YmY2NTIyOWU5MDJiMTBiNGYwNGE0NWRkMGJhODI1NSIsIm5vdGUiOm51\nbGwsIm5vdGVfdXJsIjpudWxsLCJjcmVhdGVkX2F0IjoiMjAxMy0wOC0yOVQx\nOTozNjoyNFoiLCJ1cGRhdGVkX2F0IjoiMjAxMy0wOC0yOVQxOTozNjoyNFoi\nLCJzY29wZXMiOlsiZ2lzdCJdfQ==\n"},"http_version":null},"recorded_at":"Thu, 29 Aug 2013 19:36:24 GMT"}],"recorded_with":"VCR 2.4.0"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"http_interactions":[{"request":{"method":"post","uri":"https://<GITHUB_LOGIN>:<GITHUB_PASSWORD>@api.github.com/authorizations","body":{"encoding":"UTF-8","base64_string":"e30=\n"},"headers":{"Accept":["application/vnd.github.beta+json"],"User-Agent":["Octokit Ruby Gem 2.0.0"]}},"response":{"status":{"code":201,"message":"Created"},"headers":{"Server":["GitHub.com"],"Date":["Thu, 29 Aug 2013 19:36:23 GMT"],"Content-Type":["application/json; charset=utf-8"],"Status":["201 Created"],"X-Ratelimit-Limit":["5000"],"X-Ratelimit-Remaining":["4993"],"X-Ratelimit-Reset":["1377808149"],"Location":["https://api.github.com/authorizations/3459488"],"X-Github-Media-Type":["github.beta; format=json"],"X-Content-Type-Options":["nosniff"],"Content-Length":["365"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Expose-Headers":["ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes"],"Access-Control-Allow-Origin":["*"],"Etag":["\"1444ccd8d64cae453cd92448ff936d37\""],"Cache-Control":["max-age=0, private, must-revalidate"],"X-Github-Request-Id":["a27f469a-1e1c-49ab-9080-829e48d3430f"]},"body":{"encoding":"US-ASCII","base64_string":"eyJpZCI6MzQ1OTQ4OCwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9h\ndXRob3JpemF0aW9ucy8zNDU5NDg4IiwiYXBwIjp7Im5hbWUiOiJHaXRIdWIg\nQVBJIiwidXJsIjoiaHR0cDovL2RldmVsb3Blci5naXRodWIuY29tL3YzL29h\ndXRoLyNvYXV0aC1hdXRob3JpemF0aW9ucy1hcGkiLCJjbGllbnRfaWQiOiIw\nMDAwMDAwMDAwMDAwMDAwMDAwMCJ9LCJ0b2tlbiI6IjdlMTY5NmNlM2JlOGRl\nMGQ1ZTA4ODE1MzgzNTNmMTYzYTZhNjZhMmMiLCJub3RlIjpudWxsLCJub3Rl\nX3VybCI6bnVsbCwiY3JlYXRlZF9hdCI6IjIwMTMtMDgtMjlUMTk6MzY6MjNa\nIiwidXBkYXRlZF9hdCI6IjIwMTMtMDgtMjlUMTk6MzY6MjNaIiwic2NvcGVz\nIjpbXX0=\n"},"http_version":null},"recorded_at":"Thu, 29 Aug 2013 19:36:23 GMT"},{"request":{"method":"post","uri":"https://<GITHUB_LOGIN>:<GITHUB_PASSWORD>@api.github.com/authorizations","body":{"encoding":"UTF-8","base64_string":"e30=\n"},"headers":{"Accept":["application/vnd.github.beta+json"],"User-Agent":["Octokit Ruby Gem 2.0.0"]}},"response":{"status":{"code":201,"message":"Created"},"headers":{"Server":["GitHub.com"],"Date":["Thu, 29 Aug 2013 19:36:23 GMT"],"Content-Type":["application/json; charset=utf-8"],"Status":["201 Created"],"X-Ratelimit-Limit":["5000"],"X-Ratelimit-Remaining":["4992"],"X-Ratelimit-Reset":["1377808149"],"Location":["https://api.github.com/authorizations/3459490"],"X-Github-Media-Type":["github.beta; format=json"],"X-Content-Type-Options":["nosniff"],"Content-Length":["365"],"Access-Control-Allow-Credentials":["true"],"Access-Control-Expose-Headers":["ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes"],"Access-Control-Allow-Origin":["*"],"Etag":["\"39f0b27375ce598f0cf13230ea91b0d9\""],"Cache-Control":["max-age=0, private, must-revalidate"],"X-Github-Request-Id":["2574b4a5-0b8a-46eb-8571-8858eb8a1b0c"]},"body":{"encoding":"US-ASCII","base64_string":"eyJpZCI6MzQ1OTQ5MCwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9h\ndXRob3JpemF0aW9ucy8zNDU5NDkwIiwiYXBwIjp7Im5hbWUiOiJHaXRIdWIg\nQVBJIiwidXJsIjoiaHR0cDovL2RldmVsb3Blci5naXRodWIuY29tL3YzL29h\ndXRoLyNvYXV0aC1hdXRob3JpemF0aW9ucy1hcGkiLCJjbGllbnRfaWQiOiIw\nMDAwMDAwMDAwMDAwMDAwMDAwMCJ9LCJ0b2tlbiI6IjM0ZjRlM2M3N2VjZTZm\nMzFmOTY5MTNhMzRlNDMyYTE2NWI4Yjg1OWUiLCJub3RlIjpudWxsLCJub3Rl\nX3VybCI6bnVsbCwiY3JlYXRlZF9hdCI6IjIwMTMtMDgtMjlUMTk6MzY6MjNa\nIiwidXBkYXRlZF9hdCI6IjIwMTMtMDgtMjlUMTk6MzY6MjNaIiwic2NvcGVz\nIjpbXX0=\n"},"http_version":null},"recorded_at":"Thu, 29 Aug 2013 19:36:23 GMT"}],"recorded_with":"VCR 2.4.0"}
|
File without changes
|
File without changes
|
data/spec/helper.rb
CHANGED
@@ -30,6 +30,12 @@ VCR.configure do |c|
|
|
30
30
|
c.filter_sensitive_data("<<ACCESS_TOKEN>>") do
|
31
31
|
ENV['OCTOKIT_TEST_GITHUB_TOKEN']
|
32
32
|
end
|
33
|
+
c.filter_sensitive_data("<GITHUB_CLIENT_ID>") do
|
34
|
+
ENV['OCTOKIT_TEST_GITHUB_CLIENT_ID']
|
35
|
+
end
|
36
|
+
c.filter_sensitive_data("<GITHUB_CLIENT_SECRET>") do
|
37
|
+
ENV['OCTOKIT_TEST_GITHUB_CLIENT_SECRET']
|
38
|
+
end
|
33
39
|
c.default_cassette_options = {
|
34
40
|
:serialize_with => :json,
|
35
41
|
# TODO: Track down UTF-8 issue and remove
|
@@ -53,6 +59,14 @@ def test_github_token
|
|
53
59
|
ENV.fetch 'OCTOKIT_TEST_GITHUB_TOKEN'
|
54
60
|
end
|
55
61
|
|
62
|
+
def test_github_client_id
|
63
|
+
ENV.fetch 'OCTOKIT_TEST_GITHUB_CLIENT_ID'
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_github_client_secret
|
67
|
+
ENV.fetch 'OCTOKIT_TEST_GITHUB_CLIENT_SECRET'
|
68
|
+
end
|
69
|
+
|
56
70
|
def stub_delete(url)
|
57
71
|
stub_request(:delete, github_url(url))
|
58
72
|
end
|
@@ -8,18 +8,54 @@ describe Octokit::Client::Authorizations do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
describe ".create_authorization", :vcr do
|
11
|
-
|
12
|
-
authorization
|
13
|
-
|
14
|
-
|
11
|
+
context 'without :idempotent => true' do
|
12
|
+
it "creates an API authorization" do
|
13
|
+
authorization = @client.create_authorization
|
14
|
+
expect(authorization.app.name).to_not be_nil
|
15
|
+
assert_requested :post, basic_github_url("/authorizations")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "creates a new API authorization each time" do
|
19
|
+
first_authorization = @client.create_authorization
|
20
|
+
second_authorization = @client.create_authorization
|
21
|
+
expect(first_authorization.id).to_not eq second_authorization.id
|
22
|
+
end
|
23
|
+
|
24
|
+
it "creates a new authorization with options" do
|
25
|
+
info = {
|
26
|
+
:scopes => ["gist"],
|
27
|
+
}
|
28
|
+
authorization = @client.create_authorization info
|
29
|
+
expect(authorization.scopes).to be_kind_of Array
|
30
|
+
assert_requested :post, basic_github_url("/authorizations")
|
31
|
+
end
|
15
32
|
end
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
33
|
+
|
34
|
+
context 'with :idempotent => true' do
|
35
|
+
subject do
|
36
|
+
lambda do |info = {}|
|
37
|
+
@client.create_authorization({
|
38
|
+
:idempotent => true,
|
39
|
+
:client_id => test_github_client_id,
|
40
|
+
:client_secret => test_github_client_secret
|
41
|
+
}.merge(info))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "creates a new authorization with options" do
|
46
|
+
info = {
|
47
|
+
:scopes => ["gist"],
|
48
|
+
}
|
49
|
+
authorization = subject.call info
|
50
|
+
expect(authorization.scopes).to be_kind_of Array
|
51
|
+
assert_requested :put, basic_github_url("/authorizations/clients/#{test_github_client_id}")
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns an existing API authorization if one already exists' do
|
55
|
+
first_authorization = subject.call
|
56
|
+
second_authorization = subject.call
|
57
|
+
expect(first_authorization.id).to eql second_authorization.id
|
58
|
+
end
|
23
59
|
end
|
24
60
|
end # .create_authorization
|
25
61
|
|
@@ -198,14 +198,17 @@ describe Octokit::Client::Users do
|
|
198
198
|
end
|
199
199
|
end # .subscriptions
|
200
200
|
|
201
|
-
describe '.
|
201
|
+
describe '.exchange_code_for_token' do
|
202
202
|
it 'returns the access_token' do
|
203
203
|
VCR.turn_off!
|
204
|
-
stub_post("https://github.com/login/oauth/access_token").
|
205
|
-
|
204
|
+
post = stub_post("https://github.com/login/oauth/access_token").
|
205
|
+
with(:headers => {
|
206
|
+
:accept => "application/json",
|
207
|
+
:content_type => "application/json"
|
208
|
+
}).to_return(json_response("web_flow_token.json"))
|
206
209
|
response = Octokit.exchange_code_for_token('code', 'id_here', 'secret_here')
|
207
210
|
expect(response.access_token).to eq 'this_be_ye_token/use_it_wisely'
|
208
|
-
assert_requested
|
211
|
+
assert_requested post
|
209
212
|
VCR.turn_on!
|
210
213
|
end
|
211
214
|
end # .access_token
|
data/spec/octokit/client_spec.rb
CHANGED
@@ -480,4 +480,34 @@ describe Octokit::Client do
|
|
480
480
|
end
|
481
481
|
end
|
482
482
|
|
483
|
+
it "knows the difference between unauthorized and needs OTP" do
|
484
|
+
stub_get('/authorizations').to_return(:status => 401)
|
485
|
+
expect { Octokit.get('/authorizations') }.to raise_error Octokit::Unauthorized
|
486
|
+
|
487
|
+
stub_get('/authorizations/1').to_return \
|
488
|
+
:status => 401,
|
489
|
+
:headers => {
|
490
|
+
:content_type => "application/json",
|
491
|
+
"X-GitHub-OTP" => "required; sms"
|
492
|
+
},
|
493
|
+
:body => {:message => "Must specify two-factor authentication OTP code."}.to_json
|
494
|
+
expect { Octokit.get('/authorizations/1') }.to raise_error Octokit::OneTimePasswordRequired
|
495
|
+
end
|
496
|
+
|
497
|
+
it "knows the password delivery mechanism when needs OTP" do
|
498
|
+
stub_get('/authorizations/1').to_return \
|
499
|
+
:status => 401,
|
500
|
+
:headers => {
|
501
|
+
:content_type => "application/json",
|
502
|
+
"X-GitHub-OTP" => "required; app"
|
503
|
+
},
|
504
|
+
:body => {:message => "Must specify two-factor authentication OTP code."}.to_json
|
505
|
+
|
506
|
+
begin
|
507
|
+
Octokit.get('/authorizations/1')
|
508
|
+
rescue Octokit::OneTimePasswordRequired => otp_error
|
509
|
+
expect(otp_error.password_delivery).to eql 'app'
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
483
513
|
end
|
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: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-
|
14
|
+
date: 2013-09-03 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -111,8 +111,11 @@ files:
|
|
111
111
|
- spec/cassettes/Octokit_Client/error_handling/raises_on_404.json
|
112
112
|
- spec/cassettes/Octokit_Client_Authorizations/_authorization/returns_a_single_authorization.json
|
113
113
|
- spec/cassettes/Octokit_Client_Authorizations/_authorizations/lists_existing_authorizations.json
|
114
|
-
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/creates_a_new_authorization_with_options.json
|
115
|
-
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/
|
114
|
+
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/with_idempotent_true/creates_a_new_authorization_with_options.json
|
115
|
+
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/with_idempotent_true/returns_an_existing_API_authorization_if_one_already_exists.json
|
116
|
+
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/without_idempotent_true/creates_a_new_API_authorization_each_time.json
|
117
|
+
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/without_idempotent_true/creates_a_new_authorization_with_options.json
|
118
|
+
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/without_idempotent_true/creates_an_API_authorization.json
|
116
119
|
- spec/cassettes/Octokit_Client_Authorizations/_scopes/checks_the_scopes_on_a_one-off_token.json
|
117
120
|
- spec/cassettes/Octokit_Client_Authorizations/_scopes/checks_the_scopes_on_the_current_token.json
|
118
121
|
- spec/cassettes/Octokit_Client_Authorizations/_update_authorization/updates_and_existing_authorization.json
|
@@ -455,8 +458,11 @@ test_files:
|
|
455
458
|
- spec/cassettes/Octokit_Client/error_handling/raises_on_404.json
|
456
459
|
- spec/cassettes/Octokit_Client_Authorizations/_authorization/returns_a_single_authorization.json
|
457
460
|
- spec/cassettes/Octokit_Client_Authorizations/_authorizations/lists_existing_authorizations.json
|
458
|
-
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/creates_a_new_authorization_with_options.json
|
459
|
-
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/
|
461
|
+
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/with_idempotent_true/creates_a_new_authorization_with_options.json
|
462
|
+
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/with_idempotent_true/returns_an_existing_API_authorization_if_one_already_exists.json
|
463
|
+
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/without_idempotent_true/creates_a_new_API_authorization_each_time.json
|
464
|
+
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/without_idempotent_true/creates_a_new_authorization_with_options.json
|
465
|
+
- spec/cassettes/Octokit_Client_Authorizations/_create_authorization/without_idempotent_true/creates_an_API_authorization.json
|
460
466
|
- spec/cassettes/Octokit_Client_Authorizations/_scopes/checks_the_scopes_on_a_one-off_token.json
|
461
467
|
- spec/cassettes/Octokit_Client_Authorizations/_scopes/checks_the_scopes_on_the_current_token.json
|
462
468
|
- spec/cassettes/Octokit_Client_Authorizations/_update_authorization/updates_and_existing_authorization.json
|