aptible-cli 0.14.1 → 0.15.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -1
  3. data/aptible-cli.gemspec +1 -0
  4. data/bin/aptible +9 -5
  5. data/lib/aptible/cli.rb +36 -0
  6. data/lib/aptible/cli/agent.rb +10 -6
  7. data/lib/aptible/cli/error.rb +6 -0
  8. data/lib/aptible/cli/formatter.rb +21 -0
  9. data/lib/aptible/cli/formatter/grouped_keyed_list.rb +54 -0
  10. data/lib/aptible/cli/formatter/keyed_list.rb +25 -0
  11. data/lib/aptible/cli/formatter/keyed_object.rb +16 -0
  12. data/lib/aptible/cli/formatter/list.rb +33 -0
  13. data/lib/aptible/cli/formatter/node.rb +8 -0
  14. data/lib/aptible/cli/formatter/object.rb +38 -0
  15. data/lib/aptible/cli/formatter/root.rb +46 -0
  16. data/lib/aptible/cli/formatter/value.rb +25 -0
  17. data/lib/aptible/cli/helpers/app.rb +1 -0
  18. data/lib/aptible/cli/helpers/database.rb +22 -6
  19. data/lib/aptible/cli/helpers/operation.rb +3 -2
  20. data/lib/aptible/cli/helpers/tunnel.rb +1 -3
  21. data/lib/aptible/cli/helpers/vhost.rb +9 -46
  22. data/lib/aptible/cli/renderer.rb +26 -0
  23. data/lib/aptible/cli/renderer/base.rb +8 -0
  24. data/lib/aptible/cli/renderer/json.rb +26 -0
  25. data/lib/aptible/cli/renderer/text.rb +99 -0
  26. data/lib/aptible/cli/resource_formatter.rb +136 -0
  27. data/lib/aptible/cli/subcommands/apps.rb +26 -14
  28. data/lib/aptible/cli/subcommands/backup.rb +22 -4
  29. data/lib/aptible/cli/subcommands/config.rb +15 -11
  30. data/lib/aptible/cli/subcommands/db.rb +82 -31
  31. data/lib/aptible/cli/subcommands/deploy.rb +1 -1
  32. data/lib/aptible/cli/subcommands/endpoints.rb +11 -8
  33. data/lib/aptible/cli/subcommands/operation.rb +2 -1
  34. data/lib/aptible/cli/subcommands/rebuild.rb +1 -1
  35. data/lib/aptible/cli/subcommands/restart.rb +1 -1
  36. data/lib/aptible/cli/subcommands/services.rb +8 -9
  37. data/lib/aptible/cli/version.rb +1 -1
  38. data/spec/aptible/cli/agent_spec.rb +11 -14
  39. data/spec/aptible/cli/formatter_spec.rb +4 -0
  40. data/spec/aptible/cli/renderer/json_spec.rb +63 -0
  41. data/spec/aptible/cli/renderer/text_spec.rb +150 -0
  42. data/spec/aptible/cli/resource_formatter_spec.rb +113 -0
  43. data/spec/aptible/cli/subcommands/apps_spec.rb +144 -28
  44. data/spec/aptible/cli/subcommands/backup_spec.rb +37 -16
  45. data/spec/aptible/cli/subcommands/config_spec.rb +95 -0
  46. data/spec/aptible/cli/subcommands/db_spec.rb +185 -93
  47. data/spec/aptible/cli/subcommands/endpoints_spec.rb +10 -8
  48. data/spec/aptible/cli/subcommands/operation_spec.rb +0 -1
  49. data/spec/aptible/cli/subcommands/rebuild_spec.rb +17 -0
  50. data/spec/aptible/cli/subcommands/services_spec.rb +8 -12
  51. data/spec/aptible/cli_spec.rb +31 -0
  52. data/spec/fabricators/account_fabricator.rb +11 -0
  53. data/spec/fabricators/app_fabricator.rb +15 -0
  54. data/spec/fabricators/configuration_fabricator.rb +8 -0
  55. data/spec/fabricators/database_image_fabricator.rb +17 -0
  56. data/spec/fabricators/operation_fabricator.rb +1 -0
  57. data/spec/fabricators/service_fabricator.rb +4 -0
  58. data/spec/spec_helper.rb +63 -1
  59. metadata +55 -4
  60. data/spec/aptible/cli/helpers/vhost_spec.rb +0 -105
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4b9fd4e188e1528e1b563686014af146adb94682
4
- data.tar.gz: 357b0531bc1e827cf48a9a6ed260b6d181d3da11
3
+ metadata.gz: b0ef65d679c775ddb6867c82a3dcd03ff8b89242
4
+ data.tar.gz: 1f59dcda5ee8d9dc6c66adc1253442602c79c33c
5
5
  SHA512:
6
- metadata.gz: c961a51996a5653d72ea6c43a34756e803442957e74b62d5e982bd8f9d198895243b259699f03fcbf0895b4b1c306d9d4baad5b392934735aaafd3d402474bd2
7
- data.tar.gz: c5fece56955f0d3157661cb2a3219cdad0b69b0983fec6b360ae39f6647afec4eb5c3ea8d7ab694320c9c235cf0d2b5155380753549461935c9b09cd707fdeb8
6
+ metadata.gz: 52cb99978e5c6ec6fdb91d9bbd8903d26df80a1ba4d1aecc62c63ee47bc415c24f864541a2d35e4b0e293be5f3b84d2ce482a1a5c1c8a8324f30d529b8ff0abf
7
+ data.tar.gz: f50356c6dba2433f232b545415b887de601acc8f3e3ef9ec46d8dd9c0417c4e37dd31db3a2dd3cc2921cb3825822f9a5b894b37dbba5e7789c8fce22b76d4926
data/README.md CHANGED
@@ -42,7 +42,7 @@ Commands:
42
42
  aptible config:unset # Alias for config:rm
43
43
  aptible db:backup HANDLE # Backup a database
44
44
  aptible db:clone SOURCE DEST # Clone a database to create a new one
45
- aptible db:create HANDLE[--type TYPE] [--container-size SIZE_MB] [--size SIZE_GB] # Create a new database
45
+ aptible db:create HANDLE [--type TYPE] [--version VERSION] [--container-size SIZE_MB] [--size SIZE_GB] # Create a new database
46
46
  aptible db:deprovision HANDLE # Deprovision a database
47
47
  aptible db:dump HANDLE # Dump a remote database to file
48
48
  aptible db:execute HANDLE SQL_FILE # Executes sql against a database
@@ -51,6 +51,7 @@ Commands:
51
51
  aptible db:restart HANDLE [--container-size SIZE_MB] [--size SIZE_GB] # Restart a database
52
52
  aptible db:tunnel HANDLE # Create a local tunnel to a database
53
53
  aptible db:url HANDLE # Display a database URL
54
+ aptible db:versions # List available database versions
54
55
  aptible deploy [OPTIONS] [VAR1=VAL1] [VAR=VAL2] ... # Deploy an app
55
56
  aptible domains # Print an app's current virtual domains - DEPRECATED
56
57
  aptible endpoints:database:create DATABASE # Create a Database Endpoint
@@ -76,6 +77,14 @@ Commands:
76
77
  ```
77
78
  <!-- END USAGE -->
78
79
 
80
+ ### Output Format
81
+
82
+ By default, the Aptible CLI outputs data as unstructured text, designed for human consumption.
83
+
84
+ If you need to parse the output in another program, set the `APTIBLE_OUTPUT_FORMAT` environment variable to `json` when calling the Aptible CLI for JSON output.
85
+
86
+ The default format is `text`.
87
+
79
88
  ## Contributing
80
89
 
81
90
  1. Fork the project.
data/aptible-cli.gemspec CHANGED
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_dependency 'term-ansicolor'
30
30
  spec.add_dependency 'chronic_duration', '~> 0.10.6'
31
31
  spec.add_dependency 'win32-process' if Gem.win_platform?
32
+ spec.add_dependency 'activesupport', '>= 4.0', '< 6.0'
32
33
  spec.add_development_dependency 'bundler', '~> 1.3'
33
34
  spec.add_development_dependency 'aptible-tasks', '~> 0.5.8'
34
35
  spec.add_development_dependency 'rake'
data/bin/aptible CHANGED
@@ -10,10 +10,14 @@ end
10
10
  begin
11
11
  Aptible::CLI::Agent.start
12
12
  rescue HyperResource::ClientError => e
13
- if e.body['error'] == 'invalid_token'
14
- STDERR.puts 'API authentication error: please run aptible login'
15
- else
16
- STDERR.puts "An error occurred: #{e.body['message']}"
17
- end
13
+ m = if e.body['error'] == 'invalid_token'
14
+ 'API authentication error: please run aptible login'
15
+ else
16
+ "An error occurred: #{e.body['message']}"
17
+ end
18
+ Aptible::CLI.logger.error(m)
19
+ exit 1
20
+ rescue Aptible::CLI::UserError => e
21
+ Aptible::CLI.logger.error e.message
18
22
  exit 1
19
23
  end
data/lib/aptible/cli.rb CHANGED
@@ -1,7 +1,43 @@
1
+ require 'logger'
2
+
1
3
  require 'aptible/cli/version'
2
4
  require 'aptible/cli/agent'
5
+ require 'aptible/cli/error'
6
+ require 'aptible/cli/formatter'
7
+ require 'aptible/cli/renderer'
8
+ require 'aptible/cli/resource_formatter'
3
9
 
4
10
  module Aptible
5
11
  module CLI
12
+ class LogFormatter
13
+ include Term::ANSIColor
14
+
15
+ def call(severity, _, _, msg)
16
+ color = case severity
17
+ when 'DEBUG'
18
+ :no_color
19
+ when 'INFO'
20
+ :green
21
+ when 'WARN'
22
+ :yellow
23
+ when 'ERROR', 'FATAL'
24
+ :red
25
+ else
26
+ :no_color
27
+ end
28
+
29
+ "#{public_send(color, msg)}\n"
30
+ end
31
+
32
+ def no_color(msg)
33
+ msg
34
+ end
35
+ end
36
+
37
+ def self.logger
38
+ @logger ||= Logger.new($stderr).tap do |l|
39
+ l.formatter = LogFormatter.new
40
+ end
41
+ end
6
42
  end
7
43
  end
@@ -68,7 +68,11 @@ module Aptible
68
68
 
69
69
  desc 'version', 'Print Aptible CLI version'
70
70
  def version
71
- puts version_string
71
+ Formatter.render(Renderer.current) do |root|
72
+ root.keyed_object('version') do |node|
73
+ node.value('version', version_string)
74
+ end
75
+ end
72
76
  end
73
77
 
74
78
  desc 'login', 'Log in to Aptible'
@@ -111,19 +115,19 @@ module Aptible
111
115
  end
112
116
 
113
117
  save_token(token.access_token)
114
- puts "Token written to #{token_file}"
118
+ CLI.logger.info "Token written to #{token_file}"
115
119
 
116
120
  lifetime_format = { units: 2, joiner: ', ' }
117
121
  token_lifetime = (token.expires_at - token.created_at).round
118
122
  expires_in = ChronicDuration.output(token_lifetime, lifetime_format)
119
- puts "This token will expire after #{expires_in} " \
120
- '(use --lifetime to customize)'
123
+ CLI.logger.info "This token will expire after #{expires_in} " \
124
+ '(use --lifetime to customize)'
121
125
  end
122
126
 
123
127
  private
124
128
 
125
129
  def deprecated(msg)
126
- $stderr.puts yellow([
130
+ CLI.logger.warn([
127
131
  "DEPRECATION NOTICE: #{msg}",
128
132
  'Please contact support@aptible.com with any questions.'
129
133
  ].join("\n"))
@@ -147,7 +151,7 @@ module Aptible
147
151
  now = Time.now.utc.to_i
148
152
 
149
153
  if last_nag < now - nag_frequency
150
- $stderr.puts yellow([
154
+ CLI.logger.warn([
151
155
  'You have installed the Aptible CLI from source.',
152
156
  'This is not recommended: some functionality may not work!',
153
157
  'Review this support topic for more information:',
@@ -0,0 +1,6 @@
1
+ module Aptible
2
+ module CLI
3
+ class UserError < StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'formatter/node'
2
+ require_relative 'formatter/list'
3
+ require_relative 'formatter/keyed_list'
4
+ require_relative 'formatter/grouped_keyed_list'
5
+ require_relative 'formatter/object'
6
+ require_relative 'formatter/keyed_object'
7
+ require_relative 'formatter/root'
8
+ require_relative 'formatter/value'
9
+
10
+ module Aptible
11
+ module CLI
12
+ module Formatter
13
+ def self.render(renderer)
14
+ root = Root.new
15
+ yield root
16
+ out = renderer.render(root)
17
+ puts out if out
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,54 @@
1
+ module Aptible
2
+ module CLI
3
+ module Formatter
4
+ class GroupedKeyedList < KeyedList
5
+ attr_reader :group
6
+
7
+ class InvalidGroup
8
+ def initialize(group)
9
+ m = 'group argument must be a string or a hash with one key ' \
10
+ "and a string value. #{group} is invalid"
11
+ super(m)
12
+ end
13
+ end
14
+
15
+ def initialize(group, y)
16
+ @group = group
17
+ validate_group!
18
+ super(y)
19
+ end
20
+
21
+ def groups
22
+ children.group_by(&grouper)
23
+ end
24
+
25
+ private
26
+
27
+ def grouper
28
+ case group
29
+ when String
30
+ lambda do |n|
31
+ n.children.fetch(group)
32
+ end
33
+ when Hash
34
+ first, second = group.to_a.first
35
+ lambda do |n|
36
+ n.children.fetch(first).children.fetch(second)
37
+ end
38
+ end
39
+ end
40
+
41
+ def validate_group!
42
+ return if group.is_a?(String)
43
+ if group.is_a?(Hash)
44
+ keys = group.keys
45
+ raise InvalidGroup, group if keys.size != 1
46
+ raise InvalidGroup, group unless group[keys.first].is_a?(String)
47
+ return
48
+ end
49
+ raise InvalidGroup(group)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,25 @@
1
+ module Aptible
2
+ module CLI
3
+ module Formatter
4
+ class KeyedList < List
5
+ # KeyedList is a list of objects with one key that is more important
6
+ # than the others. Some renderers may opt to only display this key when
7
+ # rendering the list.
8
+ attr_reader :key
9
+
10
+ def initialize(key)
11
+ @key = key
12
+ super()
13
+ end
14
+
15
+ def value(_)
16
+ raise "not supported on #{self.class}"
17
+ end
18
+
19
+ def list
20
+ raise "not supported on #{self.class}"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ module Aptible
2
+ module CLI
3
+ module Formatter
4
+ class KeyedObject < Object
5
+ # KeyedObject is rendered as an Object, but flags a given key as being
6
+ # more important. Renderers may opt to only render this key.
7
+ attr_reader :key
8
+
9
+ def initialize(key)
10
+ @key = key
11
+ super()
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,33 @@
1
+ module Aptible
2
+ module CLI
3
+ module Formatter
4
+ class List < Node
5
+ attr_reader :children
6
+
7
+ def initialize
8
+ @children = []
9
+ end
10
+
11
+ def value(s)
12
+ # TODO: Fail if block?
13
+ @children << Value.new(s)
14
+ nil
15
+ end
16
+
17
+ def object
18
+ o = Object.new
19
+ yield o
20
+ @children << o
21
+ nil
22
+ end
23
+
24
+ def list
25
+ l = List.new
26
+ yield l
27
+ @children << l
28
+ nil
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,8 @@
1
+ module Aptible
2
+ module CLI
3
+ module Formatter
4
+ class Node
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,38 @@
1
+ module Aptible
2
+ module CLI
3
+ module Formatter
4
+ class Object < Node
5
+ attr_reader :children
6
+
7
+ def initialize
8
+ @children = {}
9
+ end
10
+
11
+ def value(k, v)
12
+ assign_child(k, Value.new(v)) {}
13
+ end
14
+
15
+ def object(k, &block)
16
+ assign_child(k, Object.new, &block)
17
+ end
18
+
19
+ def keyed_object(k, object_key, &block)
20
+ assign_child(k, KeyedObject.new(object_key), &block)
21
+ end
22
+
23
+ def list(k, &block)
24
+ assign_child(k, List.new, &block)
25
+ end
26
+
27
+ private
28
+
29
+ def assign_child(k, node)
30
+ raise "Overwriting keys (#{k}) is not allowed" if @children[k]
31
+ yield node
32
+ @children[k] = node
33
+ nil
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,46 @@
1
+ module Aptible
2
+ module CLI
3
+ module Formatter
4
+ class Root < Node
5
+ attr_reader :root
6
+
7
+ def initialize
8
+ @root = nil
9
+ end
10
+
11
+ def value(s)
12
+ assign_root(Value.new(s)) {}
13
+ end
14
+
15
+ def object(&block)
16
+ assign_root(Object.new, &block)
17
+ end
18
+
19
+ def keyed_object(key, &block)
20
+ assign_root(KeyedObject.new(key), &block)
21
+ end
22
+
23
+ def list(&block)
24
+ assign_root(List.new, &block)
25
+ end
26
+
27
+ def keyed_list(key, &block)
28
+ assign_root(KeyedList.new(key), &block)
29
+ end
30
+
31
+ def grouped_keyed_list(group, key, &block)
32
+ assign_root(GroupedKeyedList.new(group, key), &block)
33
+ end
34
+
35
+ private
36
+
37
+ def assign_root(node)
38
+ raise "root has already been initialized: #{@root.inspect}" if @root
39
+ yield node
40
+ @root = node
41
+ nil
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ module Aptible
2
+ module CLI
3
+ module Formatter
4
+ class Value < Node
5
+ include Comparable
6
+
7
+ attr_reader :value
8
+
9
+ def initialize(value)
10
+ @value = value
11
+ end
12
+
13
+ def <=>(other)
14
+ value <=> other.value
15
+ end
16
+
17
+ alias eql? ==
18
+
19
+ def hash
20
+ value.hash
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end