kontena-cli 1.4.0.pre7 → 1.4.0.pre8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dd17b046ef3c5df923edb5330692544a30c68f31
4
- data.tar.gz: 86ab9db88b8bffe961692ad0c7716aacc450e556
3
+ metadata.gz: e5fbe13d6c43974ce734828c192b42c582b56a04
4
+ data.tar.gz: a2de0cbe2555ea75327028a9f1f6417f839a876f
5
5
  SHA512:
6
- metadata.gz: 9ce3ee493ee6919a392b71e4218bc301849caf3d8a0f25a4aa831c81aaeab1a6e57e3d88927cee4e0c9a50bac10ec195476eb5d6b88cb934234d6fc1c09119e2
7
- data.tar.gz: 1a257b2cb1d8f72f4c9d69dd4ca1b5530fd1ecf51dac56a7e3b787b3d579e574ba85e625e7e0350d9512d34875778aa02961e0b45623efc2b4bbc8b57b7f5556
6
+ metadata.gz: 9ed72921adf1a691ed03ea9ec1223800191136b686d89c0e1ca2af21306755e83cb9844c69db3831da566a1592d700d12c2126a99ae9f620c1817d0bf3ce6441
7
+ data.tar.gz: f1fd2b0a344552704f2e3c1de967daed63e9cf66532791af1040aea5f19262b7b123b2ee1f19d1799525cb02556784192fa9329b2e68a00636cfebc01c31463d
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.0.pre7
1
+ 1.4.0.pre8
@@ -7,6 +7,7 @@ module Kontena::Cli::Services
7
7
  include ServicesHelper
8
8
 
9
9
  parameter "NAME", "Service name"
10
+ option '--[no-]wait', :flag, 'Do not wait for service deployment', default: true
10
11
  option '--force', :flag, 'Force deploy even if service does not have any changes'
11
12
 
12
13
  def execute
@@ -17,7 +18,7 @@ module Kontena::Cli::Services
17
18
  data[:force] = true if force?
18
19
  spinner "Deploying service #{name.colorize(:cyan)} " do
19
20
  deployment = deploy_service(token, name, data)
20
- wait_for_deploy_to_finish(token, deployment)
21
+ wait_for_deploy_to_finish(token, deployment) if wait?
21
22
  end
22
23
  end
23
24
  end
@@ -433,7 +433,8 @@ module Kontena
433
433
 
434
434
  # @param [String] image
435
435
  # @return [String]
436
- def parse_image(image)
436
+ def parse_image(image = nil)
437
+ return if image.nil?
437
438
  unless image.include?(":")
438
439
  image = "#{image}:latest"
439
440
  end
@@ -94,9 +94,17 @@ module Kontena::Cli::Stacks
94
94
  def self.included(where)
95
95
  where.prepend InstanceMethods
96
96
 
97
- where.option '--values-from', '[FILE]', 'Read variable values from YAML' do |filename|
97
+ where.option '--values-from', '[FILE]', 'Read variable values from a YAML file', multivalued: true do |filename|
98
98
  values_from_file.merge!(::YAML.safe_load(File.read(filename)))
99
- true
99
+ filename
100
+ end
101
+
102
+ where.option '--values-from-stack', '[STACK_NAME]', 'Read variable values from an installed stack', multivalued: true do |stackname|
103
+ variables = read_values_from_stacks(stackname)
104
+ Kontena.logger.debug { "Received variables from stack #{stackname} on Master: #{variables.inspect}" }
105
+ warn "Stack #{stackname} does not have any values for variables" if variables.empty?
106
+ values_from_installed_stacks.merge!(variables)
107
+ stackname
100
108
  end
101
109
 
102
110
  where.option '-v', "VARIABLE=VALUE", "Set stack variable values, example: -v domain=example.com. Can be used multiple times.", multivalued: true, attribute_name: :var_option do |var_pair|
@@ -106,6 +114,27 @@ module Kontena::Cli::Stacks
106
114
  end
107
115
 
108
116
  module InstanceMethods
117
+ def read_values_from_stacks(stackname)
118
+ result = {}
119
+ response = client.get("stacks/#{current_grid}/#{stackname}")
120
+ result.merge!(response['variables']) if response['variables']
121
+ if response['children']
122
+ response['children'].each do |child_info|
123
+ result.merge!(
124
+ read_values_from_stacks(child_info['name']).tap do |child_result|
125
+ child_result.keys.each do |key|
126
+ new_key = child_info['name'].dup # foofoo-redis-monitor
127
+ new_key.sub!("#{stackname}-", '') # monitor
128
+ new_key.concat ".#{key}" # monitor.foovariable
129
+ child_result[new_key] = child_result.delete(key)
130
+ end
131
+ end
132
+ )
133
+ end
134
+ end
135
+ result
136
+ end
137
+
109
138
  def values_from_file
