kontena-cli 1.1.0 → 1.1.1.rc1

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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/kontena-cli.gemspec +1 -1
  4. data/lib/kontena/callbacks/master/deploy/70_invite_self_after_deploy.rb +9 -6
  5. data/lib/kontena/cli/common.rb +2 -0
  6. data/lib/kontena/cli/plugins/install_command.rb +4 -0
  7. data/lib/kontena/cli/services/link_command.rb +12 -4
  8. data/lib/kontena/cli/services/unlink_command.rb +11 -5
  9. data/lib/kontena/cli/stacks/service_generator.rb +10 -7
  10. data/lib/kontena/cli/stacks/yaml/opto.rb +15 -0
  11. data/lib/kontena/cli/stacks/yaml/opto/prompt_resolver.rb +13 -5
  12. data/lib/kontena/cli/stacks/yaml/opto/service_instances_resolver.rb +1 -1
  13. data/lib/kontena/cli/stacks/yaml/opto/service_link_resolver.rb +66 -35
  14. data/lib/kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver.rb +33 -10
  15. data/lib/kontena/cli/stacks/yaml/opto/vault_resolver.rb +1 -1
  16. data/lib/kontena/cli/stacks/yaml/opto/vault_setter.rb +1 -2
  17. data/lib/kontena/cli/stacks/yaml/reader.rb +7 -8
  18. data/lib/kontena/plugin_manager.rb +1 -2
  19. data/lib/kontena_cli.rb +1 -1
  20. data/spec/kontena/cli/cloud/master/add_command_spec.rb +0 -1
  21. data/spec/kontena/cli/common_spec.rb +28 -21
  22. data/spec/kontena/cli/master/init_cloud_command_spec.rb +28 -0
  23. data/spec/kontena/cli/services/link_command_spec.rb +2 -2
  24. data/spec/kontena/cli/services/unlink_command_spec.rb +1 -1
  25. data/spec/kontena/cli/stacks/service_generator_spec.rb +7 -3
  26. data/spec/kontena/cli/stacks/yaml/opto/prompt_resolver_spec.rb +27 -0
  27. data/spec/kontena/cli/stacks/yaml/opto/service_link_resolver_spec.rb +54 -0
  28. data/spec/kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver_spec.rb +73 -0
  29. data/spec/kontena/kontena_cli_spec.rb +15 -6
  30. data/spec/kontena/main_command_spec.rb +16 -0
  31. metadata +19 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7e2dfaafb984f7f7c0ca63566203262c8692a33f
4
- data.tar.gz: '0280a6505d2d6568203b61221cc753dd297a4461'
3
+ metadata.gz: 76963be4ff231516ea09ffc1261b2945f7728f78
4
+ data.tar.gz: ea1f2e4fa944e33af0d7c5b9abea939485805346
5
5
  SHA512:
6
- metadata.gz: 537c7d6ee6d2aea359559e70ce0a8b593fd22c6a1da3c612a839b8adc32aed53f98d4e3f99625824afb900fc888005f34ff5f0a0faa06bbf563f795c4da56b58
7
- data.tar.gz: 8d1f092a778f4f0933cd785d6ea7e149dc2d9ca843b5172380aed4ff81654da622782402b85a80a838b7439306689e108e9346a03b7c266792d24157eedfc15a
6
+ metadata.gz: 66580e1af2b505487e82ae8458f5fed6f2965438df752e0ae8581108fe067932dc8205276117f3fc0a00bba46ddb17f3c5b19f8d224b82c78cd2e90af8853b0c
7
+ data.tar.gz: ce4aef539d02fb0ee56f6850a7657d8d0b2466bca5db2d7633ae4d01c28e75ce36330ef1df8a7c46644abd6df79cd8fa9ffbe7d716595bc0155ad71466e8e27f
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.1.1.rc1
data/kontena-cli.gemspec CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_runtime_dependency "launchy", "~> 2.4.3"
30
30
  spec.add_runtime_dependency "hash_validator", "~> 0.7.0"
31
31
  spec.add_runtime_dependency "retriable", "~> 2.1.0"
32
- spec.add_runtime_dependency "opto", "~> 1.8.0"
32
+ spec.add_runtime_dependency "opto", "1.8.3"
33
33
  spec.add_runtime_dependency "semantic", "~> 1.5"
34
34
  spec.add_runtime_dependency "safe_yaml", "~> 1.0"
35
35
  spec.add_runtime_dependency "liquid", "~> 4.0.0"
@@ -4,7 +4,7 @@ module Kontena
4
4
 
5
5
  include Kontena::Cli::Common
6
6
 
7
- matches_commands 'master create'
7
+ matches_commands 'master create', 'master init_cloud'
8
8
 
9
9
  def cloud_user_data
10
10
  return @cloud_user_data if @cloud_user_data
@@ -27,8 +27,7 @@ module Kontena
27
27
  def after
28
28
  return unless current_master
29
29
  return unless command.exit_code == 0
30
- return unless current_master.username.to_s == 'admin'
31
- return nil if command.skip_auth_provider?
30
+ return nil if command.respond_to?(:skip_auth_provider?) && command.skip_auth_provider?
32
31
  return nil unless cloud_user_data
33
32
 
34
33
  invite_response = nil
@@ -51,11 +50,15 @@ module Kontena
51
50
 
52
51
  return nil if role_status.to_i > 0
53
52
 
