scalingo 3.0.0.beta.2 → 3.0.0.beta.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/CHANGELOG.md +11 -0
  4. data/README.md +4 -14
  5. data/lib/scalingo/api/client.rb +38 -10
  6. data/lib/scalingo/api/endpoint.rb +12 -2
  7. data/lib/scalingo/api/response.rb +7 -1
  8. data/lib/scalingo/auth/keys.rb +4 -4
  9. data/lib/scalingo/auth/scm_integrations.rb +4 -4
  10. data/lib/scalingo/auth/tokens.rb +6 -6
  11. data/lib/scalingo/auth/two_factor_auth.rb +4 -4
  12. data/lib/scalingo/auth/user.rb +2 -2
  13. data/lib/scalingo/bearer_token.rb +15 -0
  14. data/lib/scalingo/billing/profile.rb +3 -3
  15. data/lib/scalingo/client.rb +26 -113
  16. data/lib/scalingo/configuration.rb +7 -36
  17. data/lib/scalingo/core_client.rb +106 -0
  18. data/lib/scalingo/regional/addons.rb +21 -8
  19. data/lib/scalingo/regional/apps.rb +8 -8
  20. data/lib/scalingo/regional/collaborators.rb +4 -4
  21. data/lib/scalingo/regional/containers.rb +4 -4
  22. data/lib/scalingo/regional/deployments.rb +3 -3
  23. data/lib/scalingo/regional/domains.rb +5 -5
  24. data/lib/scalingo/regional/environment.rb +6 -6
  25. data/lib/scalingo/regional/events.rb +4 -4
  26. data/lib/scalingo/regional/logs.rb +2 -2
  27. data/lib/scalingo/regional/metrics.rb +2 -2
  28. data/lib/scalingo/regional/notifiers.rb +7 -7
  29. data/lib/scalingo/regional/operations.rb +1 -1
  30. data/lib/scalingo/regional/scm_repo_links.rb +8 -8
  31. data/lib/scalingo/token_holder.rb +31 -0
  32. data/lib/scalingo/version.rb +1 -1
  33. data/samples/regional/addons/token-200.json +49 -0
  34. data/samples/regional/addons/token-404.json +24 -0
  35. data/scalingo.gemspec +1 -1
  36. data/spec/scalingo/api/client_spec.rb +58 -11
  37. data/spec/scalingo/api/endpoint_spec.rb +3 -2
  38. data/spec/scalingo/api/response_spec.rb +16 -16
  39. data/spec/scalingo/auth_spec.rb +1 -1
  40. data/spec/scalingo/billing_spec.rb +11 -0
  41. data/spec/scalingo/configuration_spec.rb +32 -30
  42. data/spec/scalingo/regional/addons_spec.rb +16 -0
  43. data/spec/scalingo/regional_spec.rb +1 -1
  44. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6582ca860b783b598a3f31874afc37958ead26c29c17c099e6cba1ef094f933d
4
- data.tar.gz: c0206b25118775599be97e0c6a7ef06c40914a34711c882a21268521f964ae24
3
+ metadata.gz: b8b0dc7d7cdf0153981710c5892540959c678f74a1a563f1f4c116e2727ef84c
4
+ data.tar.gz: 42d6d9577d47d7c34470471a9e30a1cccd1509611fefd5e68cb9da730d2607c1
5
5
  SHA512:
6
- metadata.gz: 1e7e41bb52927a17d3de0c840f281754ee1907a000db36735ec779d5115a345f91bf944aad068421e9292fcb3ab9f92db49690a25e61f4f81cd8ff45c625f550
7
- data.tar.gz: e2ebc1468f18304b3086ad927db4e89f09ef1d6256395a6f72a089776eeba8643b923bec88af1690f0264786dd46d6982b421f741b99f23a86ec513a3841fba9
6
+ metadata.gz: 7912d747ee122a34cd73be6f4a143c31f8a3e0e23c4f903a630c7b18fc157075d84ebb47545a5853e804ce9d4fd389e966277aff7bc67445ea348fd0d5661ede
7
+ data.tar.gz: 5099227b25fc7e8e5453dbe2919d14fc003da860864bc20464fa91b3d81cec7d46cdd78639e9988c5c6c6d0102746603bdba3f3f4d4c9d2e98d13841b1df7259
@@ -11,6 +11,14 @@ Style/TrailingCommaInArguments:
11
11
  Enabled: true
