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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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