aptible-cli 0.24.1 → 0.24.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +16 -1
  3. data/Gemfile.lock +1 -1
  4. data/lib/aptible/cli/agent.rb +9 -1
  5. data/lib/aptible/cli/helpers/app.rb +16 -1
  6. data/lib/aptible/cli/helpers/database.rb +20 -5
  7. data/lib/aptible/cli/helpers/environment.rb +28 -3
  8. data/lib/aptible/cli/helpers/operation.rb +11 -4
  9. data/lib/aptible/cli/helpers/telemetry.rb +58 -0
  10. data/lib/aptible/cli/helpers/token.rb +6 -0
  11. data/lib/aptible/cli/renderer.rb +5 -1
  12. data/lib/aptible/cli/resource_formatter.rb +7 -0
  13. data/lib/aptible/cli/subcommands/apps.rb +31 -2
  14. data/lib/aptible/cli/subcommands/backup.rb +9 -0
  15. data/lib/aptible/cli/subcommands/backup_retention_policy.rb +5 -0
  16. data/lib/aptible/cli/subcommands/config.rb +11 -0
  17. data/lib/aptible/cli/subcommands/db.rb +68 -3
  18. data/lib/aptible/cli/subcommands/deploy.rb +3 -0
  19. data/lib/aptible/cli/subcommands/endpoints.rb +26 -0
  20. data/lib/aptible/cli/subcommands/environment.rb +11 -0
  21. data/lib/aptible/cli/subcommands/log_drain.rb +26 -5
  22. data/lib/aptible/cli/subcommands/logs.rb +5 -0
  23. data/lib/aptible/cli/subcommands/maintenance.rb +5 -0
  24. data/lib/aptible/cli/subcommands/metric_drain.rb +25 -5
  25. data/lib/aptible/cli/subcommands/operation.rb +7 -0
  26. data/lib/aptible/cli/subcommands/rebuild.rb +3 -0
  27. data/lib/aptible/cli/subcommands/restart.rb +3 -0
  28. data/lib/aptible/cli/subcommands/services.rb +12 -3
  29. data/lib/aptible/cli/subcommands/ssh.rb +3 -0
  30. data/lib/aptible/cli/version.rb +1 -1
  31. data/spec/aptible/cli/subcommands/apps_spec.rb +13 -1
  32. data/spec/aptible/cli/subcommands/config_spec.rb +4 -2
  33. data/spec/aptible/cli/subcommands/db_spec.rb +7 -1
  34. data/spec/aptible/cli/subcommands/endpoints_spec.rb +9 -3
  35. data/spec/aptible/cli/subcommands/environment_spec.rb +3 -1
  36. data/spec/aptible/cli/subcommands/log_drain_spec.rb +15 -2
  37. data/spec/aptible/cli/subcommands/maintenance_spec.rb +3 -2
  38. data/spec/aptible/cli/subcommands/metric_drain_spec.rb +15 -2
  39. data/spec/aptible/cli/subcommands/operation_spec.rb +4 -2
  40. data/spec/aptible/cli/subcommands/services_spec.rb +3 -1
  41. data/spec/fabricators/account_fabricator.rb +8 -0
  42. data/spec/fabricators/app_fabricator.rb +9 -0
  43. data/spec/fabricators/database_fabricator.rb +8 -0
  44. data/spec/fabricators/log_drain_fabricator.rb +8 -0
  45. data/spec/fabricators/metric_drain_fabricator.rb +8 -0
  46. data/spec/spec_helper.rb +9 -1
  47. metadata +6 -5
@@ -5,10 +5,13 @@ module Aptible
5
5
  def self.included(thor)
6
6
  thor.class_eval do
7
7
  include Helpers::App
8
+ include Helpers::Telemetry
8
9
 
9
10
  desc 'services', 'List Services for an App'
10
11
  app_options
11
12
  def services
13
+ telemetry(__method__, options)
14
+
12
15
  app = ensure_app(options)
13
16
 
14
17
  Formatter.render(Renderer.current) do |root|