110
139
  @values_from_file ||= {}
111
140
  end
@@ -114,8 +143,12 @@ module Kontena::Cli::Stacks
114
143
  @values_from_value_options ||= {}
115
144
  end
116
145
 
146
+ def values_from_installed_stacks
147
+ @values_from_installed_stacks ||= {}
148
+ end
149
+
117
150
  def values_from_options
118
- @values_from_options ||= values_from_file.merge(values_from_value_options)
151
+ @values_from_options ||= values_from_installed_stacks.merge(values_from_file).merge(values_from_value_options)
119
152
  end
120
153
 
121
154
  # Transforms a hash
@@ -10,7 +10,7 @@ module Kontena::Cli::Stacks
10
10
 
11
11
  parameter "NAME", "Stack name"
12
12
 
13
- option '--[no-]wait', :flag, 'Do not wait service deployment', default: true
13
+ option '--[no-]wait', :flag, 'Do not wait for service deployment', default: true
14
14
 
15
15
  requires_current_master
16
16
  requires_current_master_token
@@ -28,6 +28,8 @@ module Kontena::Cli::Stacks
28
28
 
29
29
  install_dependencies unless skip_dependencies?
30
30
 
31
+ stack # runs validations
32
+
31
33
  hint_on_validation_notifications(reader.notifications)
32
34
  abort_on_validation_errors(reader.errors)
33
35
 
@@ -139,9 +139,11 @@ module Kontena::Cli::Stacks
139
139
  else
140
140
  cmd = ['stack', 'install', '--name', stackname]
141
141
  cmd.concat ['--parent-name', stack['parent_name']] if stack['parent_name']
142
+
142
143
  stack['variables'].merge(dependency_values_from_options(stackname)).each do |k, v|
143
144
  cmd.concat ['-v', "#{k}=#{v}"]
144
145
  end
146
+
145
147
  cmd << '--no-deploy'
146
148
  cmd << data[:local][:loader].source
147
149
  caret "Installing new dependency #{cmd.last} as #{stackname}"
@@ -51,6 +51,8 @@ module Kontena::Cli::Stacks
51
51
 
52
52
  validate_dependencies if dependencies?
53
53
 
54
+ stack # runs validations
55
+
54
56
  hint_on_validation_notifications(reader.notifications, dependencies? ? loader.source : nil)
55
57
  abort_on_validation_errors(reader.errors, dependencies? ? loader.source : nil)
56
58
 
@@ -11,7 +11,7 @@ module Kontena::Cli::Stacks::YAML::Validations::CustomValidators
11
11
  end
12
12
 
13
13
  value.keys.each do |hook|
14
- unless %w(pre_build post_start).include?(hook)
14
+ unless %w(pre_build pre_start post_start pre_stop).include?(hook)
15
15
  errors[key] = "invalid hook #{hook}"
16
16
  end
17
17
  end
@@ -20,9 +20,17 @@ module Kontena::Cli::Stacks::YAML::Validations::CustomValidators
20
20
  validate_pre_build_hooks(key, value['pre_build'], errors)
21
21
  end
22
22
 
23
+ if value['pre_start']
24
+ validate_pre_start_hooks(key, value['pre_start'], errors)
25
+ end
26
+
23
27
  if value['post_start']
24
28
  validate_post_start_hooks(key, value['post_start'], errors)
25
29
  end
30
+
31
+ if value['pre_stop']
32
+ validate_pre_stop_hooks(key, value['pre_stop'], errors)
33
+ end
26
34
  end
27
35
 
28
36
  def validate_pre_build_hooks(key, pre_build_hooks, errors)
@@ -40,6 +48,23 @@ module Kontena::Cli::Stacks::YAML::Validations::CustomValidators
40
48
  end
41
49
  end
42
50
 
51
+ def validate_pre_start_hooks(key, pre_start_hooks, errors)
52
+ unless pre_start_hooks.is_a?(Array)
53
+ errors[key] = { 'pre_start' => 'must be an array' }
54
+ return
55
+ end
56
+ pre_start_validation = {
57
+ 'name' => 'string',
58
+ 'instances' => (-> (value) { value.is_a?(Integer) || value == '*' }),
59
+ 'cmd' => 'string',
60
+ 'oneshot' => HashValidator.optional('boolean')
61
+ }
62
+ validator = HashValidator.validator_for(pre_start_validation)
63
+ pre_start_hooks.each do |pre_start|
64
+ validator.validate('hooks.pre_start', pre_start, pre_start_validation, errors)
65
+ end
66
+ end
67
+
43
68
  def validate_post_start_hooks(key, post_start_hooks, errors)
44
69
  unless post_start_hooks.is_a?(Array)
45
70
  errors[key] = { 'post_start' => 'must be an array' }
@@ -56,5 +81,22 @@ module Kontena::Cli::Stacks::YAML::Validations::CustomValidators
56
81
  validator.validate('hooks.post_start', post_start, post_start_validation, errors)
57
82
  end
58
83
  end
84
+
85
+ def validate_pre_stop_hooks(key, pre_stop_hooks, errors)
86
+ unless pre_stop_hooks.is_a?(Array)
87
+ errors[key] = { 'pre_stop' => 'must be an array' }
88
+ return
89
+ end
90
+ pre_stop_validation = {
91
+ 'name' => 'string',
92
+ 'instances' => (-> (value) { value.is_a?(Integer) || value == '*' }),
93
+ 'cmd' => 'string',
94
+ 'oneshot' => HashValidator.optional('boolean')
95
+ }
96
+ validator = HashValidator.validator_for(pre_stop_validation)
97
+ pre_stop_hooks.each do |pre_stop|
98
+ validator.validate('hooks.pre_stop', pre_stop, pre_stop_validation, errors)
99
+ end
100
+ end
59
101
  end
60
102
  end
@@ -201,21 +201,26 @@ module Kontena::Cli::Stacks
201
201
 
202
202
  validate unless skip_validation
203
203
 
204
- {}.tap do |result|
205
- Dir.chdir(from_file? ? File.dirname(File.expand_path(file)) : Dir.pwd) do
206
- result['stack'] = raw_yaml['stack']
207
- result['version'] = loader.stack_name.version || '0.0.1'
208
- result['name'] = name
209
- result['registry'] = loader.registry
210
- result['expose'] = fully_interpolated_yaml['expose']
211
- result['services'] = errors.empty? ? parse_services(service_name) : {}
212
- result['volumes'] = errors.empty? ? parse_volumes : {}
213
- result['dependencies'] = dependencies
214
- result['source'] = raw_content
215
- result['variables'] = variable_values(without_defaults: true, without_vault: true)
216
- result['parent_name'] = parent_name
204
+ result = {}
205
+ Dir.chdir(from_file? ? File.dirname(File.expand_path(file)) : Dir.pwd) do
206
+ result['stack'] = raw_yaml['stack']
207
+ result['version'] = loader.stack_name.version || '0.0.1'
208
+ result['name'] = name
209
+ result['registry'] = loader.registry
210
+ result['expose'] = fully_interpolated_yaml['expose']
211
+ result['services'] = errors.empty? ? parse_services(service_name) : {}
212
+ result['volumes'] = errors.empty? ? parse_volumes : {}
213
+ result['dependencies'] = dependencies
214
+ result['source'] = raw_content
215
+ result['variables'] = variable_values(without_defaults: true, without_vault: true)
216
+ result['parent_name'] = parent_name
217
+ end
218
+ if service_name.nil?
219
+ result['services'].each do |service|
220
+ errors << { 'services' => { service['name'] => { 'image' => "image is missing" } } } if service['image'].to_s.empty?
217
221
  end
218
222
  end
223
+ result
219
224
  end
220
225
 
221
226
  # Returns an array of hashes containing the dependency tree starting from this file
@@ -317,7 +322,6 @@ module Kontena::Cli::Stacks
317
322
  service_config.delete('extends')
318
323
  end
319
324
  if name
320
- exit_with_error("Image is missing for #{name}. Aborting.") unless service_config['image'] # why isn't this a validation?
321
325
  ServiceGeneratorV2.new(service_config).generate.merge('name' => name)
322
326
  else
323
327
  ServiceGeneratorV2.new(service_config).generate
@@ -345,10 +349,10 @@ module Kontena::Cli::Stacks
345
349
  end
346
350
 
347
351
  def from_external_file(filename, service_name)
