aptible-cli 0.19.3 → 0.19.6

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.
@@ -197,6 +197,47 @@ describe Aptible::CLI::Agent do
197
197
  end
198
198
  end
199
199
 
200
+ describe '#apps:rename' do
201
+ before do
202
+ allow(Aptible::Api::App).to receive(:all) { [app] }
203
+ allow(Aptible::Api::Account).to receive(:all) { [account] }
204
+ end
205
+
206
+ before(:each) do
207
+ allow(subject).to receive(:options)
208
+ .and_return(environment: account.handle)
209
+ end
210
+
211
+ context 'with environment and app' do
212
+ it 'should rename properly' do
213
+ expect(app).to receive(:update!)
214
+ .with(handle: 'hello2').and_return(app)
215
+ subject.send('apps:rename', 'hello', 'hello2')
216
+ expect(captured_logs).to include(
217
+ 'In order for the new app name (hello2) to appear in log drain and '\
218
+ 'metric drain destinations, you must restart the app.'
219
+ )
220
+ expect(captured_logs).to include(
221
+ "(git@beta.aptible.com:#{account.handle}/hello2.git)"
222
+ )
223
+ end
224
+ it 'should fail if app does not exist' do
225
+ expect { subject.send('apps:rename', 'hello2', 'hello3') }
226
+ .to raise_error(/Could not find app hello/)
227
+ end
228
+ it 'should raise error if update fails' do
229
+ response = Faraday::Response.new(status: 422)
230
+ error = HyperResource::ClientError.new('ActiveRecord::RecordInvalid:'\
231
+ ' Validation failed: Handle has already been taken, Handle has already'\
232
+ ' been taken', response: response)
233
+ expect(app).to receive(:update!)
234
+ .with(handle: 'hello2').and_raise(error)
235
+ expect { subject.send('apps:rename', 'hello', 'hello2') }
236
+ .to raise_error(HyperResource::ClientError)
237
+ end
238
+ end
239
+ end
240
+
200
241
  describe '#apps:scale' do
201
242
  before do
202
243
  allow(Aptible::Api::App).to receive(:all) { [app] }
@@ -22,6 +22,9 @@ describe Aptible::CLI::Agent do
22
22
  before do
23
23
  allow(Aptible::Api::Account).to receive(:all).and_return([account])
24
24
  end
25
+ before do
26
+ subject.stub(:validate_image_type) { true }
27
+ end
25
28
 
26
29
  def expect_provision_database(create_opts, provision_opts = {})
27
30
  db = Fabricate(:database)
@@ -876,4 +879,39 @@ describe Aptible::CLI::Agent do
876
879
  expect(captured_output_text).to eq(expected)
877
880
  end
878
881
  end
882
+
883
+ describe '#db:rename' do
884
+ before do
885
+ allow(subject).to receive(:options)
886
+ .and_return(environment: account.handle)
887
+ allow(Aptible::Api::Account).to receive(:all) { [account] }
888
+ end
889
+ context 'with environment and db' do
890
+ it 'should rename properly' do
891
+ expect(database).to receive(:update!)
892
+ .with(handle: 'foo2').and_return(database)
893
+ subject.send('db:rename', database.handle, 'foo2')
894
+ expect(captured_logs).to include(
895
+ 'In order for the new database name (foo2) to appear in log drain '\
896
+ 'and metric drain destinations, you must reload the database.'
897
+ )
898
+ end
899
+ it 'should fail if db does not exist' do
900
+ expect { subject.send('db:rename', 'foo2', 'foo3') }
901
+ .to raise_error(/Could not find database foo2/)
902
+ end
903
+ it 'should raise error if update fails' do
904
+ response = Faraday::Response.new(status: 500)
905
+ error = HyperResource::ClientError.new(
906
+ 'An error occurred: Validation failed: Handle has '\
907
+ 'already been taken, Handle has already been taken',
908
+ response: response
909
+ )
910
+ expect(database).to receive(:update!)
911
+ .with(handle: 'foo2').and_raise(error)
912
+ expect { subject.send('db:rename', database.handle, 'foo2') }
913
+ .to raise_error(HyperResource::ClientError)
914
+ end
915
+ end
916
+ end
879
917
  end
@@ -10,47 +10,82 @@ describe Aptible::CLI::Agent do
10
10
 
11
11
  let(:token) { double 'token' }
12
12
 
13
- before do
13
+ before(:each) do
14
14
  allow(subject).to receive(:fetch_token) { token }