@@ -35,6 +38,8 @@ module Aptible
35
38
  type: :boolean, default: false,
36
39
  desc: 'Use a simple uptime healthcheck during deployments'
37
40
  define_method 'services:settings' do |service|
41
+ telemetry(__method__, options.merge(service: service))
42
+
38
43
  service = ensure_service(options, service)
39
44
  updates = {}
40
45
  updates[:force_zero_downtime] =
@@ -49,6 +54,8 @@ module Aptible
49
54
  'Returns the associated sizing policy, if any'
50
55
  app_options
51
56
  define_method 'services:autoscaling_policy' do |service|
57
+ telemetry(__method__, options.merge(service: service))
58
+
52
59
  service = ensure_service(options, service)
53
60
  policy = service.service_sizing_policy
54
61
 
@@ -119,9 +126,9 @@ module Aptible
119
126
  'be considered.'
120
127
  option :post_release_cooldown_seconds,
121
128
  type: :numeric,
122
- desc: '(Default: 300) The time in seconds to wait '\
123
- 'following a deploy before another scaling action can '\
124
- 'be considered.'
129
+ desc: '(Default: 60) The time in seconds to ignore in '\
130
+ 'metrics following a deploy to allow for service '\
131
+ 'stabilization.'
125
132
  option :mem_cpu_ratio_r_threshold,
126
133
  type: :numeric,
127
134
  desc: '(Default: 4.0) Establishes the ratio of Memory '\
@@ -187,6 +194,8 @@ module Aptible
187
194
  ' a value of 2 will go from 4->2->1). Container count '\
188
195
  'will never exceed the configured minimum.'
189
196
  define_method 'services:autoscaling_policy:set' do |service|
197
+ telemetry(__method__, options.merge(service: service))
198
+
190
199
  service = ensure_service(options, service)
191
200
  ignored_attrs = %i(autoscaling_type app environment remote)
192
201
  args = options.except(*ignored_attrs)
@@ -8,6 +8,7 @@ module Aptible
8
8
  thor.class_eval do
9
9
  include Helpers::Operation
10
10
  include Helpers::App
11
+ include Helpers::Telemetry
11
12
 
12
13
  desc 'ssh [COMMAND]', 'Run a command against an app'
13
14
  long_desc <<-LONGDESC
@@ -18,6 +19,8 @@ module Aptible
18
19
  app_options
19
20
  option :force_tty, type: :boolean
20
21
  def ssh(*args)
22
+ telemetry(__method__, options)
23
+
21
24
  app = ensure_app(options)
22
25
 
23
26
  # SSH's default behavior is as follows:
@@ -1,5 +1,5 @@
1
1
  module Aptible
2
2
  module CLI
3
- VERSION = '0.24.1'.freeze
3
+ VERSION = '0.24.3'.freeze
4
4
  end
5
5
  end
@@ -31,6 +31,9 @@ describe Aptible::CLI::Agent do
31
31
  describe '#apps' do
32
32
  it 'lists an app in an account' do
33
33
  allow(Aptible::Api::Account).to receive(:all).and_return([account])
34
+ allow(Aptible::Api::App)
35
+ .to receive(:all)
36
+ .and_return([app])
34
37
  subject.send('apps')
35
38
 
36
39
  expect(captured_output_text)
@@ -40,8 +43,11 @@ describe Aptible::CLI::Agent do
40
43
  it 'lists multiple apps in an account' do
41
44
  allow(Aptible::Api::Account).to receive(:all).and_return([account])
42
45
  app2 = Fabricate(:app, handle: 'foobar', account: account)
43
- subject.send('apps')
46
+ allow(Aptible::Api::App)
47
+ .to receive(:all)
48
+ .and_return([app, app2])
44
49
 
50
+ subject.send('apps')
45
51
  expect(captured_output_text)
46
52
  .to eq("=== #{account.handle}\n#{app.handle}\n#{app2.handle}\n")
47
53
  end
@@ -54,6 +60,9 @@ describe Aptible::CLI::Agent do
54
60
  app21 = Fabricate(:app, account: account2, handle: 'app21')
55
61
  app22 = Fabricate(:app, account: account2, handle: 'app21')
56
62
 
63
+ allow(Aptible::Api::App)
64
+ .to receive(:all)
65
+ .and_return([app11, app21, app22])
57
66
  allow(Aptible::Api::Account).to receive(:all)
58
67
  .and_return([account1, account2])
59
68
 
@@ -77,6 +86,7 @@ describe Aptible::CLI::Agent do
77
86
  app2 = Fabricate(:app, account: account2, handle: 'app2')
78
87
  allow(subject).to receive(:options)
79
88
  .and_return(environment: account2.handle)
89
+ allow(Aptible::Api::App).to receive(:all).and_return([app2])
80
90
 
81
91
  allow(Aptible::Api::Account).to receive(:all)
82
92
  .and_return([account, account2])
@@ -90,6 +100,7 @@ describe Aptible::CLI::Agent do
90
100
  account = Fabricate(:account, handle: 'account')
91
101
  app = Fabricate(:app, account: account, handle: 'app')
92
102
  allow(Aptible::Api::Account).to receive(:all).and_return([account])
103
+ allow(Aptible::Api::App).to receive(:all).and_return([app])
93
104
 
94
105
  s1 = Fabricate(
95
106
  :service,
@@ -148,6 +159,7 @@ describe Aptible::CLI::Agent do
148
159
  app = Fabricate(:app, account: account, handle: 'app',
149
160
  last_deploy_operation: op)
150
161
  allow(Aptible::Api::Account).to receive(:all).and_return([account])
162
+ allow(Aptible::Api::App).to receive(:all).and_return([app])
151
163
 
152
164
  expected_json = [
153
165
  {
@@ -9,9 +9,11 @@ describe Aptible::CLI::Agent do
9
9
 
10
10
  before do
11
11
  allow(Aptible::Api::App).to receive(:all)
12
- .with(token: token).and_return([app])
12
+ .with(token: token, href: '/apps?per_page=5000&no_embed=true')
13
+ .and_return([app])
13
14
  allow(Aptible::Api::Account).to receive(:all)
14
- .with(token: token).and_return([account])
15
+ .with(token: token, href: '/apps?per_page=5000&no_embed=true')
16
+ .and_return([account])
15
17
  end
16
18
 
17
19
  before { allow(subject).to receive(:options) { { app: app.handle } } }
@@ -269,6 +269,7 @@ describe Aptible::CLI::Agent do
269
269
  staging = Fabricate(:account, handle: 'staging')
270
270
  prod = Fabricate(:account, handle: 'production')
271
271
 
272
+ dbs = []
272
273
  [
273
274
  [staging, 'staging-redis-db'],
274
275
  [staging, 'staging-postgres-db'],
@@ -276,12 +277,17 @@ describe Aptible::CLI::Agent do
276
277
  [prod, 'prod-postgres-db']
277
278
  ].each do |a, h|
278
279
  d = Fabricate(:database, account: a, handle: h)
280
+ dbs << d
279
281
  Fabricate(:database_credential, database: d)
280
282
  end
281
283
 
282
284
  token = 'the-token'
283
285
  allow(subject).to receive(:fetch_token) { token }
284
- allow(Aptible::Api::Account).to receive(:all).with(token: token)
286
+ allow(Aptible::Api::Database).to receive(:all)
287
+ .with(token: token, href: '/databases?per_page=5000&no_embed=true')
288
+ .and_return(dbs)
289
+ allow(Aptible::Api::Account).to receive(:all)
290
+ .with(token: token, href: '/accounts?per_page=5000&no_embed=true')
285
291
  .and_return([staging, prod])
286
292
  end
287
293
 
@@ -8,7 +8,9 @@ describe Aptible::CLI::Agent do
8
8
 
9
9
  before do
10
10
  allow(subject).to receive(:fetch_token) { token }
11
- allow(Aptible::Api::Account).to receive(:all).with(token: token)
11
+ allow(Aptible::Api::Account)
12
+ .to receive(:all)
13
+ .with(token: token, href: '/accounts?per_page=5000&no_embed=true')
12
14
  .and_return([a1, a2])
13
15
  end
14
16
 
@@ -60,7 +62,9 @@ describe Aptible::CLI::Agent do
60
62
  let!(:db) { Fabricate(:database, handle: 'mydb', account: a1) }
61
63
 
62
64
  before do
63
- allow(Aptible::Api::Database).to receive(:all).with(token: token)
65
+ allow(Aptible::Api::Database)
66
+ .to receive(:all)
67
+ .with(token: token, href: '/databases?per_page=5000&no_embed=true')
64
68
  .and_return([db])
65
69
  allow(db).to receive(:class).and_return(Aptible::Api::Database)
66
70
  stub_options
@@ -185,7 +189,9 @@ describe Aptible::CLI::Agent do
185
189
  let!(:service) { Fabricate(:service, app: app, process_type: 'web') }
186
190
 
187
191
  before do
188
- allow(Aptible::Api::App).to receive(:all).with(token: token)
192
+ allow(Aptible::Api::App)
193
+ .to receive(:all)
194
+ .with(token: token, href: '/apps?per_page=5000&no_embed=true')
189
195
  .and_return([app])
190
196
  allow(app).to receive(:class).and_return(Aptible::Api::App)
191
197
  stub_options
@@ -12,7 +12,9 @@ describe Aptible::CLI::Agent do
12
12
 
13
13
  before(:each) do
14
14
  allow(subject).to receive(:fetch_token) { token }
15
- allow(Aptible::Api::Account).to receive(:all).with(token: token)
15
+ allow(Aptible::Api::Account)
16
+ .to receive(:all)
17
+ .with(token: token, href: '/accounts?per_page=5000&no_embed=true')
16
18
  .and_return([a1, a2])
17
19
  end
18
20
 
@@ -10,8 +10,13 @@ describe Aptible::CLI::Agent do
10
10
  before { allow(subject).to receive(:fetch_token).and_return(token) }
11
11
 
12
12
  before do
13
+ allow(Aptible::Api::LogDrain).to receive(:all)
14
+ .with(token: token, href: '/log_drains?per_page=5000')
15
+ .and_return([log_drain])
16
+
13
17
  allow(Aptible::Api::Account).to receive(:all)
14
- .with(token: token).and_return([account])
18
+ .with(token: token, href: '/accounts?per_page=5000&no_embed=true')
19
+ .and_return([account])
15
20
  end
16
21
 
17
22
  describe '#log_drain:list' do
@@ -25,8 +30,16 @@ describe Aptible::CLI::Agent do
25
30
 
26
31
  it 'lists log drains across multiple accounts' do
27
32
  other_account = Fabricate(:account)
28
- Fabricate(:log_drain, handle: 'test2', account: other_account)
33
+ other_drain = Fabricate(
34
+ :log_drain,
35
+ handle: 'test2',
36
+ account: other_account
37
+ )
29
38
  accounts = [account, other_account]
39
+
40
+ allow(Aptible::Api::LogDrain).to receive(:all)
41
+ .with(token: token, href: '/log_drains?per_page=5000')
42
+ .and_return([log_drain, other_drain])
30
43
  allow(Aptible::Api::Account).to receive(:all).and_return(accounts)
31
44
 
32
45
  subject.send('log_drain:list')
@@ -55,7 +55,7 @@ describe Aptible::CLI::Agent do
55
55
  token = 'the-token'
56
56
  allow(subject).to receive(:fetch_token) { token }
57
57
  allow(Aptible::Api::Account).to receive(:all)
58
- .with(token: token)
58
+ .with(token: token, href: '/accounts?per_page=5000&no_embed=true')
59
59
  .and_return([staging, prod])
60
60
  allow(Aptible::Api::MaintenanceDatabase).to receive(:all)
61
61
  .with(token: token)
@@ -123,7 +123,8 @@ describe Aptible::CLI::Agent do
123
123
  before do
124
124
  token = 'the-token'
125
125
  allow(subject).to receive(:fetch_token) { token }
126
- allow(Aptible::Api::Account).to receive(:all).with(token: token)
126
+ allow(Aptible::Api::Account).to receive(:all)
127
+ .with(token: token, href: '/accounts?per_page=5000&no_embed=true')
127
128
  .and_return([staging, prod])
128
129
  allow(Aptible::Api::MaintenanceApp).to receive(:all).with(token: token)
129
130
  .and_return(maintenance_apps)
@@ -10,8 +10,13 @@ describe Aptible::CLI::Agent do
10
10
  before { allow(subject).to receive(:fetch_token).and_return(token) }
11
11
 
12
12
  before do
13
+ allow(Aptible::Api::MetricDrain).to receive(:all)
14
+ .with(token: token, href: '/metric_drains?per_page=5000')
15
+ .and_return([metric_drain])
16
+
13
17
  allow(Aptible::Api::Account).to receive(:all)
14
- .with(token: token).and_return([account])
18
+ .with(token: token, href: '/accounts?per_page=5000&no_embed=true')
19
+ .and_return([account])
15
20
  end
16
21
 
17
22
  describe '#metric_drain:list' do
@@ -25,8 +30,16 @@ describe Aptible::CLI::Agent do
25
30
 
26
31
  it 'lists metric drains across multiple accounts' do
27
32
  other_account = Fabricate(:account)
28
- Fabricate(:metric_drain, handle: 'test2', account: other_account)
33
+ other_drain = Fabricate(
34
+ :metric_drain,
35
+ handle: 'test2',
36
+ account: other_account
37
+ )
29
38
  accounts = [account, other_account]
39
+
40
+ allow(Aptible::Api::MetricDrain).to receive(:all)
41
+ .with(token: token, href: '/metric_drains?per_page=5000')
42
+ .and_return([metric_drain, other_drain])
30
43
  allow(Aptible::Api::Account).to receive(:all).and_return(accounts)
31
44
 
32
45
  subject.send('metric_drain:list')
@@ -142,7 +142,8 @@ describe Aptible::CLI::Agent do
142
142
 
143
143
  expect { subject.send('operation:logs', 1) }
144
144
  .to raise_error('Unable to retrieve the operation\'s logs. '\
145
- 'If the issue persists please contact support for assistance.')
145
+ 'If the issue persists please contact support for assistance, ' \
146
+ "or view them at https://app.aptible.com/operations/#{operation_id}")
146
147
  end
147
148
  it 'errors when body is empty' do
148
149
  operation_id = SecureRandom.uuid
@@ -163,7 +164,8 @@ describe Aptible::CLI::Agent do
163
164
 
164
165
  expect { subject.send('operation:logs', 1) }
165
166
  .to raise_error('Unable to retrieve the operation\'s logs. '\
166
- 'If the issue persists please contact support for assistance.')
167
+ 'If the issue persists please contact support for assistance, ' \
168
+ "or view them at https://app.aptible.com/operations/#{operation_id}")
167
169
  end
168
170
  it 'errors when s3 itself returns an error code' do
169
171
  operation_id = SecureRandom.uuid
@@ -6,7 +6,9 @@ describe Aptible::CLI::Agent do
6
6
 
7
7
  before do
8
8
  allow(subject).to receive(:fetch_token) { token }
9
- allow(Aptible::Api::App).to receive(:all).with(token: token)
9
+ allow(Aptible::Api::App)
10
+ .to receive(:all)
11
+ .with(token: token, href: '/apps?per_page=5000&no_embed=true')
10
12
  .and_return([app])
11
13
  end
12
14
 
@@ -30,4 +30,12 @@ Fabricator(:account, from: :stub_account) do
30
30
  metric_drains { [] }
31
31
  backup_retention_policies { [] }
32
32
  created_at { Time.now }
33
+ links do |attrs|
34
+ hash = {
35
+ self: OpenStruct.new(
36
+ href: "/accounts/#{attrs[:id]}"
37
+ )
38
+ }
39
+ OpenStruct.new(hash)
40
+ end
33
41
  end
@@ -31,5 +31,14 @@ Fabricator(:app, from: :stub_app) do
31
31
  errors { Aptible::Resource::Errors.new }
32
32
  created_at { Time.now }
33
33
 
34
+ links do |attrs|
35
+ hash = {
36
+ account: OpenStruct.new(
37
+ href: "/accounts/#{attrs[:account].id}"
38
+ )
39
+ }
40
+ OpenStruct.new(hash)
41
+ end
42
+
34
43
  after_create { |app| app.account.apps << app }
35
44
  end
@@ -19,6 +19,14 @@ Fabricator(:database, from: :stub_database) do
19
19
  database_image
20
20
  disk { Fabricate(:database_disk) }
21
21
  service { nil }
22
+ links do |attrs|
23
+ hash = {
24
+ account: OpenStruct.new(
25
+ href: "/accounts/#{attrs[:account].id}"
26
+ )
27
+ }
28
+ OpenStruct.new(hash)
29
+ end
22
30
 
23
31
  backups { [] }
24
32
  database_credentials { [] }
@@ -16,6 +16,14 @@ end
16
16
  Fabricator(:log_drain, from: :stub_log_drain) do
17
17
  id { sequence(:log_drain_id) }
18
18
  account
19
+ links do |attrs|
20
+ hash = {
21
+ account: OpenStruct.new(
22
+ href: "/accounts/#{attrs[:account].id}"
23
+ )
24
+ }
25
+ OpenStruct.new(hash)
26
+ end
19
27
 
20
28
  after_create { |drain| drain.account.log_drains << drain }
21
29
  end
@@ -3,6 +3,14 @@ class StubMetricDrain < OpenStruct; end
3
3
  Fabricator(:metric_drain, from: :stub_metric_drain) do
4
4
  id { sequence(:metric_drain_id) }
5
5
  account
6
+ links do |attrs|
7
+ hash = {
8
+ account: OpenStruct.new(
9
+ href: "/accounts/#{attrs[:account].id}"
10
+ )
11
+ }
12
+ OpenStruct.new(hash)
13
+ end
6
14
 
7
15
  after_create { |drain| drain.account.metric_drains << drain }
8
16
  end
data/spec/spec_helper.rb CHANGED
@@ -76,7 +76,15 @@ module SpecHarness
76
76
  end
77
77
 
78
78
  RSpec.configure do |config|
79
- config.before(:each) { reset_spec_harness }
79
+ config.before(:each) do
80
+ reset_spec_harness
81
+ begin
82
+ allow(subject)
83
+ .to receive(:telemetry)
84
+ .and_return nil
85
+ rescue
86
+ end
87
+ end
80
88
 
81
89
  config.include(SpecHarness)
82
90
 
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.24.1
4
+ version: 0.24.3
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: 2024-12-26 00:00:00.000000000 Z
11
+ date: 2025-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -376,6 +376,7 @@ files:
376
376
  - lib/aptible/cli/helpers/security_key.rb
377
377
  - lib/aptible/cli/helpers/ssh.rb
378
378
  - lib/aptible/cli/helpers/system.rb
379
+ - lib/aptible/cli/helpers/telemetry.rb
379
380
  - lib/aptible/cli/helpers/token.rb
380
381
  - lib/aptible/cli/helpers/tunnel.rb
381
382
  - lib/aptible/cli/helpers/vhost.rb
@@ -472,7 +473,7 @@ homepage: https://github.com/aptible/aptible-cli
472
473
  licenses:
473
474
  - MIT
474
475
  metadata: {}
475
- post_install_message:
476
+ post_install_message:
476
477
  rdoc_options: []
477
478
  require_paths:
478
479
  - lib
@@ -488,7 +489,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
488
489
  version: '0'
489
490
  requirements: []
490
491
  rubygems_version: 3.0.3.1
491
- signing_key:
492
+ signing_key:
492
493
  specification_version: 4
493
494
  summary: Command-line interface for Aptible services
494
495
  test_files: