scalingo 3.5.0 → 4.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +41 -0
- data/CHANGELOG.md +14 -1
- data/Gemfile +2 -0
- data/README.md +13 -62
- data/bin/console +11 -1
- data/bin/lint +2 -0
- data/bin/setup +21 -6
- data/bin/specs +2 -0
- data/lib/scalingo/api/client.rb +21 -39
- data/lib/scalingo/api/endpoint.rb +88 -11
- data/lib/scalingo/auth/keys.rb +4 -50
- data/lib/scalingo/auth/scm_integrations.rb +4 -51
- data/lib/scalingo/auth/tokens.rb +5 -72
- data/lib/scalingo/auth/two_factor_auth.rb +4 -55
- data/lib/scalingo/auth/user.rb +3 -38
- data/lib/scalingo/bearer_token.rb +16 -9
- data/lib/scalingo/billing/profile.rb +3 -40
- data/lib/scalingo/client.rb +21 -31
- data/lib/scalingo/configuration.rb +0 -24
- data/lib/scalingo/core_client.rb +9 -29
- data/lib/scalingo/database/backups.rb +9 -0
- data/lib/scalingo/database/databases.rb +8 -0
- data/lib/scalingo/{regional_database.rb → database.rb} +3 -3
- data/lib/scalingo/faraday/extract_meta.rb +33 -0
- data/lib/scalingo/faraday/extract_root_value.rb +18 -0
- data/lib/scalingo/faraday/response.rb +36 -0
- data/lib/scalingo/regional/addons.rb +18 -130
- data/lib/scalingo/regional/apps.rb +10 -103
- data/lib/scalingo/regional/autoscalers.rb +5 -64
- data/lib/scalingo/regional/collaborators.rb +4 -51
- data/lib/scalingo/regional/containers.rb +4 -51
- data/lib/scalingo/regional/deployments.rb +3 -38
- data/lib/scalingo/regional/domains.rb +5 -64
- data/lib/scalingo/regional/environment.rb +6 -77
- data/lib/scalingo/regional/events.rb +5 -50
- data/lib/scalingo/regional/logs.rb +10 -28
- data/lib/scalingo/regional/metrics.rb +2 -34
- data/lib/scalingo/regional/notifiers.rb +7 -90
- data/lib/scalingo/regional/operations.rb +5 -18
- data/lib/scalingo/regional/scm_repo_links.rb +8 -103
- data/lib/scalingo/token_holder.rb +1 -46
- data/lib/scalingo/version.rb +1 -1
- data/scalingo.gemspec +3 -0
- metadata +59 -200
- data/lib/scalingo/api/response.rb +0 -69
- data/lib/scalingo/regional_database/backups.rb +0 -44
- data/lib/scalingo/regional_database/databases.rb +0 -31
- data/samples/auth/keys/_meta.json +0 -13
- data/samples/auth/keys/all-200.json +0 -62
- data/samples/auth/keys/create-201.json +0 -67
- data/samples/auth/keys/create-422.json +0 -34
- data/samples/auth/keys/destroy-204.json +0 -19
- data/samples/auth/keys/destroy-404.json +0 -19
- data/samples/auth/keys/show-200.json +0 -60
- data/samples/auth/keys/show-404.json +0 -19
- data/samples/auth/scm_integrations/_meta.json +0 -14
- data/samples/auth/scm_integrations/all-200.json +0 -41
- data/samples/auth/scm_integrations/create-201.json +0 -41
- data/samples/auth/scm_integrations/create-422.json +0 -36
- data/samples/auth/scm_integrations/destroy-204.json +0 -15
- data/samples/auth/scm_integrations/destroy-404.json +0 -23
- data/samples/auth/scm_integrations/show-200.json +0 -34
- data/samples/auth/scm_integrations/show-404.json +0 -23
- data/samples/auth/tokens/_meta.json +0 -13
- data/samples/auth/tokens/all-200.json +0 -32
- data/samples/auth/tokens/create-201.json +0 -37
- data/samples/auth/tokens/destroy-204.json +0 -19
- data/samples/auth/tokens/destroy-404.json +0 -19
- data/samples/auth/tokens/exchange-200.json +0 -25
- data/samples/auth/tokens/exchange-401.json +0 -24
- data/samples/auth/tokens/renew-200.json +0 -32
- data/samples/auth/tokens/renew-404.json +0 -20
- data/samples/auth/two_factor_auth/_meta.json +0 -10
- data/samples/auth/two_factor_auth/disable-not-initiated.json +0 -23
- data/samples/auth/two_factor_auth/disable-success.json +0 -29
- data/samples/auth/two_factor_auth/initiate-already-enabled.json +0 -29
- data/samples/auth/two_factor_auth/initiate-success.json +0 -36
- data/samples/auth/two_factor_auth/initiate-wrong-provider.json +0 -29
- data/samples/auth/two_factor_auth/status.json +0 -29
- data/samples/auth/two_factor_auth/validate-not-initiated.json +0 -29
- data/samples/auth/two_factor_auth/validate-success.json +0 -49
- data/samples/auth/two_factor_auth/validate-wrong.json +0 -29
- data/samples/auth/user/_meta.json +0 -10
- data/samples/auth/user/self.json +0 -54
- data/samples/auth/user/stop-free-trial.json +0 -24
- data/samples/auth/user/update-200.json +0 -59
- data/samples/auth/user/update-422.json +0 -33
- data/samples/billing/profile/_meta.json +0 -23
- data/samples/billing/profile/create-201.json +0 -50
- data/samples/billing/profile/create-400.json +0 -27
- data/samples/billing/profile/create-422.json +0 -44
- data/samples/billing/profile/show-200.json +0 -41
- data/samples/billing/profile/show-404.json +0 -22
- data/samples/billing/profile/update-200.json +0 -47
- data/samples/billing/profile/update-422.json +0 -32
- data/samples/regional/addons/_meta.json +0 -22
- data/samples/regional/addons/categories-guest.json +0 -36
- data/samples/regional/addons/categories-logged.json +0 -37
- data/samples/regional/addons/destroy-204.json +0 -19
- data/samples/regional/addons/destroy-404.json +0 -24
- data/samples/regional/addons/find-200.json +0 -48
- data/samples/regional/addons/find-404.json +0 -24
- data/samples/regional/addons/for-200.json +0 -50
- data/samples/regional/addons/providers-guest.json +0 -588
- data/samples/regional/addons/providers-logged.json +0 -705
- data/samples/regional/addons/provision-201.json +0 -58
- data/samples/regional/addons/provision-400.json +0 -29
- data/samples/regional/addons/sso-200.json +0 -49
- data/samples/regional/addons/sso-404.json +0 -24
- data/samples/regional/addons/token-200.json +0 -49
- data/samples/regional/addons/token-404.json +0 -24
- data/samples/regional/addons/update-200.json +0 -58
- data/samples/regional/addons/update-404.json +0 -30
- data/samples/regional/apps/_meta.json +0 -52
- data/samples/regional/apps/all.json +0 -99
- data/samples/regional/apps/create-201.json +0 -66
- data/samples/regional/apps/create-422.json +0 -34
- data/samples/regional/apps/destroy-204.json +0 -19
- data/samples/regional/apps/destroy-404.json +0 -24
- data/samples/regional/apps/destroy-422.json +0 -27
- data/samples/regional/apps/find-200.json +0 -60
- data/samples/regional/apps/find-404.json +0 -24
- data/samples/regional/apps/logs_url.json +0 -62
- data/samples/regional/apps/rename-200.json +0 -65
- data/samples/regional/apps/rename-404.json +0 -29
- data/samples/regional/apps/rename-422.json +0 -33
- data/samples/regional/apps/transfer-200.json +0 -65
- data/samples/regional/apps/transfer-404.json +0 -27
- data/samples/regional/apps/transfer-422.json +0 -34
- data/samples/regional/apps/update-200.json +0 -66
- data/samples/regional/apps/update-stack-404.json +0 -30
- data/samples/regional/autoscalers/_meta.json +0 -27
- data/samples/regional/autoscalers/create-201.json +0 -49
- data/samples/regional/autoscalers/create-500.json +0 -32
- data/samples/regional/autoscalers/destroy-204.json +0 -20
- data/samples/regional/autoscalers/destroy-404.json +0 -25
- data/samples/regional/autoscalers/find-200.json +0 -39
- data/samples/regional/autoscalers/find-404.json +0 -25
- data/samples/regional/autoscalers/for-200.json +0 -41
- data/samples/regional/autoscalers/update-200.json +0 -45
- data/samples/regional/autoscalers/update-404.json +0 -31
- data/samples/regional/autoscalers/update-500.json +0 -30
- data/samples/regional/collaborators/_meta.json +0 -17
- data/samples/regional/collaborators/accept-200.json +0 -60
- data/samples/regional/collaborators/accept-400.json +0 -24
- data/samples/regional/collaborators/accept-404.json +0 -24
- data/samples/regional/collaborators/destroy-204.json +0 -19
- data/samples/regional/collaborators/destroy-404.json +0 -24
- data/samples/regional/collaborators/for-200.json +0 -34
- data/samples/regional/collaborators/invite-201.json +0 -37
- data/samples/regional/collaborators/invite-422.json +0 -34
- data/samples/regional/containers/_meta.json +0 -25
- data/samples/regional/containers/for-200.json +0 -39
- data/samples/regional/containers/restart-202.json +0 -28
- data/samples/regional/containers/restart-422.json +0 -33
- data/samples/regional/containers/scale-202.json +0 -48
- data/samples/regional/containers/scale-422.json +0 -36
- data/samples/regional/containers/sizes-guest.json +0 -115
- data/samples/regional/containers/sizes-logged.json +0 -116
- data/samples/regional/deployments/_meta.json +0 -8
- data/samples/regional/deployments/find-200.json +0 -45
- data/samples/regional/deployments/find-404.json +0 -24
- data/samples/regional/deployments/for-with-paging.json +0 -35
- data/samples/regional/deployments/for-without-pages.json +0 -56
- data/samples/regional/deployments/logs-200.json +0 -22
- data/samples/regional/deployments/logs-404.json +0 -24
- data/samples/regional/domains/_meta.json +0 -21
- data/samples/regional/domains/create-201.json +0 -44
- data/samples/regional/domains/create-422.json +0 -33
- data/samples/regional/domains/destroy-204.json +0 -19
- data/samples/regional/domains/destroy-404.json +0 -24
- data/samples/regional/domains/find-200.json +0 -38
- data/samples/regional/domains/find-404.json +0 -24
- data/samples/regional/domains/for-200.json +0 -40
- data/samples/regional/domains/update-200.json +0 -44
- data/samples/regional/domains/update-404.json +0 -30
- data/samples/regional/domains/update-422.json +0 -33
- data/samples/regional/environment/_meta.json +0 -43
- data/samples/regional/environment/bulk-destroy-204.json +0 -19
- data/samples/regional/environment/bulk-update-200.json +0 -70
- data/samples/regional/environment/create-201.json +0 -36
- data/samples/regional/environment/create-422.json +0 -37
- data/samples/regional/environment/destroy-204.json +0 -19
- data/samples/regional/environment/destroy-404.json +0 -24
- data/samples/regional/environment/for-200.json +0 -31
- data/samples/regional/environment/update-200.json +0 -35
- data/samples/regional/environment/update-404.json +0 -30
- data/samples/regional/events/_meta.json +0 -3
- data/samples/regional/events/all-200.json +0 -619
- data/samples/regional/events/categories-guest.json +0 -66
- data/samples/regional/events/categories-logged.json +0 -67
- data/samples/regional/events/for-200.json +0 -404
- data/samples/regional/events/types-guest.json +0 -288
- data/samples/regional/events/types-logged.json +0 -289
- data/samples/regional/logs/_meta.json +0 -11
- data/samples/regional/logs/archives-200.json +0 -28
- data/samples/regional/logs/get-guest-200.json +0 -18
- data/samples/regional/logs/get-logged-200.json +0 -19
- data/samples/regional/logs/get-with-limit-200.json +0 -18
- data/samples/regional/metrics/_meta.json +0 -15
- data/samples/regional/metrics/for-invalid-400.json +0 -23
- data/samples/regional/metrics/for-valid-cpu-200.json +0 -747
- data/samples/regional/metrics/for-valid-router-404.json +0 -23
- data/samples/regional/metrics/types-guest.json +0 -66
- data/samples/regional/metrics/types-logged.json +0 -67
- data/samples/regional/notifiers/_meta.json +0 -23
- data/samples/regional/notifiers/create-201.json +0 -55
- data/samples/regional/notifiers/create-404.json +0 -30
- data/samples/regional/notifiers/create-422.json +0 -36
- data/samples/regional/notifiers/destroy-204.json +0 -19
- data/samples/regional/notifiers/destroy-404.json +0 -24
- data/samples/regional/notifiers/find-200.json +0 -47
- data/samples/regional/notifiers/find-404.json +0 -24
- data/samples/regional/notifiers/for-200.json +0 -49
- data/samples/regional/notifiers/platforms-guest.json +0 -184
- data/samples/regional/notifiers/platforms-logged.json +0 -185
- data/samples/regional/notifiers/test-200.json +0 -22
- data/samples/regional/notifiers/test-404.json +0 -25
- data/samples/regional/notifiers/update-200.json +0 -53
- data/samples/regional/operations/_meta.json +0 -5
- data/samples/regional/operations/find-200.json +0 -31
- data/samples/regional/operations/find-404.json +0 -24
- data/samples/regional/scm_repo_links/_meta.json +0 -22
- data/samples/regional/scm_repo_links/create-201.json +0 -54
- data/samples/regional/scm_repo_links/destroy-204.json +0 -15
- data/samples/regional/scm_repo_links/manual-deploy-200.json +0 -32
- data/samples/regional/scm_repo_links/show-200.json +0 -43
- data/samples/regional/scm_repo_links/update-200.json +0 -50
- data/samples/regional_database/backups/_meta.json +0 -4
- data/samples/regional_database/backups/archive-200.json +0 -24
- data/samples/regional_database/backups/archive-400.json +0 -24
- data/samples/regional_database/backups/create-201.json +0 -32
- data/samples/regional_database/backups/create-400.json +0 -24
- data/samples/regional_database/backups/for-200.json +0 -52
- data/samples/regional_database/backups/for-400.json +0 -24
- data/samples/regional_database/databases/_meta.json +0 -3
- data/samples/regional_database/databases/find-200.json +0 -47
- data/samples/regional_database/databases/find-400.json +0 -24
- data/samples/regional_database/databases/upgrade-202.json +0 -39
- data/samples/regional_database/databases/upgrade-400.json +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e81dc5d1e89b30c848e17b2ef1ef0cbe73fd96555659225cf4d6bbd3558fa60
|
4
|
+
data.tar.gz: 6ebe2d660f1c2d696839d8db23a48932057003390fe55bedebf427898b36df27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b851279a78169fc9ae01c8eea2c3e5ba9cf9898af057d3941a7d481fb6dd4372b4ada7beb54638c6b6fb0fb734a463bac4773cecc91af0462210a27372d3598
|
7
|
+
data.tar.gz: b9617375ab3230a1993874b8fc4b64e34cf07d9e1d7f9fc3341f37dd5c9d885b54cce1099d18bc51ba07fb990dedb6d950eb839efbe6881aea1e849851ba2f79
|
data/.rubocop.yml
CHANGED
@@ -3,6 +3,7 @@ require:
|
|
3
3
|
- standard-custom
|
4
4
|
- standard-performance
|
5
5
|
- rubocop-performance
|
6
|
+
- rubocop-rspec
|
6
7
|
|
7
8
|
inherit_gem:
|
8
9
|
standard: config/base.yml
|
@@ -18,3 +19,43 @@ AllCops:
|
|
18
19
|
- 'tmp/**/*'
|
19
20
|
- 'vendor/**/*'
|
20
21
|
- '.git/**/*'
|
22
|
+
|
23
|
+
# Line-base counting is not reliable enough
|
24
|
+
RSpec/ExampleLength:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
# Deprecated cop, will be removed
|
28
|
+
RSpec/FilePath:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
# Not convinced by how strict this cop is by default
|
32
|
+
RSpec/MultipleExpectations:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
RSpec/MultipleMemoizedHelpers:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
# Really not convinced by this one
|
39
|
+
RSpec/NamedSubject:
|
40
|
+
Enabled: false
|
41
|
+
|
42
|
+
# Default is 3, but 4 is used and relevant (class / method / global state / local state)
|
43
|
+
RSpec/NestedGroups:
|
44
|
+
Max: 4
|
45
|
+
|
46
|
+
# Not always relevant for libs
|
47
|
+
RSpec/SpecFilePathFormat:
|
48
|
+
Exclude:
|
49
|
+
- 'spec/scalingo/faraday/**/*'
|
50
|
+
|
51
|
+
# Not sure about this one - requires more research
|
52
|
+
RSpec/MessageSpies:
|
53
|
+
Enabled: false
|
54
|
+
|
55
|
+
# Not sure about this one - requires more research
|
56
|
+
RSpec/StubbedMock:
|
57
|
+
Enabled: false
|
58
|
+
|
59
|
+
# Not sure about this one - requires more research
|
60
|
+
RSpec/SubjectStub:
|
61
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,17 @@
|
|
1
|
-
##
|
1
|
+
## 4.0.beta1 - 2024-04-15
|
2
|
+
|
3
|
+
* Breaking change: exceptions are raised on error responses (4xx, 5xx) and other errors (connection issue, timeouts)
|
4
|
+
* Trying to reach an endpoint without having the client authenticated will raise an exception without attempting the request
|
5
|
+
* Same when the token is expired. Expiration date is read from the token directly
|
6
|
+
* Associated configuration options have been removed
|
7
|
+
* Breaking change: rework DB api exposition
|
8
|
+
* Specs: rewrite all specs
|
9
|
+
* Breaking change: endpoint methods declaration is simplified:
|
10
|
+
* based on URI templates
|
11
|
+
* argument and method names are unified
|
12
|
+
* one "main" internal method, `Endpoint#request`
|
13
|
+
* Breaking change: automatic digging of the value if the reponse body is an object with a single key
|
14
|
+
* Breaking change: remove `Scalingo::API::Reponse` in favor of `Faraday::Response`
|
2
15
|
|
3
16
|
## 3.5.0 - 2023-12-28
|
4
17
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,18 +2,10 @@
|
|
2
2
|
|
3
3
|
A ruby wrapper for the Scalingo API
|
4
4
|
|
5
|
-
### Migration from v2
|
6
|
-
|
7
|
-
This gem is changing its name from `scalingo-ruby-api` to `scalingo`,
|
8
|
-
and the versioning does **not** reset; the first major version of `scalingo`
|
9
|
-
will therefore be `3.x.x`.
|
10
|
-
|
11
|
-
You can check the version 2 at [the v2 branch of this repository](https://github.com/Scalingo/scalingo-ruby-api/tree/v2)
|
12
|
-
|
13
5
|
## Installation
|
14
6
|
|
15
7
|
```ruby
|
16
|
-
gem "scalingo"
|
8
|
+
gem "scalingo"
|
17
9
|
```
|
18
10
|
|
19
11
|
And then execute:
|
@@ -29,7 +21,7 @@ require "scalingo"
|
|
29
21
|
|
30
22
|
scalingo = Scalingo::Client.new
|
31
23
|
scalingo.authenticate_with(access_token: ENV["SCALINGO_TOKEN"])
|
32
|
-
scalingo.
|
24
|
+
scalingo.self
|
33
25
|
```
|
34
26
|
|
35
27
|
## Conventions
|
@@ -37,16 +29,13 @@ scalingo.user.self
|
|
37
29
|
Most methods map to one (and only one) request, and their signature follows this format:
|
38
30
|
|
39
31
|
```ruby
|
40
|
-
client.section.request(id
|
32
|
+
client.section.request(app_id:, id:, body:)
|
41
33
|
```
|
42
34
|
|
43
35
|
* Depending on the request, there may be no id (collection and/or singular resource, such as `user`), one, or two ids (many resources are nested under an app).
|
44
36
|
* Most of the time, this library won't do any processing of the payload, but there's a few things to know:
|
45
|
-
* the root key
|
37
|
+
* the root key doesn't need to be specified, the library handles it
|
46
38
|
* in some cases, the payload isn't passed as supplied (`metrics`, for instance, extracts the parts that are meant to be used as url fragments)
|
47
|
-
* headers can be supplied on a per-request basis, using either the last argument or the block version:
|
48
|
-
* when using the last argument, you may have to pass an empty hash payload (`{}`)
|
49
|
-
* when using the block form, the faraday object is supplied as argument, and you can do any kind of treatment you would like
|
50
39
|
|
51
40
|
## Configuration
|
52
41
|
|
@@ -58,23 +47,13 @@ changing the configuration globally will therefore not affect already existing o
|
|
58
47
|
|
59
48
|
```ruby
|
60
49
|
Scalingo.configure do |config|
|
61
|
-
# Default region. Must be a supported region (
|
50
|
+
# Default region. Must be a supported region (osc_fr1, osc_secnum_fr1)
|
62
51
|
config.default_region = :osc_fr1
|
63
52
|
|
64
53
|
# Configure the User Agent header
|
65
54
|
config.user_agent = "Scalingo Ruby Client v#{Scalingo::VERSION}"
|
66
55
|
|
67
|
-
#
|
68
|
-
# Set to nil to never raise.
|
69
|
-
config.exchanged_token_validity = 1.hour
|
70
|
-
|
71
|
-
# Having this setting to true prevents performing requests that would fail due to lack of authentication headers.
|
72
|
-
config.raise_on_missing_authentication = true
|
73
|
-
|
74
|
-
# Raise an exception when the bearer token in use is supposed to be invalid
|
75
|
-
config.raise_on_expired_token = false
|
76
|
-
|
77
|
-
# These headers will be added to every request. Individual methods may override them.
|
56
|
+
# These headers will be added to every request
|
78
57
|
# This should be a hash or a callable object that returns a hash.
|
79
58
|
config.additional_headers = {}
|
80
59
|
|
@@ -87,26 +66,9 @@ You can also configure each client separately.
|
|
87
66
|
Values not supplied will be copied from the global configuration.
|
88
67
|
|
89
68
|
```ruby
|
90
|
-
scalingo = Scalingo::Client.new(
|
69
|
+
scalingo = Scalingo::Client.new(user_agent: "A new kind of agent")
|
91
70
|
```
|
92
71
|
|
93
|
-
## Response object
|
94
|
-
|
95
|
-
Responses are parsed with the keys symbolized and then encapsulated in a `Scalingo::API::Response` object:
|
96
|
-
|
97
|
-
* `response.status` containts the HTTP status code
|
98
|
-
* `response.data` contains the "relevant" data, without the json root key (when relevant)
|
99
|
-
* `response.full_body` contains the full response body
|
100
|
-
* `response.meta` contains the meta object, if there's any
|
101
|
-
* `response.headers` containts all the response headers
|
102
|
-
|
103
|
-
Some helper methods are defined on this object:
|
104
|
-
* `response.successful?` returns true when the code is 2XX
|
105
|
-
* `response.paginated?` returns true if the reponse has metadata relative to pagination
|
106
|
-
* `response.operation?` returns true if the response contains a header relative to an ongoing operation
|
107
|
-
* `response.operation_url` returns the URL to query to get the status of the operation
|
108
|
-
* `response.operation` performs a request to retrieve the operation
|
109
|
-
|
110
72
|
## Other details on the code architecture
|
111
73
|
|
112
74
|
* `Scalingo::Client` instances hold configuration and the token used for authentication
|
@@ -127,13 +89,13 @@ scalingo.authenticate_with(access_token: "my_access_token")
|
|
127
89
|
scalingo.authenticate_with(bearer_token: "my_bearer_jwt")
|
128
90
|
|
129
91
|
# Return your profile
|
130
|
-
scalingo.user.
|
92
|
+
scalingo.self # or scalingo.auth.user.find
|
131
93
|
|
132
94
|
# List your SSH Keys
|
133
95
|
scalingo.keys.all # OR scalingo.auth.keys.all
|
134
96
|
|
135
97
|
# Show one SSH Key
|
136
|
-
scalingo.keys.show("my-key-id")
|
98
|
+
scalingo.keys.show(id: "my-key-id")
|
137
99
|
|
138
100
|
# List your apps on the default region
|
139
101
|
scalingo.apps.all # OR scalingo.region.apps.all
|
@@ -151,8 +113,6 @@ Requests to the [database API](https://developers.scalingo.com/databases/) requi
|
|
151
113
|
extra authentication for each addon you want to interact with. [Addon authentication
|
152
114
|
tokens are valid for one hour](https://developers.scalingo.com/addons#get-addon-token).
|
153
115
|
|
154
|
-
Supported regions for database API are `db_api_osc_fr1` and `db_api_osc_secnum_fr1`.
|
155
|
-
|
156
116
|
```ruby
|
157
117
|
require "scalingo"
|
158
118
|
|
@@ -160,23 +120,20 @@ scalingo = Scalingo::Client.new
|
|
160
120
|
scalingo.authenticate_with(access_token: "my_access_token")
|
161
121
|
|
162
122
|
# First, authenticate using the `addons` API
|
163
|
-
scalingo.osc_fr1.addons.
|
123
|
+
dbclient = scalingo.osc_fr1.addons.database_client_for(app_id:, id:)
|
164
124
|
|
165
125
|
# Once authenticated for that specific addon, you can interact with
|
166
126
|
# database and backup APIs.
|
167
127
|
# IDs of databases are the IDs of the corresponding addons
|
168
128
|
|
169
129
|
# get all information for a given database
|
170
|
-
|
130
|
+
dbclient.databases.find(id:)
|
171
131
|
|
172
132
|
# get all backups for a given database
|
173
|
-
|
133
|
+
dbclient.backups.list(addon_id:)
|
174
134
|
|
175
135
|
# get URL to download backup archive
|
176
|
-
|
177
|
-
|
178
|
-
# you can omit the region to use the default one
|
179
|
-
scalingo.databases.find(addon_id)
|
136
|
+
dbclient.backups.archive(addon_id:, id:)
|
180
137
|
|
181
138
|
```
|
182
139
|
|
@@ -193,9 +150,3 @@ bundle
|
|
193
150
|
```bash
|
194
151
|
bundle exec rspec
|
195
152
|
```
|
196
|
-
|
197
|
-
### Release a new version
|
198
|
-
|
199
|
-
```bash
|
200
|
-
# TODO
|
201
|
-
```
|
data/bin/console
CHANGED
@@ -3,10 +3,20 @@
|
|
3
3
|
require "bundler/setup"
|
4
4
|
require "scalingo"
|
5
5
|
|
6
|
+
begin
|
7
|
+
require "dotenv"
|
8
|
+
Dotenv.load(".env.local")
|
9
|
+
rescue LoadError
|
10
|
+
puts("dotenv not available - no .env.local loading")
|
11
|
+
end
|
12
|
+
|
6
13
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
14
|
# with your gem easier. You can also use a different console, if you like.
|
8
15
|
|
9
16
|
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
17
|
require "pry"
|
11
18
|
|
12
|
-
|
19
|
+
client = Scalingo::Client.new
|
20
|
+
client.authenticate_with(access_token: ENV["SCALINGO_API_TOKEN"]) if ENV["SCALINGO_API_TOKEN"].present?
|
21
|
+
|
22
|
+
Pry.start(binding, quiet: true)
|
data/bin/lint
ADDED
data/bin/setup
CHANGED
@@ -1,8 +1,23 @@
|
|
1
|
-
#!/usr/bin/env
|
2
|
-
|
3
|
-
IFS=$'\n\t'
|
4
|
-
set -vx
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "fileutils"
|
5
3
|
|
6
|
-
|
4
|
+
# path to your application root.
|
5
|
+
GEM_ROOT = File.expand_path("..", __dir__)
|
7
6
|
|
8
|
-
|
7
|
+
def system!(*args)
|
8
|
+
system(*args, exception: true)
|
9
|
+
end
|
10
|
+
|
11
|
+
FileUtils.chdir GEM_ROOT do
|
12
|
+
# This script is a way to set up or update your development environment automatically.
|
13
|
+
# This script is idempotent, so that you can run it at any time and get an expectable outcome.
|
14
|
+
# Add necessary setup steps to this file.
|
15
|
+
|
16
|
+
puts "== Installing dependencies =="
|
17
|
+
system! "gem install bundler --conservative"
|
18
|
+
system("bundle check") || system!("bundle install")
|
19
|
+
|
20
|
+
# Creating useful but unversioned env files
|
21
|
+
puts "\n== Creating .env.*.local files =="
|
22
|
+
FileUtils.touch(".env.local")
|
23
|
+
end
|
data/bin/specs
ADDED
data/lib/scalingo/api/client.rb
CHANGED
@@ -1,14 +1,20 @@
|
|
1
1
|
require "scalingo/token_holder"
|
2
|
+
require "scalingo/faraday/response"
|
3
|
+
require "scalingo/faraday/extract_meta"
|
4
|
+
require "scalingo/faraday/extract_root_value"
|
5
|
+
require "active_support/core_ext/hash"
|
2
6
|
|
3
7
|
module Scalingo
|
4
8
|
module API
|
5
9
|
class Client
|
6
10
|
include TokenHolder
|
7
11
|
|
8
|
-
attr_reader :config, :token_holder, :url
|
12
|
+
attr_reader :config, :token_holder, :url, :region
|
9
13
|
|
10
|
-
def initialize(url, scalingo: nil, config: {})
|
14
|
+
def initialize(url, scalingo: nil, region: nil, config: {})
|
11
15
|
@url = url
|
16
|
+
@region = region
|
17
|
+
|
12
18
|
parent_config = Scalingo.config
|
13
19
|
|
14
20
|
if scalingo
|
@@ -40,15 +46,15 @@ module Scalingo
|
|
40
46
|
end
|
41
47
|
end
|
42
48
|
|
49
|
+
# :nocov:
|
43
50
|
def inspect
|
44
51
|
str = %(<#{self.class}:0x#{object_id.to_s(16)} url:"#{@url}" methods:)
|
45
52
|
|
46
|
-
|
47
|
-
str << methods.to_s
|
48
|
-
|
53
|
+
str << self.class.instance_methods(false).to_s
|
49
54
|
str << ">"
|
50
55
|
str
|
51
56
|
end
|
57
|
+
# :nocov:
|
52
58
|
|
53
59
|
## Faraday objects
|
54
60
|
def headers
|
@@ -71,59 +77,35 @@ module Scalingo
|
|
71
77
|
}
|
72
78
|
end
|
73
79
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
authenticated_connection
|
79
|
-
rescue Error::Unauthenticated
|
80
|
-
raise unless fallback_to_guest
|
81
|
-
|
82
|
-
unauthenticated_connection
|
83
|
-
end
|
84
|
-
|
85
|
-
def unauthenticated_connection
|
86
|
-
@unauthenticated_conn ||= Faraday.new(connection_options) { |conn|
|
80
|
+
def guest_connection
|
81
|
+
@guest_connection ||= Faraday.new(connection_options) { |conn|
|
82
|
+
conn.response :extract_root_value
|
83
|
+
conn.response :extract_meta
|
87
84
|
conn.response :json, content_type: /\bjson$/, parser_options: {symbolize_names: true}
|
85
|
+
conn.response :raise_error
|
88
86
|
conn.request :json
|
89
87
|
|
90
88
|
conn.adapter(config.faraday_adapter) if config.faraday_adapter
|
91
89
|
}
|
92
90
|
end
|
93
91
|
|
94
|
-
def
|
92
|
+
def connection
|
95
93
|
return @connection if @connection
|
96
94
|
|
97
95
|
# Missing token handling. Token expiration is handled in the `value` method.
|
98
|
-
unless token_holder.token&.value
|
99
|
-
if config.raise_on_missing_authentication
|
100
|
-
raise Error::Unauthenticated
|
101
|
-
else
|
102
|
-
return unauthenticated_connection
|
103
|
-
end
|
104
|
-
end
|
96
|
+
raise Error::Unauthenticated unless token_holder.token&.value&.present?
|
105
97
|
|
106
98
|
@connection = Faraday.new(connection_options) { |conn|
|
99
|
+
conn.response :extract_root_value
|
100
|
+
conn.response :extract_meta
|
107
101
|
conn.response :json, content_type: /\bjson$/, parser_options: {symbolize_names: true}
|
108
102
|
conn.request :json
|
103
|
+
conn.response :raise_error
|
109
104
|
conn.request :authorization, "Bearer", -> { token_holder.token&.value }
|
110
105
|
|
111
106
|
conn.adapter(config.faraday_adapter) if config.faraday_adapter
|
112
107
|
}
|
113
108
|
end
|
114
|
-
|
115
|
-
def database_connection(database_id)
|
116
|
-
raise Error::Unauthenticated unless token_holder.authenticated_for_database?(database_id)
|
117
|
-
|
118
|
-
@database_connections ||= {}
|
119
|
-
@database_connections[database_id] ||= Faraday.new(connection_options) { |conn|
|
120
|
-
conn.response :json, content_type: /\bjson$/, parser_options: {symbolize_names: true}
|
121
|
-
conn.request :json
|
122
|
-
conn.request :authorization, "Bearer", -> { token_holder.database_tokens[database_id]&.value }
|
123
|
-
|
124
|
-
conn.adapter(config.faraday_adapter) if config.faraday_adapter
|
125
|
-
}
|
126
|
-
end
|
127
109
|
end
|
128
110
|
end
|
129
111
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
+
require "addressable/template"
|
1
2
|
require "forwardable"
|
2
|
-
require "scalingo/api/response"
|
3
3
|
|
4
4
|
module Scalingo
|
5
5
|
module API
|
@@ -7,28 +7,105 @@ module Scalingo
|
|
7
7
|
extend Forwardable
|
8
8
|
attr_reader :client
|
9
9
|
|
10
|
+
# Add a handler for a given endpoint
|
11
|
+
%i[get post put patch delete].each do |method|
|
12
|
+
# @example
|
13
|
+
# class Example < API::Endpoint
|
14
|
+
# get :all, "some-endpoint/{id}/subthings{?query*}", optional: [:query]
|
15
|
+
# post :create, "some-endpoint", root_key: :subthing
|
16
|
+
# end
|
17
|
+
define_singleton_method(method) do |name, path, **default_attrs, &default_block|
|
18
|
+
# @example
|
19
|
+
# endpoint = Example.new
|
20
|
+
# endpoint.all(id: "1", query: {page: 1})
|
21
|
+
# endpoint.create(name: "thing")
|
22
|
+
define_method(name) do |**runtime_attrs, &runtime_block|
|
23
|
+
params = {**default_attrs, **runtime_attrs}
|
24
|
+
|
25
|
+
request(method, path, **params) do |req|
|
26
|
+
default_block&.call(req, params)
|
27
|
+
runtime_block&.call(req, params)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Those methods are not meant to be used outside of a class definition
|
33
|
+
private_class_method method
|
34
|
+
end
|
35
|
+
|
10
36
|
def initialize(client)
|
11
37
|
@client = client
|
12
38
|
end
|
13
39
|
|
14
40
|
def_delegator :client, :connection
|
15
|
-
def_delegator :client, :database_connection
|
16
41
|
|
17
|
-
|
18
|
-
|
42
|
+
# Perform a request to the API.
|
43
|
+
# path can be an URI template; and faraday expect valid URIs - the parser raises when templates aren't fully expanded.
|
44
|
+
# therefore, we have to take care of the expansion before passing the path to faraday.
|
45
|
+
# note: This method is not unit-tested directly, but integrations tests are covering it extensively.
|
46
|
+
# @see https://github.com/sporkmonger/addressable?tab=readme-ov-file#uri-templates
|
47
|
+
# @see https://www.rfc-editor.org/rfc/rfc6570.txt
|
48
|
+
# @see https://github.com/lostisland/faraday/issues/1487
|
49
|
+
def request(method, path, body: nil, root_key: nil, connected: true, basic: nil, dry_run: false, params_as_body: false, **params, &block)
|
50
|
+
template = Addressable::Template.new(path)
|
19
51
|
|
20
|
-
|
52
|
+
# If the template has keys, we need to expand it with the params
|
53
|
+
if template.keys.present?
|
54
|
+
# We assume every variable in the template is required
|
55
|
+
expected_keys = Set.new(template.keys.map(&:to_sym))
|
56
|
+
# ... but we can opt out by specifying :optional when performing the request or in the endpoint definition
|
57
|
+
expected_keys -= params[:optional] if params[:optional].present?
|
21
58
|
|
22
|
-
|
23
|
-
|
24
|
-
|
59
|
+
# if any required key is missing, raise an error with the missing keys,
|
60
|
+
# as if it was a regular keyword argument that was not supplied
|
61
|
+
if expected_keys.present?
|
62
|
+
received_keys = Set.new(params.keys.map(&:to_sym))
|
63
|
+
|
64
|
+
unless received_keys.superset?(expected_keys)
|
65
|
+
missings = (expected_keys - received_keys).map { |item| sprintf("%p", item) }.join(" ")
|
66
|
+
raise ArgumentError, "missing keyword: #{missings}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Now, we can expand the template with the supplied params
|
71
|
+
actual_path = template.expand(params).to_s
|
72
|
+
else
|
73
|
+
# Otherwise, it's not a template but a string to be used as it is
|
74
|
+
actual_path = path
|
75
|
+
end
|
76
|
+
|
77
|
+
# we nest the given body under the root_key if it's present
|
78
|
+
request_body = body
|
79
|
+
request_body = {root_key => body} if request_body && root_key
|
80
|
+
|
81
|
+
# We can use the client in either connected or unconnected mode
|
82
|
+
conn = connected ? client.connection : client.guest_connection
|
83
|
+
|
84
|
+
# We can specify basic auth credentials if needed
|
85
|
+
conn.request :authorization, :basic, basic[:user], basic[:password] if basic.present?
|
86
|
+
|
87
|
+
# Finally, perform the request.
|
88
|
+
# Faraday sends params as query string for GET/HEAD/DELETE requests and as request body for the others;
|
89
|
+
# in some rare cases (variables bulk-delete) we need to send them as actual body.
|
90
|
+
if Faraday::METHODS_WITH_QUERY.include?(method.to_s) && params_as_body
|
91
|
+
conn.public_send(method, actual_path) do |req|
|
92
|
+
req.body = request_body
|
93
|
+
block&.call(req) || req
|
94
|
+
end
|
95
|
+
else
|
96
|
+
conn.public_send(method, actual_path, request_body, &block)
|
97
|
+
end
|
25
98
|
end
|
26
99
|
|
27
|
-
|
100
|
+
# :nocov:
|
101
|
+
def inspect
|
102
|
+
str = %(<#{self.class}:0x#{object_id.to_s(16)} base_url:"#{@client.url}" endpoints:)
|
28
103
|
|
29
|
-
|
30
|
-
|
104
|
+
str << self.class.instance_methods(false).to_s
|
105
|
+
str << ">"
|
106
|
+
str
|
31
107
|
end
|
108
|
+
# :nocov:
|
32
109
|
end
|
33
110
|
end
|
34
111
|
end
|
data/lib/scalingo/auth/keys.rb
CHANGED
@@ -2,55 +2,9 @@ require "scalingo/api/endpoint"
|
|
2
2
|
|
3
3
|
module Scalingo
|
4
4
|
class Auth::Keys < API::Endpoint
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
"keys",
|
10
|
-
data,
|
11
|
-
headers,
|
12
|
-
&block
|
13
|
-
)
|
14
|
-
|
15
|
-
unpack(:keys) { response }
|
16
|
-
end
|
17
|
-
|
18
|
-
def show(id, headers = nil, &block)
|
19
|
-
data = nil
|
20
|
-
|
21
|
-
response = connection.get(
|
22
|
-
"keys/#{id}",
|
23
|
-
data,
|
24
|
-
headers,
|
25
|
-
&block
|
26
|
-
)
|
27
|
-
|
28
|
-
unpack(:key) { response }
|
29
|
-
end
|
30
|
-
|
31
|
-
def create(payload, headers = nil, &block)
|
32
|
-
data = {key: payload}
|
33
|
-
|
34
|
-
response = connection.post(
|
35
|
-
"keys",
|
36
|
-
data,
|
37
|
-
headers,
|
38
|
-
&block
|
39
|
-
)
|
40
|
-
|
41
|
-
unpack(:key) { response }
|
42
|
-
end
|
43
|
-
|
44
|
-
def destroy(id, headers = nil, &block)
|
45
|
-
data = nil
|
46
|
-
response = connection.delete(
|
47
|
-
"keys/#{id}",
|
48
|
-
data,
|
49
|
-
headers,
|
50
|
-
&block
|
51
|
-
)
|
52
|
-
|
53
|
-
unpack { response }
|
54
|
-
end
|
5
|
+
get :list, "keys"
|
6
|
+
get :find, "keys/{id}"
|
7
|
+
post :create, "keys", root_key: :key
|
8
|
+
delete :delete, "keys/{id}"
|
55
9
|
end
|
56
10
|
end
|
@@ -2,56 +2,9 @@ require "scalingo/api/endpoint"
|
|
2
2
|
|
3
3
|
module Scalingo
|
4
4
|
class Auth::ScmIntegrations < API::Endpoint
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
"scm_integrations",
|
10
|
-
data,
|
11
|
-
headers,
|
12
|
-
&block
|
13
|
-
)
|
14
|
-
|
15
|
-
unpack(:scm_integrations) { response }
|
16
|
-
end
|
17
|
-
|
18
|
-
def show(id, headers = nil, &block)
|
19
|
-
data = nil
|
20
|
-
|
21
|
-
response = connection.get(
|
22
|
-
"scm_integrations/#{id}",
|
23
|
-
data,
|
24
|
-
headers,
|
25
|
-
&block
|
26
|
-
)
|
27
|
-
|
28
|
-
unpack(:scm_integration) { response }
|
29
|
-
end
|
30
|
-
|
31
|
-
def create(payload, headers = nil, &block)
|
32
|
-
data = {scm_integration: payload}
|
33
|
-
|
34
|
-
response = connection.post(
|
35
|
-
"scm_integrations",
|
36
|
-
data,
|
37
|
-
headers,
|
38
|
-
&block
|
39
|
-
)
|
40
|
-
|
41
|
-
unpack(:scm_integration) { response }
|
42
|
-
end
|
43
|
-
|
44
|
-
def destroy(id, headers = nil, &block)
|
45
|
-
data = nil
|
46
|
-
|
47
|
-
response = connection.delete(
|
48
|
-
"scm_integrations/#{id}",
|
49
|
-
data,
|
50
|
-
headers,
|
51
|
-
&block
|
52
|
-
)
|
53
|
-
|
54
|
-
unpack { response }
|
55
|
-
end
|
5
|
+
get :list, "scm_integrations"
|
6
|
+
get :find, "scm_integrations/{id}"
|
7
|
+
post :create, "scm_integrations", root_key: :scm_integration
|
8
|
+
delete :delete, "scm_integrations/{id}"
|
56
9
|
end
|
57
10
|
end
|