12
12
  EnforcedStyleForMultiline: consistent_comma
13
13
 
14
+ Style/TrailingCommaInArrayLiteral:
15
+ Enabled: true
16
+ EnforcedStyleForMultiline: consistent_comma
17
+
18
+ Style/TrailingCommaInHashLiteral:
19
+ Enabled: true
20
+ EnforcedStyleForMultiline: consistent_comma
21
+
14
22
  Style/Alias:
15
23
  Enabled: true
16
24
  EnforcedStyle: prefer_alias_method
@@ -1,5 +1,16 @@
1
1
  ## Unreleased
2
2
 
3
+ ## 3.0.0.beta.3 - 2020/08/15
4
+
5
+ * Change: Requests have the header `Accept: application/json` by default
6
+ * Private API Change: `unpack` signature
7
+ * Change: allow api clients standalone use (without a main scalingo client)
8
+ * Change: remove regions-related configuration, except for the default region
9
+ * Bugfix: remove `https` configuration option (development artifact) (#20)
10
+ * Improv: configure the faraday adapter to use (#20)
11
+ * Improv: prettier `inspect` for common objects (#20)
12
+ * New: Add `addons#token` endpoint (#20)
13
+
3
14
  ## 3.0.0.beta.2 - 2020/06/18
4
15
 
5
16
  * Bugfix: do not "dig" into the response body if it is not a 2XX (#18, #19)
data/README.md CHANGED
@@ -63,20 +63,7 @@ changing the configuration globally will therefore not affect already existing o
63
63
 
64
64
  ```ruby
65
65
  Scalingo.configure do |config|
66
- # Authentication API url
67
- config.auth = "https://auth.scalingo.com/v1"
68
-
69
- # Billing API url
70
- config.billing = "https://cashmachine.scalingo.com"
71
-
72
- # Known regions and their api's url
73
- config.regions = {
74
- agora_fr1: "https://api.agora-fr1.scalingo.com/v1",
75
- osc_fr1: "https://api.osc-fr1.scalingo.com/v1",
76
- osc_secnum_fr1: "https://api.osc-secnum-fr1.scalingo.com/v1"
77
- }
78
-
79
- # Default region. Must match an entry in `regions`
66
+ # Default region. Must be a supported region (agora_fr1, osc_fr1, osc_secnum_fr1)
80
67
  config.default_region = :osc_fr1
81
68
 
82
69
  # Configure the User Agent header
@@ -95,6 +82,9 @@ Scalingo.configure do |config|
95
82
  # These headers will be added to every request. Individual methods may override them.
96
83
  # This should be a hash or a callable object that returns a hash.
97
84
  config.additional_headers = {}
85
+
86
+ # Specify an adapter for faraday. Leave nil for the default one (Net::HTTP)
87
+ config.faraday_adapter = nil
98
88
  end
99
89
  ```
100
90
 
@@ -1,11 +1,24 @@
1
+ require "scalingo/token_holder"
2
+
1
3
  module Scalingo
2
4
  module API
3
5
  class Client
4
- attr_reader :scalingo, :url
6
+ include TokenHolder
7
+
8
+ attr_reader :config, :token_holder, :url
5
9
 
6
- def initialize(scalingo, url)
7
- @scalingo = scalingo
10
+ def initialize(url, scalingo: nil, config: {})
8
11
  @url = url
12
+ parent_config = Scalingo.config
13
+
14
+ if scalingo
15
+ @token_holder = scalingo
16
+ parent_config = scalingo.config
17
+ else
18
+ @token_holder = self
19
+ end
20
+
21
+ @config = Configuration.new(config, parent_config)
9
22
  end
10
23
 
11
24
  def self.register_handlers!(handlers)
@@ -27,13 +40,24 @@ module Scalingo
27
40
  end
28
41
  end
29
42
 
43
+ def inspect
44
+ str = %(<#{self.class}:0x#{object_id.to_s(16)} url:"#{@url}" methods:)
45
+
46
+ methods = self.class.instance_methods - Scalingo::API::Client.instance_methods
47
+ str << methods.to_s
48
+
49
+ str << ">"
50
+ str
51
+ end
52
+
30
53
  ## Faraday objects
31
54
  def headers
32
55
  hash = {
33
- "User-Agent" => scalingo.config.user_agent
56
+ "User-Agent" => config.user_agent,
57
+ "Accept" => "application/json",
34
58
  }
35
59
 
36
- if (extra = scalingo.config.additional_headers).present?
60
+ if (extra = config.additional_headers).present?
37
61
  extra.respond_to?(:call) ? hash.update(extra.call) : hash.update(extra)
38
62
  end
39
63
 
@@ -43,7 +67,7 @@ module Scalingo
43
67
  def connection_options
44
68
  {
45
69
  url: url,
46
- headers: headers
70
+ headers: headers,
47
71
  }
48
72
  end
49
73
 
@@ -66,6 +90,8 @@ module Scalingo
66
90
  @unauthenticated_conn ||= Faraday.new(connection_options) { |conn|
67
91
  conn.response :json, content_type: /\bjson$/, parser_options: {symbolize_names: true}
68
92
  conn.request :json
93
+
94
+ conn.adapter(config.faraday_adapter) if config.faraday_adapter
69
95
  }
70
96
  end
71
97
 
@@ -73,8 +99,8 @@ module Scalingo
73
99
  return @connection if @connection
74
100
 
75
101
  # Missing token handling. Token expiration is handled in the `value` method.
76
- unless scalingo.token&.value
77
- if scalingo.config.raise_on_missing_authentication
102
+ unless token_holder.token&.value
103
+ if config.raise_on_missing_authentication
78
104
  raise Error::Unauthenticated
79
105
  else
80
106
  return unauthenticated_connection
@@ -85,10 +111,12 @@ module Scalingo
85
111
  conn.response :json, content_type: /\bjson$/, parser_options: {symbolize_names: true}
86
112
  conn.request :json
87
113
 
88
- if scalingo.token&.value
89
- auth_header = Faraday::Request::Authorization.header "Bearer", scalingo.token.value
114
+ if token_holder.token&.value
115
+ auth_header = Faraday::Request::Authorization.header "Bearer", token_holder.token.value
90
116
  conn.headers[Faraday::Request::Authorization::KEY] = auth_header
91
117
  end
118
+
119
+ conn.adapter(config.faraday_adapter) if config.faraday_adapter
92
120
  }
93
121
  end
94
122
  end
@@ -13,10 +13,20 @@ module Scalingo
13
13
 
14
14
  def_delegator :client, :connection
15
15
 
16
+ def inspect
17
+ str = %(<#{self.class}:0x#{object_id.to_s(16)} base_url:"#{@client.url}" endpoints:)
18
+
19
+ methods = self.class.instance_methods - Scalingo::API::Endpoint.instance_methods
20
+
21
+ str << methods.to_s
22
+ str << ">"
23
+ str
24
+ end
25
+
16
26
  private
17
27
 
18
- def unpack(*args)
19
- Response.unpack(client, *args)
28
+ def unpack(key = nil, &block)
29
+ Response.unpack(client, key: key, &block)
20
30
  end
21
31
  end
22
32
  end
@@ -1,7 +1,9 @@
1
1
  module Scalingo
2
2
  module API
3
3
  class Response
4
- def self.unpack(client, response, key: nil)
4
+ def self.unpack(client, key: nil, &block)
5
+ response = block.call
6
+
5
7
  body = response.body
6
8
  has_hash_body = body.present? && body.respond_to?(:key)
7
9
 
@@ -34,6 +36,10 @@ module Scalingo
34
36
  @meta = meta
35
37
  end
36
38
 
39
+ def inspect
40
+ %(<#{self.class}:0x#{object_id.to_s(16)} status:#{@status} data:#{@data} meta:#{@meta}>)
41
+ end
42
+
37
43
  def successful?
38
44
  status >= 200 && status < 300
39
45
  end
@@ -12,7 +12,7 @@ module Scalingo
12
12
  &block
13
13
  )
14
14
 
15
- unpack(response, key: :keys)
15
+ unpack(:keys) { response }
16
16
  end
17
17
 
18
18
  def show(id, headers = nil, &block)
@@ -25,7 +25,7 @@ module Scalingo
25
25
  &block
26
26
  )
27
27
 
28
- unpack(response, key: :key)
28
+ unpack(:key) { response }
29
29
  end
30
30
 
31
31
  def create(payload, headers = nil, &block)
@@ -38,7 +38,7 @@ module Scalingo
38
38
  &block
39
39
  )
40
40
 
41
- unpack(response, key: :key)
41
+ unpack(:key) { response }
42
42
  end
43
43
 
44
44
  def destroy(id, headers = nil, &block)
@@ -50,7 +50,7 @@ module Scalingo
50
50
  &block
51
51
  )
52
52
 
53
- unpack(response)
53
+ unpack { response }
54
54
  end
55
55
  end
56
56
  end
@@ -12,7 +12,7 @@ module Scalingo
12
12
  &block
13
13
  )
14
14
 
15
- unpack(response, key: :scm_integrations)
15
+ unpack(:scm_integrations) { response }
16
16
  end
17
17
 
18
18
  def show(id, headers = nil, &block)
@@ -25,7 +25,7 @@ module Scalingo
25
25
  &block
26
26
  )
27
27
 
28
- unpack(response, key: :scm_integration)
28
+ unpack(:scm_integration) { response }
29
29
  end
30
30
 
31
31
  def create(payload, headers = nil, &block)
@@ -38,7 +38,7 @@ module Scalingo
38
38
  &block
39
39
  )
