aptible-cli 0.14.1 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
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