54
- spinner "Adding #{cloud_user_data[:email]} to grid 'test'" do |spin|
55
- grid_add_status = Kontena.run("grid user add --grid test #{cloud_user_data[:email].shellescape}")
56
- spin.fail if grid_add_status.to_i > 0
53
+ if current_master.grid
54
+ spinner "Adding #{cloud_user_data[:email]} to grid '#{current_master.grid}'" do |spin|
55
+ grid_add_status = Kontena.run("grid user add --grid #{current_master.grid} #{cloud_user_data[:email].shellescape}")
56
+ spin.fail if grid_add_status.to_i > 0
57
+ end
57
58
  end
58
59
 
60
+ return unless current_master.username.to_s == 'admin'
61
+
59
62
  new_user_token = nil
60
63
  spinner "Creating an access token for #{cloud_user_data[:email]}" do |spin|
61
64
  new_user_token = Kontena.run("master token create -e 0 -s user --return -u #{cloud_user_data[:email].shellescape}", returning: :result)
@@ -247,6 +247,7 @@ module Kontena
247
247
  if self.respond_to?(:force?) && self.force?
248
248
  return
249
249
  end
250
+ exit_with_error 'Command requires --force' unless $stdout.tty? && $stdin.tty?
250
251
  puts message if message
251
252
  puts "Destructive command. To proceed, type \"#{name}\" or re-run this command with --force option."
252
253
 
@@ -257,6 +258,7 @@ module Kontena
257
258
  if self.respond_to?(:force?) && self.force?
258
259
  return
259
260
  end
261
+ exit_with_error 'Command requires --force' unless $stdout.tty? && $stdin.tty?
260
262
  prompt.yes?(message) || error('Aborted command.')
261
263
  end
262
264
 
@@ -23,6 +23,10 @@ module Kontena::Cli::Plugins
23
23
  spin.fail!
24
24
  end
25
25
  end
26
+
27
+ spinner "Running cleanup" do |spin|
28
+ Kontena::PluginManager.instance.cleanup_plugin(name)
29
+ end
26
30
  else
27
31
  installed = spinner "Installing plugin #{name.colorize(:cyan)}" do |spin|
28
32
  begin
@@ -13,12 +13,20 @@ module Kontena::Cli::Services
13
13
  def execute
14
14
  require_api_url
15
15
  token = require_token
16
+ target_service = target
17
+
18
+ target_service = "null/#{target_service}" unless target_service.include?('/')
16
19
 
17
20
  service = client(token).get("services/#{parse_service_id(name)}")
18
- existing_targets = service['links'].map{|l| l['grid_service_id'].split('/')[1]}
19
- exit_with_error("Service is already linked to #{target.to_s}") if existing_targets.include?(target.to_s)
20
- links = service['links'].map{|l| {name: l['grid_service_id'].split('/')[1], alias: l['alias']} }
21
- links << {name: target.to_s, alias: target.to_s}
21
+ existing_targets = service['links'].map{ |l| l['id'].split('/', 2)[1] }
22
+ if existing_targets.include?(target_service.to_s)
23
+ exit_with_error("Service is already linked to #{target.to_s}")
24
+ end
25
+ links = service['links'].map{ |l|
26
+ { name: l['id'].split('/', 2)[1], alias: l['alias'] }
27
+ }
28
+ links << {name: target_service.to_s, alias: target.to_s}
29
+ links.compact!
22
30
  data = {links: links}
23
31
  spinner "Linking #{name.colorize(:cyan)} to #{target.colorize(:cyan)} " do
24
32
  update_service(token, name, data)
@@ -13,13 +13,19 @@ module Kontena::Cli::Services
13
13
  def execute
14
14
  require_api_url
15
15
  token = require_token
16
-
16
+ target_service = target
17
+ target_service = "null/#{target_service}" unless target_service.include?('/')
18
+ target_id = "#{current_grid}/#{target_service}"
17
19
  service = client(token).get("services/#{parse_service_id(name)}")
18
- links = service['links'].map{|l| {name: l['grid_service_id'].split('/')[1], alias: l['alias']} }
19
- exit_with_error("Service is not linked to #{target.to_s}") unless links.find{|l| l[:name] == target.to_s}
20
- links.delete_if{|l| l[:name] == target.to_s}
20
+ links = service['links']
21
+ unless links.find { |l| l['id'] == target_id }
22
+ exit_with_error("Service is not linked to #{target.to_s}")
23
+ end
24
+ links.delete_if { |l| l['id'] == target_id }
21
25
  data = {links: links}
22
- update_service(token, name, data)
26
+ spinner "Unlinking #{name.colorize(:cyan)} from #{target.colorize(:cyan)} " do
27
+ update_service(token, name, data)
28
+ end
23
29
  end
24
30
  end
25
31
  end
@@ -49,13 +49,16 @@ module Kontena::Cli::Stacks
49
49
  data['log_opts'] = options['log_opt'] if options['log_opt'] && !options['log_opt'].empty?
50
50
  deploy_opts = options['deploy'] || {}
51
51
  data['strategy'] = deploy_opts['strategy'] if deploy_opts['strategy']
