r10k 3.3.3 → 3.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/.github/pull_request_template.md +1 -0
  3. data/.github/workflows/docker.yml +56 -0
  4. data/.github/workflows/release.yml +36 -0
  5. data/.travis.yml +23 -8
  6. data/CHANGELOG.mkd +57 -4
  7. data/CODEOWNERS +1 -0
  8. data/Gemfile +1 -1
  9. data/README.mkd +4 -3
  10. data/azure-pipelines.yml +2 -1
  11. data/bin/r10k +1 -1
  12. data/doc/dynamic-environments/configuration.mkd +160 -2
  13. data/doc/dynamic-environments/git-environments.mkd +1 -1
  14. data/doc/dynamic-environments/master-configuration.mkd +28 -58
  15. data/doc/faq.mkd +6 -1
  16. data/doc/puppetfile.mkd +2 -0
  17. data/docker/Makefile +39 -17
  18. data/docker/r10k/Dockerfile +36 -15
  19. data/docker/r10k/adduser.sh +13 -0
  20. data/docker/r10k/docker-entrypoint.d/10-analytics.sh +1 -1
  21. data/docker/r10k/release.Dockerfile +54 -0
  22. data/docker/spec/dockerfile_spec.rb +4 -3
  23. data/docker/spec/fixtures/Puppetfile +1 -1
  24. data/integration/Rakefile +2 -2
  25. data/lib/r10k/action/deploy/environment.rb +7 -3
  26. data/lib/r10k/action/deploy/module.rb +5 -1
  27. data/lib/r10k/action/runner.rb +4 -4
  28. data/lib/r10k/cli/deploy.rb +1 -1
  29. data/lib/r10k/environment.rb +30 -0
  30. data/lib/r10k/environment/bare.rb +16 -0
  31. data/lib/r10k/environment/git.rb +6 -5
  32. data/lib/r10k/environment/svn.rb +2 -0
  33. data/lib/r10k/environment/with_modules.rb +139 -0
  34. data/lib/r10k/forge/module_release.rb +2 -2
  35. data/lib/r10k/logging/terminaloutputter.rb +1 -1
  36. data/lib/r10k/module/base.rb +5 -0
  37. data/lib/r10k/module/forge.rb +5 -1
  38. data/lib/r10k/puppetfile.rb +6 -0
  39. data/lib/r10k/source.rb +4 -0
  40. data/lib/r10k/source/exec.rb +51 -0
  41. data/lib/r10k/source/hash.rb +182 -0
  42. data/lib/r10k/source/yaml.rb +20 -0
  43. data/lib/r10k/source/yamldir.rb +32 -0
  44. data/lib/r10k/util/attempt.rb +1 -1
  45. data/lib/r10k/version.rb +4 -1
  46. data/locales/r10k.pot +65 -22
  47. data/r10k.gemspec +6 -2
  48. data/spec/unit/action/deploy/environment_spec.rb +1 -0
  49. data/spec/unit/action/deploy/module_spec.rb +13 -0
  50. data/spec/unit/action/puppetfile/install_spec.rb +3 -1
  51. data/spec/unit/action/runner_spec.rb +2 -2
  52. data/spec/unit/forge/module_release_spec.rb +14 -10
  53. data/spec/unit/source/exec_spec.rb +81 -0
  54. data/spec/unit/source/hash_spec.rb +54 -0
  55. data/spec/unit/source/yaml_spec.rb +42 -0
  56. metadata +64 -22
  57. data/MAINTAINERS +0 -18
  58. data/docker/distelli-manifest.yml +0 -9
  59. data/integration/scripts/README.mkd +0 -86
  60. data/integration/scripts/setup_r10k_env_centos5.sh +0 -23
  61. data/integration/scripts/setup_r10k_env_centos6.sh +0 -23
  62. data/integration/scripts/setup_r10k_env_rhel7.sh +0 -23
  63. data/integration/scripts/setup_r10k_env_sles11.sh +0 -23
  64. data/integration/scripts/setup_r10k_env_sles12.sh +0 -23
  65. data/integration/scripts/setup_r10k_env_ubuntu1004.sh +0 -23
  66. data/integration/scripts/setup_r10k_env_ubuntu1204.sh +0 -23
  67. data/integration/scripts/setup_r10k_env_ubuntu1404.sh +0 -23
@@ -0,0 +1,20 @@
1
+ class R10K::Source::Yaml < R10K::Source::Hash
2
+ R10K::Source.register(:yaml, self)
3
+
4
+ def initialize(name, basedir, options = {})
5
+ config = options[:config] || '/etc/puppetlabs/r10k/environments.yaml'
6
+
7
+ begin
8
+ contents = ::YAML.load_file(config)
9
+ rescue => e
10
+ raise ConfigError, _("Couldn't open environments file %{file}: %{err}") % {file: config, err: e.message}
11
+ end
12
+
13
+ # Set the environments key for the parent class to consume
14
+ options[:environments] = contents
15
+
16
+ # All we need to do is supply options with the :environments hash.
17
+ # The R10K::Source::Hash parent class takes care of the rest.
18
+ super(name, basedir, options)
19
+ end
20
+ end
@@ -0,0 +1,32 @@
1
+ class R10K::Source::Yamldir < R10K::Source::Hash
2
+ R10K::Source.register(:yamldir, self)
3
+
4
+ def initialize(name, basedir, options = {})
5
+ config = options[:config] || '/etc/puppetlabs/r10k/environments.d'
6
+
7
+ unless File.directory?(config)
8
+ raise R10K::Deployment::Config::ConfigError, _("Error opening %{dir}: config must be a directory") % {dir: config}
9
+ end
10
+
11
+ unless File.readable?(config)
12
+ raise R10K::Deployment::Config::ConfigError, _("Error opening %{dir}: permission denied") % {dir: config}
13
+ end
14
+
15
+ environment_data = Dir.glob(File.join(config, '*.yaml')).reduce({}) do |memo,path|
16
+ name = File.basename(path, '.yaml')
17
+ begin
18
+ contents = ::YAML.load_file(path)
19
+ rescue => e
20
+ raise R10K::Deployment::Config::ConfigError, _("Error loading %{path}: %{err}") % {path: path, err: e.message}
21
+ end
22
+ memo.merge({name => contents })
23
+ end
24
+
25
+ # Set the environments key for the parent class to consume
26
+ options[:environments] = environment_data
27
+
28
+ # All we need to do is supply options with the :environments hash.
29
+ # The R10K::Source::Hash parent class takes care of the rest.
30
+ super(name, basedir, options)
31
+ end
32
+ end
@@ -1,7 +1,7 @@
1
1
  require 'r10k/logging'
2
2
  require 'r10k/errors/formatting'
3
3
  require 'r10k/util/setopts'
4
- require 'colored'
4
+ require 'colored2'
5
5
 
6
6
  module R10K
7
7
  module Util
@@ -1,3 +1,6 @@
1
1
  module R10K
2
- VERSION = '3.3.3'
2
+ # When updating to a new major (X) or minor (Y) version, include `#major` or
3
+ # `#minor` (respectively) in your commit message to trigger the appropriate
4
+ # release. Otherwise, a new patch (Z) version will be released.
5
+ VERSION = '3.5.2'
3
6
  end
@@ -1,16 +1,16 @@
1
1
  # SOME DESCRIPTIVE TITLE.
2
- # Copyright (C) 2019 Puppet, Inc.
2
+ # Copyright (C) 2020 Puppet, Inc.
3
3
  # This file is distributed under the same license as the r10k package.
4
- # FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
5
5
  #
6
6
  #, fuzzy
7
7
  msgid ""
8
8
  msgstr ""
9
- "Project-Id-Version: r10k 3.3.0-7-g6a2159a\n"
9
+ "Project-Id-Version: r10k 3.4.1-20-g8fe925b\n"
10
10
  "\n"
11
11
  "Report-Msgid-Bugs-To: docs@puppetlabs.com\n"
12
- "POT-Creation-Date: 2019-06-14 22:40+0000\n"
13
- "PO-Revision-Date: 2019-06-14 22:40+0000\n"
12
+ "POT-Creation-Date: 2020-04-28 18:41+0000\n"
13
+ "PO-Revision-Date: 2020-04-28 18:41+0000\n"
14
14
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
15
15
  "Language-Team: LANGUAGE <LL@li.org>\n"
16
16
  "Language: \n"
@@ -52,7 +52,7 @@ msgid "Environment %{env_dir} is new, updating all modules"
52
52
  msgstr ""
53
53
 
54
54
  #: ../lib/r10k/action/deploy/environment.rb:143
55
- msgid "Deploying Puppetfile content %{mod_path}"
55
+ msgid "Deploying %{origin} content %{path}"
56
56
  msgstr ""
57
57
 
58
58
  #: ../lib/r10k/action/deploy/module.rb:49
@@ -107,6 +107,14 @@ msgstr ""
107
107
  msgid "%{class} has not implemented method %{method}"
108
108
  msgstr ""
109
109
 
110
+ #: ../lib/r10k/environment/with_modules.rb:104
111
+ msgid "Puppetfile cannot contain module names defined by environment %{name}"
112
+ msgstr ""
113
+
114
+ #: ../lib/r10k/environment/with_modules.rb:106
115
+ msgid "Remove the conflicting definitions of the following modules: %{conflicts}"
116
+ msgstr ""
117
+
110
118
  #: ../lib/r10k/feature.rb:27
111
119
  msgid "Testing to see if feature %{name} is available."
112
120
  msgstr ""
@@ -131,19 +139,19 @@ msgstr ""
131
139
  msgid "Proc %{block} for feature %{name} returned %{output}"
132
140
  msgstr ""
133
141
 
134
- #: ../lib/r10k/forge/module_release.rb:164
142
+ #: ../lib/r10k/forge/module_release.rb:196
135
143
  msgid "Unpacking %{tarball_cache_path} to %{target_dir} (with tmpdir %{tmp_path})"
136
144
  msgstr ""
137
145
 
138
- #: ../lib/r10k/forge/module_release.rb:166
146
+ #: ../lib/r10k/forge/module_release.rb:198
139
147
  msgid "Valid files unpacked: %{valid_files}"
140
148
  msgstr ""
141
149
 
142
- #: ../lib/r10k/forge/module_release.rb:168
150
+ #: ../lib/r10k/forge/module_release.rb:200
143
151
  msgid "These files existed in the module's tar file, but are invalid filetypes and were not unpacked: %{invalid_files}"
144
152
  msgstr ""
145
153
 
146
- #: ../lib/r10k/forge/module_release.rb:171
154
+ #: ../lib/r10k/forge/module_release.rb:203
147
155
  msgid "Symlinks are unsupported and were not unpacked from the module tarball. %{release_slug} contained these ignored symlinks: %{symlinks}"
148
156
  msgstr ""
149
157
 
@@ -295,19 +303,19 @@ msgstr ""
295
303
  msgid "Module %{name} with args %{args} doesn't have an implementation. (Are you using the right arguments?)"
296
304
  msgstr ""
297
305
 
298
- #: ../lib/r10k/module/base.rb:105
306
+ #: ../lib/r10k/module/base.rb:110
299
307
  msgid "Module name (%{title}) must match either 'modulename' or 'owner/modulename'"
300
308
  msgstr ""
301
309
 
302
- #: ../lib/r10k/module/forge.rb:70 ../lib/r10k/module/forge.rb:95
310
+ #: ../lib/r10k/module/forge.rb:70 ../lib/r10k/module/forge.rb:99
303
311
  msgid "The module %{title} does not exist on %{url}."
304
312
  msgstr ""
305
313
 
306
- #: ../lib/r10k/module/forge.rb:170
314
+ #: ../lib/r10k/module/forge.rb:174
307
315
  msgid "Forge module names must match 'owner/modulename'"
308
316
  msgstr ""
309
317
 
310
- #: ../lib/r10k/module/git.rb:92
318
+ #: ../lib/r10k/module/git.rb:97
311
319
  msgid "Unhandled options %{unhandled} specified for %{class}"
312
320
  msgstr ""
313
321
 
@@ -323,35 +331,35 @@ msgstr ""
323
331
  msgid "Using Puppetfile '%{puppetfile}'"
324
332
  msgstr ""
325
333
 
326
- #: ../lib/r10k/puppetfile.rb:70
334
+ #: ../lib/r10k/puppetfile.rb:71
327
335
  msgid "Puppetfile %{path} missing or unreadable"
328
336
  msgstr ""
329
337
 
330
- #: ../lib/r10k/puppetfile.rb:80
338
+ #: ../lib/r10k/puppetfile.rb:84
331
339
  msgid "Failed to evaluate %{path}"
332
340
  msgstr ""
333
341
 
334
- #: ../lib/r10k/puppetfile.rb:90
342
+ #: ../lib/r10k/puppetfile.rb:98
335
343
  msgid "Puppetfiles cannot contain duplicate module names."
336
344
  msgstr ""
337
345
 
338
- #: ../lib/r10k/puppetfile.rb:92
346
+ #: ../lib/r10k/puppetfile.rb:100
339
347
  msgid "Remove the duplicates of the following modules: %{dupes}"
340
348
  msgstr ""
341
349
 
342
- #: ../lib/r10k/puppetfile.rb:179
350
+ #: ../lib/r10k/puppetfile.rb:192
343
351
  msgid "Updating modules with %{pool_size} threads"
344
352
  msgstr ""
345
353
 
346
- #: ../lib/r10k/puppetfile.rb:190
354
+ #: ../lib/r10k/puppetfile.rb:203
347
355
  msgid "Error during concurrent deploy of a module: %{message}"
348
356
  msgstr ""
349
357
 
350
- #: ../lib/r10k/puppetfile.rb:212
358
+ #: ../lib/r10k/puppetfile.rb:225
351
359
  msgid "Module thread %{id} exiting: %{message}"
352
360
  msgstr ""
353
361
 
354
- #: ../lib/r10k/puppetfile.rb:269
362
+ #: ../lib/r10k/puppetfile.rb:282
355
363
  msgid "unrecognized declaration '%{method}'"
356
364
  msgstr ""
357
365
 
@@ -415,6 +423,25 @@ msgstr ""
415
423
  msgid "Setting %{name} requires a URL but '%{value}' could not be parsed as a URL"
416
424
  msgstr ""
417
425
 
426
+ #: ../lib/r10k/source/exec.rb:10
427
+ msgid "Environment source %{name} missing required parameter: command"
428
+ msgstr ""
429
+
430
+ #: ../lib/r10k/source/exec.rb:36
431
+ msgid ""
432
+ "Error parsing command output for exec source %{name}:\n"
433
+ "Not valid JSON: %{j_msg}\n"
434
+ "Not valid YAML: %{y_msg}\n"
435
+ "Stdout:\n"
436
+ "%{out}"
437
+ msgstr ""
438
+
439
+ #: ../lib/r10k/source/exec.rb:44
440
+ msgid ""
441
+ "Environment source %{name} command %{cmd} did not return valid environment data.\n"
442
+ "Returned: %{data}"
443
+ msgstr ""
444
+
418
445
  #: ../lib/r10k/source/git.rb:72
419
446
  msgid "Fetching '%{remote}' to determine current branches."
420
447
  msgstr ""
@@ -435,6 +462,22 @@ msgstr ""
435
462
  msgid "Branch %{branch} filtered out by ignore_branch_prefixes %{ibp}"
436
463
  msgstr ""
437
464
 
465
+ #: ../lib/r10k/source/yaml.rb:10
466
+ msgid "Couldn't open environments file %{file}: %{err}"
467
+ msgstr ""
468
+
469
+ #: ../lib/r10k/source/yamldir.rb:8
470
+ msgid "Error opening %{dir}: config must be a directory"
471
+ msgstr ""
472
+
473
+ #: ../lib/r10k/source/yamldir.rb:12
474
+ msgid "Error opening %{dir}: permission denied"
475
+ msgstr ""
476
+
477
+ #: ../lib/r10k/source/yamldir.rb:20
478
+ msgid "Error loading %{path}: %{err}"
479
+ msgstr ""
480
+
438
481
  #: ../lib/r10k/svn/working_dir.rb:43
439
482
  msgid "Both username and password must be specified"
440
483
  msgstr ""
@@ -22,8 +22,8 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.license = 'Apache-2.0'
24
24
 
25
- s.add_dependency 'colored', '1.2'
26
- s.add_dependency 'cri', '2.15.6'
25
+ s.add_dependency 'colored2', '3.1.2'
26
+ s.add_dependency 'cri', ['>= 2.15.10', '< 3.0.0']
27
27
 
28
28
  s.add_dependency 'log4r', '1.1.10'
29
29
  s.add_dependency 'multi_json', '~> 1.10'
@@ -31,6 +31,10 @@ Gem::Specification.new do |s|
31
31
  s.add_dependency 'puppet_forge', '~> 2.3.0'
32
32
 
33
33
  s.add_dependency 'gettext-setup', '~>0.24'
34
+ # These two pins narrow what is allowed by gettext-setup,
35
+ # to preserver compatability with Ruby 2.4
36
+ s.add_dependency 'fast_gettext', '~> 1.1.0'
37
+ s.add_dependency 'gettext', ['>= 3.0.2', '< 3.3.0']
34
38
 
35
39
  s.add_development_dependency 'rspec', '~> 3.1'
36
40
 
@@ -369,6 +369,7 @@ describe R10K::Action::Deploy::Environment do
369
369
  allow(mock_forge_module_1).to receive(:repo).and_raise(NoMethodError)
370
370
 
371
371
  fake_env = Fake_Environment.new(@tmp_path, {:name => "my_cool_environment", :signature => "pablo picasso"})
372
+ allow(fake_env).to receive(:modules).and_return(mock_puppetfile.modules)
372
373
  subject.send(:write_environment_info!, fake_env, "2019-01-01 23:23:22 +0000", true)
373
374
 
374
375
  file_contents = File.read("#{@tmp_path}/.r10k-deploy.json")
@@ -25,6 +25,10 @@ describe R10K::Action::Deploy::Module do
25
25
  it 'can accept a puppet-path option' do
26
26
  described_class.new({ 'puppet-path': '/nonexistent' }, [])
27
27
  end
28
+
29
+ it 'can accept a cachedir option' do
30
+ described_class.new({ cachedir: '/nonexistent' }, [])
31
+ end
28
32
  end
29
33
 
30
34
  describe "with no-force" do
@@ -123,4 +127,13 @@ describe R10K::Action::Deploy::Module do
123
127
  expect(subject.instance_variable_get(:@puppet_path)).to eq('/nonexistent')
124
128
  end
125
129
  end
130
+
131
+ describe 'with cachedir' do
132
+
133
+ subject { described_class.new({ config: '/some/nonexistent/path', cachedir: '/nonexistent' }, []) }
134
+
135
+ it 'sets puppet_path' do
136
+ expect(subject.instance_variable_get(:@cachedir)).to eq('/nonexistent')
137
+ end
138
+ end
126
139
  end
@@ -19,7 +19,9 @@ describe R10K::Action::Puppetfile::Install do
19
19
 
20
20
  describe "installing modules" do
21
21
  let(:modules) do
22
- Array.new(4, R10K::Module::Base.new('author/modname', "/some/nonexistent/path/modname", nil))
22
+ (1..4).map do |idx|
23
+ R10K::Module::Base.new("author/modname#{idx}", "/some/nonexistent/path/modname#{idx}", nil)
24
+ end
23
25
  end
24
26
 
25
27
  before do
@@ -94,7 +94,7 @@ describe R10K::Action::Runner do
94
94
  else
95
95
  { "#{conf_path}": override }
96
96
  end
97
- expect(global_settings).to receive(:evaluate).with(overrides).and_call_original
97
+ expect(global_settings).to receive(:evaluate).with(hash_including(overrides)).and_call_original
98
98
  runner.call
99
99
  end
100
100
  end
@@ -109,7 +109,7 @@ describe R10K::Action::Runner do
109
109
  else
110
110
  { "#{conf_path}": override }
111
111
  end
112
- expect(global_settings).to receive(:evaluate).with(overrides).and_call_original
112
+ expect(global_settings).to receive(:evaluate).with(hash_including(overrides)).and_call_original
113
113
  runner.call
114
114
  end
115
115
  end
@@ -166,33 +166,37 @@ describe R10K::Forge::ModuleRelease do
166
166
  end
167
167
 
168
168
  describe "#cleanup_unpack_path" do
169
- it "ignores the unpack_path if it doesn't exist" do
170
- expect(unpack_path).to receive(:exist?).and_return false
171
- expect(unpack_path).to_not receive(:parent)
169
+ it "ignores the unpack_path if the parent doesn't exist" do
170
+ parent = instance_double('Pathname')
171
+ expect(parent).to receive(:exist?).and_return false
172
+ expect(parent).to_not receive(:rmtree)
173
+ expect(unpack_path).to receive(:parent).and_return(parent)
172
174
  subject.cleanup_unpack_path
173
175
  end
174
176
 
175
177
  it "removes the containing directory of unpack_path if it exists" do
176
178
  parent = instance_double('Pathname')
177
179
  expect(parent).to receive(:rmtree)
178
- expect(unpack_path).to receive(:exist?).and_return true
179
- expect(unpack_path).to receive(:parent).and_return(parent)
180
+ expect(parent).to receive(:exist?).and_return true
181
+ expect(unpack_path).to receive(:parent).and_return(parent).exactly(2).times
180
182
  subject.cleanup_unpack_path
181
183
  end
182
184
  end
183
185
 
184
186
  describe "#cleanup_download_path" do
185
- it "ignores the download_path if it doesn't exist" do
186
- expect(download_path).to receive(:exist?).and_return false
187
- expect(download_path).to_not receive(:parent)
187
+ it "ignores the download_path if the parent doesn't exist" do
188
+ parent = instance_double('Pathname')
189
+ expect(parent).to receive(:exist?).and_return false
190
+ expect(parent).to_not receive(:rmtree)
191
+ expect(download_path).to receive(:parent).and_return(parent)
188
192
  subject.cleanup_download_path
189
193
  end
190
194
 
191
195
  it "removes the containing directory of download_path if it exists" do
192
196
  parent = instance_double('Pathname')
193
197
  expect(parent).to receive(:rmtree)
194
- expect(download_path).to receive(:exist?).and_return true
195
- expect(download_path).to receive(:parent).and_return(parent)
198
+ expect(parent).to receive(:exist?).and_return true
199
+ expect(download_path).to receive(:parent).and_return(parent).exactly(2).times
196
200
  subject.cleanup_download_path
197
201
  end
198
202
  end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+ require 'r10k/source'
3
+ require 'json'
4
+ require 'yaml'
5
+
6
+ describe R10K::Source::Exec do
7
+
8
+ let(:environments_hash) do
9
+ {
10
+ 'production' => {
11
+ 'remote' => 'https://git.example.com/puppet/control-repo.git',
12
+ 'ref' => 'release-141',
13
+ 'modules' => {
14
+ 'puppetlabs-stdlib' => '6.1.0',
15
+ 'puppetlabs-ntp' => '8.1.0',
16
+ 'example-myapp1' => {
17
+ 'git' => 'https://git.example.com/puppet/example-myapp1.git',
18
+ 'ref' => 'v1.3.0'
19
+ }
20
+ }
21
+ },
22
+ 'development' => {
23
+ 'remote' => 'https://git.example.com/puppet/control-repo.git',
24
+ 'ref' => 'master',
25
+ 'modules' => {
26
+ 'puppetlabs-stdlib' => '6.1.0',
27
+ 'puppetlabs-ntp' => '8.1.0',
28
+ 'example-myapp1' => {
29
+ 'git' => 'https://git.example.com/puppet/example-myapp1.git',
30
+ 'ref' => 'v1.3.1'
31
+ }
32
+ }
33
+ }
34
+ }
35
+ end
36
+
37
+ describe 'initialize' do
38
+ context 'with a valid command' do
39
+ context 'that produces valid output' do
40
+ it 'accepts json' do
41
+ allow_any_instance_of(R10K::Util::Subprocess)
42
+ .to receive(:execute)
43
+ .and_return(double('result', stdout: environments_hash.to_json))
44
+
45
+ source = described_class.new('execsource', '/some/nonexistent/dir', command: '/path/to/command')
46
+ expect(source.environments.map(&:name)).to contain_exactly('production', 'development')
47
+ end
48
+
49
+ it 'accepts yaml' do
50
+ allow_any_instance_of(R10K::Util::Subprocess)
51
+ .to receive(:execute)
52
+ .and_return(double('result', stdout: environments_hash.to_yaml))
53
+
54
+ source = described_class.new('execsource', '/some/nonexistent/dir', command: '/path/to/command')
55
+ expect(source.environments.map(&:name)).to contain_exactly('production', 'development')
56
+ end
57
+
58
+ end
59
+
60
+ context 'that produces invalid output' do
61
+ it 'raises an error for non-json, non-yaml data' do
62
+ allow_any_instance_of(R10K::Util::Subprocess)
63
+ .to receive(:execute)
64
+ .and_return(double('result', stdout: "one:\ntwo\n"))
65
+
66
+ source = described_class.new('execsource', '/some/nonexistent/dir', command: '/path/to/command')
67
+ expect { source.environments }.to raise_error(/Error parsing command output/)
68
+ end
69
+
70
+ it 'raises an error for yaml data that is not a hash' do
71
+ allow_any_instance_of(R10K::Util::Subprocess)
72
+ .to receive(:execute)
73
+ .and_return(double('result', stdout: "[one, two]"))
74
+
75
+ source = described_class.new('execsource', '/some/nonexistent/dir', command: '/path/to/command')
76
+ expect { source.environments }.to raise_error(R10K::Error, /Environment source execsource.*did not return valid environment data.*one.*two.*/m)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end