348
- external_reader = Reader.new(filename)
352
+ external_reader = FileLoader.new(filename, loader).reader
349
353
  outcome = external_reader.execute(service_name)
350
- errors.concat external_reader.errors unless errors.any? { |item| item.key?(filename) }
351
- notifications.concat external_reader.notifications unless notifications.any? { |item| item.key?(filename) }
354
+ errors.concat external_reader.errors unless external_reader.errors.empty? || errors.include?(external_reader.errors)
355
+ notifications.concat external_reader.notifications unless external_reader.notifications.empty? || notifications.include?(external_reader.notifications)
352
356
  outcome['services']
353
357
  end
354
358
 
@@ -445,13 +449,12 @@ module Kontena::Cli::Stacks
445
449
  end
446
450
 
447
451
  def store_failures(data)
448
- data['errors'] = data[:errors] unless data['errors']
449
- data['notifications'] = data[:notifications] unless data['notifications']
450
- errors << { file => data['errors'] || data[:errors] } unless data['errors'].empty?
451
- notifications << { file => data['notifications'] } unless data['notifications'].empty?
452
+ data['errors'] ||= data[:errors] || []
453
+ data['notifications'] ||= data[:notifications] || []
454
+ errors << { File.basename(file) => data['errors'] } unless data['errors'].empty?
455
+ notifications << { File.basename(file) => data['notifications'] } unless data['notifications'].empty?
452
456
  end
453
457
 
454
-
455
458
  # @param [Hash] options - service config
456
459
  def normalize_env_vars(options)
457
460
  if options['environment'].kind_of?(Hash)
@@ -21,7 +21,7 @@ module Kontena::Cli::Stacks
21
21
 
22
22
  def initialize(*args)
23
23
  super
24
- @source = self.class.with_context(@source, parent)
24
+ @source = self.class.with_context(@source, @parent)
25
25
  end
26
26
 
27
27
  def read_content
@@ -3,6 +3,10 @@ require "kontena/cli/stacks/yaml/reader"
3
3
 
4
4
  describe Kontena::Cli::Stacks::Common do
5
5
  include FixturesHelpers
6
+ include RequirementsHelper
7
+ include ClientHelpers
8
+
9
+ mock_current_master
6
10
 
7
11
  let(:klass) do
8
12
  Class.new(Kontena::Command) do
@@ -12,10 +16,6 @@ describe Kontena::Cli::Stacks::Common do
12
16
  include Kontena::Cli::Stacks::Common::StackNameOption
13
17
  include Kontena::Cli::Stacks::Common::StackValuesToOption
14
18
  include Kontena::Cli::Stacks::Common::StackValuesFromOption
15
-
16
- def what
17
- [source]
18
- end
19
19
  end
20
20
  end
21
21
 
@@ -57,7 +57,7 @@ describe Kontena::Cli::Stacks::Common do
57
57
  expect(subject.instance(['-v', 'foo=bar', '-v', 'bar=baz', fixture_path('kontena_v3.yml')]).values_from_options).to match hash_including('foo' => 'bar', 'bar' => 'baz')
58
58
  end
59
59
 
60
- context '--values-from' do
60
+ describe '--values-from' do
61
61
  before do
62
62
  allow(File).to receive(:exist?).with('vars.yml').and_return(true)
63
63
  expect(File).to receive(:read).with('vars.yml').and_return(::YAML.dump('baz' => 'bag', 'bar' => 'boo'))
@@ -71,5 +71,29 @@ describe Kontena::Cli::Stacks::Common do
71
71
  expect(subject.instance(['-v', 'foo=bar', '-v', 'bar=baz', '--values-from', 'vars.yml', fixture_path('kontena_v3.yml')]).values_from_options).to match hash_including('foo' => 'bar', 'bar' => 'baz', 'baz' => 'bag')
72
72
  end
73
73
  end
74
+
75
+ describe '--values-from-stack' do
76
+ let(:instance) { subject.instance(['--values-from-stack', 'redisproxy', fixture_path('kontena_v3.yml')]) }
77
+
78
+ it 'reads all dependent stack variables' do
79
+ expect(client).to receive(:get).with('stacks/test-grid/redisproxy').and_return(
80
+ 'variables' => { 'foo' => 'bar' },
81
+ 'children' => [ { 'name' => 'redisproxy-redis1' } ]
82
+ )
83
+
84
+ expect(client).to receive(:get).with('stacks/test-grid/redisproxy-redis1').and_return(
85
+ 'variables' => { 'redisvar' => 'test' },
86
+ 'children' => [ { 'name' => 'redisproxy-redis1-monitor' } ]
87
+ )
88
+
89
+ expect(client).to receive(:get).with('stacks/test-grid/redisproxy-redis1-monitor').and_return(
90
+ 'variables' => { 'monitorvar' => 'test2' },
91
+ 'children' => []
92
+ )
93
+
94
+ expect(instance.values_from_options).to match hash_including('foo' => 'bar', 'redis1.redisvar' => 'test', 'redis1.monitor.monitorvar' => 'test2')
95
+ end
96
+
97
+ end
74
98
  end
