kontena-cli 0.16.3 → 0.17.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +1 -0
  3. data/.gitignore +3 -1
  4. data/VERSION +1 -1
  5. data/lib/kontena/callbacks/master/deploy/40_install_ssl_certificate_after_deploy.rb +32 -0
  6. data/lib/kontena/cli/apps/deploy_command.rb +2 -2
  7. data/lib/kontena/cli/apps/scale_command.rb +2 -2
  8. data/lib/kontena/cli/apps/show_command.rb +3 -2
  9. data/lib/kontena/cli/apps/yaml/validations.rb +10 -6
  10. data/lib/kontena/cli/apps/yaml/validator.rb +1 -0
  11. data/lib/kontena/cli/apps/yaml/validator_v2.rb +1 -0
  12. data/lib/kontena/cli/cloud/login_command.rb +66 -64
  13. data/lib/kontena/cli/common.rb +0 -10
  14. data/lib/kontena/cli/grids/logs_command.rb +0 -1
  15. data/lib/kontena/cli/localhost_web_server.rb +11 -3
  16. data/lib/kontena/cli/master/login_command.rb +213 -163
  17. data/lib/kontena/cli/nodes/label_command.rb +2 -0
  18. data/lib/kontena/cli/nodes/labels/add_command.rb +7 -8
  19. data/lib/kontena/cli/nodes/labels/list_command.rb +17 -0
  20. data/lib/kontena/cli/nodes/labels/remove_command.rb +7 -12
  21. data/lib/kontena/cli/nodes/show_command.rb +1 -0
  22. data/lib/kontena/cli/plugins/common.rb +8 -0
  23. data/lib/kontena/cli/plugins/install_command.rb +21 -2
  24. data/lib/kontena/cli/plugins/list_command.rb +4 -2
  25. data/lib/kontena/cli/plugins/search_command.rb +4 -2
  26. data/lib/kontena/cli/registry/create_command.rb +19 -12
  27. data/lib/kontena/cli/registry/remove_command.rb +4 -4
  28. data/lib/kontena/cli/registry_command.rb +0 -1
  29. data/lib/kontena/cli/services/create_command.rb +6 -6
  30. data/lib/kontena/cli/services/deploy_command.rb +8 -4
  31. data/lib/kontena/cli/services/list_command.rb +34 -21
  32. data/lib/kontena/cli/services/logs_command.rb +1 -1
  33. data/lib/kontena/cli/services/scale_command.rb +3 -3
  34. data/lib/kontena/cli/services/services_helper.rb +18 -14
  35. data/lib/kontena/cli/services/show_command.rb +1 -0
  36. data/lib/kontena/cli/services/update_command.rb +6 -6
  37. data/lib/kontena/cli/stack_command.rb +12 -6
  38. data/lib/kontena/cli/stacks/build_command.rb +110 -0
  39. data/lib/kontena/cli/stacks/common.rb +85 -20
  40. data/lib/kontena/cli/stacks/deploy_command.rb +30 -7
  41. data/lib/kontena/cli/stacks/install_command.rb +30 -0
  42. data/lib/kontena/cli/stacks/list_command.rb +74 -14
  43. data/lib/kontena/cli/stacks/logs_command.rb +31 -0
  44. data/lib/kontena/cli/stacks/monitor_command.rb +91 -0
  45. data/lib/kontena/cli/stacks/remove_command.rb +24 -7
  46. data/lib/kontena/cli/stacks/service_generator.rb +115 -0
  47. data/lib/kontena/cli/stacks/service_generator_v2.rb +27 -0
  48. data/lib/kontena/cli/stacks/show_command.rb +65 -13
  49. data/lib/kontena/cli/stacks/upgrade_command.rb +28 -0
  50. data/lib/kontena/cli/stacks/yaml/custom_validators/affinities_validator.rb +19 -0
  51. data/lib/kontena/cli/stacks/yaml/custom_validators/build_validator.rb +22 -0
  52. data/lib/kontena/cli/stacks/yaml/custom_validators/extends_validator.rb +21 -0
  53. data/lib/kontena/cli/stacks/yaml/custom_validators/hooks_validator.rb +54 -0
  54. data/lib/kontena/cli/stacks/yaml/custom_validators/secrets_validator.rb +22 -0
  55. data/lib/kontena/cli/stacks/yaml/reader.rb +219 -0
  56. data/lib/kontena/cli/stacks/yaml/service_extender.rb +78 -0
  57. data/lib/kontena/cli/stacks/yaml/validations.rb +71 -0
  58. data/lib/kontena/cli/stacks/yaml/validator_v3.rb +52 -0
  59. data/lib/kontena/cli/version_command.rb +5 -1
  60. data/lib/kontena/cli/vpn/create_command.rb +20 -17
  61. data/lib/kontena/cli/vpn/remove_command.rb +4 -3
  62. data/lib/kontena/client.rb +21 -20
  63. data/lib/kontena/machine/cert_helper.rb +4 -0
  64. data/lib/kontena/machine/cloud_config/cloudinit.yml +1 -1
  65. data/lib/kontena/main_command.rb +1 -1
  66. data/spec/fixtures/kontena-build.yml +2 -2
  67. data/spec/fixtures/kontena-invalid.yml +1 -1
  68. data/spec/fixtures/kontena-not-hash-service-config.yml +1 -1
  69. data/spec/fixtures/kontena-with-env-file.yml +2 -2
  70. data/spec/fixtures/kontena_build_v3.yml +23 -0
  71. data/spec/fixtures/kontena_v3.yml +20 -0
  72. data/spec/fixtures/stack-internal-extend.yml +11 -0
  73. data/spec/fixtures/stack-with-env-file.yml +21 -0
  74. data/spec/fixtures/stack-with-variables.yml +22 -0
  75. data/spec/kontena/cli/app/scale_spec.rb +3 -1
  76. data/spec/kontena/cli/cloud/login_command_spec.rb +283 -0
  77. data/spec/kontena/cli/master/login_command_spec.rb +324 -145
  78. data/spec/kontena/cli/services/link_command_spec.rb +1 -1
  79. data/spec/kontena/cli/services/secrets/link_command_spec.rb +4 -4
  80. data/spec/kontena/cli/services/secrets/unlink_command_spec.rb +2 -2
  81. data/spec/kontena/cli/services/services_helper_spec.rb +15 -11
  82. data/spec/kontena/cli/services/unlink_command_spec.rb +1 -1
  83. data/spec/kontena/cli/stacks/deploy_command_spec.rb +26 -0
  84. data/spec/kontena/cli/stacks/install_command_spec.rb +54 -0
  85. data/spec/kontena/cli/stacks/list_command_spec.rb +27 -0
  86. data/spec/kontena/cli/stacks/remove_command_spec.rb +45 -0
  87. data/spec/kontena/cli/stacks/service_generator_spec.rb +385 -0
  88. data/spec/kontena/cli/stacks/service_generator_v2_spec.rb +74 -0
  89. data/spec/kontena/cli/stacks/show_command_spec.rb +26 -0
  90. data/spec/kontena/cli/stacks/upgrade_command_spec.rb +50 -0
  91. data/spec/kontena/cli/stacks/yaml/reader_spec.rb +370 -0
  92. data/spec/kontena/cli/stacks/yaml/service_extender_spec.rb +128 -0
  93. data/spec/kontena/cli/stacks/yaml/validator_v3_spec.rb +302 -0
  94. data/spec/spec_helper.rb +6 -4
  95. data/spec/support/client_helpers.rb +1 -0
  96. metadata +57 -7
  97. data/lib/kontena/cli/registry/delete_command.rb +0 -18
  98. data/lib/kontena/cli/stacks/create_command.rb +0 -27
  99. data/lib/kontena/cli/stacks/update_command.rb +0 -27