15
15
  allow(Aptible::Api::Account).to receive(:all).with(token: token)
16
16
  .and_return([a1, a2])
17
17
  end
18
18
 
19
- it 'lists avaliable environments' do
20
- subject.send('environment:list')
19
+ describe('#environment:list') do
20
+ it 'lists avaliable environments' do
21
+ subject.send('environment:list')
21
22
 
22
- expect(captured_output_text.split("\n")).to include('foo')
23
- expect(captured_output_text.split("\n")).to include('bar')
23
+ expect(captured_output_text.split("\n")).to include('foo')
24
+ expect(captured_output_text.split("\n")).to include('bar')
25
+ end
24
26
  end
25
27
 
26
- it 'fetches certs for all avaliable environments' do
27
- subject.send('environment:ca_cert')
28
-
29
- expect(captured_output_text.split("\n")).to include('account 1 cert')
30
- expect(captured_output_text.split("\n")).to include('--account 2 cert--')
31
-
32
- expected_accounts = [
33
- {
34
- 'handle' => 'foo',
35
- 'ca_body' => 'account 1 cert',
36
- 'created_at' => fmt_time(a1.created_at)
37
- },
38
- {
39
- 'handle' => 'bar',
40
- 'ca_body' => '--account 2 cert--',
41
- 'created_at' => fmt_time(a2.created_at)
42
- }
43
- ]
44
- expect(captured_output_json.map! { |account| account.except('id') })
45
- .to eq(expected_accounts)
46
- end
28
+ describe('#environment:ca_cert') do
29
+ it 'fetches certs for all avaliable environments' do
30
+ subject.send('environment:ca_cert')
31
+
32
+ expect(captured_output_text.split("\n")).to include('account 1 cert')
33
+ expect(captured_output_text.split("\n")).to include('--account 2 cert--')
34
+
35
+ expected_accounts = [
36
+ {
37
+ 'handle' => 'foo',
38
+ 'ca_body' => 'account 1 cert',
39
+ 'created_at' => fmt_time(a1.created_at)
40
+ },
41
+ {
42
+ 'handle' => 'bar',
43
+ 'ca_body' => '--account 2 cert--',
44
+ 'created_at' => fmt_time(a2.created_at)
45
+ }
46
+ ]
47
+ expect(captured_output_json.map! { |account| account.except('id') })
48
+ .to eq(expected_accounts)
49
+ end
47
50
 
48
- it 'fetches certs for specified environment' do
49
- subject.options = { environment: 'foo' }
50
- subject.send('environment:ca_cert')
51
+ it 'fetches certs for specified environment' do
52
+ subject.options = { environment: 'foo' }
53
+ subject.send('environment:ca_cert')
54
+
55
+ expect(captured_output_text.split("\n")).to include('account 1 cert')
56
+ expect(captured_output_text.split("\n"))
57
+ .to_not include('--account 2 cert--')
58
+ end
59
+ end
51
60
 
52
- expect(captured_output_text.split("\n")).to include('account 1 cert')
53
- expect(captured_output_text.split("\n"))
54
- .to_not include('--account 2 cert--')
61
+ describe('#environment:rename') do
62
+ it 'should rename properly' do
63
+ expect(a1).to receive(:update!)
64
+ .with(handle: 'foo-renamed').and_return(a1)
65
+ subject.send('environment:rename', 'foo', 'foo-renamed')
66
+ expect(captured_logs).to include(
67
+ 'In order for the new environment handle (foo-renamed)'
68
+ )
69
+ expect(captured_logs).to include(
70
+ '* Your own external scripts (e.g. for CI/CD)'
71
+ )
72
+ expect(captured_logs).to include(
73
+ '* Git remote URLs (ex: git@beta.aptible.com:foo-renamed'
74
+ )
75
+ end
76
+ it 'should fail if env does not exist' do
77
+ expect { subject.send('environment:rename', 'foo1', 'foo2') }
78
+ .to raise_error(/Could not find environment foo1/)
79
+ end
80
+ it 'should raise error if update fails' do
81
+ response = Faraday::Response.new(status: 422)
82
+ error = HyperResource::ClientError.new('ActiveRecord::RecordInvalid:'\
83
+ ' Validation failed: Handle has already been taken, Handle has already'\
84
+ ' been taken', response: response)
85
+ expect(a1).to receive(:update!)
86
+ .with(handle: 'bar').and_raise(error)
87
+ expect { subject.send('environment:rename', 'foo', 'bar') }
88
+ .to raise_error(HyperResource::ClientError)
89
+ end
55
90
  end
56
91
  end
@@ -60,4 +60,137 @@ describe Aptible::CLI::Agent do
60
60
  expect { subject.send(:logs) }.to raise_error(/only one of/im)
61
61
  end
62
62
  end
63
+
64
+ describe '#logs_from_archive' do
65
+ context 'using string-matches' do
66
+ let(:files) { %w(file_1 file_2) }
67
+
68
+ before do
69
+ subject.options = {
70
+ region: 'some-region',
71
+ bucket: 'some-bucket',
72
+ decryption_keys: 'mykey',
73
+ string_matches: 'foo',
74
+ download_location: './'
75
+ }
76
+ subject.stub(:info_from_path) { { shasum: 'foo' } }
77
+ subject.stub(:encryption_key) { subject.options[:decryption_keys] }
78
+ end
79
+
80
+ it 'download all files' do
81
+ expect(subject).to receive(:ensure_aws_creds)
82
+ expect(subject).to receive(:validate_log_search_options)
83
+ .with(subject.options)
84
+
85
+ expect(subject).to receive(:find_s3_files_by_string_match)
86
+ .with(
87
+ subject.options[:region],
88
+ subject.options[:bucket],
89
+ subject.options[:stack],
90
+ subject.options[:string_matches]
91
+ ).and_return(files)
92
+
93
+ files.each do |f|
94
+ expect(subject).to receive(:decrypt_and_translate_s3_file)
95
+ .with(
96
+ f,
97
+ subject.options[:decryption_keys],
98
+ subject.options[:region],
99
+ subject.options[:bucket],
100
+ subject.options[:download_location]
101
+ )
102
+ end
103
+ subject.send('logs_from_archive')
104
+ end
105
+ end
106
+
107
+ context 'using app/database/endpoint id' do
108
+ let(:files) { %w(file_1 file_2) }
109
+
110
+ before do
111
+ subject.options = {
112
+ region: 'some-region',
113
+ bucket: 'some-bucket',
114
+ stack: 'mystack',
115
+ decryption_keys: 'mykey',
116
+ app_id: 123,
117
+ download_location: './'
118
+ }
119
+ subject.stub(:info_from_path) { { shasum: 'foo' } }
120
+ subject.stub(:encryption_key) { subject.options[:decryption_keys] }
121
+ end
122
+
123
+ it 'download all files' do
124
+ expect(subject).to receive(:ensure_aws_creds)
125
+ expect(subject).to receive(:validate_log_search_options)
126
+ .with(subject.options)
127
+
128
+ expect(subject).to receive(:find_s3_files_by_attrs)
129
+ .with(
130
+ subject.options[:region],
131
+ subject.options[:bucket],
132
+ subject.options[:stack],
133
+ { type: 'apps', id: 123 },
134
+ nil
135
+ ).and_return(files)
136
+
137
+ files.each do |f|
138
+ expect(subject).to receive(:decrypt_and_translate_s3_file)
139
+ .with(
140
+ f,
141
+ subject.options[:decryption_keys],
142
+ subject.options[:region],
143
+ subject.options[:bucket],
144
+ subject.options[:download_location]
145
+ )
146
+ end
147
+ subject.send('logs_from_archive')
148
+ end
149
+ end
150
+
151
+ context 'using container id' do
152
+ let(:files) { %w(file_1 file_2) }
153
+
154
+ before do
155
+ subject.options = {
156
+ region: 'some-region',
157
+ bucket: 'some-bucket',
158
+ stack: 'mystack',
159
+ decryption_keys: 'mykey',
160
+ container_id:
161
+ '9080b96447f98b31ef9831d5fd98b09e3c5c545269734e2e825644571152457c',
162
+ download_location: './'
163
+ }
164
+ subject.stub(:info_from_path) { { shasum: 'foo' } }
165
+ subject.stub(:encryption_key) { subject.options[:decryption_keys] }
166
+ end
167
+
168
+ it 'download all files' do
169
+ expect(subject).to receive(:ensure_aws_creds)
170
+ expect(subject).to receive(:validate_log_search_options)
171
+ .with(subject.options)
172
+
173
+ expect(subject).to receive(:find_s3_files_by_attrs)
174
+ .with(
175
+ subject.options[:region],
176
+ subject.options[:bucket],
177
+ subject.options[:stack],
178
+ { container_id: subject.options[:container_id] },
179
+ nil
180
+ ).and_return(files)
181
+
182
+ files.each do |f|
183
+ expect(subject).to receive(:decrypt_and_translate_s3_file)
184
+ .with(
185
+ f,
186
+ subject.options[:decryption_keys],
187
+ subject.options[:region],
188
+ subject.options[:bucket],
189
+ subject.options[:download_location]
190
+ )
191
+ end
192
+ subject.send('logs_from_archive')
193
+ end
194
+ end
195
+ end
63
196
  end