75
99
  end
@@ -65,7 +65,7 @@ describe Kontena::Cli::Stacks::InstallCommand do
65
65
  context '--[no-]deploy' do
66
66
  it 'runs deploy for the stack after install by default' do
67
67
  expect(client).to receive(:post).with(
68
- 'grids/test-grid/stacks', hash_including(stack_expectation)
68
+ 'grids/test-grid/stacks', hash_including(stack_expectation)
69
69
  )
70
70
  expect(Kontena).to receive(:run!).with(['stack', 'deploy', 'stackname']).and_return(true)
71
71
  subject.run([fixture_path('kontena_v3.yml')])
@@ -82,4 +82,102 @@ describe Kontena::Cli::Stacks::InstallCommand do
82
82
  end
83
83
  end
84
84
  end
85
+
86
+ context 'variable value input' do
87
+ let(:expectation) do
88
+ {
89
+ 'services' => array_including(
90
+ hash_including(
91
+ 'name' => 'mysql',
92
+ 'image' => 'mysqlimage:latest',
93
+ 'env' => array_including(
94
+ 'TEST_VAR=abc'
95
+ )
96
+ ),
97
+ hash_including(
98
+ 'name' => 'wordpress',
99
+ 'image' => 'wordpress:def'
100
+ )
101
+ )
102
+ }
103
+ end
104
+
105
+ describe '--values-from' do
106
+ it 'sends stack to master, loading values from a file' do
107
+ allow(File).to receive(:exist?).with('values.yml').and_return(true)
108
+ expect(File).to receive(:read).with('values.yml').and_return(
109
+ YAML.dump('TEST_ENV_VAR' => 'abc', 'MYSQL_IMAGE' => 'mysqlimage', 'tag' => 'def')
110
+ )
111
+ expect(client).to receive(:post) do |path, data|
112
+ expect(path).to eq 'grids/test-grid/stacks'
113
+ expect(data).to match hash_including(expectation)
114
+ end.and_return({})
115
+ subject.run(['--no-deploy', '--values-from', 'values.yml', fixture_path('stack-with-variables.yml')])
116
+ end
117
+ end
118
+
119
+ describe '--values-from-stack' do
120
+ it 'sends stack to master, loading values from another stack on master' do
121
+ expect(client).to receive(:get).with('stacks/test-grid/otherdep').and_return(
122
+ 'variables' => { 'foo' => 'bar' },
123
+ 'children' => [
124
+ { 'name' => 'otherdep-dep_1' } ,
125
+ { 'name' => 'otherdep-dep_2' }
126
+ ]
127
+ )
128
+
129
+ expect(client).to receive(:get).with('stacks/test-grid/otherdep-dep_1').and_return(
130
+ 'variables' => { 'dep1var' => 'test' },
131
+ 'children' => [
132
+ { 'name' => 'otherdep-dep_1-dep_1' }
133
+ ]
134
+ )
135
+
136
+ expect(client).to receive(:get).with('stacks/test-grid/otherdep-dep_1-dep_1').and_return(
137
+ 'variables' => { 'dep1dep1var' => 'test11' },
138
+ 'children' => []
139
+ )
140
+
141
+ expect(client).to receive(:get).with('stacks/test-grid/otherdep-dep_2').and_return(
142
+ 'variables' => { 'dep2var' => 'test2' },
143
+ 'children' => [ ]
144
+ )
145
+
146
+ expect(Kontena).to receive(:run!).with(["stack", "install", "-n", "deptest-dep_1", "--parent-name", "deptest", '-v', 'dep1var=test', '-v', 'dep_1.dep1dep1var=test11', '--no-deploy', fixture_path('stack-with-dependencies-dep-1.yml')]).and_return(true)
147
+ expect(Kontena).to receive(:run!).with(["stack", "install", "-n", "deptest-dep_2", "--parent-name", "deptest", '-v', 'dep_var=1', '-v', 'dep2var=test2', '--no-deploy', fixture_path('stack-with-dependencies-dep-2.yml')]).and_return(true)
148
+
149
+ allow(client).to receive(:post).and_return({})
150
+
151
+ subject.run(['--values-from-stack', 'otherdep', '-n', 'deptest', '--no-deploy', fixture_path('stack-with-dependencies.yml')])
152
+ end
153
+ end
154
+
155
+ describe '-v' do
156
+ it 'sends stack to master, loading values from command line' do
157
+ expect(client).to receive(:post) do |path, data|
158
+ expect(path).to eq 'grids/test-grid/stacks'
159
+ expect(data).to match hash_including(expectation)
160
+ end.and_return({})
161
+ YAML.dump('TEST_ENV_VAR' => 'abc', 'MYSQL_IMAGE' => 'mysqlimage', 'tag' => 'def')
162
+ subject.run(['--no-deploy', '-v', 'TEST_ENV_VAR=abc', '-v', 'MYSQL_IMAGE=mysqlimage', '-v', 'tag=def', fixture_path('stack-with-variables.yml')])
163
+ end
164
+ end
165
+
166
+ describe 'combination of value inputs' do
167
+ it 'can combine multiple inputs' do
168
+ allow(File).to receive(:exist?).with('values.yml').and_return(true)
169
+ expect(File).to receive(:read).with('values.yml').and_return(
170
+ YAML.dump('TEST_ENV_VAR' => 'abc')
171
+ )
172
+ allow(client).to receive(:get).with('stacks/test-grid/foostack').and_return(
173
+ 'variables' => { 'MYSQL_IMAGE' => 'mysqlimage' }
174
+ )
175
+ expect(client).to receive(:post) do |path, data|
176
+ expect(path).to eq 'grids/test-grid/stacks'
177
+ expect(data).to match hash_including(expectation)
178
+ end.and_return({})
179
+ subject.run(['--no-deploy', '--values-from-stack', 'foostack', '--values-from', 'values.yml', '-v', 'tag=def', fixture_path('stack-with-variables.yml')])
180
+ end
181
+ end
182
+ end
85
183
  end
