r10k 3.9.2 → 3.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec_tests.yml +1 -1
  3. data/.travis.yml +0 -10
  4. data/CHANGELOG.mkd +33 -0
  5. data/README.mkd +6 -0
  6. data/doc/dynamic-environments/configuration.mkd +25 -0
  7. data/doc/dynamic-environments/usage.mkd +26 -0
  8. data/doc/puppetfile.mkd +18 -5
  9. data/integration/Rakefile +3 -1
  10. data/integration/tests/basic_functionality/basic_deployment.rb +176 -0
  11. data/integration/tests/user_scenario/basic_workflow/negative/neg_specify_deleted_forge_module.rb +3 -9
  12. data/integration/tests/user_scenario/basic_workflow/single_env_purge_unmanaged_modules.rb +21 -25
  13. data/integration/tests/user_scenario/complex_workflow/multi_env_add_change_remove.rb +3 -3
  14. data/integration/tests/user_scenario/complex_workflow/multi_env_remove_re-add.rb +3 -3
  15. data/integration/tests/user_scenario/complex_workflow/multi_env_unamanaged.rb +3 -3
  16. data/lib/r10k/action/deploy/environment.rb +17 -2
  17. data/lib/r10k/action/deploy/module.rb +38 -7
  18. data/lib/r10k/action/puppetfile/check.rb +7 -5
  19. data/lib/r10k/action/puppetfile/install.rb +22 -16
  20. data/lib/r10k/action/puppetfile/purge.rb +12 -9
  21. data/lib/r10k/action/runner.rb +45 -10
  22. data/lib/r10k/cli/deploy.rb +5 -0
  23. data/lib/r10k/cli/puppetfile.rb +0 -1
  24. data/lib/r10k/content_synchronizer.rb +16 -4
  25. data/lib/r10k/environment/base.rb +64 -11
  26. data/lib/r10k/environment/with_modules.rb +6 -10
  27. data/lib/r10k/git/cache.rb +1 -1
  28. data/lib/r10k/git/rugged/credentials.rb +77 -0
  29. data/lib/r10k/git/stateful_repository.rb +8 -0
  30. data/lib/r10k/git.rb +3 -0
  31. data/lib/r10k/initializers.rb +4 -0
  32. data/lib/r10k/module/base.rb +42 -1
  33. data/lib/r10k/module/definition.rb +64 -0
  34. data/lib/r10k/module/forge.rb +17 -4
  35. data/lib/r10k/module/git.rb +24 -2
  36. data/lib/r10k/module/local.rb +2 -3
  37. data/lib/r10k/module/svn.rb +12 -1
  38. data/lib/r10k/module.rb +20 -2
  39. data/lib/r10k/module_loader/puppetfile/dsl.rb +42 -0
  40. data/lib/r10k/module_loader/puppetfile.rb +272 -0
  41. data/lib/r10k/puppetfile.rb +82 -160
  42. data/lib/r10k/settings/definition.rb +1 -1
  43. data/lib/r10k/settings.rb +58 -2
  44. data/lib/r10k/source/base.rb +10 -0
  45. data/lib/r10k/source/git.rb +5 -0
  46. data/lib/r10k/source/svn.rb +4 -0
  47. data/lib/r10k/util/purgeable.rb +70 -8
  48. data/lib/r10k/version.rb +1 -1
  49. data/locales/r10k.pot +165 -65
  50. data/r10k.gemspec +2 -0
  51. data/spec/fixtures/unit/action/r10k_forge_auth.yaml +4 -0
  52. data/spec/fixtures/unit/action/r10k_forge_auth_no_url.yaml +3 -0
  53. data/spec/fixtures/unit/puppetfile/forge-override/Puppetfile +8 -0
  54. data/spec/fixtures/unit/puppetfile/various-modules/Puppetfile +9 -0
  55. data/spec/fixtures/unit/puppetfile/various-modules/Puppetfile.new +9 -0
  56. data/spec/fixtures/unit/util/purgeable/managed_one/managed_subdir_1/managed_subdir_2/ignored_1 +0 -0
  57. data/spec/fixtures/unit/util/purgeable/managed_two/.hidden/unmanaged_3 +0 -0
  58. data/spec/r10k-mocks/mock_env.rb +3 -0
  59. data/spec/r10k-mocks/mock_source.rb +7 -3
  60. data/spec/unit/action/deploy/environment_spec.rb +105 -30
  61. data/spec/unit/action/deploy/module_spec.rb +232 -42
  62. data/spec/unit/action/puppetfile/check_spec.rb +17 -5
  63. data/spec/unit/action/puppetfile/install_spec.rb +42 -36
  64. data/spec/unit/action/puppetfile/purge_spec.rb +15 -17
  65. data/spec/unit/action/runner_spec.rb +122 -26
  66. data/spec/unit/environment/base_spec.rb +30 -17
  67. data/spec/unit/environment/git_spec.rb +2 -2
  68. data/spec/unit/environment/svn_spec.rb +4 -3
  69. data/spec/unit/environment/with_modules_spec.rb +2 -1
  70. data/spec/unit/git/cache_spec.rb +14 -0
  71. data/spec/unit/git/rugged/credentials_spec.rb +29 -0
  72. data/spec/unit/git/stateful_repository_spec.rb +5 -0
  73. data/spec/unit/module/base_spec.rb +54 -8
  74. data/spec/unit/module/forge_spec.rb +59 -5
  75. data/spec/unit/module/git_spec.rb +67 -17
  76. data/spec/unit/module/svn_spec.rb +35 -5
  77. data/spec/unit/module_loader/puppetfile_spec.rb +403 -0
  78. data/spec/unit/module_spec.rb +28 -0
  79. data/spec/unit/puppetfile_spec.rb +125 -189
  80. data/spec/unit/settings_spec.rb +47 -2
  81. data/spec/unit/util/purgeable_spec.rb +38 -6
  82. metadata +28 -2
@@ -6,6 +6,13 @@ describe R10K::Module::SVN do
6
6
 
7
7
  include_context 'fail on execution'
8
8
 
9
+ describe "statically determined version support" do
10
+ it 'is unsupported by svn backed modules' do
11
+ static_version = described_class.statically_defined_version('branan/eight_hundred', { svn: 'my/remote', revision: '123adf' })
12
+ expect(static_version).to eq(nil)
13
+ end
14
+ end
15
+
9
16
  describe "determining it implements a Puppetfile mod" do
10
17
  it "implements mods with the :svn hash key" do
11
18
  implements = described_class.implement?('r10k-fixture-repo', :svn => 'https://github.com/adrienthebo/r10k-fixture-repo')
@@ -119,6 +126,23 @@ describe R10K::Module::SVN do
119
126
  end
120
127
  end
121
128
 
129
+ describe 'the default spec dir' do
130
+ let(:module_org) { "coolorg" }
131
+ let(:module_name) { "coolmod" }
132
+ let(:title) { "#{module_org}-#{module_name}" }
133
+ let(:dirname) { Pathname.new(Dir.mktmpdir) }
134
+ let(:spec_path) { dirname + module_name + 'spec' }
135
+ subject { described_class.new(title, dirname, {}) }
136
+
137
+ it 'is kept by default' do
138
+ FileUtils.mkdir_p(spec_path)
139
+ expect(subject).to receive(:status).and_return(:absent)
140
+ expect(subject).to receive(:install).and_return(nil)
141
+ subject.sync
142
+ expect(Dir.exist?(spec_path)).to eq true
143
+ end
144
+ end
145
+
122
146
  describe "synchronizing" do
123
147
 
124
148
  subject { described_class.new('foo', '/moduledir', :svn => 'https://github.com/adrienthebo/r10k-fixture-repo', :rev => 123) }
@@ -132,7 +156,7 @@ describe R10K::Module::SVN do
132
156
 
133
157
  it "installs the SVN module" do
134
158
  expect(subject).to receive(:install)
135
- subject.sync
159
+ expect(subject.sync).to be true
136
160
  end
137
161
  end
138
162
 
@@ -142,14 +166,14 @@ describe R10K::Module::SVN do
142
166
  it "reinstalls the module" do
143
167
  expect(subject).to receive(:reinstall)
144
168
 
145
- subject.sync
169
+ expect(subject.sync).to be true
146
170
  end
147
171
 
148
172
  it "removes the existing directory" do
149
173
  expect(subject.path).to receive(:rmtree)
150
174
  allow(subject).to receive(:install)
151
175
 
152
- subject.sync
176
+ expect(subject.sync).to be true
153
177
  end
154
178
  end
155
179
 
@@ -159,7 +183,7 @@ describe R10K::Module::SVN do
159
183
  it "upgrades the repository" do
160
184
  expect(subject).to receive(:update)
161
185
 
162
- subject.sync
186
+ expect(subject.sync).to be true
163
187
  end
164
188
  end
165
189
 
@@ -171,8 +195,14 @@ describe R10K::Module::SVN do
171
195
  expect(subject).to receive(:reinstall).never
172
196
  expect(subject).to receive(:update).never
173
197
 
174
- subject.sync
198
+ expect(subject.sync).to be false
175
199
  end
176
200
  end
201
+
202
+ it 'and `should_sync?` is false' do
203
+ # modules do not sync if they are not requested
204
+ mod = described_class.new('my_mod', '/path/to/mod', { overrides: { modules: { requested_modules: ['other_mod'] } } })
205
+ expect(mod.sync).to be false
206
+ end
177
207
  end
178
208
  end
@@ -0,0 +1,403 @@
1
+ require 'spec_helper'
2
+ require 'r10k/module_loader/puppetfile'
3
+ require 'tmpdir'
4
+
5
+ describe R10K::ModuleLoader::Puppetfile do
6
+ describe 'initial parameters' do
7
+ describe 'honor' do
8
+ let(:options) do
9
+ {
10
+ basedir: '/test/basedir/env',
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_path)).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_path)).to eq('/test/basedir/env/Puppetfile.global')
47
+ end
48
+ end
49
+
50
+ it 'the overrides' do
51
+ expect(subject.instance_variable_get(:@overrides)).to eq({ modules: { deploy_modules: true }})
52
+ end
53
+
54
+ it 'the environment' do
55
+ expect(subject.instance_variable_get(:@environment).name).to eq('env')
56
+ end
57
+ end
58
+
59
+ describe 'sane defaults' do
60
+ subject { R10K::ModuleLoader::Puppetfile.new(basedir: '/test/basedir') }
61
+
62
+ it 'has a moduledir rooted in the basedir' do
63
+ expect(subject.instance_variable_get(:@moduledir)).to eq('/test/basedir/modules')
64
+ end
65
+
66
+ it 'has a Puppetfile rooted in the basedir' do
67
+ expect(subject.instance_variable_get(:@puppetfile_path)).to eq('/test/basedir/Puppetfile')
68
+ end
69
+
70
+ it 'creates an empty overrides' do
71
+ expect(subject.instance_variable_get(:@overrides)).to eq({})
72
+ end
73
+
74
+ it 'does not require an environment' do
75
+ expect(subject.instance_variable_get(:@environment)).to eq(nil)
76
+ end
77
+ end
78
+ end
79
+
80
+ describe 'adding modules' do
81
+ let(:basedir) { '/test/basedir' }
82
+
83
+ subject { R10K::ModuleLoader::Puppetfile.new(basedir: basedir) }
84
+
85
+ it 'should transform Forge modules with a string arg to have a version key' do
86
+ expect(R10K::Module).to receive(:from_metadata).with('puppet/test_module', subject.moduledir, hash_including(version: '1.2.3'), anything).and_call_original
87
+
88
+ expect { subject.add_module('puppet/test_module', '1.2.3') }.to change { subject.modules }
89
+ expect(subject.modules.collect(&:name)).to include('test_module')
90
+ end
91
+
92
+ it 'should not accept Forge modules with a version comparison' do
93
+ expect(R10K::Module).to receive(:from_metadata).with('puppet/test_module', subject.moduledir, hash_including(version: '< 1.2.0'), anything).and_call_original
94
+
95
+ expect {
96
+ subject.add_module('puppet/test_module', '< 1.2.0')
97
+ }.to raise_error(RuntimeError, /module puppet\/test_module.*doesn't have an implementation/i)
98
+
99
+ expect(subject.modules.collect(&:name)).not_to include('test_module')
100
+ end
101
+
102
+ it 'should set :spec_deletable to true for modules in the basedir' do
103
+ module_opts = { git: 'git@example.com:puppet/test_module.git' }
104
+ subject.add_module('puppet/test_module', module_opts)
105
+ expect(subject.modules[0].spec_deletable).to be true
106
+ end
107
+
108
+ it 'should set :spec_deletable to false for modules outside the basedir' do
109
+ module_opts = { git: 'git@example.com:puppet/test_module.git', install_path: 'some/path' }
110
+ subject.add_module('puppet/test_module', module_opts)
111
+ expect(subject.modules[0].spec_deletable).to be false
112
+ end
113
+
114
+ it 'should accept non-Forge modules with a hash arg' do
115
+ module_opts = { git: 'git@example.com:puppet/test_module.git' }
116
+
117
+ expect(R10K::Module).to receive(:from_metadata).with('puppet/test_module', subject.moduledir, 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 accept non-Forge modules with a valid relative :install_path option' do
124
+ module_opts = {
125
+ install_path: 'vendor',
126
+ git: 'git@example.com:puppet/test_module.git',
127
+ }
128
+
129
+ expect(R10K::Module).to receive(:from_metadata).with('puppet/test_module', File.join(basedir, 'vendor'), module_opts, anything).and_call_original
130
+
131
+ expect { subject.add_module('puppet/test_module', module_opts) }.to change { subject.modules }
132
+ expect(subject.modules.collect(&:name)).to include('test_module')
133
+ end
134
+
135
+ it 'should accept non-Forge modules with a valid absolute :install_path option' do
136
+ install_path = File.join(basedir, 'vendor')
137
+
138
+ module_opts = {
139
+ install_path: install_path,
140
+ git: 'git@example.com:puppet/test_module.git',
141
+ }
142
+
143
+ expect(R10K::Module).to receive(:from_metadata).with('puppet/test_module', install_path, module_opts, anything).and_call_original
144
+
145
+ expect { subject.add_module('puppet/test_module', module_opts) }.to change { subject.modules }
146
+ expect(subject.modules.collect(&:name)).to include('test_module')
147
+ end
148
+
149
+ it 'should reject non-Forge modules with an invalid relative :install_path option' do
150
+ module_opts = {
151
+ install_path: '../../vendor',
152
+ git: 'git@example.com:puppet/test_module.git',
153
+ }
154
+
155
+ 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 }
156
+ end
157
+
158
+ it 'should reject non-Forge modules with an invalid absolute :install_path option' do
159
+ module_opts = {
160
+ install_path: '/tmp/mydata/vendor',
161
+ git: 'git@example.com:puppet/test_module.git',
162
+ }
163
+
164
+ 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 }
165
+ end
166
+
167
+ it 'should disable and not add modules that conflict with the environment' do
168
+ env = instance_double('R10K::Environment::Base')
169
+ mod = instance_double('R10K::Module::Base', name: 'conflict', origin: :puppetfile, 'origin=': nil)
170
+ loader = R10K::ModuleLoader::Puppetfile.new(basedir: basedir, environment: env)
171
+ allow(env).to receive(:'module_conflicts?').with(mod).and_return(true)
172
+ allow(mod).to receive(:spec_deletable=)
173
+
174
+ expect(R10K::Module).to receive(:from_metadata).with('conflict', anything, anything, anything).and_return(mod)
175
+ expect { loader.add_module('conflict', {}) }.not_to change { loader.modules }
176
+ end
177
+ end
178
+
179
+ describe '#purge_exclusions' do
180
+ let(:managed_dirs) { ['dir1', 'dir2'] }
181
+ subject { R10K::ModuleLoader::Puppetfile.new(basedir: '/test/basedir') }
182
+
183
+ it 'includes managed_directories' do
184
+ expect(subject.send(:determine_purge_exclusions, managed_dirs)).to match_array(managed_dirs)
185
+ end
186
+
187
+ context 'when belonging to an environment' do
188
+ let(:env_contents) { ['env1', 'env2' ] }
189
+ let(:env) { double(:environment, desired_contents: env_contents) }
190
+
191
+ subject { R10K::ModuleLoader::Puppetfile.new(basedir: '/test/basedir', environment: env) }
192
+
193
+ it "includes environment's desired_contents" do
194
+ expect(subject.send(:determine_purge_exclusions, managed_dirs)).to match_array(managed_dirs + env_contents)
195
+ end
196
+ end
197
+ end
198
+
199
+ describe '#managed_directories' do
200
+
201
+ let(:basedir) { '/test/basedir' }
202
+ subject { R10K::ModuleLoader::Puppetfile.new(basedir: basedir) }
203
+
204
+ before do
205
+ allow(subject).to receive(:puppetfile_content).and_return('')
206
+ end
207
+
208
+ it 'returns an array of paths that #purge! will operate within' do
209
+ expect(R10K::Module).to receive(:from_metadata).with('puppet/test_module', subject.moduledir, hash_including(version: '1.2.3'), anything).and_call_original
210
+ subject.add_module('puppet/test_module', '1.2.3')
211
+ subject.load!
212
+
213
+ expect(subject.modules.length).to be 1
214
+ expect(subject.managed_directories).to match_array([subject.moduledir])
215
+ end
216
+
217
+ context "with a module with install_path == ''" do
218
+ it "basedir isn't in the list of paths to purge" do
219
+ module_opts = { install_path: '', git: 'git@example.com:puppet/test_module.git' }
220
+
221
+ expect(R10K::Module).to receive(:from_metadata).with('puppet/test_module', basedir, module_opts, anything).and_call_original
222
+ subject.add_module('puppet/test_module', module_opts)
223
+ subject.load!
224
+
225
+ expect(subject.modules.length).to be 1
226
+ expect(subject.managed_directories).to be_empty
227
+ end
228
+ end
229
+ end
230
+
231
+ describe 'evaluating a Puppetfile' do
232
+ def expect_wrapped_error(error, pf_path, error_type)
233
+ expect(error).to be_a_kind_of(R10K::Error)
234
+ expect(error.message).to eq("Failed to evaluate #{pf_path}")
235
+ expect(error.original).to be_a_kind_of(error_type)
236
+ end
237
+
238
+ subject { described_class.new(basedir: @path) }
239
+
240
+ it 'wraps and re-raises syntax errors' do
241
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'invalid-syntax')
242
+ pf_path = File.join(@path, 'Puppetfile')
243
+ expect {
244
+ subject.load!
245
+ }.to raise_error do |e|
246
+ expect_wrapped_error(e, pf_path, SyntaxError)
247
+ end
248
+ end
249
+
250
+ it 'wraps and re-raises load errors' do
251
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'load-error')
252
+ pf_path = File.join(@path, 'Puppetfile')
253
+ expect {
254
+ subject.load!
255
+ }.to raise_error do |e|
256
+ expect_wrapped_error(e, pf_path, LoadError)
257
+ end
258
+ end
259
+
260
+ it 'wraps and re-raises argument errors' do
261
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'argument-error')
262
+ pf_path = File.join(@path, 'Puppetfile')
263
+ expect {
264
+ subject.load!
265
+ }.to raise_error do |e|
266
+ expect_wrapped_error(e, pf_path, ArgumentError)
267
+ end
268
+ end
269
+
270
+ describe 'forge declaration' do
271
+ before(:each) do
272
+ PuppetForge.host = ""
273
+ end
274
+
275
+ it 'is respected if `allow_puppetfile_override` is true' do
276
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'forge-override')
277
+ puppetfile = R10K::ModuleLoader::Puppetfile.new(basedir: @path, overrides: { forge: { allow_puppetfile_override: true } })
278
+ puppetfile.load!
279
+ expect(PuppetForge.host).to eq("my.custom.forge.com/")
280
+ end
281
+
282
+ it 'is ignored if `allow_puppetfile_override` is false' do
283
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'forge-override')
284
+ puppetfile = R10K::ModuleLoader::Puppetfile.new(basedir: @path, overrides: { forge: { allow_puppetfile_override: false } })
285
+ expect(PuppetForge).not_to receive(:host=).with("my.custom.forge.com")
286
+ puppetfile.load!
287
+ expect(PuppetForge.host).to eq("/")
288
+ end
289
+ end
290
+
291
+ it 'rejects Puppetfiles with duplicate module names' do
292
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'duplicate-module-error')
293
+ pf_path = File.join(@path, 'Puppetfile')
294
+ expect {
295
+ subject.load!
296
+ }.to raise_error(R10K::Error, /Puppetfiles cannot contain duplicate module names/i)
297
+ end
298
+
299
+ it 'wraps and re-raises name errors' do
300
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'name-error')
301
+ pf_path = File.join(@path, 'Puppetfile')
302
+ expect {
303
+ subject.load!
304
+ }.to raise_error do |e|
305
+ expect_wrapped_error(e, pf_path, NameError)
306
+ end
307
+ end
308
+
309
+ it 'accepts a forge module with a version' do
310
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'valid-forge-with-version')
311
+ pf_path = File.join(@path, 'Puppetfile')
312
+ expect { subject.load! }.not_to raise_error
313
+ end
314
+
315
+ describe 'setting a custom moduledir' do
316
+ it 'allows setting an absolute moduledir' do
317
+ @path = '/fake/basedir'
318
+ allow(subject).to receive(:puppetfile_content).and_return('moduledir "/fake/moduledir"')
319
+ subject.load!
320
+ expect(subject.instance_variable_get(:@moduledir)).to eq('/fake/moduledir')
321
+ end
322
+
323
+ it 'roots relative moduledirs in the basedir' do
324
+ @path = '/fake/basedir'
325
+ allow(subject).to receive(:puppetfile_content).and_return('moduledir "my/moduledir"')
326
+ subject.load!
327
+ expect(subject.instance_variable_get(:@moduledir)).to eq(File.join(@path, 'my/moduledir'))
328
+ end
329
+ end
330
+
331
+ it 'accepts a forge module without a version' do
332
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'valid-forge-without-version')
333
+ pf_path = File.join(@path, 'Puppetfile')
334
+ expect { subject.load! }.not_to raise_error
335
+ end
336
+
337
+ it 'creates a git module and applies the default branch specified in the Puppetfile' do
338
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'default-branch-override')
339
+ pf_path = File.join(@path, 'Puppetfile')
340
+ expect { subject.load! }.not_to raise_error
341
+ git_module = subject.modules[0]
342
+ expect(git_module.default_ref).to eq 'here_lies_the_default_branch'
343
+ end
344
+
345
+ it 'creates a git module and applies the provided default_branch_override' do
346
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'default-branch-override')
347
+ pf_path = File.join(@path, 'Puppetfile')
348
+ default_branch_override = 'default_branch_override_name'
349
+ subject.default_branch_override = default_branch_override
350
+ expect { subject.load! }.not_to raise_error
351
+ git_module = subject.modules[0]
352
+ expect(git_module.default_override_ref).to eq default_branch_override
353
+ expect(git_module.default_ref).to eq 'here_lies_the_default_branch'
354
+ end
355
+
356
+ describe 'using module metadata' do
357
+ it 'properly loads module metadata' do
358
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'various-modules')
359
+ metadata = subject.load_metadata[:modules].map { |mod| [ mod.name, mod.version ] }.to_h
360
+ expect(metadata['apt']).to eq('2.1.1')
361
+ expect(metadata['stdlib']).to eq(nil)
362
+ expect(metadata['concat']).to eq(nil)
363
+ expect(metadata['rpm']).to eq('2.1.1-pre1')
364
+ expect(metadata['foo']).to eq(nil)
365
+ expect(metadata['bar']).to eq('v1.2.3')
366
+ expect(metadata['baz']).to eq('123abc456')
367
+ expect(metadata['fizz']).to eq('1234567890abcdef1234567890abcdef12345678')
368
+ expect(metadata['buzz']).to eq(nil)
369
+ end
370
+
371
+ it 'does not load module implementations for static versioned' do
372
+ @path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'various-modules')
373
+ subject.load_metadata
374
+ modules = subject.load[:modules].map { |mod| [ mod.name, mod ] }.to_h
375
+ expect(modules['apt']).to be_a_kind_of(R10K::Module::Definition)
376
+ expect(modules['stdlib']).to be_a_kind_of(R10K::Module::Forge)
377
+ expect(modules['concat']).to be_a_kind_of(R10K::Module::Forge)
378
+ expect(modules['rpm']).to be_a_kind_of(R10K::Module::Definition)
379
+ expect(modules['foo']).to be_a_kind_of(R10K::Module::Git)
380
+ expect(modules['bar']).to be_a_kind_of(R10K::Module::Definition)
381
+ expect(modules['baz']).to be_a_kind_of(R10K::Module::Definition)
382
+ expect(modules['fizz']).to be_a_kind_of(R10K::Module::Definition)
383
+ expect(modules['buzz']).to be_a_kind_of(R10K::Module::Git)
384
+ end
385
+
386
+ it 'loads module implementations whose static versions are different' do
387
+ fixture_path = File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'puppetfile', 'various-modules')
388
+ @path = Dir.mktmpdir
389
+ unsynced_pf_path = File.join(fixture_path, 'Puppetfile')
390
+ FileUtils.cp(unsynced_pf_path, @path)
391
+
392
+ subject.load_metadata
393
+
394
+ synced_pf_path = File.join(fixture_path, 'Puppetfile.new')
395
+ FileUtils.cp(synced_pf_path, File.join(@path, 'Puppetfile'))
396
+
397
+ modules = subject.load[:modules].map { |mod| [ mod.name, mod ] }.to_h
398
+
399
+ expect(modules['apt']).to be_a_kind_of(R10K::Module::Forge)
400
+ end
401
+ end
402
+ end
403
+ end