@@ -145,7 +145,7 @@ describe Aptible::CLI::Agent do
145
145
  drain_type: :datadog,
146
146
  drain_configuration: {
147
147
  api_key: 'foobar',
148
- series_url: 'https://app.datadoghq.eu'
148
+ series_url: 'https://app.datadoghq.eu/api/v1/series'
149
149
  }
150
150
  }
151
151
  expect_provision_metric_drain(opts)
@@ -3,6 +3,8 @@ require 'spec_helper'
3
3
  describe Aptible::CLI::Agent do
4
4
  let(:token) { 'some-token' }
5
5
  let(:operation) { Fabricate(:operation) }
6
+ let(:net_http_double) { double('Net::HTTP') }
7
+ let(:net_http_get_double) { double('Net::HTTP::Get') }
6
8
 
7
9
  before do
8
10
  allow(subject).to receive(:fetch_token).and_return(token)
@@ -26,4 +28,174 @@ describe Aptible::CLI::Agent do
26
28
  subject.send('operation:cancel', 1)
27
29
  end
28
30
  end
31
+
32
+ describe '#operation:follow' do
33
+ it 'fails if the operation cannot be found' do
34
+ expect(Aptible::Api::Operation).to receive(:find).with(1, token: token)
35
+ .and_return(nil)
36
+
37
+ expect { subject.send('operation:follow', 1) }
38
+ .to raise_error('Operation #1 not found')
39
+ end
40
+
41
+ it 'connects to a running operation' do
42
+ op = Fabricate(:operation, status: 'running', type: 'restart')
43
+ expect(Aptible::Api::Operation).to receive(:find)
44
+ .with(op.id.to_s, token: token).and_return(op)
45
+
46
+ expect(subject).to receive(:attach_to_operation_logs).with(op)
47
+ subject.send('operation:follow', op.id.to_s)
48
+ end
49
+
50
+ it 'connects to a queued operation' do
51
+ op = Fabricate(:operation, status: 'queued', type: 'restart')
52
+ expect(Aptible::Api::Operation).to receive(:find)
53
+ .with(op.id.to_s, token: token).and_return(op)
54
+
55
+ expect(subject).to receive(:attach_to_operation_logs).with(op)
56
+ subject.send('operation:follow', op.id.to_s)
57
+ end
58
+
59
+ it 'does not connect to a failed operation' do
60
+ id = 34
61
+ status = 'failed'
62
+ op = Fabricate(:operation, id: id, status: status)
63
+ expect(Aptible::Api::Operation).to receive(:find)
64
+ .with(op.id.to_s, token: token).and_return(op)
65
+
66
+ expect { subject.send('operation:follow', op.id.to_s) }
67
+ .to raise_error(Thor::Error, /aptible operation:logs #{id}/)
68
+ end
69
+
70
+ it 'does not connect to a succeeded operation' do
71
+ id = 43
72
+ status = 'succeeded'
73
+ op = Fabricate(:operation, id: id, status: status)
74
+ expect(Aptible::Api::Operation).to receive(:find)
75
+ .with(op.id.to_s, token: token).and_return(op)
76
+
77
+ expect { subject.send('operation:follow', op.id.to_s) }
78
+ .to raise_error(Thor::Error, /aptible operation:logs #{id}/)
79
+ end
80
+ end
81
+
82
+ describe '#operation:logs' do
83
+ it 'sends operation logs request when subcommand sent' do
84
+ operation_id = SecureRandom.uuid
85
+ expect(Aptible::Api::Operation).to receive(:find).with(1, token: token)
86
+ .and_return(Fabricate(
87
+ :operation, status: 'succeeded', id: operation_id
88
+ ))
89
+
90
+ # stub out operations call
91
+ response = instance_double(Net::HTTPResponse, body: 'https://s3.aptible.com/not-real/s3')
92
+
93
+ # stub out s3 call
94
+ s3_response = instance_double(Net::HTTPResponse, body: 'Mock logs')
95
+
96
+ allow(Net::HTTP).to receive(:new).twice do |_, _, _|
97
+ net_http_double
98
+ end
99
+ expect(response).to receive(:code).and_return('200')
100
+ expect(s3_response).to receive(:code).and_return('200')
101
+ expect(net_http_double).to receive(:use_ssl=).twice
102
+ expect(net_http_double).to receive(:request).twice do |request|
103
+ if request.path == "/operations/#{operation_id}/logs"
104
+ response
105
+ elsif request.path == '/not-real/s3'
106
+ s3_response
107
+ end
108
+ end
109
+
110
+ subject.send('operation:logs', 1)
111
+ end
112
+
113
+ it 'errors when operation is not found' do
114
+ expect(Aptible::Api::Operation).to receive(:find).with(1, token: token)
115
+ .and_return(nil)
116
+
117
+ expect { subject.send('operation:logs', 1) }
118
+ .to raise_error('Operation #1 not found')
119
+ end
120
+ it 'errors when operation is not status expected' do
121
+ operation_id = SecureRandom.uuid
122
+ expect(Aptible::Api::Operation).to receive(:find).with(1, token: token)
123
+ .and_return(Fabricate(:operation, status: 'queued', id: operation_id))
124
+
125
+ expect { subject.send('operation:logs', 1) }
126
+ .to raise_error('Error - You can view the logs when operation '\
127
+ 'is complete.')
128
+ end
129
+ it 'errors when operation logs are not found' do
130
+ operation_id = SecureRandom.uuid
131
+ expect(Aptible::Api::Operation).to receive(:find).with(1, token: token)
132
+ .and_return(
133
+ Fabricate(:operation, status: 'succeeded', id: operation_id)
134
+ )
135
+
136
+ # stub out operations call
137
+ response = Net::HTTPSuccess.new(1.0, '404', 'Not Found')
138
+ expect_any_instance_of(Net::HTTP)
139
+ .to receive(:request)
140
+ .with(an_instance_of(Net::HTTP::Get))
141
+ .and_return(response)
142
+
143
+ expect { subject.send('operation:logs', 1) }
144
+ .to raise_error('Unable to retrieve the operation\'s logs. '\
145
+ 'If the issue persists please contact support for assistance.')
146
+ end
147
+ it 'errors when body is empty' do
148
+ operation_id = SecureRandom.uuid
149
+ expect(Aptible::Api::Operation).to receive(:find).with(1, token: token)
150
+ .and_return(Fabricate(
151
+ :operation, status: 'succeeded', id: operation_id
152
+ ))
153
+
154
+ # stub out operations call
155
+ response = instance_double(Net::HTTPResponse, body: nil)
156
+
157
+ allow(Net::HTTP).to receive(:new) do |_, _, _|
158
+ net_http_double
159
+ end
160
+ expect(response).to receive(:code).and_return('200')
161
+ expect(net_http_double).to receive(:use_ssl=)
162
+ expect(net_http_double).to receive(:request).and_return(response)
163
+
164
+ expect { subject.send('operation:logs', 1) }
165
+ .to raise_error('Unable to retrieve the operation\'s logs. '\
166
+ 'If the issue persists please contact support for assistance.')
167
+ end
168
+ it 'errors when s3 itself returns an error code' do
169
+ operation_id = SecureRandom.uuid
170
+ expect(Aptible::Api::Operation).to receive(:find).with(1, token: token)
171
+ .and_return(Fabricate(
172
+ :operation, status: 'succeeded', id: operation_id
173
+ ))
174
+
175
+ # stub out operations call
176
+ response = instance_double(Net::HTTPResponse, body: 'https://s3.aptible.com/not-real/s3')
177
+
178
+ # stub out s3 call (to fail)
179
+ expect(response).to receive(:code).and_return('200')
180
+ s3_response = Net::HTTPSuccess.new(1.0, '404', 'Not Found')
181
+
182
+ allow(Net::HTTP).to receive(:new).twice do |_, _, _|
183
+ net_http_double
184
+ end
185
+ expect(net_http_double).to receive(:use_ssl=).twice
186
+ expect(net_http_double).to receive(:request).twice do |request|
187
+ if request.path == "/operations/#{operation_id}/logs"
188
+ response
189
+ elsif request.path == '/not-real/s3'
190
+ s3_response
191
+ end
192
+ end
193
+
194
+ expect { subject.send('operation:logs', 1) }
195
+ .to raise_error('Unable to retrieve operation logs, '\
196
+ 'S3 returned response code 404. '\
197
+ 'If the issue persists please contact support for '\
198
+ 'assistance.')
199
+ end
200
+ end
29
201
  end
@@ -1,7 +1,12 @@
1
1
  class StubOperation < OpenStruct; end
2
2
 
3
+ def mock_logs_url(id)
4
+ "https://api.aptible.com/operations/#{id}/logs"
5
+ end
6
+
3
7
  Fabricator(:operation, from: :stub_operation) do
4
8
  status 'queued'
5
- resource { Fabricate(:app) }
6
9
  errors { Aptible::Resource::Errors.new }
10
+ resource { Fabricate(:app) }
11
+ after_save { |operation| operation.logs_url = mock_logs_url(operation.id) }
7
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aptible-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.3
4
+ version: 0.19.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frank Macreery
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-01 00:00:00.000000000 Z
11
+ date: 2022-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aptible-resource
@@ -136,6 +136,20 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: aws-sdk
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '2.0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '2.0'
139
153
  - !ruby/object:Gem::Dependency
140
154
  name: activesupport
141
155
  requirement: !ruby/object:Gem::Requirement
@@ -294,6 +308,7 @@ files:
294
308
  - lib/aptible/cli/helpers/log_drain.rb
295
309
  - lib/aptible/cli/helpers/metric_drain.rb
296
310
  - lib/aptible/cli/helpers/operation.rb
311
+ - lib/aptible/cli/helpers/s3_log_helpers.rb
297
312
  - lib/aptible/cli/helpers/security_key.rb
298
313
  - lib/aptible/cli/helpers/ssh.rb
299
314
  - lib/aptible/cli/helpers/system.rb
@@ -326,10 +341,12 @@ files:
326
341
  - script/sync-readme-usage
327
342
  - spec/aptible/cli/agent_spec.rb
328
343
  - spec/aptible/cli/formatter_spec.rb
344
+ - spec/aptible/cli/helpers/database_spec.rb
329
345
  - spec/aptible/cli/helpers/git_remote_handle_strategy_spec.rb
330
346
  - spec/aptible/cli/helpers/handle_from_git_remote_spec.rb
331
347
  - spec/aptible/cli/helpers/operation_spec.rb
332
348
  - spec/aptible/cli/helpers/options_handle_strategy_spec.rb
349
+ - spec/aptible/cli/helpers/s3_log_helpers_spec.rb
333
350
  - spec/aptible/cli/helpers/ssh_spec.rb
334
351
  - spec/aptible/cli/helpers/token_spec.rb
335
352
  - spec/aptible/cli/helpers/tunnel_spec.rb
@@ -382,7 +399,7 @@ homepage: https://github.com/aptible/aptible-cli
382
399
  licenses:
383
400
  - MIT
384
401
  metadata: {}
385
- post_install_message:
402
+ post_install_message:
386
403
  rdoc_options: []
387
404
  require_paths:
388
405
  - lib
@@ -397,17 +414,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
397
414
  - !ruby/object:Gem::Version
398
415
  version: '0'
399
416
  requirements: []
400
- rubygems_version: 3.0.3.1
401
- signing_key:
417
+ rubygems_version: 3.0.3
418
+ signing_key:
402
419
  specification_version: 4
403
420
  summary: Command-line interface for Aptible services
404
421
  test_files:
405
422
  - spec/aptible/cli/agent_spec.rb
406
423
  - spec/aptible/cli/formatter_spec.rb
424
+ - spec/aptible/cli/helpers/database_spec.rb
407
425
  - spec/aptible/cli/helpers/git_remote_handle_strategy_spec.rb
408
426
  - spec/aptible/cli/helpers/handle_from_git_remote_spec.rb
409
427
  - spec/aptible/cli/helpers/operation_spec.rb
410
428
  - spec/aptible/cli/helpers/options_handle_strategy_spec.rb
429
+ - spec/aptible/cli/helpers/s3_log_helpers_spec.rb
411
430
  - spec/aptible/cli/helpers/ssh_spec.rb
412
431
  - spec/aptible/cli/helpers/token_spec.rb
413
432
  - spec/aptible/cli/helpers/tunnel_spec.rb