scalingo 3.5.0 → 4.0.beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +1 -1
- data/.github/workflows/ruby.yml +1 -1
- data/.rubocop.yml +40 -0
- data/CHANGELOG.md +22 -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 +4 -1
- metadata +61 -205
- 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: 5b71852cdaac8d4401623f89773aa2191bc598dadab8f95c18cf466adb5996f6
|
4
|
+
data.tar.gz: 061daaeac33ab02683b9a826a419ab86c04ddf9ecc01a001ef3abf1942c16e2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f06e001affb8d65086b146ef55714fd28f6a3876f456031f6f6c0ee08c60e456592fcaf37c7808e428e9804118b6cc2a1bd564f89738f89e75b1d376edb7b40e
|
7
|
+
data.tar.gz: 3114674390afd5031c900713431c34f976ec73969d61025d1e9a0d74b347277ec9829bbdfa70c944f5bf0c3ccbd468b700040e03978ad0a534ad79747ed46dc7
|
data/.github/dependabot.yml
CHANGED
data/.github/workflows/ruby.yml
CHANGED
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,42 @@ 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
|
+
RSpec/SpecFilePathSuffix:
|
28
|
+
Enabled: true
|
29
|
+
|
30
|
+
# Not convinced by how strict this cop is by default
|
31
|
+
RSpec/MultipleExpectations:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
RSpec/MultipleMemoizedHelpers:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
# Really not convinced by this one
|
38
|
+
RSpec/NamedSubject:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
# Default is 3, but 4 is used and relevant (class / method / global state / local state)
|
42
|
+
RSpec/NestedGroups:
|
43
|
+
Max: 4
|
44
|
+
|
45
|
+
# Not always relevant for libs
|
46
|
+
RSpec/SpecFilePathFormat:
|
47
|
+
Exclude:
|
48
|
+
- 'spec/scalingo/faraday/**/*'
|
49
|
+
|
50
|
+
# Not sure about this one - requires more research
|
51
|
+
RSpec/MessageSpies:
|
52
|
+
Enabled: false
|
53
|
+
|
54
|
+
# Not sure about this one - requires more research
|
55
|
+
RSpec/StubbedMock:
|
56
|
+
Enabled: false
|
57
|
+
|
58
|
+
# Not sure about this one - requires more research
|
59
|
+
RSpec/SubjectStub:
|
60
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,25 @@
|
|
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`
|
15
|
+
|
16
|
+
## 4.0.beta2 - 2025-03-07
|
17
|
+
|
18
|
+
* Added support for Ruby on Rails 8.0 ([PR#67](https://github.com/Scalingo/scalingo-ruby-api/pull/67) by [@zaratan](https://github.com/zaratan))
|
19
|
+
|
20
|
+
## 3.6.0 - 2025-03-07
|
21
|
+
|
22
|
+
* Added support for Ruby on Rails 8.0 ([PR#67](https://github.com/Scalingo/scalingo-ruby-api/pull/67) by [@zaratan](https://github.com/zaratan))
|
2
23
|
|
3
24
|
## 3.5.0 - 2023-12-28
|
4
25
|
|
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
|