r10k 3.9.3 → 3.10.0

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec_tests.yml +1 -1
  3. data/CHANGELOG.mkd +9 -0
  4. data/doc/dynamic-environments/configuration.mkd +7 -0
  5. data/integration/Rakefile +1 -1
  6. data/integration/tests/user_scenario/basic_workflow/negative/neg_specify_deleted_forge_module.rb +3 -9
  7. data/integration/tests/user_scenario/basic_workflow/single_env_purge_unmanaged_modules.rb +8 -14
  8. data/lib/r10k/action/deploy/environment.rb +3 -0
  9. data/lib/r10k/action/runner.rb +11 -6
  10. data/lib/r10k/git/cache.rb +1 -1
  11. data/lib/r10k/initializers.rb +7 -0
  12. data/lib/r10k/module/forge.rb +5 -1
  13. data/lib/r10k/module_loader/puppetfile.rb +195 -0
  14. data/lib/r10k/module_loader/puppetfile/dsl.rb +37 -0
  15. data/lib/r10k/puppetfile.rb +77 -153
  16. data/lib/r10k/settings.rb +3 -0
  17. data/lib/r10k/source/base.rb +10 -0
  18. data/lib/r10k/source/git.rb +5 -0
  19. data/lib/r10k/source/svn.rb +4 -0
  20. data/lib/r10k/util/purgeable.rb +70 -8
  21. data/lib/r10k/version.rb +1 -1
  22. data/locales/r10k.pot +37 -33
  23. data/spec/fixtures/unit/action/r10k_forge_auth.yaml +4 -0
  24. data/spec/fixtures/unit/action/r10k_forge_auth_no_url.yaml +3 -0
  25. data/spec/fixtures/unit/util/purgeable/managed_one/managed_subdir_1/managed_subdir_2/ignored_1 +0 -0
  26. data/spec/fixtures/unit/util/purgeable/managed_two/.hidden/unmanaged_3 +0 -0
  27. data/spec/unit/action/deploy/environment_spec.rb +9 -0
  28. data/spec/unit/action/deploy/module_spec.rb +38 -14
  29. data/spec/unit/action/runner_spec.rb +49 -25
  30. data/spec/unit/git/cache_spec.rb +14 -0
  31. data/spec/unit/module/forge_spec.rb +8 -1
  32. data/spec/unit/module_loader/puppetfile_spec.rb +330 -0
  33. data/spec/unit/puppetfile_spec.rb +99 -193
  34. data/spec/unit/settings_spec.rb +6 -2
  35. data/spec/unit/util/purgeable_spec.rb +38 -6
  36. metadata +10 -3
@@ -0,0 +1,330 @@
1
+ require 'spec_helper'
2
+ require 'r10k/module_loader/puppetfile'
3
+
4
+ describe R10K::ModuleLoader::Puppetfile do
5
+ describe 'initial parameters' do
6
+ describe 'honor' do
7
+ let(:options) do
8
+ {
9
+ basedir: '/test/basedir/env',
10
+ forge: 'localforge.internal.corp',
11
+ overrides: { modules: { deploy_modules: true } },
12
+ environment: R10K::Environment::Git.new('env',
13
+ '/test/basedir/',
14
+ 'env',
15
+ { remote: 'git://foo/remote',
16
+ ref: 'env' })
17
+ }
18
+ end
19
+
20
+ subject { R10K::ModuleLoader::Puppetfile.new(**options) }
21
+
22
+ describe 'the moduledir' do
23
+ it 'respects absolute paths' do
24
+ absolute_options = options.merge({moduledir: '/opt/puppetlabs/special/modules'})
25
+ puppetfile = R10K::ModuleLoader::Puppetfile.new(**absolute_options)
26
+ expect(puppetfile.instance_variable_get(:@moduledir)).to eq('/opt/puppetlabs/special/modules')
27
+ end
28
+
29
+ it 'roots the moduledir in the basepath if a relative path is specified' do
30
+ relative_options = options.merge({moduledir: 'my/special/modules'})
31
+ puppetfile = R10K::ModuleLoader::Puppetfile.new(**relative_options)
32
+ expect(puppetfile.instance_variable_get(:@moduledir)).to eq('/test/basedir/env/my/special/modules')
33
+ end
34
+ end
35
+
36
+ describe 'the Puppetfile' do
37
+ it 'respects absolute paths' do
38
+ absolute_options = options.merge({puppetfile: '/opt/puppetlabs/special/Puppetfile'})
39
+ puppetfile = R10K::ModuleLoader::Puppetfile.new(**absolute_options)
40
+ expect(puppetfile.instance_variable_get(:@puppetfile)).to eq('/opt/puppetlabs/special/Puppetfile')
41
+ end
42
+
43
+ it 'roots the Puppetfile in the basepath if a relative path is specified' do
44
+ relative_options = options.merge({puppetfile: 'Puppetfile.global'})
45
+ puppetfile = R10K::ModuleLoader::Puppetfile.new(**relative_options)
46
+ expect(puppetfile.instance_variable_get(:@puppetfile)).to eq('/test/basedir/env/Puppetfile.global')
47
+ end
48
+ end
49
+
50
+ it 'the forge' do
51
+ expect(subject.instance_variable_get(:@forge)).to eq('localforge.internal.corp')
52
+ end
53
+
54
+ it 'the overrides' do
55
+ expect(subject.instance_variable_get(:@overrides)).to eq({ modules: { deploy_modules: true }})
56
+ end
57
+
58
+ it 'the environment' do
59
+ expect(subject.instance_variable_get(:@environment).name).to eq('env')
60
+ end
61
+ end
62
+
63
+ describe 'sane defaults' do
64
+ subject { R10K::ModuleLoader::Puppetfile.new(basedir: '/test/basedir') }
65
+
66
+ it 'has a moduledir rooted in the basedir' do
67
+ expect(subject.instance_variable_get(:@moduledir)).to eq('/test/basedir/modules')
68
+ end
69
+
70
+ it 'has a Puppetfile rooted in the basedir' do
71
+ expect(subject.instance_variable_get(:@puppetfile)).to eq('/test/basedir/Puppetfile')
72
+ end
73
+
74
+ it 'uses the public forge' do
75
+ expect(subject.instance_variable_get(:@forge)).to eq('forgeapi.puppetlabs.com')
76
+ end
77
+
78
+ it 'creates an empty overrides' do
79
+ expect(subject.instance_variable_get(:@overrides)).to eq({})
80
+ end
81
+
82
+ it 'does not require an environment' do
83
+ expect(subject.instance_variable_get(:@environment)).to eq(nil)
84
+ end
85
+ end
86
+ end
87
+
88
+ describe 'adding modules' do
89
+ let(:basedir) { '/test/basedir' }
90
+
91
+ subject { R10K::ModuleLoader::Puppetfile.new(basedir: basedir) }
92
+
93
+ it 'should transform Forge modules with a string arg to have a version key' do
94
+ expect(R10K::Module).to receive(:new).with('puppet/test_module', subject.moduledir, hash_including(version: '1.2.3'), anything).and_call_original
95
+
96
+ expect { subject.add_module('puppet/test_module', '1.2.3') }.to change { subject.modules }
97
+ expect(subject.modules.collect(&:name)).to include('test_module')
98
+ end
99
+
100
+ it 'should not accept Forge modules with a version comparison' do
101
+ expect(R10K::Module).to receive(:new).with('puppet/test_module', subject.moduledir, hash_including(version: '< 1.2.0'), anything).and_call_original
102
+
103
+ expect {
104
+ subject.add_module('puppet/test_module', '< 1.2.0')
105
+ }.to raise_error(RuntimeError, /module puppet\/test_module.*doesn't have an implementation/i)
106
+
107
+ expect(subject.modules.collect(&:name)).not_to include('test_module')
108
+ end
109
+
110
+ it 'should accept non-Forge modules with a hash arg' do
111
+ module_opts = { git: 'git@example.com:puppet/test_module.git' }
112
+
113
+ expect(R10K::Module).to receive(:new).with('puppet/test_module', subject.moduledir, module_opts, anything).and_call_original
114
+
115
+ expect { subject.add_module('puppet/test_module', module_opts) }.to change { subject.modules }
116
+ expect(subject.modules.collect(&:name)).to include('test_module')
117
+ end
118
+
119
+ it 'should accept non-Forge modules with a valid relative :install_path option' do
120
+ module_opts = {
121
+ install_path: 'vendor',
122
+ git: 'git@example.com:puppet/test_module.git',
123
+ }
124
+
125
+ expect(R10K::Module).to receive(:new).with('puppet/test_module', File.join(basedir, 'vendor'), module_opts, anything).and_call_original
126
+
127
+ expect { subject.add_module('puppet/test_module', module_opts) }.to change { subject.modules }
128
+ expect(subject.modules.collect(&:name)).to include('test_module')
129
+ end
130
+
131
+ it 'should accept non-Forge modules with a valid absolute :install_path option' do
132
+ install_path = File.join(basedir, 'vendor')
133
+
134
+ module_opts = {
135
+ install_path: install_path,
136
+ git: 'git@example.com:puppet/test_module.git',
137
+ }
138
+
139
+ expect(R10K::Module).to receive(:new).with('puppet/test_module', install_path, module_opts, anything).and_call_original
140
+
141
+ expect { subject.add_module('puppet/test_module', module_opts) }.to change { subject.modules }
142
+ expect(subject.modules.collect(&:name)).to include('test_module')
143
+ end
144
+
145
+ it 'should reject non-Forge modules with an invalid relative :install_path option' do
146
+ module_opts = {
147
+ install_path: '../../vendor',
148
+ git: 'git@example.com:puppet/test_module.git',
149
+ }
150
+
151
+ expect { subject.add_module('puppet/test_module', module_opts) }.to raise_error(R10K::Error, /cannot manage content.*is not within/i).and not_change { subject.modules }
152
+ end
153
+
154
+ it 'should reject non-Forge modules with an invalid absolute :install_path option' do
155
+ module_opts = {
156
+ install_path: '/tmp/mydata/vendor',
157
+ git: 'git@example.com:puppet/test_module.git',
158
+ }
159
+
160
+ expect { subject.add_module('puppet/test_module', module_opts) }.to raise_error(R10K::Error, /cannot manage content.*is not within/i).and not_change { subject.modules }
161
+ end
162
+
163
+ it 'should disable and not add modules that conflict with the environment' do
164
+ env = instance_double('R10K::Environment::Base')
165
+ mod = instance_double('R10K::Module::Base', name: 'conflict', origin: :puppetfile, 'origin=': nil)
166
+ loader = R10K::ModuleLoader::Puppetfile.new(basedir: basedir, environment: env)
167
+ allow(env).to receive(:'module_conflicts?').with(mod).and_return(true)
168
+
169
+ expect(R10K::Module).to receive(:new).with('conflict', anything, anything, anything).and_return(mod)
170
+ expect { loader.add_module('conflict', {}) }.not_to change { loader.modules }
171
+ end
172
+ end
173
+
174
+ describe '#purge_exclusions' do
175
+ let(:managed_dirs) { ['dir1', 'dir2'] }
176
+ subject { R10K::ModuleLoader::Puppetfile.new(basedir: '/test/basedir') }
177
+
178
+ it 'includes managed_directories' do
179
+ expect(subject.send(:determine_purge_exclusions, managed_dirs)).to match_array(managed_dirs)
180
+ end
181
+
182
+ context 'when belonging to an environment' do
183
+ let(:env_contents) { ['env1', 'env2' ] }
184
+ let(:env) { double(:environment, desired_contents: env_contents) }
185
+
186
+ subject { R10K::ModuleLoader::Puppetfile.new(basedir: '/test/basedir', environment: env) }
187
+
188
+ it "includes environment's desired_contents" do
189
+ expect(subject.send(:determine_purge_exclusions, managed_dirs)).to match_array(managed_dirs + env_contents)
190
+ end
191
+ end
192
+ end
193
+
194
+ describe '#managed_directories' do
195
+
196
+ let(:basedir) { '/test/basedir' }
197
+ subject { R10K::ModuleLoader::Puppetfile.new(basedir: basedir) }
198
+
199
+ before do
200
+ allow(subject).to receive(:puppetfile_content).and_return('')
201
+ end
202
+
203
+ it 'returns an array of paths that #purge! will operate within' do
204
+ expect(R10K::Module).to receive(:new).with('puppet/test_module', subject.moduledir, hash_including(version: '1.2.3'), anything).and_call_original
205
+ subject.add_module('puppet/test_module', '1.2.3')
206
+ subject.load
207
+
208
+ expect(subject.modules.length).to be 1
209
+ expect(subject.managed_directories).to match_array([subject.moduledir])
210
+ end
211
+
212
+ context "with a module with install_path == ''" do
213
+ it "basedir isn't in the list of paths to purge" do
214
+ module_opts = { install_path: '', git: 'git@example.com:puppet/test_module.git' }
215
+
216
+ expect(R10K::Module).to receive(:new).with('puppet/test_module', basedir, module_opts, anything).and_call_original
217
+ subject.add_module('puppet/test_module', module_opts)
218
+ subject.load
219
+
220
+ expect(subject.modules.length).to be 1
221
+ expect(subject.managed_directories).to be_empty
222
+ end
223
+ end
224
+ end
225
+
226
+ describe 'evaluating a Puppetfile' do
227
+ def expect_wrapped_error(error, pf_path, error_type)
228
+ expect(error).to be_a_kind_of(R10K::Error)
229
+ expect(error.message).to eq("Failed to evaluate #{pf_path}")
230
+ expect(error.original).to be_a_kind_of(error_type)
231
+ end
232
+
233
+ subject { described_class.new(basedir: @path) }
234
+
235
+ it 'wraps and re-raises syntax errors' do
236
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'invalid-syntax')
237
+ pf_path = File.join(@path, 'Puppetfile')
238
+ expect {
239
+ subject.load
240
+ }.to raise_error do |e|
241
+ expect_wrapped_error(e, pf_path, SyntaxError)
242
+ end
243
+ end
244
+
245
+ it 'wraps and re-raises load errors' do
246
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'load-error')
247
+ pf_path = File.join(@path, 'Puppetfile')
248
+ expect {
249
+ subject.load
250
+ }.to raise_error do |e|
251
+ expect_wrapped_error(e, pf_path, LoadError)
252
+ end
253
+ end
254
+
255
+ it 'wraps and re-raises argument errors' do
256
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'argument-error')
257
+ pf_path = File.join(@path, 'Puppetfile')
258
+ expect {
259
+ subject.load
260
+ }.to raise_error do |e|
261
+ expect_wrapped_error(e, pf_path, ArgumentError)
262
+ end
263
+ end
264
+
265
+ it 'rejects Puppetfiles with duplicate module names' do
266
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'duplicate-module-error')
267
+ pf_path = File.join(@path, 'Puppetfile')
268
+ expect {
269
+ subject.load
270
+ }.to raise_error(R10K::Error, /Puppetfiles cannot contain duplicate module names/i)
271
+ end
272
+
273
+ it 'wraps and re-raises name errors' do
274
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'name-error')
275
+ pf_path = File.join(@path, 'Puppetfile')
276
+ expect {
277
+ subject.load
278
+ }.to raise_error do |e|
279
+ expect_wrapped_error(e, pf_path, NameError)
280
+ end
281
+ end
282
+
283
+ it 'accepts a forge module with a version' do
284
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'valid-forge-with-version')
285
+ pf_path = File.join(@path, 'Puppetfile')
286
+ expect { subject.load }.not_to raise_error
287
+ end
288
+
289
+ describe 'setting a custom moduledir' do
290
+ it 'allows setting an absolute moduledir' do
291
+ @path = '/fake/basedir'
292
+ allow(subject).to receive(:puppetfile_content).and_return('moduledir "/fake/moduledir"')
293
+ subject.load
294
+ expect(subject.instance_variable_get(:@moduledir)).to eq('/fake/moduledir')
295
+ end
296
+
297
+ it 'roots relative moduledirs in the basedir' do
298
+ @path = '/fake/basedir'
299
+ allow(subject).to receive(:puppetfile_content).and_return('moduledir "my/moduledir"')
300
+ subject.load
301
+ expect(subject.instance_variable_get(:@moduledir)).to eq(File.join(@path, 'my/moduledir'))
302
+ end
303
+ end
304
+
305
+ it 'accepts a forge module without a version' do
306
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'valid-forge-without-version')
307
+ pf_path = File.join(@path, 'Puppetfile')
308
+ expect { subject.load }.not_to raise_error
309
+ end
310
+
311
+ it 'creates a git module and applies the default branch specified in the Puppetfile' do
312
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'default-branch-override')
313
+ pf_path = File.join(@path, 'Puppetfile')
314
+ expect { subject.load }.not_to raise_error
315
+ git_module = subject.modules[0]
316
+ expect(git_module.default_ref).to eq 'here_lies_the_default_branch'
317
+ end
318
+
319
+ it 'creates a git module and applies the provided default_branch_override' do
320
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'default-branch-override')
321
+ pf_path = File.join(@path, 'Puppetfile')
322
+ default_branch_override = 'default_branch_override_name'
323
+ subject.default_branch_override = default_branch_override
324
+ expect { subject.load }.not_to raise_error
325
+ git_module = subject.modules[0]
326
+ expect(git_module.default_override_ref).to eq default_branch_override
327
+ expect(git_module.default_ref).to eq 'here_lies_the_default_branch'
328
+ end
329
+ end
330
+ end
@@ -67,230 +67,136 @@ describe R10K::Puppetfile do
67
67
  end
68
68
  end
69
69
 
70
- describe "adding modules" do
71
- it "should transform Forge modules with a string arg to have a version key" do
72
- allow(R10K::Module).to receive(:new).with('puppet/test_module', subject.moduledir, hash_including(version: '1.2.3'), anything).and_call_original
70
+ describe "loading a Puppetfile" do
71
+ context 'using load' do
72
+ it "returns the loaded content" do
73
+ path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'valid-forge-with-version')
74
+ subject = described_class.new(path, {})
73
75
 
74
- expect { subject.add_module('puppet/test_module', '1.2.3') }.to change { subject.modules }
75
- expect(subject.modules.collect(&:name)).to include('test_module')
76
- end
77
-
78
- it "should not accept Forge modules with a version comparison" do
79
- allow(R10K::Module).to receive(:new).with('puppet/test_module', subject.moduledir, hash_including(version: '< 1.2.0'), anything).and_call_original
80
-
81
- expect {
82
- subject.add_module('puppet/test_module', '< 1.2.0')
83
- }.to raise_error(RuntimeError, /module puppet\/test_module.*doesn't have an implementation/i)
84
-
85
- expect(subject.modules.collect(&:name)).not_to include('test_module')
86
- end
87
-
88
- it "should accept non-Forge modules with a hash arg" do
89
- module_opts = { git: 'git@example.com:puppet/test_module.git' }
90
-
91
- allow(R10K::Module).to receive(:new).with('puppet/test_module', subject.moduledir, module_opts, anything).and_call_original
92
-
93
- expect { subject.add_module('puppet/test_module', module_opts) }.to change { subject.modules }
94
- expect(subject.modules.collect(&:name)).to include('test_module')
95
- end
96
-
97
- it "should accept non-Forge modules with a valid relative :install_path option" do
98
- module_opts = {
99
- install_path: 'vendor',
100
- git: 'git@example.com:puppet/test_module.git',
101
- }
102
-
103
- allow(R10K::Module).to receive(:new).with('puppet/test_module', File.join(subject.basedir, 'vendor'), module_opts, anything).and_call_original
104
-
105
- expect { subject.add_module('puppet/test_module', module_opts) }.to change { subject.modules }
106
- expect(subject.modules.collect(&:name)).to include('test_module')
107
- end
76
+ loaded_content = subject.load
77
+ expect(loaded_content).to be_an_instance_of(Hash)
108
78
 
109
- it "should accept non-Forge modules with a valid absolute :install_path option" do
110
- install_path = File.join(subject.basedir, 'vendor')
111
-
112
- module_opts = {
113
- install_path: install_path,
114
- git: 'git@example.com:puppet/test_module.git',
115
- }
116
-
117
- allow(R10K::Module).to receive(:new).with('puppet/test_module', install_path, module_opts, anything).and_call_original
118
-
119
- expect { subject.add_module('puppet/test_module', module_opts) }.to change { subject.modules }
120
- expect(subject.modules.collect(&:name)).to include('test_module')
121
- end
122
-
123
- it "should reject non-Forge modules with an invalid relative :install_path option" do
124
- module_opts = {
125
- install_path: '../../vendor',
126
- git: 'git@example.com:puppet/test_module.git',
127
- }
128
-
129
- allow(R10K::Module).to receive(:new).with('puppet/test_module', File.join(subject.basedir, 'vendor'), module_opts, anything).and_call_original
130
-
131
- expect { subject.add_module('puppet/test_module', module_opts) }.to raise_error(R10K::Error, /cannot manage content.*is not within/i).and not_change { subject.modules }
132
- end
133
-
134
- it "should reject non-Forge modules with an invalid absolute :install_path option" do
135
- module_opts = {
136
- install_path: '/tmp/mydata/vendor',
137
- git: 'git@example.com:puppet/test_module.git',
138
- }
139
-
140
- allow(R10K::Module).to receive(:new).with('puppet/test_module', File.join(subject.basedir, 'vendor'), module_opts, anything).and_call_original
79
+ has_some_data = loaded_content.values.none?(&:empty?)
80
+ expect(has_some_data).to be true
81
+ end
141
82
 
142
- expect { subject.add_module('puppet/test_module', module_opts) }.to raise_error(R10K::Error, /cannot manage content.*is not within/i).and not_change { subject.modules }
143
- end
83
+ it "is idempotent" do
84
+ path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'valid-forge-with-version')
85
+ subject = described_class.new(path, {})
144
86
 
145
- it "should disable and not add modules that conflict with the environment" do
146
- env = instance_double('R10K::Environment::Base')
147
- mod = instance_double('R10K::Module::Base', name: 'conflict', origin: :puppetfile)
148
- allow(mod).to receive(:origin=).and_return(nil)
149
- allow(subject).to receive(:environment).and_return(env)
150
- allow(env).to receive(:'module_conflicts?').with(mod).and_return(true)
87
+ expect(subject.loader).to receive(:load).and_call_original.once
151
88
 
152
- allow(R10K::Module).to receive(:new).with('test', anything, anything, anything).and_return(mod)
153
- expect { subject.add_module('test', {}) }.not_to change { subject.modules }
154
- end
155
- end
89
+ loaded_content1 = subject.load
90
+ expect(subject.loaded?).to be true
91
+ loaded_content2 = subject.load
156
92
 
157
- describe "#purge_exclusions" do
158
- let(:managed_dirs) { ['dir1', 'dir2'] }
93
+ expect(loaded_content2).to eq(loaded_content1)
94
+ end
159
95
 
160
- before(:each) do
161
- allow(subject).to receive(:managed_directories).and_return(managed_dirs)
96
+ it "returns nil if Puppetfile doesn't exist" do
97
+ path = '/rando/path/that/wont/exist'
98
+ subject = described_class.new(path, {})
99
+ expect(subject.load).to eq nil
100
+ end
162
101
  end
163
102
 
164
- it "includes managed_directories" do
165
- expect(subject.purge_exclusions).to match_array(managed_dirs)
166
- end
103
+ context 'using load!' do
104
+ it "returns the loaded content" do
105
+ path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'valid-forge-with-version')
106
+ subject = described_class.new(path, {})
167
107
 
168
- context "when belonging to an environment" do
169
- let(:env_contents) { ['env1', 'env2' ] }
108
+ loaded_content = subject.load!
109
+ expect(loaded_content).to be_an_instance_of(Hash)
170
110
 
171
- before(:each) do
172
- mock_env = double(:environment, desired_contents: env_contents)
173
- allow(subject).to receive(:environment).and_return(mock_env)
111
+ has_some_data = loaded_content.values.none?(&:empty?)
112
+ expect(has_some_data).to be true
174
113
  end
175
114
 
176
- it "includes environment's desired_contents" do
177
- expect(subject.purge_exclusions).to match_array(managed_dirs + env_contents)
115
+ it "raises if Puppetfile doesn't exist" do
116
+ path = '/rando/path/that/wont/exist'
117
+ subject = described_class.new(path, {})
118
+ expect {
119
+ subject.load!
120
+ }.to raise_error(/No such file or directory.*\/rando\/path\/.*/)
178
121
  end
179
122
  end
180
123
  end
181
124
 
182
- describe '#managed_directories' do
183
- it 'returns an array of paths that can be purged' do
184
- allow(R10K::Module).to receive(:new).with('puppet/test_module', subject.moduledir, hash_including(version: '1.2.3'), anything).and_call_original
125
+ describe 'default_branch_override' do
126
+ it 'is passed correctly to module loader init' do
127
+ # This path doesn't matter so long as it has a Puppetfile within it
128
+ path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'valid-forge-with-version')
129
+ subject = described_class.new(path, {overrides: {environments: {default_branch_override: 'foo'}}})
185
130
 
186
- subject.add_module('puppet/test_module', '1.2.3')
187
- expect(subject.managed_directories).to match_array(["/some/nonexistent/basedir/modules"])
188
- end
131
+ repo = instance_double('R10K::Git::StatefulRepository')
132
+ allow(repo).to receive(:resolve).with('foo').and_return(true)
133
+ allow(R10K::Git::StatefulRepository).to receive(:new).and_return(repo)
189
134
 
190
- context 'with a module with install_path == \'\'' do
191
- it 'basedir isn\'t in the list of paths to purge' do
192
- module_opts = { install_path: '', git: 'git@example.com:puppet/test_module.git' }
135
+ allow(subject.loader).to receive(:puppetfile_content).and_return <<-EOPF
136
+ # Track control branch and fall-back to main if no matching branch.
137
+ mod 'hieradata',
138
+ :git => 'git@git.example.com:organization/hieradata.git',
139
+ :branch => :control_branch,
140
+ :default_branch => 'main'
141
+ EOPF
193
142
 
194
- allow(R10K::Module).to receive(:new).with('puppet/test_module', subject.basedir, module_opts, anything).and_call_original
143
+ expect(subject.logger).not_to receive(:warn).
144
+ with(/Mismatch between passed and initialized.*preferring passed value/)
195
145
 
196
- subject.add_module('puppet/test_module', module_opts)
197
- expect(subject.managed_directories).to be_empty
198
- end
199
- end
200
- end
146
+ subject.load
201
147
 
202
- describe "evaluating a Puppetfile" do
203
- def expect_wrapped_error(orig, pf_path, wrapped_error)
204
- expect(orig).to be_a_kind_of(R10K::Error)
205
- expect(orig.message).to eq("Failed to evaluate #{pf_path}")
206
- expect(orig.original).to be_a_kind_of(wrapped_error)
148
+ loaded_module = subject.modules.first
149
+ expect(loaded_module.version).to eq('foo')
207
150
  end
208
151
 
209
- it "wraps and re-raises syntax errors" do
210
- path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'invalid-syntax')
211
- pf_path = File.join(path, 'Puppetfile')
212
- subject = described_class.new(path, {})
213
- expect {
214
- subject.load!
215
- }.to raise_error do |e|
216
- expect_wrapped_error(e, pf_path, SyntaxError)
217
- end
218
- end
152
+ it 'overrides module loader init if needed' do
153
+ # This path doesn't matter so long as it has a Puppetfile within it
154
+ path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'valid-forge-with-version')
155
+ subject = described_class.new(path, {overrides: {environments: {default_branch_override: 'foo'}}})
219
156
 
220
- it "wraps and re-raises load errors" do
221
- path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'load-error')
222
- pf_path = File.join(path, 'Puppetfile')
223
- subject = described_class.new(path, {})
224
- expect {
225
- subject.load!
226
- }.to raise_error do |e|
227
- expect_wrapped_error(e, pf_path, LoadError)
228
- end
229
- end
157
+ repo = instance_double('R10K::Git::StatefulRepository')
158
+ allow(repo).to receive(:resolve).with('bar').and_return(true)
159
+ allow(R10K::Git::StatefulRepository).to receive(:new).and_return(repo)
230
160
 
231
- it "wraps and re-raises argument errors" do
232
- path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'argument-error')
233
- pf_path = File.join(path, 'Puppetfile')
234
- subject = described_class.new(path, {})
235
- expect {
236
- subject.load!
237
- }.to raise_error do |e|
238
- expect_wrapped_error(e, pf_path, ArgumentError)
239
- end
240
- end
161
+ allow(subject.loader).to receive(:puppetfile_content).and_return <<-EOPF
162
+ # Track control branch and fall-back to main if no matching branch.
163
+ mod 'hieradata',
164
+ :git => 'git@git.example.com:organization/hieradata.git',
165
+ :branch => :control_branch,
166
+ :default_branch => 'main'
167
+ EOPF
241
168
 
242
- it "rejects Puppetfiles with duplicate module names" do
243
- path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'duplicate-module-error')
244
- pf_path = File.join(path, 'Puppetfile')
245
- subject = described_class.new(path, {})
246
- expect {
247
- subject.load!
248
- }.to raise_error(R10K::Error, /Puppetfiles cannot contain duplicate module names/i)
249
- end
169
+ expect(subject.logger).to receive(:warn).
170
+ with(/Mismatch between passed and initialized.*preferring passed value/)
250
171
 
251
- it "wraps and re-raises name errors" do
252
- path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'name-error')
253
- pf_path = File.join(path, 'Puppetfile')
254
- subject = described_class.new(path, {})
255
- expect {
256
- subject.load!
257
- }.to raise_error do |e|
258
- expect_wrapped_error(e, pf_path, NameError)
259
- end
172
+ subject.load('bar')
173
+ loaded_module = subject.modules.first
174
+ expect(loaded_module.version).to eq('bar')
260
175
  end
261
176
 
262
- it "accepts a forge module with a version" do
177
+ it 'does not warn if passed and initialized default_branch_overrides match' do
178
+ # This path doesn't matter so long as it has a Puppetfile within it
263
179
  path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'valid-forge-with-version')
264
- pf_path = File.join(path, 'Puppetfile')
265
- subject = described_class.new(path, {})
266
- expect { subject.load! }.not_to raise_error
267
- end
268
-
269
- it "accepts a forge module without a version" do
270
- path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'valid-forge-without-version')
271
- pf_path = File.join(path, 'Puppetfile')
272
- subject = described_class.new(path, {})
273
- expect { subject.load! }.not_to raise_error
274
- end
275
-
276
- it "creates a git module and applies the default branch sepcified in the Puppetfile" do
277
- path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'default-branch-override')
278
- pf_path = File.join(path, 'Puppetfile')
279
- subject = described_class.new(path, {})
280
- expect { subject.load! }.not_to raise_error
281
- git_module = subject.modules[0]
282
- expect(git_module.default_ref).to eq 'here_lies_the_default_branch'
283
- end
284
-
285
- it "creates a git module and applies the provided default_branch_override" do
286
- path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'default-branch-override')
287
- pf_path = File.join(path, 'Puppetfile')
288
- subject = described_class.new(path, {})
289
- default_branch_override = 'default_branch_override_name'
290
- expect { subject.load!(default_branch_override) }.not_to raise_error
291
- git_module = subject.modules[0]
292
- expect(git_module.default_override_ref).to eq default_branch_override
293
- expect(git_module.default_ref).to eq "here_lies_the_default_branch"
180
+ subject = described_class.new(path, {overrides: {environments: {default_branch_override: 'foo'}}})
181
+
182
+ repo = instance_double('R10K::Git::StatefulRepository')
183
+ allow(repo).to receive(:resolve).with('foo').and_return(true)
184
+ allow(R10K::Git::StatefulRepository).to receive(:new).and_return(repo)
185
+
186
+ allow(subject.loader).to receive(:puppetfile_content).and_return <<-EOPF
187
+ # Track control branch and fall-back to main if no matching branch.
188
+ mod 'hieradata',
189
+ :git => 'git@git.example.com:organization/hieradata.git',
190
+ :branch => :control_branch,
191
+ :default_branch => 'main'
192
+ EOPF
193
+
194
+ expect(subject.logger).not_to receive(:warn).
195
+ with(/Mismatch between passed and initialized.*preferring passed value/)
196
+
197
+ subject.load('foo')
198
+ loaded_module = subject.modules.first
199
+ expect(loaded_module.version).to eq('foo')
294
200
  end
295
201
  end
296
202