scalingo 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +8 -0
- data/.github/workflows/publish.yml +1 -1
- data/.github/workflows/ruby.yml +2 -6
- data/.sclng/metadata.toml +8 -0
- data/CHANGELOG.md +7 -0
- data/README.md +32 -1
- data/lib/scalingo/api/client.rb +23 -9
- data/lib/scalingo/api/endpoint.rb +1 -0
- data/lib/scalingo/client.rb +17 -7
- data/lib/scalingo/regional/addons.rb +15 -0
- data/lib/scalingo/regional_database/backups.rb +44 -0
- data/lib/scalingo/regional_database/databases.rb +18 -0
- data/lib/scalingo/regional_database.rb +13 -0
- data/lib/scalingo/token_holder.rb +44 -13
- data/lib/scalingo/version.rb +1 -1
- data/samples/regional_database/backups/_meta.json +4 -0
- data/samples/regional_database/backups/archive-200.json +24 -0
- data/samples/regional_database/backups/archive-400.json +24 -0
- data/samples/regional_database/backups/create-201.json +30 -0
- data/samples/regional_database/backups/create-400.json +24 -0
- data/samples/regional_database/backups/for-200.json +52 -0
- data/samples/regional_database/backups/for-400.json +24 -0
- data/samples/regional_database/databases/_meta.json +3 -0
- data/samples/regional_database/databases/find-200.json +45 -0
- data/samples/regional_database/databases/find-400.json +24 -0
- data/spec/scalingo/api/client_spec.rb +41 -0
- data/spec/scalingo/regional/addons_spec.rb +20 -0
- data/spec/scalingo/regional_database/backups_spec.rb +58 -0
- data/spec/scalingo/regional_database/databases_spec.rb +23 -0
- data/spec/scalingo/regional_database_spec.rb +11 -0
- data/spec/scalingo/token_holder_spec.rb +81 -0
- metadata +26 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bc653c0172dd4bc1b2b1cb80948582e0069c058d615f74dcc2bb9fac3d467245
|
|
4
|
+
data.tar.gz: 4482433e8ca28c3a7ab72d2f22471f2ef2f61a5aa6b0f34d40c2faba9ecb5d98
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 708a8fbe40bf16f20e0cb2fcd94506d2e2e21d3c02c0d9e521fc02396897835efb695fda4b472f0eafb48d29e262e3f679166af8c5e1efeab4978bf841539d15
|
|
7
|
+
data.tar.gz: 5d75e30a6bdef5ae37be20869ffb81da7ceb82cd01d1a6cb97387054de87c3e1b4c6e2d6927deaaee22eb8195dd5d6ab0b51e177dfd66b57fc0fca6ec4a289ff
|
data/.github/workflows/ruby.yml
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
# This workflow uses actions that are not certified by GitHub.
|
|
2
|
-
# They are provided by a third-party and are governed by
|
|
3
|
-
# separate terms of service, privacy policy, and support
|
|
4
|
-
# documentation.
|
|
5
1
|
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
|
6
2
|
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
|
7
3
|
|
|
@@ -18,7 +14,7 @@ jobs:
|
|
|
18
14
|
lint:
|
|
19
15
|
runs-on: ubuntu-latest
|
|
20
16
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
17
|
+
- uses: actions/checkout@v3
|
|
22
18
|
- name: Set up Ruby
|
|
23
19
|
uses: ruby/setup-ruby@v1
|
|
24
20
|
with:
|
|
@@ -33,7 +29,7 @@ jobs:
|
|
|
33
29
|
matrix:
|
|
34
30
|
ruby-version: ['2.6', '2.7', '3.0']
|
|
35
31
|
steps:
|
|
36
|
-
- uses: actions/checkout@
|
|
32
|
+
- uses: actions/checkout@v3
|
|
37
33
|
- name: Set up Ruby
|
|
38
34
|
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
|
39
35
|
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
## 3.2.0 - 2022-12-23
|
|
4
|
+
|
|
5
|
+
* Removal: `Scalingo::Client#agora_fr1` had been removed since the region no longer exists.
|
|
6
|
+
* New: Add `addons#authenticate!` endpoint
|
|
7
|
+
* New API: database API
|
|
8
|
+
* New API: backup API
|
|
9
|
+
|
|
3
10
|
## 3.1.0
|
|
4
11
|
|
|
5
12
|
* Compat: support for ActiveSupport (and therefore Rails) 7, @Intrepidd
|
data/README.md
CHANGED
|
@@ -5,7 +5,7 @@ A ruby wrapper for the Scalingo API
|
|
|
5
5
|
### Migration from v2
|
|
6
6
|
|
|
7
7
|
This gem is changing its name from `scalingo-ruby-api` to `scalingo`,
|
|
8
|
-
and the
|
|
8
|
+
and the versioning does **not** reset; the first major version of `scalingo`
|
|
9
9
|
will therefore be `3.x.x`.
|
|
10
10
|
|
|
11
11
|
You can check the version 2 at [the v2 branch of this repository](https://github.com/Scalingo/scalingo-ruby-api/tree/v2)
|
|
@@ -145,6 +145,37 @@ scalingo.osc_fr1.apps.all # OR scalingo.region(:osc_fr1).apps.all
|
|
|
145
145
|
scalingo.apps.create(name: "my-new-app", dry_run: true)
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
+
### Interacting with databases
|
|
149
|
+
|
|
150
|
+
Requests to the [database API](https://developers.scalingo.com/databases/) requires
|
|
151
|
+
extra authentication for each addon you want to interact with. [Addon authentication
|
|
152
|
+
tokens are valid for one hour](https://developers.scalingo.com/addons#get-addon-token).
|
|
153
|
+
|
|
154
|
+
Supported regions for database API are `db_api_osc_fr1` and `db_api_osc_secnum_fr1`.
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
require "scalingo"
|
|
158
|
+
|
|
159
|
+
scalingo = Scalingo::Client.new
|
|
160
|
+
scalingo.authenticate_with(access_token: "my_access_token")
|
|
161
|
+
|
|
162
|
+
# First, authenticate using the `addons` API
|
|
163
|
+
scalingo.osc_fr1.addons.authenticate!(app_id, addon_id)
|
|
164
|
+
|
|
165
|
+
# Once authenticated for that specific addon, you can interact with
|
|
166
|
+
# database and backup APIs.
|
|
167
|
+
# IDs of databases are the IDs of the corresponding addons
|
|
168
|
+
|
|
169
|
+
# get all information for a given database
|
|
170
|
+
scalingo.db_api_osc_fr1.databases.find(addon_id)
|
|
171
|
+
|
|
172
|
+
# get all backups for a given database
|
|
173
|
+
scalingo.db_api_osc_fr1.backups.for(addon_id)
|
|
174
|
+
|
|
175
|
+
# get URL to download backup archive
|
|
176
|
+
scalingo.db_api_osc_fr1.backups.archive(addon_id, backup_id)
|
|
177
|
+
```
|
|
178
|
+
|
|
148
179
|
## Development
|
|
149
180
|
|
|
150
181
|
### Install
|
data/lib/scalingo/api/client.rb
CHANGED
|
@@ -75,15 +75,11 @@ module Scalingo
|
|
|
75
75
|
# this method may return the unauthenticated connection
|
|
76
76
|
# even with `fallback_to_guest: false`
|
|
77
77
|
def connection(fallback_to_guest: false)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
end
|
|
84
|
-
else
|
|
85
|
-
authenticated_connection
|
|
86
|
-
end
|
|
78
|
+
authenticated_connection
|
|
79
|
+
rescue Error::Unauthenticated
|
|
80
|
+
raise unless fallback_to_guest
|
|
81
|
+
|
|
82
|
+
unauthenticated_connection
|
|
87
83
|
end
|
|
88
84
|
|
|
89
85
|
def unauthenticated_connection
|
|
@@ -119,6 +115,24 @@ module Scalingo
|
|
|
119
115
|
conn.adapter(config.faraday_adapter) if config.faraday_adapter
|
|
120
116
|
}
|
|
121
117
|
end
|
|
118
|
+
|
|
119
|
+
def database_connection(database_id)
|
|
120
|
+
raise Error::Unauthenticated unless token_holder.authenticated_for_database?(database_id)
|
|
121
|
+
|
|
122
|
+
@database_connections ||= {}
|
|
123
|
+
@database_connections[database_id] ||= Faraday.new(connection_options) { |conn|
|
|
124
|
+
conn.response :json, content_type: /\bjson$/, parser_options: {symbolize_names: true}
|
|
125
|
+
conn.request :json
|
|
126
|
+
|
|
127
|
+
bearer_token = token_holder.database_tokens[database_id]&.value
|
|
128
|
+
if bearer_token
|
|
129
|
+
auth_header = Faraday::Request::Authorization.header "Bearer", bearer_token
|
|
130
|
+
conn.headers[Faraday::Request::Authorization::KEY] = auth_header
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
conn.adapter(config.faraday_adapter) if config.faraday_adapter
|
|
134
|
+
}
|
|
135
|
+
end
|
|
122
136
|
end
|
|
123
137
|
end
|
|
124
138
|
end
|
data/lib/scalingo/client.rb
CHANGED
|
@@ -2,6 +2,7 @@ require "scalingo/core_client"
|
|
|
2
2
|
require "scalingo/auth"
|
|
3
3
|
require "scalingo/billing"
|
|
4
4
|
require "scalingo/regional"
|
|
5
|
+
require "scalingo/regional_database"
|
|
5
6
|
|
|
6
7
|
module Scalingo
|
|
7
8
|
class Client < CoreClient
|
|
@@ -20,19 +21,13 @@ module Scalingo
|
|
|
20
21
|
)
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
def agora_fr1
|
|
24
|
-
@agora_fr1 ||= Regional.new(
|
|
25
|
-
"https://api.agora-fr1.scalingo.com/v1",
|
|
26
|
-
scalingo: self,
|
|
27
|
-
)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
24
|
def osc_fr1
|
|
31
25
|
@osc_fr1 ||= Regional.new(
|
|
32
26
|
"https://api.osc-fr1.scalingo.com/v1",
|
|
33
27
|
scalingo: self,
|
|
34
28
|
)
|
|
35
29
|
end
|
|
30
|
+
alias_method :apps_api_osc_fr1, :osc_fr1
|
|
36
31
|
|
|
37
32
|
def osc_secnum_fr1
|
|
38
33
|
@osc_secnum_fr1 ||= Regional.new(
|
|
@@ -40,5 +35,20 @@ module Scalingo
|
|
|
40
35
|
scalingo: self,
|
|
41
36
|
)
|
|
42
37
|
end
|
|
38
|
+
alias_method :apps_api_osc_secnum_fr1, :osc_secnum_fr1
|
|
39
|
+
|
|
40
|
+
def db_api_osc_fr1
|
|
41
|
+
@db_api_osc_fr1 ||= RegionalDatabase.new(
|
|
42
|
+
"https://db-api.osc-fr1.scalingo.com/api",
|
|
43
|
+
scalingo: self,
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def db_api_osc_secnum_fr1
|
|
48
|
+
@db_api_osc_secnum_fr1 ||= RegionalDatabase.new(
|
|
49
|
+
"https://db-api.osc-secnum-fr1.scalingo.com/api",
|
|
50
|
+
scalingo: self,
|
|
51
|
+
)
|
|
52
|
+
end
|
|
43
53
|
end
|
|
44
54
|
end
|
|
@@ -80,6 +80,21 @@ module Scalingo
|
|
|
80
80
|
unpack(:addon) { response }
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
def authenticate!(app_id, addon_id, headers = nil, &block)
|
|
84
|
+
response = token(app_id, addon_id, headers, &block)
|
|
85
|
+
return response unless response.status == 200
|
|
86
|
+
|
|
87
|
+
token = response.data[:token]
|
|
88
|
+
client.token_holder.authenticate_database_with_bearer_token(
|
|
89
|
+
addon_id,
|
|
90
|
+
token,
|
|
91
|
+
expires_at: Time.now + 1.hour,
|
|
92
|
+
raise_on_expired_token: client.config.raise_on_expired_token,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
response
|
|
96
|
+
end
|
|
97
|
+
|
|
83
98
|
def token(app_id, addon_id, headers = nil, &block)
|
|
84
99
|
data = nil
|
|
85
100
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require "scalingo/api/endpoint"
|
|
2
|
+
|
|
3
|
+
module Scalingo
|
|
4
|
+
class RegionalDatabase::Backups < API::Endpoint
|
|
5
|
+
def create(addon_id, headers = nil, &block)
|
|
6
|
+
data = nil
|
|
7
|
+
|
|
8
|
+
response = database_connection(addon_id).post(
|
|
9
|
+
"databases/#{addon_id}/backups",
|
|
10
|
+
data,
|
|
11
|
+
headers,
|
|
12
|
+
&block
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
unpack { response }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def for(addon_id, headers = nil, &block)
|
|
19
|
+
data = nil
|
|
20
|
+
|
|
21
|
+
response = database_connection(addon_id).get(
|
|
22
|
+
"databases/#{addon_id}/backups",
|
|
23
|
+
data,
|
|
24
|
+
headers,
|
|
25
|
+
&block
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
unpack(:database_backups) { response }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def archive(addon_id, backup_id, headers = nil, &block)
|
|
32
|
+
data = nil
|
|
33
|
+
|
|
34
|
+
response = database_connection(addon_id).get(
|
|
35
|
+
"databases/#{addon_id}/backups/#{backup_id}/archive",
|
|
36
|
+
data,
|
|
37
|
+
headers,
|
|
38
|
+
&block
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
unpack { response }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require "scalingo/api/endpoint"
|
|
2
|
+
|
|
3
|
+
module Scalingo
|
|
4
|
+
class RegionalDatabase::Databases < API::Endpoint
|
|
5
|
+
def find(id, headers = nil, &block)
|
|
6
|
+
data = nil
|
|
7
|
+
|
|
8
|
+
response = database_connection(id).get(
|
|
9
|
+
"databases/#{id}",
|
|
10
|
+
data,
|
|
11
|
+
headers,
|
|
12
|
+
&block
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
unpack(:database) { response }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require "scalingo/api/client"
|
|
2
|
+
|
|
3
|
+
module Scalingo
|
|
4
|
+
class RegionalDatabase < API::Client
|
|
5
|
+
require "scalingo/regional_database/databases"
|
|
6
|
+
require "scalingo/regional_database/backups"
|
|
7
|
+
|
|
8
|
+
register_handlers!(
|
|
9
|
+
databases: Databases,
|
|
10
|
+
backups: Backups,
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -4,28 +4,59 @@ module Scalingo
|
|
|
4
4
|
module TokenHolder
|
|
5
5
|
def self.included(base)
|
|
6
6
|
base.attr_reader :token
|
|
7
|
+
base.attr_reader :database_tokens
|
|
7
8
|
end
|
|
8
9
|
|
|
9
10
|
def token=(input)
|
|
10
|
-
@token =
|
|
11
|
+
@token = bearer_token(input)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def add_database_token(database_id, token)
|
|
15
|
+
@database_tokens ||= {}
|
|
16
|
+
@database_tokens[database_id] = bearer_token(token)
|
|
11
17
|
end
|
|
12
18
|
|
|
13
19
|
def authenticated?
|
|
14
|
-
|
|
20
|
+
valid?(token)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def authenticated_for_database?(database_id)
|
|
24
|
+
return false if database_tokens.nil?
|
|
25
|
+
return false unless database_tokens.has_key?(database_id)
|
|
26
|
+
|
|
27
|
+
valid?(database_tokens[database_id])
|
|
15
28
|
end
|
|
16
29
|
|
|
17
30
|
def authenticate_with_bearer_token(bearer_token, expires_at:, raise_on_expired_token:)
|
|
18
|
-
self.token =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
self.token = build_bearer_token(bearer_token, expires_at: expires_at, raise_on_expired_token: raise_on_expired_token)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def authenticate_database_with_bearer_token(database_id, bearer_token, expires_at:, raise_on_expired_token:)
|
|
35
|
+
bearer_token = build_bearer_token(bearer_token, expires_at: expires_at, raise_on_expired_token: raise_on_expired_token)
|
|
36
|
+
|
|
37
|
+
add_database_token(database_id, bearer_token)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def valid?(token)
|
|
43
|
+
token.present? && !token.expired?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def bearer_token(token)
|
|
47
|
+
token.is_a?(BearerToken) ? token : BearerToken.new(token.to_s, raise_on_expired: config.raise_on_expired_token)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def build_bearer_token(bearer_token, expires_at:, raise_on_expired_token:)
|
|
51
|
+
return bearer_token unless expires_at
|
|
52
|
+
|
|
53
|
+
token = bearer_token.is_a?(BearerToken) ? bearer_token.value : bearer_token.to_s
|
|
54
|
+
|
|
55
|
+
BearerToken.new(
|
|
56
|
+
token,
|
|
57
|
+
expires_at: expires_at,
|
|
58
|
+
raise_on_expired: raise_on_expired_token,
|
|
59
|
+
)
|
|
29
60
|
end
|
|
30
61
|
end
|
|
31
62
|
end
|
data/lib/scalingo/version.rb
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"path": "/databases/ad-5ed10967884fef000f5e4fff/backups/5bb95a904ffb096e9a2831b8/archive",
|
|
3
|
+
"method": "get",
|
|
4
|
+
"request": {
|
|
5
|
+
"headers": {
|
|
6
|
+
"Authorization": "Bearer the-bearer-token"
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"response": {
|
|
10
|
+
"status": 200,
|
|
11
|
+
"headers": {
|
|
12
|
+
"Date": "Fri, 29 May 2020 13:08:59 GMT",
|
|
13
|
+
"Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"",
|
|
14
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
15
|
+
"Transfer-Encoding": "chunked",
|
|
16
|
+
"Connection": "keep-alive",
|
|
17
|
+
"Cache-Control": "max-age=0, private, must-revalidate",
|
|
18
|
+
"Referrer-Policy": "strict-origin-when-cross-origin"
|
|
19
|
+
},
|
|
20
|
+
"json_body": {
|
|
21
|
+
"download_url": "https://regional-database.scalingo.test/databases/ad-5ed10967884fef000f5e4fff/backups/5bb95a904ffb096e9a2831b8/download?token=token1234"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"path": "/databases/ad-5ed10967884fef000f5e4fff/backups/5bb95a904ffb096e9a2831b8/archive",
|
|
3
|
+
"method": "get",
|
|
4
|
+
"request": {
|
|
5
|
+
"headers": {
|
|
6
|
+
"Authorization": "Bearer the-bearer-token"
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"response": {
|
|
10
|
+
"status": 400,
|
|
11
|
+
"headers": {
|
|
12
|
+
"Date": "Fri, 29 May 2020 13:08:59 GMT",
|
|
13
|
+
"Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"",
|
|
14
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
15
|
+
"Transfer-Encoding": "chunked",
|
|
16
|
+
"Connection": "keep-alive",
|
|
17
|
+
"Cache-Control": "max-age=0, private, must-revalidate",
|
|
18
|
+
"Referrer-Policy": "strict-origin-when-cross-origin"
|
|
19
|
+
},
|
|
20
|
+
"json_body": {
|
|
21
|
+
"error": "unauthorized"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"path": "/databases/ad-5ed10967884fef000f5e4fff/backups",
|
|
3
|
+
"method": "post",
|
|
4
|
+
"request": {
|
|
5
|
+
"headers": {
|
|
6
|
+
"Authorization": "Bearer the-bearer-token"
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"response": {
|
|
10
|
+
"status": 201,
|
|
11
|
+
"headers": {
|
|
12
|
+
"Date": "Fri, 29 May 2020 13:08:59 GMT",
|
|
13
|
+
"Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"",
|
|
14
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
15
|
+
"Transfer-Encoding": "chunked",
|
|
16
|
+
"Connection": "keep-alive",
|
|
17
|
+
"Cache-Control": "max-age=0, private, must-revalidate",
|
|
18
|
+
"Referrer-Policy": "strict-origin-when-cross-origin"
|
|
19
|
+
},
|
|
20
|
+
"json_body": {
|
|
21
|
+
"id": "5b8b36104ffb090be1ac3ce1",
|
|
22
|
+
"created_at": "2019-07-18T03:00:00.178+02:00",
|
|
23
|
+
"name": "20180902010000_kibana-3938",
|
|
24
|
+
"size": 0,
|
|
25
|
+
"status": "pending",
|
|
26
|
+
"database_id": "597601234ffb097af4f3099b",
|
|
27
|
+
"type": "postgresql"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"path": "/databases/ad-5ed10967884fef000f5e4fff/backups",
|
|
3
|
+
"method": "post",
|
|
4
|
+
"request": {
|
|
5
|
+
"headers": {
|
|
6
|
+
"Authorization": "Bearer the-bearer-token"
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"response": {
|
|
10
|
+
"status": 400,
|
|
11
|
+
"headers": {
|
|
12
|
+
"Date": "Fri, 29 May 2020 13:08:59 GMT",
|
|
13
|
+
"Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"",
|
|
14
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
15
|
+
"Transfer-Encoding": "chunked",
|
|
16
|
+
"Connection": "keep-alive",
|
|
17
|
+
"Cache-Control": "max-age=0, private, must-revalidate",
|
|
18
|
+
"Referrer-Policy": "strict-origin-when-cross-origin"
|
|
19
|
+
},
|
|
20
|
+
"json_body": {
|
|
21
|
+
"error": "unauthorized"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"path": "/databases/ad-5ed10967884fef000f5e4fff/backups",
|
|
3
|
+
"method": "get",
|
|
4
|
+
"request": {
|
|
5
|
+
"headers": {
|
|
6
|
+
"Authorization": "Bearer the-bearer-token"
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"response": {
|
|
10
|
+
"status": 200,
|
|
11
|
+
"headers": {
|
|
12
|
+
"Date": "Fri, 29 May 2020 13:08:59 GMT",
|
|
13
|
+
"Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"",
|
|
14
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
15
|
+
"Transfer-Encoding": "chunked",
|
|
16
|
+
"Connection": "keep-alive",
|
|
17
|
+
"Cache-Control": "max-age=0, private, must-revalidate",
|
|
18
|
+
"Referrer-Policy": "strict-origin-when-cross-origin"
|
|
19
|
+
},
|
|
20
|
+
"json_body": {
|
|
21
|
+
"database_backups": [
|
|
22
|
+
{
|
|
23
|
+
"id": "5bde44904ffb096c714be89c",
|
|
24
|
+
"created_at": "2018-11-04T02:00:00.154+01:00",
|
|
25
|
+
"name": "20181104010000_kibana-3938",
|
|
26
|
+
"size": 0,
|
|
27
|
+
"status": "pending",
|
|
28
|
+
"database_id": "597601234ffb097af4f3099b",
|
|
29
|
+
"type": "postgresql"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "5bb95a904ffb096e9a2831b8",
|
|
33
|
+
"created_at": "2018-10-07T03:00:00.150+02:00",
|
|
34
|
+
"name": "20181007010000_kibana-3938",
|
|
35
|
+
"size": 0,
|
|
36
|
+
"status": "error",
|
|
37
|
+
"database_id": "597601234ffb097af4f3099b",
|
|
38
|
+
"type": "postgresql"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "5b8b36104ffb090be1ac3ce1",
|
|
42
|
+
"created_at": "2018-09-02T03:00:00.178+02:00",
|
|
43
|
+
"name": "20180902010000_kibana-3938",
|
|
44
|
+
"size": 17484513608,
|
|
45
|
+
"status": "done",
|
|
46
|
+
"database_id": "597601234ffb097af4f3099b",
|
|
47
|
+
"type": "postgresql"
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"path": "/databases/ad-5ed10967884fef000f5e4fff/backups",
|
|
3
|
+
"method": "get",
|
|
4
|
+
"request": {
|
|
5
|
+
"headers": {
|
|
6
|
+
"Authorization": "Bearer the-bearer-token"
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"response": {
|
|
10
|
+
"status": 400,
|
|
11
|
+
"headers": {
|
|
12
|
+
"Date": "Fri, 29 May 2020 13:08:59 GMT",
|
|
13
|
+
"Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"",
|
|
14
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
15
|
+
"Transfer-Encoding": "chunked",
|
|
16
|
+
"Connection": "keep-alive",
|
|
17
|
+
"Cache-Control": "max-age=0, private, must-revalidate",
|
|
18
|
+
"Referrer-Policy": "strict-origin-when-cross-origin"
|
|
19
|
+
},
|
|
20
|
+
"json_body": {
|
|
21
|
+
"error": "unauthorized"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"path": "/databases/ad-5ed10967884fef000f5e4fff",
|
|
3
|
+
"method": "get",
|
|
4
|
+
"request": {
|
|
5
|
+
"headers": {
|
|
6
|
+
"Authorization": "Bearer the-bearer-token"
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"response": {
|
|
10
|
+
"status": 200,
|
|
11
|
+
"headers": {
|
|
12
|
+
"Date": "Fri, 29 May 2020 13:08:59 GMT",
|
|
13
|
+
"Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"",
|
|
14
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
15
|
+
"Transfer-Encoding": "chunked",
|
|
16
|
+
"Connection": "keep-alive",
|
|
17
|
+
"Cache-Control": "max-age=0, private, must-revalidate",
|
|
18
|
+
"Referrer-Policy": "strict-origin-when-cross-origin"
|
|
19
|
+
},
|
|
20
|
+
"json_body": {
|
|
21
|
+
"database": {
|
|
22
|
+
"id": "ad-5ed10967884fef000f5e4fff",
|
|
23
|
+
"resource_id": "my-db-123",
|
|
24
|
+
"app_name": "my-app",
|
|
25
|
+
"created_at": "2019-02-05T15:38:14.343+01:00",
|
|
26
|
+
"encryption_at_rest": true,
|
|
27
|
+
"features": [
|
|
28
|
+
{
|
|
29
|
+
"name": "redis-rdb",
|
|
30
|
+
"status": "ACTIVATED"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"plan": "free",
|
|
34
|
+
"status": "running",
|
|
35
|
+
"type_id": "5bf30d1104c87f000161285a",
|
|
36
|
+
"type_name": "redis",
|
|
37
|
+
"version_id": "5bf30d1104c87f000161285b",
|
|
38
|
+
"instances": [],
|
|
39
|
+
"readable_version": "3.2.9-1",
|
|
40
|
+
"periodic_backups_enabled": true,
|
|
41
|
+
"periodic_backups_scheduled_at": [0]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"path": "/databases/ad-5ed10967884fef000f5e4fff",
|
|
3
|
+
"method": "get",
|
|
4
|
+
"request": {
|
|
5
|
+
"headers": {
|
|
6
|
+
"Authorization": "Bearer the-bearer-token"
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"response": {
|
|
10
|
+
"status": 400,
|
|
11
|
+
"headers": {
|
|
12
|
+
"Date": "Fri, 29 May 2020 13:08:59 GMT",
|
|
13
|
+
"Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"",
|
|
14
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
15
|
+
"Transfer-Encoding": "chunked",
|
|
16
|
+
"Connection": "keep-alive",
|
|
17
|
+
"Cache-Control": "max-age=0, private, must-revalidate",
|
|
18
|
+
"Referrer-Policy": "strict-origin-when-cross-origin"
|
|
19
|
+
},
|
|
20
|
+
"json_body": {
|
|
21
|
+
"error": "unauthorized"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -170,6 +170,47 @@ RSpec.describe Scalingo::API::Client do
|
|
|
170
170
|
end
|
|
171
171
|
end
|
|
172
172
|
|
|
173
|
+
describe "database_connection" do
|
|
174
|
+
let(:database_id) { "db-id-1234" }
|
|
175
|
+
|
|
176
|
+
context "without bearer token" do
|
|
177
|
+
let(:scalingo) { scalingo_guest }
|
|
178
|
+
|
|
179
|
+
it "raises" do
|
|
180
|
+
expect {
|
|
181
|
+
subject.database_connection(database_id)
|
|
182
|
+
}.to raise_error(Scalingo::Error::Unauthenticated)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
context "with bearer token" do
|
|
187
|
+
it "has an authentication header set with a bearer scheme" do
|
|
188
|
+
scalingo.authenticate_database_with_bearer_token(
|
|
189
|
+
database_id,
|
|
190
|
+
"1234",
|
|
191
|
+
expires_at: Time.now + 1.hour,
|
|
192
|
+
raise_on_expired_token: false,
|
|
193
|
+
)
|
|
194
|
+
expect(subject.database_connection(database_id).headers["Authorization"]).to eq "Bearer #{subject.token_holder.database_tokens[database_id].value}"
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
context "with wrong bearer token" do
|
|
199
|
+
it "raises" do
|
|
200
|
+
database_id_2 = "db-id-5678"
|
|
201
|
+
scalingo.authenticate_database_with_bearer_token(
|
|
202
|
+
database_id_2,
|
|
203
|
+
"1234",
|
|
204
|
+
expires_at: Time.now + 1.hour,
|
|
205
|
+
raise_on_expired_token: false,
|
|
206
|
+
)
|
|
207
|
+
expect {
|
|
208
|
+
subject.database_connection(database_id)
|
|
209
|
+
}.to raise_error(Scalingo::Error::Unauthenticated)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
173
214
|
describe "connection" do
|
|
174
215
|
context "logged" do
|
|
175
216
|
context "no fallback to guest" do
|
|
@@ -115,6 +115,26 @@ RSpec.describe Scalingo::Regional::Addons do
|
|
|
115
115
|
end
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
+
describe_method "authenticate!" do
|
|
119
|
+
context "success" do
|
|
120
|
+
let(:arguments) { [meta[:app_id], meta[:id]] }
|
|
121
|
+
let(:stub_pattern) { "token-200" }
|
|
122
|
+
|
|
123
|
+
it_behaves_like "a singular object response"
|
|
124
|
+
it "authenticates" do
|
|
125
|
+
response
|
|
126
|
+
expect(scalingo.authenticated_for_database?(meta[:id])).to be true
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context "not found" do
|
|
131
|
+
let(:arguments) { [meta[:app_id], meta[:not_found_id]] }
|
|
132
|
+
let(:stub_pattern) { "token-404" }
|
|
133
|
+
|
|
134
|
+
it_behaves_like "a not found response"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
118
138
|
describe_method "update" do
|
|
119
139
|
context "success" do
|
|
120
140
|
let(:arguments) { [meta[:app_id], meta[:id], meta[:update][:valid]] }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe Scalingo::RegionalDatabase::Backups do
|
|
4
|
+
before do
|
|
5
|
+
scalingo.add_database_token(meta[:addon_id], "the-bearer-token")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe_method "create" do
|
|
9
|
+
context "success" do
|
|
10
|
+
let(:arguments) { [meta[:addon_id]] }
|
|
11
|
+
let(:stub_pattern) { "create-201" }
|
|
12
|
+
|
|
13
|
+
it_behaves_like "a singular object response", 201
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context "failure" do
|
|
17
|
+
let(:arguments) { [meta[:addon_id]] }
|
|
18
|
+
let(:stub_pattern) { "create-400" }
|
|
19
|
+
|
|
20
|
+
it_behaves_like "a client error"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe_method "for" do
|
|
25
|
+
context "success" do
|
|
26
|
+
let(:arguments) { [meta[:addon_id]] }
|
|
27
|
+
let(:stub_pattern) { "for-200" }
|
|
28
|
+
let(:expected_count) { 3 }
|
|
29
|
+
|
|
30
|
+
it_behaves_like "a collection response"
|
|
31
|
+
it_behaves_like "a non-paginated collection"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "failure" do
|
|
35
|
+
let(:arguments) { [meta[:addon_id]] }
|
|
36
|
+
let(:stub_pattern) { "for-400" }
|
|
37
|
+
|
|
38
|
+
it_behaves_like "a client error"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe_method "archive" do
|
|
43
|
+
context "success" do
|
|
44
|
+
let(:arguments) { [meta[:addon_id], meta[:backup_id]] }
|
|
45
|
+
let(:stub_pattern) { "archive-200" }
|
|
46
|
+
let(:expected_keys) { %i[download_url] }
|
|
47
|
+
|
|
48
|
+
it_behaves_like "a singular object response"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context "failure" do
|
|
52
|
+
let(:arguments) { [meta[:addon_id], meta[:backup_id]] }
|
|
53
|
+
let(:stub_pattern) { "archive-400" }
|
|
54
|
+
|
|
55
|
+
it_behaves_like "a client error"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe Scalingo::RegionalDatabase::Databases do
|
|
4
|
+
before do
|
|
5
|
+
scalingo.add_database_token(meta[:id], "the-bearer-token")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe_method "find" do
|
|
9
|
+
context "success" do
|
|
10
|
+
let(:arguments) { [meta[:id]] }
|
|
11
|
+
let(:stub_pattern) { "find-200" }
|
|
12
|
+
|
|
13
|
+
it_behaves_like "a singular object response"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context "failure" do
|
|
17
|
+
let(:arguments) { [meta[:id]] }
|
|
18
|
+
let(:stub_pattern) { "find-400" }
|
|
19
|
+
|
|
20
|
+
it_behaves_like "a client error"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe Scalingo::RegionalDatabase do
|
|
4
|
+
subject { described_class.new("url") }
|
|
5
|
+
|
|
6
|
+
%w[databases backups].each do |section|
|
|
7
|
+
it "handles requests for #{section}" do
|
|
8
|
+
expect(subject.respond_to?(section)).to be true
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe Scalingo::TokenHolder do
|
|
4
|
+
subject(:token_holder_dummy_class) do
|
|
5
|
+
Class.new {
|
|
6
|
+
include(Scalingo::TokenHolder)
|
|
7
|
+
attr_accessor :config
|
|
8
|
+
}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe "authenticate_with_bearer_token" do
|
|
12
|
+
subject { token_holder.authenticate_with_bearer_token(token, expires_at: expires_at, raise_on_expired_token: false) }
|
|
13
|
+
|
|
14
|
+
let(:token_holder) do
|
|
15
|
+
holder = token_holder_dummy_class.new
|
|
16
|
+
holder.config = Scalingo::Configuration.new
|
|
17
|
+
|
|
18
|
+
holder
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context "without expiration date" do
|
|
22
|
+
let(:token) { "1234" }
|
|
23
|
+
let(:expires_at) { nil }
|
|
24
|
+
|
|
25
|
+
it "set the auth token" do
|
|
26
|
+
expect(token_holder.authenticated?).to be false
|
|
27
|
+
subject
|
|
28
|
+
expect(token_holder.authenticated?).to be true
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context "with an expiration date" do
|
|
33
|
+
let(:token) { "1234" }
|
|
34
|
+
let(:expires_at) { Time.now + 1.hour }
|
|
35
|
+
|
|
36
|
+
it "refresh the auth token" do
|
|
37
|
+
token_holder.authenticate_with_bearer_token(token, expires_at: 1.hour.ago, raise_on_expired_token: false)
|
|
38
|
+
expect(token_holder.authenticated?).to be false
|
|
39
|
+
|
|
40
|
+
subject
|
|
41
|
+
expect(token_holder.authenticated?).to be true
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe "authenticate_database_with_bearer_token" do
|
|
47
|
+
subject { token_holder.authenticate_database_with_bearer_token(database_id, token, expires_at: expires_at, raise_on_expired_token: false) }
|
|
48
|
+
|
|
49
|
+
let(:token_holder) do
|
|
50
|
+
holder = token_holder_dummy_class.new
|
|
51
|
+
holder.config = Scalingo::Configuration.new
|
|
52
|
+
|
|
53
|
+
holder
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
let(:database_id) { "db-id-1234" }
|
|
57
|
+
|
|
58
|
+
context "without expiration date" do
|
|
59
|
+
let(:token) { "1234" }
|
|
60
|
+
let(:expires_at) { nil }
|
|
61
|
+
|
|
62
|
+
it "set the database auth token" do
|
|
63
|
+
expect(token_holder.authenticated_for_database?(database_id)).to be false
|
|
64
|
+
subject
|
|
65
|
+
expect(token_holder.authenticated_for_database?(database_id)).to be true
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
context "with an expiration date" do
|
|
70
|
+
let(:token) { "1234" }
|
|
71
|
+
let(:expires_at) { Time.now + 1.hour }
|
|
72
|
+
|
|
73
|
+
it "refresh the database token" do
|
|
74
|
+
token_holder.authenticate_database_with_bearer_token(database_id, token, expires_at: 1.hour.ago, raise_on_expired_token: false)
|
|
75
|
+
expect(token_holder.authenticated_for_database?(database_id)).to be false
|
|
76
|
+
subject
|
|
77
|
+
expect(token_holder.authenticated_for_database?(database_id)).to be true
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: scalingo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Leo Unbekandt
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: exe
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2022-12-23 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: activesupport
|
|
@@ -185,10 +185,12 @@ executables: []
|
|
|
185
185
|
extensions: []
|
|
186
186
|
extra_rdoc_files: []
|
|
187
187
|
files:
|
|
188
|
+
- ".github/dependabot.yml"
|
|
188
189
|
- ".github/workflows/publish.yml"
|
|
189
190
|
- ".github/workflows/ruby.yml"
|
|
190
191
|
- ".gitignore"
|
|
191
192
|
- ".rubocop.yml"
|
|
193
|
+
- ".sclng/metadata.toml"
|
|
192
194
|
- CHANGELOG.md
|
|
193
195
|
- Gemfile
|
|
194
196
|
- LICENSE.txt
|
|
@@ -230,6 +232,9 @@ files:
|
|
|
230
232
|
- lib/scalingo/regional/notifiers.rb
|
|
231
233
|
- lib/scalingo/regional/operations.rb
|
|
232
234
|
- lib/scalingo/regional/scm_repo_links.rb
|
|
235
|
+
- lib/scalingo/regional_database.rb
|
|
236
|
+
- lib/scalingo/regional_database/backups.rb
|
|
237
|
+
- lib/scalingo/regional_database/databases.rb
|
|
233
238
|
- lib/scalingo/token_holder.rb
|
|
234
239
|
- lib/scalingo/version.rb
|
|
235
240
|
- samples/auth/keys/_meta.json
|
|
@@ -413,6 +418,16 @@ files:
|
|
|
413
418
|
- samples/regional/scm_repo_links/manual-deploy-200.json
|
|
414
419
|
- samples/regional/scm_repo_links/show-200.json
|
|
415
420
|
- samples/regional/scm_repo_links/update-200.json
|
|
421
|
+
- samples/regional_database/backups/_meta.json
|
|
422
|
+
- samples/regional_database/backups/archive-200.json
|
|
423
|
+
- samples/regional_database/backups/archive-400.json
|
|
424
|
+
- samples/regional_database/backups/create-201.json
|
|
425
|
+
- samples/regional_database/backups/create-400.json
|
|
426
|
+
- samples/regional_database/backups/for-200.json
|
|
427
|
+
- samples/regional_database/backups/for-400.json
|
|
428
|
+
- samples/regional_database/databases/_meta.json
|
|
429
|
+
- samples/regional_database/databases/find-200.json
|
|
430
|
+
- samples/regional_database/databases/find-400.json
|
|
416
431
|
- scalingo.gemspec
|
|
417
432
|
- spec/scalingo/api/client_spec.rb
|
|
418
433
|
- spec/scalingo/api/endpoint_spec.rb
|
|
@@ -442,7 +457,11 @@ files:
|
|
|
442
457
|
- spec/scalingo/regional/notifiers_spec.rb
|
|
443
458
|
- spec/scalingo/regional/operations_spec.rb
|
|
444
459
|
- spec/scalingo/regional/scm_repo_links_spec.rb
|
|
460
|
+
- spec/scalingo/regional_database/backups_spec.rb
|
|
461
|
+
- spec/scalingo/regional_database/databases_spec.rb
|
|
462
|
+
- spec/scalingo/regional_database_spec.rb
|
|
445
463
|
- spec/scalingo/regional_spec.rb
|
|
464
|
+
- spec/scalingo/token_holder_spec.rb
|
|
446
465
|
homepage: https://www.scalingo.com
|
|
447
466
|
licenses:
|
|
448
467
|
- MIT
|
|
@@ -467,7 +486,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
467
486
|
- !ruby/object:Gem::Version
|
|
468
487
|
version: '0'
|
|
469
488
|
requirements: []
|
|
470
|
-
rubygems_version: 3.
|
|
489
|
+
rubygems_version: 3.3.26
|
|
471
490
|
signing_key:
|
|
472
491
|
specification_version: 4
|
|
473
492
|
summary: Ruby client for Scalingo APIs
|
|
@@ -500,4 +519,8 @@ test_files:
|
|
|
500
519
|
- spec/scalingo/regional/notifiers_spec.rb
|
|
501
520
|
- spec/scalingo/regional/operations_spec.rb
|
|
502
521
|
- spec/scalingo/regional/scm_repo_links_spec.rb
|
|
522
|
+
- spec/scalingo/regional_database/backups_spec.rb
|
|
523
|
+
- spec/scalingo/regional_database/databases_spec.rb
|
|
524
|
+
- spec/scalingo/regional_database_spec.rb
|
|
503
525
|
- spec/scalingo/regional_spec.rb
|
|
526
|
+
- spec/scalingo/token_holder_spec.rb
|