52
- deploy = {}
53
- deploy['wait_for_port'] = deploy_opts['wait_for_port'] if deploy_opts.has_key?('wait_for_port')
54
- deploy['min_health'] = deploy_opts['min_health'] if deploy_opts.has_key?('min_health')
55
- deploy['interval'] = parse_relative_time(deploy_opts['interval']) if deploy_opts.has_key?('interval')
56
- unless deploy.empty?
57
- data['deploy_opts'] = deploy
58
- end
52
+ deploy = {
53
+ 'wait_for_port' => deploy_opts['wait_for_port'],
54
+ 'min_health' => deploy_opts['min_health']
55
+ }
56
+ if deploy_opts.has_key?('interval')
57
+ deploy['interval'] = parse_relative_time(deploy_opts['interval'])
58
+ else
59
+ deploy['interval'] = nil
60
+ end
61
+ data['deploy_opts'] = deploy
59
62
  data['hooks'] = options['hooks'] || {}
60
63
  data['secrets'] = options['secrets'] if options['secrets']
61
64
  data['build'] = parse_build_options(options) if options['build']
@@ -0,0 +1,15 @@
1
+ module Kontena::Cli::Stacks
2
+ module YAML
3
+ module Opto
4
+ module Resolvers; end
5
+ module Setters; end
6
+ end
7
+ end
8
+ end
9
+ require 'opto'
10
+ require_relative 'opto/vault_setter'
11
+ require_relative 'opto/vault_resolver'
12
+ require_relative 'opto/prompt_resolver'
13
+ require_relative 'opto/service_instances_resolver'
14
+ require_relative 'opto/vault_cert_prompt_resolver'
15
+ require_relative 'opto/service_link_resolver'
@@ -1,9 +1,12 @@
1
+ require 'kontena/cli/stacks/yaml/opto'
2
+ require 'kontena/cli/common'
3
+
1
4
  module Kontena::Cli::Stacks
2
5
  module YAML
3
- class Prompt < Opto::Resolver
6
+ class Prompt < ::Opto::Resolver
4
7
  include Kontena::Cli::Common
5
8
 
6
- using Opto::Extension::HashStringOrSymbolKey
9
+ using ::Opto::Extension::HashStringOrSymbolKey
7
10
 
8
11
  def enum?
9
12
  option.type == 'enum'
@@ -50,10 +53,16 @@ module Kontena::Cli::Stacks
50
53
  prompt.yes?(question_text, default: option.default == false ? false : true)
51
54
  end
52
55
 
53
- def ask
54
- prompt.ask(question_text, default: option.default)
56
+ def echo?
57
+ return true if option.handler.nil?
58
+ return true if option.handler.options.nil?
59
+ return true if option.handler.options[:echo].nil?
60
+ option.handler.options[:echo]
55
61
  end
56
62
 
63
+ def ask
64
+ prompt.ask(question_text, default: option.default, echo: echo?)
65
+ end
57
66
 
58
67
  def resolve
59
68
  return nil if option.skip?
@@ -68,4 +77,3 @@ module Kontena::Cli::Stacks
68
77
  end
69
78
  end
70
79
  end
71
-
@@ -1,6 +1,6 @@
1
1
  module Kontena::Cli::Stacks
2
2
  module YAML
3
- class Opto::Resolvers::ServiceInstances < Opto::Resolver
3
+ class Opto::Resolvers::ServiceInstances < ::Opto::Resolver
4
4
  def resolve
5
5
  read_command = Kontena::Cli::Stacks::ShowCommand.new([self.stack])
6
6
  stack = read_command.fetch_stack(self.stack)
@@ -1,45 +1,76 @@
1
- module Kontena::Cli::Stacks
2
- module YAML
3
- class Opto::Resolvers::ServiceLink < Opto::Resolver
4
- include Kontena::Cli::Common
5
-
6
- def resolve
7
- message = hint['prompt']
8
- name_filter = hint['name']
9
- image_filter = hint['image']
10
- raise "prompt missing" unless message
11
-
12
- services = client.get("grids/#{current_grid}/services")['services']
13
- services = filter_by_image(services, image_filter) if image_filter
14
- services = filter_by_name(services, name_filter) if name_filter
15
- prompt.select(message) do |menu|
16
- menu.choice "<none>", nil unless option.required?
17
- services.each do |s|
18
- if s.dig('stack', 'name') == 'null'
19
- name = s['name']
20
- else
21
- name = "#{s.dig('stack', 'name')}/#{s['name']}"
22
- end
23
- menu.choice name, "#{s.dig('stack', 'name')}/#{s['name']}"
24
- end
1
+ module Kontena::Cli::Stacks::YAML::Opto::Resolvers
2
+ class ServiceLink < ::Opto::Resolver
3
+ include Kontena::Cli::Common
4
+
5
+ def resolve
6
+ message = hint['prompt']
7
+ name_filter = hint['name']
8
+ image_filter = hint['image']
9
+ raise "prompt missing" unless message
10
+
11
+ services = get_services
12
+ services = filter_by_image(services, image_filter) if image_filter
13
+ services = filter_by_name(services, name_filter) if name_filter
14
+ return nil if services.size == 0
15
+ prompt.select(message) do |menu|
16
+ menu.default(default_index(services)) if option.default
17
+ menu.choice "<none>", nil unless option.required?
18
+ services.each do |s|
19
+ menu.choice service_name(s), service_link(s)
25
20
  end
26
21
  end
22
+ end
27
23
 
28
- def filter_by_image(services, image)
29
- services.select { |s|
30
- s['image'].include?(image)
31
- }
32
- end
24
+ # @return [Array<Hash>]
25
+ def get_services
26
+ client.get("grids/#{current_grid}/services")['services']
27
+ rescue
28
+ []
29
+ end
33
30
 
34
- def filter_by_name(services, name)
35
- services.select { |s|
36
- s['name'].include?(name)
37
- }
31
+ # @param [Array<Hash>] services
32
+ # @return [Integer]
33
+ def default_index(services)
34
+ index = services.index {|s| service_link(s) == option.default }
35
+ if index
36
+ index.to_i + 1
37
+ else
38
+ 0
38
39
  end
40
+ end
41
+
42
+ # @param [Hash] service
43
+ # @return [String]
44
+ def service_link(service)
45
+ grid, stack, service = service['id'].split('/')
46
+ "#{stack}/#{service}"
47
+ end
39
48
 
40
- def stack
41
- ENV['STACK']
49
+ # @param [Hash] service
50
+ # @return [String]
51
+ def service_name(service)
52
+ grid, stack, service = service['id'].split('/')
53
+ if stack == 'null'.freeze
54
+ service
55
+ else
56
+ "#{stack}/#{service}"
42
57
  end
43
58
  end
59
+
60
+ def filter_by_image(services, image)
61
+ services.select { |s|
62
+ s['image'].include?(image)
63
+ }
64
+ end
65
+
66
+ def filter_by_name(services, name)
67
+ services.select { |s|
68
+ s['name'].include?(name)
69
+ }
70
+ end
71
+
72
+ def stack
73
+ ENV['STACK']
74
+ end
44
75
  end
45
76
  end
@@ -1,15 +1,38 @@
1
- module Kontena::Cli::Stacks
2
- module YAML
3
- class Opto::Resolvers::VaultCertPrompt < Opto::Resolver
4
- include Kontena::Cli::Common
1
+ module Kontena::Cli::Stacks::YAML::Opto::Resolvers
2
+ class VaultCertPrompt < ::Opto::Resolver
3
+ include Kontena::Cli::Common
5
4
 
6
- def resolve
7
- message = hint || 'Select SSL certs'
8
- secrets = client.get("grids/#{current_grid}/secrets")['secrets'].select{ |s|
9
- s['name'].match(/(ssl|cert)/i)
10
- }
11
- prompt.multi_select(hint, secrets.map{ |s| s['name'] })
5
+ def resolve
6
+ message = hint || 'Select SSL certs'
7
+ secrets = get_secrets.select{ |s|
8
+ s['name'].match(/(ssl|cert)/i)
9
+ }
10
+ if secrets.size > 0
11
+ prompt.multi_select(hint) do |menu|
12
+ menu.default(*default_indexes(secrets)) if option.default
13
+ secrets.each do |s|
14
+ menu.choice s['name']
15
+ end
16
+ end
12
17
  end
13
18
  end
19
+
20
+ # @return [Array<Hash>] secrets
21
+ def get_secrets
22
+ client.get("grids/#{current_grid}/secrets")['secrets']
23
+ rescue
24
+ []
25
+ end
26
+
27
+ # @param [Array<Hash>] secrets
28
+ # @return [Array<Integer>]
29
+ def default_indexes(secrets)
30
+ indexes = []
31
+ option.default.to_a.each do |name|
32
+ index = secrets.index { |s| s['name'] == name }
33
+ indexes << index.to_i + 1 if index
34
+ end
35
+ indexes
36
+ end
14
37
  end
15
38
  end
@@ -1,6 +1,6 @@
1
1
  module Kontena::Cli::Stacks
2
2
  module YAML
3
- class Opto::Resolvers::Vault < Opto::Resolver
3
+ class Opto::Resolvers::Vault < ::Opto::Resolver
4
4
  def resolve
5
5
  raise RuntimeError, "Missing or empty vault secret name" if hint.to_s.empty?
6
6
  require 'shellwords'
@@ -1,6 +1,6 @@
1
1
  module Kontena::Cli::Stacks
2
2
  module YAML
3
- class Opto::Setters::Vault < Opto::Setter
3
+ class Opto::Setters::Vault < ::Opto::Setter
4
4
  def set(value)
5
5
  require 'shellwords'
6
6
  ENV["DEBUG"] && STDERR.puts("Setting to vault: #{hint}")
@@ -9,4 +9,3 @@ module Kontena::Cli::Stacks
9
9
  end
10
10
  end
11
11
  end
12
-
@@ -2,6 +2,11 @@ require_relative '../../../util'
2
2
 
3
3
  module Kontena::Cli::Stacks
4
4
  module YAML
5
+ module Opto
6
+ module Resolvers; end
7
+ module Setters; end
8
+ end
9
+
5
10
  class Reader
6
11
  include Kontena::Util
7
12
  include Kontena::Cli::Common
@@ -12,13 +17,7 @@ module Kontena::Cli::Stacks
12
17
  require 'yaml'
13
18
  require_relative 'service_extender'
14
19
  require_relative 'validator_v3'
15
- require 'opto'
16
- require_relative 'opto/vault_setter'
17
- require_relative 'opto/vault_resolver'
18
- require_relative 'opto/prompt_resolver'
19
- require_relative 'opto/service_instances_resolver'
20
- require_relative 'opto/vault_cert_prompt_resolver'
21
- require_relative 'opto/service_link_resolver'
20
+ require_relative 'opto'
22
21
  require 'liquid'
23
22
 
24
23
  @file = file
@@ -88,7 +87,7 @@ module Kontena::Cli::Stacks
88
87
  # @return [Opto::Group]
89
88
  def variables
90
89
  return @variables if @variables
91
- @variables = Opto::Group.new(
90
+ @variables = ::Opto::Group.new(
92
91
  (internals_interpolated_yaml['variables'] || {}).merge('STACK' => { type: :string, value: env['STACK']}, 'GRID' => {type: :string, value: env['GRID']}),
93
92
  defaults: {
94
93
  from: :env,
@@ -33,7 +33,6 @@ module Kontena
33
33
  )
34
34
  plugin_version = version.nil? ? Gem::Requirement.default : Gem::Requirement.new(version)
35
35
  without_safe { cmd.install(prefix(plugin_name), plugin_version) }
36
- cleanup_plugin(plugin_name)
37
36
  cmd.installed_gems
38
37
  end
39
38
 
@@ -123,7 +122,7 @@ module Kontena
123
122
  def cleanup_plugin(plugin_name)
124
123
  require 'rubygems/commands/cleanup_command'
125
124
  cmd = Gem::Commands::CleanupCommand.new
126
- options = ['--norc']
125
+ options = []
127
126
  options += ['-q', '--no-verbose'] unless ENV["DEBUG"]
128
127
  cmd.handle_options options
129
128
  without_safe { cmd.execute }
data/lib/kontena_cli.rb CHANGED
@@ -41,7 +41,7 @@ module Kontena
41
41
  end
42
42
 
43
43
  def self.simple_terminal?
44
- ENV['KONTENA_SIMPLE_TERM'] || !$stdout.tty?
44
+ on_windows? || ENV['KONTENA_SIMPLE_TERM'] || !$stdout.tty?
45
45
  end
46
46
 
47
47
  def self.pastel
@@ -115,7 +115,6 @@ describe Kontena::Cli::Cloud::Master::AddCommand do
115
115
 
116
116
  subject.register_current
117
117
  end
118
-
119
118
  end
120
119
  end
121
120
 
@@ -128,35 +128,42 @@ describe Kontena::Cli::Common do
128
128
  end
129
129
  end
130
130
 
131
- describe '#confirm_command' do
132
- it 'returns true if input matches' do
133
- allow(subject).to receive(:ask).and_return('name-to-confirm')
134
-
135
- expect(subject.confirm_command('name-to-confirm')).to be_truthy
136
- expect{subject.confirm_command('name-to-confirm')}.to_not raise_error
131
+ context 'confirm' do
132
+ before(:each) do
133
+ expect($stdout).to receive(:tty?).at_least(:once).and_return(true)
134
+ expect($stdin).to receive(:tty?).at_least(:once).and_return(true)
137
135
  end
138
136
 
139
- it 'raises error unless input matches' do
140
- expect(subject).to receive(:ask).and_return('wrong-name')
141
- expect(subject).to receive(:error).with(/did not match/)
137
+ describe '#confirm_command' do
138
+ it 'returns true if input matches' do
139
+ allow(subject).to receive(:ask).and_return('name-to-confirm')
142
140
 
143
- subject.confirm_command('name-to-confirm')
144
- end
145
- end
141
+ expect(subject.confirm_command('name-to-confirm')).to be_truthy
142
+ expect{subject.confirm_command('name-to-confirm')}.to_not raise_error
143
+ end
146
144
 
147
- describe '#confirm' do
148
- it 'returns true if confirmed' do
149
- allow(subject.prompt).to receive(:yes?).and_return(true)
145
+ it 'raises error unless input matches' do
146
+ expect(subject).to receive(:ask).and_return('wrong-name')
147
+ expect(subject).to receive(:error).with(/did not match/)
150
148
 
151
- expect(subject.confirm).to be_truthy
152
- expect{subject.confirm}.to_not raise_error
149
+ subject.confirm_command('name-to-confirm')
150
+ end
153
151
  end
154
152
 
155
- it 'raises error unless confirmed' do
156
- expect(subject.prompt).to receive(:yes?).and_return(false)
157
- expect(subject).to receive(:error).with(/Aborted/)
153
+ describe '#confirm' do
154
+ it 'returns true if confirmed' do
155
+ allow(subject.prompt).to receive(:yes?).and_return(true)
158
156
 
159
- subject.confirm
157
+ expect(subject.confirm).to be_truthy
158
+ expect{subject.confirm}.to_not raise_error
159
+ end
160
+
161
+ it 'raises error unless confirmed' do
162
+ expect(subject.prompt).to receive(:yes?).and_return(false)
163
+ expect(subject).to receive(:error).with(/Aborted/)
164
+
165
+ subject.confirm
166
+ end
160
167
  end
161
168
  end
162
169
 
@@ -0,0 +1,28 @@
1
+ require_relative "../../../spec_helper"
2
+ require "kontena/cli/master/init_cloud_command"
3
+
4
+ describe Kontena::Cli::Master::InitCloudCommand do
5
+
6
+ include ClientHelpers
7
+ include RequirementsHelper
8
+
9
+ mock_current_master
10
+
11
+ let(:cloud_client) { double(:cc) }
12
+
13
+ before(:each) do
14
+ allow(subject).to receive(:current_account).and_return('foo')
15
+ allow(subject).to receive(:cloud_auth?).and_return(true)
16
+ end
17
+
18
+ describe '#execute' do
19
+ expect_to_require_current_master
20
+ expect_to_require_current_master_token
21
+ end
22
+
23
+ it 'runs the invite self after deploy callback' do
24
+ expect(Kontena).to receive(:run).with('cloud master add --current --force').and_return(true)
25
+ expect_any_instance_of(Kontena::Callbacks::InviteSelfAfterDeploy).to receive(:after).and_return(true)
26
+ subject.run(['--force'])
27
+ end
28
+ end
@@ -25,7 +25,7 @@ describe Kontena::Cli::Services::LinkCommand do
25
25
  it 'aborts if service is already linked' do
26
26
  allow(client).to receive(:get).and_return({
27
27
  'links' => [
28
- {'alias' => 'service-b', 'grid_service_id' => "grid/service-b"}
28
+ {'alias' => 'service-b', 'id' => "grid/null/service-b"}
29
29
  ]
30
30
  })
31
31
  expect {
@@ -35,7 +35,7 @@ describe Kontena::Cli::Services::LinkCommand do
35
35
 
36
36
  it 'sends link to master' do
37
37
  expect(client).to receive(:put).with(
38
- 'services/test-grid/null/service-a', {links: [{name: 'service-b', alias: 'service-b'}]}
38
+ 'services/test-grid/null/service-a', {links: [{name: 'null/service-b', alias: 'service-b'}]}
39
39
  )
40
40
  subject.run(['service-a', 'service-b'])
41
41
  end
@@ -9,7 +9,7 @@ describe Kontena::Cli::Services::UnlinkCommand do
9
9
  before(:each) do
10
10
  allow(client).to receive(:get).and_return({
11
11
  'links' => [
12
- {'alias' => 'service-b', 'grid_service_id' => "grid/service-b"}
12
+ {'alias' => 'service-b', 'id' => "test-grid/null/service-b", 'name' => 'service-b'}
13
13
  ]
14
14
  })
15
15
  end
@@ -335,12 +335,16 @@ describe Kontena::Cli::Stacks::ServiceGenerator do
335
335
  expect(result['deploy_opts']['interval']).to eq(60)
336
336
  end
337
337
 
338
- it 'does not return deploy_opts if no deploy options are defined' do
338
+ it 'returns nil values if no deploy options are defined' do
339
339
  data = {
340
340
  'image' => 'foo/bar:latest'
341
341
  }
342
342
  result = subject.send(:parse_data, data)
343
- expect(result['deploy_opts']).to be_nil
343
+ expect(result['deploy_opts']).to eq({
344
+ 'interval' => nil,
345
+ 'min_health' => nil,
346
+ 'wait_for_port' => nil
347
+ })
344
348
  end
345
349
  end
346
350
 
@@ -381,5 +385,5 @@ describe Kontena::Cli::Stacks::ServiceGenerator do
381
385
  expect(result['secrets']).to be_nil
382
386
  end
383
387
  end
384
- end
388
+ end
385
389
  end
@@ -0,0 +1,27 @@
1
+ require 'opto'
2
+ require 'kontena_cli'
3
+ require 'kontena/cli/stacks/yaml/opto'
4
+
5
+ describe Kontena::Cli::Stacks::YAML::Prompt do
6
+
7
+ describe 'echoing' do
8
+ let(:option_without_echo) { Opto::Option.new(type: 'string', name: 'foo', from: 'prompt', echo: false) }
9
+ let(:option_with_echo) { Opto::Option.new(type: 'string', name: 'foo', from: 'prompt') }
10
+ let(:prompt) { double(:prompt) }
11
+
12
+ before(:each) do
13
+ allow(Kontena).to receive(:prompt).and_return(prompt)
14
+ end
15
+
16
+ it 'turns echo off when variable has "echo: false"' do
17
+ expect(prompt).to receive(:ask).with(/Enter/, hash_including(echo: false))
18
+ option_without_echo.value
19
+ end
20
+
21
+ it 'keeps echo on when variable does not have "echo: false"' do
22
+ expect(prompt).to receive(:ask).with(/Enter/, hash_not_including(echo: false))
23
+ option_with_echo.value
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,54 @@
1
+ require 'opto'
2
+ require 'kontena/cli/stacks/yaml/opto/service_link_resolver'
3
+
4
+ describe Kontena::Cli::Stacks::YAML::Opto::Resolvers::ServiceLink do
5
+ let(:subject) do
6
+ described_class.new({'prompt' => 'foo'})
7
+ end
8
+
9
+ describe '#resolve' do
10
+ it 'returns nil if no matching services' do
11
+ expect(subject).to receive(:get_services).and_return([])
12
+ expect(subject).not_to receive(:prompt)
13
+ expect(subject.resolve).to be_nil
14
+ end
15
+
16
+ it 'prompts user if matching services' do
17
+ prompt = double(:prompt)
18
+ allow(subject).to receive(:prompt).and_return(prompt)
19
+ expect(prompt).to receive(:select).and_return('null/bar')
20
+ expect(subject).to receive(:get_services).and_return([
21
+ {'id' => 'foo/null/bar'}
22
+ ])
23
+ expect(subject.resolve).to eq('null/bar')
24
+ end
25
+ end
26
+
27
+ describe '#default_index' do
28
+ let(:option) do
29
+ ::Opto::Option.new(default: 'foo/bar')
30
+ end
31
+ let(:subject) do
32
+ described_class.new({'prompt' => 'foo'}, option)
33
+ end
34
+
35
+ it 'returns matching index' do
36
+ services = [
37
+ {'id' => 'test/foo/foo'},
38
+ {'id' => 'test/foo/bar'},
39
+ {'id' => 'test/asd/asd'}
40
+ ]
41
+ index = subject.default_index(services)
42
+ expect(index).to eq(2)
43
+ end
44
+
45
+ it 'returns 0 if no matches' do
46
+ services = [
47
+ {'id' => 'test/foo/foo'},
48
+ {'id' => 'test/asd/asd'}
49
+ ]
50
+ index = subject.default_index(services)
51
+ expect(index).to eq(0)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,73 @@
1
+ require 'opto'
2
+ require 'kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver'
3
+
4
+ describe Kontena::Cli::Stacks::YAML::Opto::Resolvers::VaultCertPrompt do
5
+ describe '#resolve' do
6
+ it 'returns nil if no matching secrets' do
7
+ expect(subject).to receive(:get_secrets).and_return([])
8
+ expect(subject).not_to receive(:prompt)
9
+ expect(subject.resolve).to be_nil
10
+ end
11
+
12
+ it 'prompts user if matching secrets' do
13
+ prompt = double(:prompt)
14
+ allow(subject).to receive(:prompt).and_return(prompt)
15
+ expect(prompt).to receive(:multi_select).and_return('ssl-cert')
16
+ expect(subject).to receive(:get_secrets).and_return([{'name' => 'ssl-cert'}])
17
+ subject.resolve
18
+ end
19
+ end
20
+
21
+ describe '#default_indexes' do
22
+ let(:option) do
23
+ Opto::Option.new(default: ['ssl-cert-1', 'ssl-cert-3'])
24
+ end
25
+
26
+ let(:subject) do
27
+ described_class.new('foo', option)
28
+ end
29
+
30
+ it 'returns all default indexes if found' do
31
+ secrets = [
32
+ {'name' => 'ssl-cert-1'},
33
+ {'name' => 'ssl-cert-2'},
34
+ {'name' => 'ssl-cert-3'}
35
+ ]
36
+ indexes = subject.default_indexes(secrets)
37
+ expect(indexes).to eq([1, 3])
38
+ end
39
+
40
+ it 'returns partially found defaults' do
41
+ secrets = [
42
+ {'name' => 'ssl-cert-a'},
43
+ {'name' => 'ssl-cert-b'},
44
+ {'name' => 'ssl-cert-3'}
45
+ ]
46
+ indexes = subject.default_indexes(secrets)
47
+ expect(indexes).to eq([3])
48
+ end
49
+
50
+ it 'returns empty array if no matches' do
51
+ secrets = [
52
+ {'name' => 'ssl-cert-a'}
53
+ ]
54
+ indexes = subject.default_indexes(secrets)
55
+ expect(indexes).to eq([])
56
+ end
57
+
58
+ it 'returns empty array if no secrets' do
59
+ secrets = []
60
+ indexes = subject.default_indexes(secrets)
61
+ expect(indexes).to eq([])
62
+ end
63
+
64
+ it 'returns empty array if no defaults' do
65
+ secrets = [
66
+ {'name' => 'ssl-cert-a'}
67
+ ]
68
+ allow(subject.option).to receive(:default).and_return([])
69
+ indexes = subject.default_indexes(secrets)
70
+ expect(indexes).to eq([])
71
+ end
72
+ end
73
+ end
@@ -1,28 +1,37 @@
1
1
  require_relative '../spec_helper'
2
2
  require 'kontena_cli'
3
+ require 'kontena/light_prompt'
3
4
 
4
5
  describe Kontena do
5
- let(:subject) { described_class }
6
+ context 'prompt' do
7
+ it 'uses light prompt on windows' do
8
+ allow(ENV).to receive(:[]).with('OS').and_return('Windows_NT')
9
+ expect(Kontena.prompt).to be_kind_of(Kontena::LightPrompt)
10
+ end
11
+ end
6
12
 
7
13
  describe '#run' do
8
- let(:whoami) { double(:whoami_command) }
14
+ let(:whoami) { double(:whoami) }
9
15
 
10
16
  before(:each) do
11
- expect(Kontena::MainCommand).to receive(:new).and_call_original
12
17
  expect(Kontena::Cli::WhoamiCommand).to receive(:new).and_return(whoami)
13
18
  expect(whoami).to receive(:run).with(['--bash-completion-path']).and_return(true)
14
19
  end
15
20
 
16
21
  it 'accepts a command line as string' do
17
- subject.run('whoami --bash-completion-path')
22
+
23
+ Kontena.run('whoami --bash-completion-path')
18
24
  end
19
25
 
20
26
  it 'accepts a command line as a list of parameters' do
21
- subject.run('whoami', '--bash-completion-path')
27
+ Kontena.run('whoami', '--bash-completion-path')
22
28
  end
23
29
 
24
30
  it 'accepts a command line as an array' do
25
- subject.run(['whoami', '--bash-completion-path'])
31
+ Kontena.run(['whoami', '--bash-completion-path'])
26
32
  end
27
33
  end
28
34
  end
35
+
36
+
37
+
@@ -0,0 +1,16 @@
1
+ require_relative '../spec_helper'
2
+ require 'kontena/main_command'
3
+
4
+ describe Kontena::MainCommand do
5
+ let(:subject) { described_class.new('kontena') }
6
+
7
+ describe '--version' do
8
+ it 'outputs the version number and exits' do
9
+ expect do
10
+ expect{subject.run(['--version'])}.to output(/kontena-cli #{Kontena::Cli::VERSION}/).to_stdout
11
+ end.to raise_error(SystemExit) do |exc|
12
+ expect(exc.status).to eq 0
13
+ end
14
+ end
15
+ end
16
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kontena-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kontena, Inc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-03 00:00:00.000000000 Z
11
+ date: 2017-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -140,16 +140,16 @@ dependencies:
140
140
  name: opto
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - "~>"
143
+ - - '='
144
144
  - !ruby/object:Gem::Version
145
- version: 1.8.0
145
+ version: 1.8.3
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - "~>"
150
+ - - '='
151
151
  - !ruby/object:Gem::Version
152
- version: 1.8.0
152
+ version: 1.8.3
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: semantic
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -433,6 +433,7 @@ files:
433
433
  - lib/kontena/cli/stacks/yaml/custom_validators/extends_validator.rb
434
434
  - lib/kontena/cli/stacks/yaml/custom_validators/hooks_validator.rb
435
435
  - lib/kontena/cli/stacks/yaml/custom_validators/secrets_validator.rb
436
+ - lib/kontena/cli/stacks/yaml/opto.rb
436
437
  - lib/kontena/cli/stacks/yaml/opto/prompt_resolver.rb
437
438
  - lib/kontena/cli/stacks/yaml/opto/service_instances_resolver.rb
438
439
  - lib/kontena/cli/stacks/yaml/opto/service_link_resolver.rb
@@ -555,6 +556,7 @@ files:
555
556
  - spec/kontena/cli/helpers/log_helper_spec.rb
556
557
  - spec/kontena/cli/main_command_spec.rb
557
558
  - spec/kontena/cli/master/current_command_spec.rb
559
+ - spec/kontena/cli/master/init_cloud_command_spec.rb
558
560
  - spec/kontena/cli/master/login_command_spec.rb
559
561
  - spec/kontena/cli/master/logout_command_spec.rb
560
562
  - spec/kontena/cli/master/use_command_spec.rb
@@ -582,6 +584,9 @@ files:
582
584
  - spec/kontena/cli/stacks/service_generator_v2_spec.rb
583
585
  - spec/kontena/cli/stacks/show_command_spec.rb
584
586
  - spec/kontena/cli/stacks/upgrade_command_spec.rb
587
+ - spec/kontena/cli/stacks/yaml/opto/prompt_resolver_spec.rb
588
+ - spec/kontena/cli/stacks/yaml/opto/service_link_resolver_spec.rb
589
+ - spec/kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver_spec.rb
585
590
  - spec/kontena/cli/stacks/yaml/reader_spec.rb
586
591
  - spec/kontena/cli/stacks/yaml/service_extender_spec.rb
587
592
  - spec/kontena/cli/stacks/yaml/validator_v3_spec.rb
@@ -592,6 +597,7 @@ files:
592
597
  - spec/kontena/client_spec.rb
593
598
  - spec/kontena/config_spec.rb
594
599
  - spec/kontena/kontena_cli_spec.rb
600
+ - spec/kontena/main_command_spec.rb
595
601
  - spec/kontena/plugin_manager_spec.rb
596
602
  - spec/spec_helper.rb
597
603
  - spec/support/client_helpers.rb
@@ -615,9 +621,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
615
621
  version: 2.1.0
616
622
  required_rubygems_version: !ruby/object:Gem::Requirement
617
623
  requirements:
618
- - - ">="
624
+ - - ">"
619
625
  - !ruby/object:Gem::Version
620
- version: '0'
626
+ version: 1.3.1
621
627
  requirements: []
622
628
  rubyforge_project:
623
629
  rubygems_version: 2.6.8
@@ -683,6 +689,7 @@ test_files:
683
689
  - spec/kontena/cli/helpers/log_helper_spec.rb
684
690
  - spec/kontena/cli/main_command_spec.rb
685
691
  - spec/kontena/cli/master/current_command_spec.rb
692
+ - spec/kontena/cli/master/init_cloud_command_spec.rb
686
693
  - spec/kontena/cli/master/login_command_spec.rb
687
694
  - spec/kontena/cli/master/logout_command_spec.rb
688
695
  - spec/kontena/cli/master/use_command_spec.rb
@@ -710,6 +717,9 @@ test_files:
710
717
  - spec/kontena/cli/stacks/service_generator_v2_spec.rb
711
718
  - spec/kontena/cli/stacks/show_command_spec.rb
712
719
  - spec/kontena/cli/stacks/upgrade_command_spec.rb
720
+ - spec/kontena/cli/stacks/yaml/opto/prompt_resolver_spec.rb
721
+ - spec/kontena/cli/stacks/yaml/opto/service_link_resolver_spec.rb
722
+ - spec/kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver_spec.rb
713
723
  - spec/kontena/cli/stacks/yaml/reader_spec.rb
714
724
  - spec/kontena/cli/stacks/yaml/service_extender_spec.rb
715
725
  - spec/kontena/cli/stacks/yaml/validator_v3_spec.rb
@@ -720,6 +730,7 @@ test_files:
720
730
  - spec/kontena/client_spec.rb
721
731
  - spec/kontena/config_spec.rb
722
732
  - spec/kontena/kontena_cli_spec.rb
733
+ - spec/kontena/main_command_spec.rb
723
734
  - spec/kontena/plugin_manager_spec.rb
724
735
  - spec/spec_helper.rb
725
736
  - spec/support/client_helpers.rb