40
40
 
41
- unpack(response, key: :scm_integration)
41
+ unpack(:scm_integration) { response }
42
42
  end
43
43
 
44
44
  def destroy(id, headers = nil, &block)
@@ -51,7 +51,7 @@ module Scalingo
51
51
  &block
52
52
  )
53
53
 
54
- unpack(response)
54
+ unpack { response }
55
55
  end
56
56
  end
57
57
  end
@@ -8,7 +8,7 @@ module Scalingo
8
8
  authorization = Faraday::Request::BasicAuthentication.header("", token)
9
9
 
10
10
  request_headers = {
11
- Faraday::Request::Authorization::KEY => authorization
11
+ Faraday::Request::Authorization::KEY => authorization,
12
12
  }
13
13
 
14
14
  request_headers.update(headers) if headers
@@ -20,7 +20,7 @@ module Scalingo
20
20
  &block
21
21
  )
22
22
 
23
- unpack(response)
23
+ unpack { response }
24
24
  end
25
25
 
26
26
  def all(headers = nil, &block)
@@ -33,7 +33,7 @@ module Scalingo
33
33
  &block
34
34
  )
35
35
 
36
- unpack(response, key: :tokens)
36
+ unpack(:tokens) { response }
37
37
  end
38
38
 
39
39
  def create(payload, headers = nil, &block)
@@ -46,7 +46,7 @@ module Scalingo
46
46
  &block
47
47
  )
48
48
 
49
- unpack(response, key: :token)
49
+ unpack(:token) { response }
50
50
  end
51
51
 
52
52
  def renew(id, headers = nil, &block)
@@ -59,7 +59,7 @@ module Scalingo
59
59
  &block
60
60
  )
61
61
 
62
- unpack(response, key: :token)
62
+ unpack(:token) { response }
63
63
  end
64
64
 
65
65
  def destroy(id, headers = nil, &block)
@@ -72,7 +72,7 @@ module Scalingo
72
72
  &block
73
73
  )
74
74
 
75
- unpack(response)
75
+ unpack { response }
76
76
  end
77
77
  end
78
78
  end
@@ -16,7 +16,7 @@ module Scalingo
16
16
  &block
17
17
  )
18
18
 
19
- unpack(response, key: :tfa)
19
+ unpack(:tfa) { response }
20
20
  end
21
21
 
22
22
  def initiate(provider = DEFAULT_PROVIDER, headers = nil, &block)
@@ -29,7 +29,7 @@ module Scalingo
29
29
  &block
30
30
  )
31
31
 
32
- unpack(response, key: :tfa)
32
+ unpack(:tfa) { response }
33
33
  end
34
34
 
35
35
  def validate(attempt, headers = nil, &block)
@@ -42,7 +42,7 @@ module Scalingo
42
42
  &block
43
43
  )
44
44
 
45
- unpack(response, key: :tfa)
45
+ unpack(:tfa) { response }
46
46
  end
47
47
 
48
48
  def disable(headers = nil, &block)
@@ -55,7 +55,7 @@ module Scalingo
55
55
  &block
56
56
  )
57
57
 
58
- unpack(response, key: :tfa)
58
+ unpack(:tfa) { response }
59
59
  end
60
60
  end
61
61
  end
@@ -12,7 +12,7 @@ module Scalingo
12
12
  &block
13
13
  )
14
14
 
15
- unpack(response, key: :user)
15
+ unpack(:user) { response }
16
16
  end
17
17
 
18
18
  def update(payload, headers = nil, &block)
@@ -25,7 +25,7 @@ module Scalingo
25
25
  &block
26
26
  )
27
27
 
28
- unpack(response, key: :user)
28
+ unpack(:user) { response }
29
29
  end
30
30
  end
31
31
  end
@@ -9,6 +9,21 @@ module Scalingo
9
9
  @raise_on_expired = raise_on_expired
10
10
  end
11
11
 
12
+ def inspect
13
+ str = "<#{self.class}:0x#{object_id.to_s(16)} "
14
+
15
+ str << if expired?
16
+ "(expired) "
17
+ elsif expires_at.present?
18
+ "expires_at: #{expires_at} "
19
+ else
20
+ "(no expiration) "
21
+ end
22
+
23
+ str << %(value:"#{value}">)
24
+ str
25
+ end
26
+
12
27
  def raise_on_expired?
13
28
  @raise_on_expired
14
29
  end
@@ -12,7 +12,7 @@ module Scalingo
12
12
  &block
13
13
  )
14
14
 
15
- unpack(response, key: :profile)
15
+ unpack(:profile) { response }
16
16
  end
17
17
 
18
18
  def create(payload = {}, headers = nil, &block)
@@ -25,7 +25,7 @@ module Scalingo
25
25
  &block
26
26
  )
27
27
 
28
- unpack(response, key: :profile)
28
+ unpack(:profile) { response }
29
29
  end
30
30
 
31
31
  def update(id, payload = {}, headers = nil, &block)
@@ -38,7 +38,7 @@ module Scalingo
38
38
  &block
39
39
  )
40
40
 
41
- unpack(response, key: :profile)
41
+ unpack(:profile) { response }
42
42
  end
43
43
 
44
44
  alias_method :self, :show
@@ -1,131 +1,44 @@
1
- require "forwardable"
2
- require "faraday"
3
- require "faraday_middleware"
4
- require "scalingo/bearer_token"
5
- require "scalingo/errors"
1
+ require "scalingo/core_client"
6
2
  require "scalingo/auth"
7
3
  require "scalingo/billing"
8
4
  require "scalingo/regional"
9
5
 
10
6
  module Scalingo
11
- class Client
12
- extend Forwardable
13
-
14
- attr_reader :config
15
-
16
- def initialize(attributes = {})
17
- @config = Configuration.new(attributes, Scalingo.config)
18
-
19
- define_regions!
20
- end
21
-
22
- ## Authentication helpers / Token management
23
- attr_reader :token
24
-
25
- def token=(input)
26
- @token = input.is_a?(BearerToken) ? input : BearerToken.new(input.to_s, raise_on_expired: config.raise_on_expired_token)
27
- end
28
-
29
- def authenticated?
30
- token.present? && !token.expired?
31
- end
32
-
33
- def authenticate_with(access_token: nil, bearer_token: nil, expires_at: nil)
34
- if !access_token && !bearer_token
35
- raise ArgumentError, "You must supply one of `access_token` or `bearer_token`"
36
- end
37
-
38
- if access_token && bearer_token
39
- raise ArgumentError, "You cannot supply both `access_token` and `bearer_token`"
40
- end
41
-
42
- if expires_at && !bearer_token
43
- raise ArgumentError, "`expires_at` can only be used with `bearer_token`. `access_token` have a 1 hour expiration."
44
- end
45
-
46
- if access_token
47
- expiration = Time.now + config.exchanged_token_validity
48
- response = auth.tokens.exchange(access_token)
49
-
50
- if response.successful?
51
- self.token = BearerToken.new(
52
- response.data[:token],
53
- expires_at: expiration,
54
- raise_on_expired: config.raise_on_expired_token,
55
- )
56
- end
57
-
58
- return response.successful?
59
- end
60
-
61
- if bearer_token
62
- self.token = if expires_at
63
- token = bearer_token.is_a?(BearerToken) ? bearer_token.value : bearer_token.to_s
64
-
65
- BearerToken.new(
66
- token,
67
- expires_at: expires_at,
68
- raise_on_expired: config.raise_on_expired_token,
69
- )
70
- else
71
- bearer_token
72
- end
73
-
74
- true
75
- end
76
- end
77
-
7
+ class Client < CoreClient
78
8
  ## API clients
79
9
  def auth
80
- @auth ||= Auth.new(self, config.auth)
10
+ @auth ||= Auth.new(
11
+ "https://auth.scalingo.com/v1",
12
+ scalingo: self,
13
+ )
81
14
  end
82
15
 
83
16
  def billing
84
- @billing ||= Billing.new(self, config.billing)
17
+ @billing ||= Billing.new(
18
+ "https://cashmachine.scalingo.com",
19
+ scalingo: self,
20
+ )
85
21
  end
86
22
 
87
- def region(name = nil)
88
- public_send(name || config.default_region)
23
+ def agora_fr1
24
+ @agora_fr1 ||= Regional.new(
25
+ "https://api.agora-fr1.scalingo.com/v1",
26
+ scalingo: self,
27
+ )
89
28
  end
90
29
 
91
- ## Delegations
92
- def_delegator :auth, :keys
93
- def_delegator :auth, :scm_integrations
94
- def_delegator :auth, :tokens
95
- def_delegator :auth, :two_factor_auth
96
- def_delegator :auth, :tfa
97
- def_delegator :auth, :user
98
-
99
- def_delegator :region, :addons
100
- def_delegator :region, :apps
101
- def_delegator :region, :collaborators
102
- def_delegator :region, :containers
103
- def_delegator :region, :deployments
104
- def_delegator :region, :domains
105
- def_delegator :region, :environment
106
- def_delegator :region, :events
107
- def_delegator :region, :logs
108
- def_delegator :region, :metrics
109
- def_delegator :region, :notifiers
110
- def_delegator :region, :operations
111
- def_delegator :region, :scm_repo_links
112
-
113
- private
114
-
115
- def define_regions!
116
- config.regions.each_pair do |region, _|
117
- define_singleton_method(region) do
118
- region_client = instance_variable_get :"@#{region}"
119
-
120
- unless region_client
121
- region_client = Regional.new(self, config.regions.public_send(region))
122
-
123
- instance_variable_set :"@#{region}", region_client
124
- end
30
+ def osc_fr1
31
+ @osc_fr1 ||= Regional.new(
32
+ "https://api.osc-fr1.scalingo.com/v1",
33
+ scalingo: self,
34
+ )
35
+ end
125
36
 
126
- region_client
127
- end
128
- end
37
+ def osc_secnum_fr1
38
+ @osc_secnum_fr1 ||= Regional.new(
39
+ "https://api.osc-secnum-fr1.scalingo.com/v1",
40
+ scalingo: self,
41
+ )
129
42
  end
130
43
  end
131
44
  end