@@ -0,0 +1,74 @@
1
+ require_relative "../../../spec_helper"
2
+ require "kontena/cli/stacks/service_generator_v2"
3
+ require 'ruby_dig'
4
+
5
+ describe Kontena::Cli::Stacks::ServiceGeneratorV2 do
6
+ let(:subject) do
7
+ described_class.new({})
8
+ end
9
+
10
+ describe '#parse_data' do
11
+ it 'parses network_mode' do
12
+ data = {
13
+ 'image' => 'wordpress:latest',
14
+ 'network_mode' => 'bridge'
15
+ }
16
+ result = subject.send(:parse_data, data)
17
+ expect(result['net']).to eq('bridge')
18
+ end
19
+
20
+ it 'parses logging' do
21
+ data = {
22
+ 'image' => 'wordpress:latest',
23
+ 'logging' => {
24
+ 'driver' => 'influxdb',
25
+ 'options' => {
26
+ 'syslog-address' => 'tcp://192.168.0.42:123'
27
+ }
28
+ }
29
+ }
30
+ result = subject.send(:parse_data, data)
31
+ expect(result['log_driver']).to eq('influxdb')
32
+ expect(result['log_opts']).to eq({
33
+ 'syslog-address' => 'tcp://192.168.0.42:123'
34
+ })
35
+ end
36
+
37
+ it 'adds depends_on to links' do
38
+ data = {
39
+ 'image' => 'wordpress:latest',
40
+ 'depends_on' => ['mysql']
41
+ }
42
+ result = subject.send(:parse_data, data)
43
+ expect(result['links']).to eq([{
44
+ 'name' => 'mysql',
45
+ 'alias' => 'mysql'
46
+ }])
47
+ end
48
+ end
49
+
50
+ describe '#parse_build_options' do
51
+ context 'when build option is a string' do
52
+ it 'converts build option to hash' do
53
+ data = {
54
+ 'build' => '.',
55
+ 'image' => 'myapp'
56
+ }
57
+ result = subject.send(:parse_build_options, data)
58
+ expect(result).to eq({ 'context' => '.' })
59
+ end
60
+ end
61
+ context 'when build options is a hash' do
62
+ it 'uses it as build options' do
63
+ data = {
64
+ 'build' => {
65
+ 'context' => '.',
66
+ 'dockerfile' => 'alternate-dockerfile'
67
+ }
68
+ }
69
+ result = subject.send(:parse_build_options, data)
70
+ expect(result).to eq(data['build'])
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,26 @@
1
+ require_relative "../../../spec_helper"
2
+ require "kontena/cli/stacks/show_command"
3
+
4
+ describe Kontena::Cli::Stacks::ShowCommand do
5
+
6
+ include ClientHelpers
7
+
8
+ describe '#execute' do
9
+ it 'requires api url' do
10
+ allow(subject).to receive(:forced?).and_return(true)
11
+ expect(subject).to receive(:require_api_url).once
12
+ subject.run(['test-stack'])
13
+ end
14
+
15
+ it 'requires token' do
16
+ allow(subject).to receive(:forced?).and_return(true)
17
+ expect(subject).to receive(:require_token).and_return(token)
18
+ subject.run(['test-stack'])
19
+ end
20
+
21
+ it 'fetches stack info from master' do
22
+ expect(client).to receive(:get).with('stacks/test-grid/test-stack')
23
+ subject.run(['test-stack'])
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,50 @@
1
+ require_relative "../../../spec_helper"
2
+ require "kontena/cli/stacks/upgrade_command"
3
+
4
+ describe Kontena::Cli::Stacks::UpgradeCommand do
5
+
6
+ include ClientHelpers
7
+
8
+ describe '#execute' do
9
+
10
+ let(:stack) do
11
+ {
12
+ 'name' => 'stack-a',
13
+ 'services' => []
14
+ }
15
+ end
16
+
17
+ it 'requires api url' do
18
+ allow(subject).to receive(:stack_from_yaml).with('kontena.yml').and_return(stack)
19
+ expect(subject).to receive(:require_api_url).once
20
+ subject.run(['stack-name', './path/to/kontena.yml'])
21
+ end
22
+
23
+ it 'requires token' do
24
+ allow(subject).to receive(:stack_from_yaml).with('kontena.yml').and_return(stack)
25
+ expect(subject).to receive(:require_token).and_return(token)
26
+ subject.run(['stack-name', './path/to/kontena.yml'])
27
+ end
28
+
29
+ it 'sends stack to master' do
30
+
31
+ allow(subject).to receive(:require_config_file).with('./path/to/kontena.yml').and_return(true)
32
+ allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml').and_return(stack)
33
+ expect(client).to receive(:put).with(
34
+ 'stacks/test-grid/stack-a', anything
35
+ )
36
+ subject.run(['stack-a', './path/to/kontena.yml'])
37
+ end
38
+
39
+ it 'allows to override stack name' do
40
+ allow(subject).to receive(:require_config_file).with('./path/to/kontena.yml').and_return(true)
41
+ allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml').and_return(stack)
42
+ stack_b = stack
43
+ stack_b[:name] = 'stack-b'
44
+ expect(client).to receive(:put).with(
45
+ 'stacks/test-grid/stack-b', anything
46
+ )
47
+ subject.run(['stack-b', './path/to/kontena.yml'])
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,370 @@
1
+ require_relative '../../../../spec_helper'
2
+ require 'kontena/cli/stacks/yaml/reader'
3
+
4
+ describe Kontena::Cli::Stacks::YAML::Reader do
5
+ include FixturesHelpers
6
+
7
+ def absolute_yaml_path(file = 'kontena_v3.yml')
8
+ "#{Dir.pwd}/#{file}"
9
+ end
10
+
11
+ let(:subject) do
12
+ described_class.new('kontena_v3.yml')
13
+ end
14
+
15
+ let(:service_extender) do
16
+ spy
17
+ end
18
+
19
+ let(:env_file) do
20
+ ['APIKEY=12345
21
+ ', 'MYSQL_ROOT_PASSWORD=secret
22
+ ', 'WP_ADMIN_PASSWORD=verysecret']
23
+ end
24
+
25
+ let(:valid_v3_result) do
26
+ {
27
+ 'stack' => 'user/stackname',
28
+ 'version' => '2',
29
+ 'services' => {
30
+ 'wordpress' => {
31
+ 'image' => 'wordpress:4.1',
32
+ 'extends' => {"file"=>"docker-compose_v2.yml", "service"=>"wordpress"},
33
+ 'ports' => ['80:80'],
34
+ 'depends_on' => ['mysql'],
35
+ 'stateful' => true,
36
+ 'environment' => ['WORDPRESS_DB_PASSWORD=test_secret'],
37
+ 'instances' => 2,
38
+ 'deploy' => { 'strategy' => 'ha' },
39
+ 'secrets' => []
40
+ },
41
+ 'mysql' => {
42
+ 'image' => 'mysql:5.6',
43
+ 'extends' => {"file"=>"docker-compose_v2.yml", "service"=>"mysql"},
44
+ 'stateful' => true,
45
+ 'environment' => ['MYSQL_ROOT_PASSWORD=test_secret'],
46
+ 'secrets' => []
47
+ }
48
+ }
49
+ }
50
+ end
51
+
52
+ before(:each) do
53
+ allow(File).to receive(:read)
54
+ .with(absolute_yaml_path('docker-compose_v2.yml'))
55
+ .and_return(fixture('docker-compose_v2.yml'))
56
+ allow(File).to receive(:read)
57
+ .with(absolute_yaml_path('kontena_v3.yml'))
58
+ .and_return(fixture('kontena_v3.yml'))
59
+ end
60
+
61
+ describe '#initialize' do
62
+ it 'reads given file' do
63
+ expect(File).to receive(:read)
64
+ .with(absolute_yaml_path)
65
+ .and_return(fixture('kontena_v3.yml'))
66
+ subject
67
+ end
68
+
69
+ context 'variable interpolation' do
70
+ before(:each) do
71
+ allow(ENV).to receive(:key?).and_return(true)
72
+ allow(ENV).to receive(:[]).with('TAG').and_return('4.1')
73
+ allow(ENV).to receive(:[]).with('STACK').and_return('test')
74
+ allow(ENV).to receive(:[]).with('grid').and_return('test-grid')
75
+ allow(ENV).to receive(:[]).with('MYSQL_IMAGE').and_return('mariadb:latest')
76
+ end
77
+
78
+ it 'interpolates $VAR variables' do
79
+ allow(File).to receive(:read)
80
+ .with(absolute_yaml_path)
81
+ .and_return(fixture('stack-with-variables.yml'))
82
+ services = subject.yaml['services']
83
+ expect(services['wordpress']['image']).to eq('wordpress:4.1')
84
+ end
85
+
86
+ it 'interpolates ${VAR} variables' do
87
+ allow(File).to receive(:read)
88
+ .with(absolute_yaml_path)
89
+ .and_return(fixture('stack-with-variables.yml'))
90
+ services = subject.yaml['services']
91
+ expect(services['mysql']['image']).to eq('mariadb:latest')
92
+ end
93
+
94
+ it 'warns about empty variables' do
95
+ allow(File).to receive(:read)
96
+ .with(absolute_yaml_path)
97
+ .and_return(fixture('stack-with-variables.yml'))
98
+ allow(ENV).to receive(:key?)
99
+ .with('MYSQL_IMAGE')
100
+ .and_return(false)
101
+
102
+ expect {
103
+ subject
104
+ }.to output('The MYSQL_IMAGE is not set. Substituting an empty string.
105
+ ').to_stdout
106
+ end
107
+ end
108
+
109
+ it 'replaces $$VAR variables to $VAR format' do
110
+ allow(ENV).to receive(:key?).and_return(true)
111
+ allow(ENV).to receive(:[]).with('TAG').and_return('4.1')
112
+ allow(ENV).to receive(:[]).with('MYSQL_IMAGE').and_return('mariadb:latest')
113
+ allow(ENV).to receive(:[]).with('STACK').and_return('test')
114
+ allow(ENV).to receive(:[]).with('grid').and_return('test-grid')
115
+ allow(File).to receive(:read)
116
+ .with(absolute_yaml_path)
117
+ .and_return(fixture('stack-with-variables.yml'))
118
+ allow(File).to receive(:read)
119
+ .with(absolute_yaml_path('docker-compose_v2.yml'))
120
+ .and_return(fixture('docker-compose_v2.yml'))
121
+ services = subject.execute[:services]
122
+ expect(services['mysql']['environment'].first).to eq('INTERNAL_VAR=$INTERNAL_VAR')
123
+ end
124
+ end
125
+
126
+ context 'when yaml file is malformed' do
127
+ it 'exits the execution' do
128
+ allow(File).to receive(:read)
129
+ .with(absolute_yaml_path)
130
+ .and_return(fixture('kontena-malformed-yaml.yml'))
131
+ expect {
132
+ subject.execute
133
+ }.to raise_error(StandardError)
134
+ end
135
+ end
136
+
137
+ context 'when service config is not hash' do
138
+ it 'returns error' do
139
+ allow(File).to receive(:read)
140
+ .with(absolute_yaml_path)
141
+ .and_return(fixture('kontena-not-hash-service-config.yml'))
142
+
143
+ outcome = subject.execute
144
+ expect(outcome[:errors].size).to eq(1)
145
+ end
146
+ end
147
+
148
+ describe '#execute' do
149
+ before(:each) do
150
+ allow(ENV).to receive(:[]).with('STACK').and_return('test')
151
+ allow(ENV).to receive(:[]).with('grid').and_return('test-grid')
152
+ end
153
+
154
+ context 'when extending services' do
155
+ it 'extends services from external file' do
156
+ docker_compose_yml = YAML.load(fixture('docker-compose_v2.yml'))
157
+ wordpress_options = {
158
+ 'extends' => {
159
+ 'file' => 'docker-compose_v2.yml',
160
+ 'service' => 'wordpress'
161
+ },
162
+ 'stateful' => true,
163
+ 'environment' => ['WORDPRESS_DB_PASSWORD=test_secret'],
164
+ 'instances' => 2,
165
+ 'deploy' => { 'strategy' => 'ha' }
166
+ }
167
+ mysql_options = {
168
+ 'extends' => {
169
+ 'file' => 'docker-compose_v2.yml',
170
+ 'service' => 'mysql'
171
+ },
172
+ 'stateful' => true,
173
+ 'environment' => ['MYSQL_ROOT_PASSWORD=test_secret']
174
+ }
175
+ expect(Kontena::Cli::Stacks::YAML::ServiceExtender).to receive(:new)
176
+ .with(wordpress_options)
177
+ .once
178
+ .and_return(service_extender)
179
+ expect(Kontena::Cli::Stacks::YAML::ServiceExtender).to receive(:new)
180
+ .with(mysql_options)
181
+ .once
182
+ .and_return(service_extender)
183
+ expect(service_extender).to receive(:extend_from).with(docker_compose_yml['services']['wordpress'])
184
+ expect(service_extender).to receive(:extend_from).with(docker_compose_yml['services']['mysql'])
185
+
186
+ subject.execute
187
+ end
188
+
189
+ it 'extends services from the same file' do
190
+ allow(File).to receive(:read)
191
+ .with(absolute_yaml_path('kontena_v3.yml'))
192
+ .and_return(fixture('stack-internal-extend.yml'))
193
+ kontena_yml = YAML.load(fixture('stack-internal-extend.yml'))
194
+
195
+ expect(Kontena::Cli::Stacks::YAML::ServiceExtender).to receive(:new)
196
+ .with(kontena_yml['services']['app'])
197
+ .once
198
+ .and_return(service_extender)
199
+ expect(service_extender).to receive(:extend_from).with(kontena_yml['services']['base'])
200
+ subject.execute
201
+ end
202
+ end
203
+
204
+ context 'environment variables' do
205
+ it 'converts env hash to array' do
206
+ result = subject.execute[:services]
207
+ expect(result['wordpress']['environment']).to eq(['WORDPRESS_DB_PASSWORD=test_secret'])
208
+ end
209
+
210
+ it 'does nothing to env array' do
211
+ result = subject.execute[:services]
212
+ expect(result['mysql']['environment']).to eq(['MYSQL_ROOT_PASSWORD=test_secret'])
213
+ end
214
+
215
+ context 'when introduced env_file' do
216
+ before(:each) do
217
+ allow(File).to receive(:read)
218
+ .with(absolute_yaml_path('kontena_v3.yml'))
219
+ .and_return(fixture('stack-with-env-file.yml'))
220
+ allow(File).to receive(:readlines).with('.env').and_return(env_file)
221
+ end
222
+
223
+ it 'reads given file' do
224
+ expect(File).to receive(:readlines).with('.env').and_return(env_file)
225
+ subject.send(:read_env_file, '.env')
226
+ end
227
+
228
+ it 'discards comment lines' do
229
+ result = env_file
230
+ result << "#COMMENTLINE"
231
+ allow(File).to receive(:readlines).with('.env').and_return(result)
232
+
233
+ variables = subject.send(:read_env_file, '.env')
234
+ expect(variables).to eq([
235
+ 'APIKEY=12345',
236
+ 'MYSQL_ROOT_PASSWORD=secret',
237
+ 'WP_ADMIN_PASSWORD=verysecret'
238
+ ])
239
+ end
240
+
241
+ it 'discards empty lines' do
242
+ result = env_file
243
+ result << '
244
+ '
245
+ allow(File).to receive(:readlines).with('.env').and_return(result)
246
+ variables = subject.send(:read_env_file, '.env')
247
+ expect(variables).to eq([
248
+ 'APIKEY=12345',
249
+ 'MYSQL_ROOT_PASSWORD=secret',
250
+ 'WP_ADMIN_PASSWORD=verysecret'
251
+ ])
252
+ end
253
+
254
+ it 'merges variables' do
255
+ result = subject.execute[:services]
256
+ expect(result['wordpress']['environment']).to eq([
257
+ 'WORDPRESS_DB_PASSWORD=test_secret',
258
+ 'APIKEY=12345',
259
+ 'MYSQL_ROOT_PASSWORD=secret',
260
+ 'WP_ADMIN_PASSWORD=verysecret'
261
+ ])
262
+ end
263
+
264
+ end
265
+ end
266
+
267
+ it 'returns result hash' do
268
+ outcome = subject.execute
269
+ expect(outcome[:services]).to eq(valid_v3_result['services'])
270
+ end
271
+
272
+ it 'returns validation errors' do
273
+ allow(File).to receive(:read)
274
+ .with(absolute_yaml_path('kontena_v3.yml'))
275
+ .and_return(fixture('kontena-invalid.yml'))
276
+ outcome = subject.execute
277
+ expect(outcome[:errors].size).to eq(1)
278
+ end
279
+ end
280
+
281
+ context 'when build option is string' do
282
+ it 'expands build option to absolute path' do
283
+ allow(File).to receive(:read)
284
+ .with(absolute_yaml_path)
285
+ .and_return(fixture('kontena_build_v3.yml'))
286
+ outcome = subject.execute
287
+ puts outcome
288
+ expect(outcome[:services]['webapp']['build']['context']).to eq(File.expand_path('.'))
289
+ end
290
+ end
291
+
292
+ context 'when build option is Hash' do
293
+ it 'expands build context to absolute path' do
294
+ allow(File).to receive(:read)
295
+ .with(absolute_yaml_path)
296
+ .and_return(fixture('kontena_build_v3.yml'))
297
+ outcome = subject.execute
298
+ expect(outcome[:services]['webapp']['build']['context']).to eq(File.expand_path('.'))
299
+ end
300
+ end
301
+
302
+ context 'normalize_build_args' do
303
+ context 'when build option is string' do
304
+ it 'skips normalizing' do
305
+ allow(File).to receive(:read)
306
+ .with(absolute_yaml_path)
307
+ .and_return(fixture('kontena_build_v3.yml'))
308
+
309
+ options = {
310
+ 'build' => '.'
311
+ }
312
+ expect {
313
+ subject.send(:normalize_build_args, options)
314
+ }.not_to raise_error
315
+ end
316
+ end
317
+
318
+ context 'when build arguments option is Hash' do
319
+ it 'does not do anything' do
320
+ allow(File).to receive(:read)
321
+ .with(absolute_yaml_path)
322
+ .and_return(fixture('kontena_build_v3.yml'))
323
+
324
+ options = {
325
+ 'build' => {
326
+ 'context' => '.',
327
+ 'args' => {
328
+ 'foo' => 'bar'
329
+ }
330
+ }
331
+ }
332
+
333
+ subject.send(:normalize_build_args, options)
334
+ expect(options.dig('build', 'args')).to eq({
335
+ 'foo' => 'bar'
336
+ })
337
+ end
338
+ end
339
+
340
+ context 'when build arguments option is Array' do
341
+ it 'converts it to array' do
342
+ allow(File).to receive(:read)
343
+ .with(absolute_yaml_path)
344
+ .and_return(fixture('kontena_build_v3.yml'))
345
+
346
+ options = {
347
+ 'build' => {
348
+ 'context' => '.',
349
+ 'args' => ['foo=bar']
350
+ }
351
+ }
352
+
353
+ subject.send(:normalize_build_args, options)
354
+ expect(options.dig('build', 'args')).to eq({
355
+ 'foo' => 'bar'
356
+ })
357
+ end
358
+ end
359
+ end
360
+
361
+ describe '#stack_name' do
362
+ it 'returns name for v3' do
363
+ allow(File).to receive(:read)
364
+ .with(absolute_yaml_path)
365
+ .and_return(fixture('kontena_v3.yml'))
366
+ name = subject.stack_name
367
+ expect(name).to eq('stackname')
368
+ end
369
+ end
370
+ end