kontena-cli 1.4.0.pre7 → 1.4.0.pre8

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.
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