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.
- checksums.yaml +4 -4
- data/README.md +10 -1
- data/aptible-cli.gemspec +1 -0
- data/bin/aptible +9 -5
- data/lib/aptible/cli.rb +36 -0
- data/lib/aptible/cli/agent.rb +10 -6
- data/lib/aptible/cli/error.rb +6 -0
- data/lib/aptible/cli/formatter.rb +21 -0
- data/lib/aptible/cli/formatter/grouped_keyed_list.rb +54 -0
- data/lib/aptible/cli/formatter/keyed_list.rb +25 -0
- data/lib/aptible/cli/formatter/keyed_object.rb +16 -0
- data/lib/aptible/cli/formatter/list.rb +33 -0
- data/lib/aptible/cli/formatter/node.rb +8 -0
- data/lib/aptible/cli/formatter/object.rb +38 -0
- data/lib/aptible/cli/formatter/root.rb +46 -0
- data/lib/aptible/cli/formatter/value.rb +25 -0
- data/lib/aptible/cli/helpers/app.rb +1 -0
- data/lib/aptible/cli/helpers/database.rb +22 -6
- data/lib/aptible/cli/helpers/operation.rb +3 -2
- data/lib/aptible/cli/helpers/tunnel.rb +1 -3
- data/lib/aptible/cli/helpers/vhost.rb +9 -46
- data/lib/aptible/cli/renderer.rb +26 -0
- data/lib/aptible/cli/renderer/base.rb +8 -0
- data/lib/aptible/cli/renderer/json.rb +26 -0
- data/lib/aptible/cli/renderer/text.rb +99 -0
- data/lib/aptible/cli/resource_formatter.rb +136 -0
- data/lib/aptible/cli/subcommands/apps.rb +26 -14
- data/lib/aptible/cli/subcommands/backup.rb +22 -4
- data/lib/aptible/cli/subcommands/config.rb +15 -11
- data/lib/aptible/cli/subcommands/db.rb +82 -31
- data/lib/aptible/cli/subcommands/deploy.rb +1 -1
- data/lib/aptible/cli/subcommands/endpoints.rb +11 -8
- data/lib/aptible/cli/subcommands/operation.rb +2 -1
- data/lib/aptible/cli/subcommands/rebuild.rb +1 -1
- data/lib/aptible/cli/subcommands/restart.rb +1 -1
- data/lib/aptible/cli/subcommands/services.rb +8 -9
- data/lib/aptible/cli/version.rb +1 -1
- data/spec/aptible/cli/agent_spec.rb +11 -14
- data/spec/aptible/cli/formatter_spec.rb +4 -0
- data/spec/aptible/cli/renderer/json_spec.rb +63 -0
- data/spec/aptible/cli/renderer/text_spec.rb +150 -0
- data/spec/aptible/cli/resource_formatter_spec.rb +113 -0
- data/spec/aptible/cli/subcommands/apps_spec.rb +144 -28
- data/spec/aptible/cli/subcommands/backup_spec.rb +37 -16
- data/spec/aptible/cli/subcommands/config_spec.rb +95 -0
- data/spec/aptible/cli/subcommands/db_spec.rb +185 -93
- data/spec/aptible/cli/subcommands/endpoints_spec.rb +10 -8
- data/spec/aptible/cli/subcommands/operation_spec.rb +0 -1
- data/spec/aptible/cli/subcommands/rebuild_spec.rb +17 -0
- data/spec/aptible/cli/subcommands/services_spec.rb +8 -12
- data/spec/aptible/cli_spec.rb +31 -0
- data/spec/fabricators/account_fabricator.rb +11 -0
- data/spec/fabricators/app_fabricator.rb +15 -0
- data/spec/fabricators/configuration_fabricator.rb +8 -0
- data/spec/fabricators/database_image_fabricator.rb +17 -0
- data/spec/fabricators/operation_fabricator.rb +1 -0
- data/spec/fabricators/service_fabricator.rb +4 -0
- data/spec/spec_helper.rb +63 -1
- metadata +55 -4
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0ef65d679c775ddb6867c82a3dcd03ff8b89242
|
4
|
+
data.tar.gz: 1f59dcda5ee8d9dc6c66adc1253442602c79c33c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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]
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
data/lib/aptible/cli/agent.rb
CHANGED
@@ -68,7 +68,11 @@ module Aptible
|
|
68
68
|
|
69
69
|
desc 'version', 'Print Aptible CLI version'
|
70
70
|
def version
|
71
|
-
|
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
|
-
|
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
|
-
|
120
|
-
|
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
|
-
|
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
|
-
|
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,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,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
|