@@ -120,17 +120,15 @@ describe Kontena::Cli::Stacks::YAML::Reader do
120
120
  it 'merges validation errors' do
121
121
  expect(File).to receive(:read).with(fixture_path('docker-compose_v2.yml')).and_return(fixture('docker-compose-invalid.yml'))
122
122
  outcome = subject.execute
123
- expect(outcome['errors']).to eq([{
124
- 'docker-compose_v2.yml' =>[
125
- {
126
- 'services' => {
127
- 'wordpress' => {
128
- 'networks' => 'key not expected'
129
- }
130
- }
131
- }
132
- ]
133
- }])
123
+ expect(subject.errors).to match array_including(
124
+ hash_including(
125
+ 'docker-compose_v2.yml' => array_including(
126
+ hash_including(
127
+ 'services' => { 'wordpress' => { 'networks' => 'key not expected' } }
128
+ )
129
+ )
130
+ )
131
+ )
134
132
  end
135
133
  end
136
134
 
@@ -324,7 +322,12 @@ describe Kontena::Cli::Stacks::YAML::Reader do
324
322
 
325
323
  it 'expands build option to absolute path' do
326
324
  outcome = subject.execute
327
- expect(outcome['services']['webapp']['build']['context']).to eq(fixture_path(''))
325
+ expect(outcome['services']).to match array_including(
326
+ hash_including(
327
+ 'name' => 'webapp',
328
+ 'build' => hash_including('context' => fixture_path(''))
329
+ )
330
+ )
328
331
  end
329
332
  end
330
333
 
@@ -335,7 +338,12 @@ describe Kontena::Cli::Stacks::YAML::Reader do
335
338
 
336
339
  it 'expands build context to absolute path' do
337
340
  outcome = subject.execute
338
- expect(outcome['services']['webapp']['build']['context']).to eq(fixture_path(''))
341
+ expect(outcome['services']).to match array_including(
342
+ hash_including(
343
+ 'name' => 'webapp',
344
+ 'build' => hash_including('context' => fixture_path(''))
345
+ )
346
+ )
339
347
  end
340
348
  end
341
349
 
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.4.0.pre7
4
+ version: 1.4.0.pre8
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-09-19 00:00:00.000000000 Z
11
+ date: 2017-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler