r10k 3.9.3 → 3.10.0

Sign up to get free protection for your applications and to get access to all the features.
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
data/lib/r10k/version.rb CHANGED
@@ -2,5 +2,5 @@ module R10K
2
2
  # When updating to a new major (X) or minor (Y) version, include `#major` or
3
3
  # `#minor` (respectively) in your commit message to trigger the appropriate
4
4
  # release. Otherwise, a new patch (Z) version will be released.
5
- VERSION = '3.9.3'
5
+ VERSION = '3.10.0'
6
6
  end
data/locales/r10k.pot CHANGED
@@ -6,11 +6,11 @@
6
6
  #, fuzzy
7
7
  msgid ""
8
8
  msgstr ""
9
- "Project-Id-Version: r10k 3.4.1-231-g5574915\n"
9
+ "Project-Id-Version: r10k 3.9.3-10-gfedc81a\n"
10
10
  "\n"
11
11
  "Report-Msgid-Bugs-To: docs@puppetlabs.com\n"
12
- "POT-Creation-Date: 2021-05-10 23:18+0000\n"
13
- "PO-Revision-Date: 2021-05-10 23:18+0000\n"
12
+ "POT-Creation-Date: 2021-07-07 21:13+0000\n"
13
+ "PO-Revision-Date: 2021-07-07 21:13+0000\n"
14
14
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
15
15
  "Language-Team: LANGUAGE <LL@li.org>\n"
16
16
  "Language: \n"
@@ -31,31 +31,31 @@ msgstr ""
31
31
  msgid "Reason: %{write_lock}"
32
32
  msgstr ""
33
33
 
34
- #: ../lib/r10k/action/deploy/environment.rb:109
34
+ #: ../lib/r10k/action/deploy/environment.rb:112
35
35
  msgid "Environment(s) \\'%{environments}\\' cannot be found in any source and will not be deployed."
36
36
  msgstr ""
37
37
 
38
- #: ../lib/r10k/action/deploy/environment.rb:139
38
+ #: ../lib/r10k/action/deploy/environment.rb:145
39
39
  msgid "Environment %{env_dir} does not match environment name filter, skipping"
40
40
  msgstr ""
41
41
 
42
- #: ../lib/r10k/action/deploy/environment.rb:147
42
+ #: ../lib/r10k/action/deploy/environment.rb:153
43
43
  msgid "Deploying environment %{env_path}"
44
44
  msgstr ""
45
45
 
46
- #: ../lib/r10k/action/deploy/environment.rb:150
46
+ #: ../lib/r10k/action/deploy/environment.rb:156
47
47
  msgid "Environment %{env_dir} is now at %{env_signature}"
48
48
  msgstr ""
49
49
 
50
- #: ../lib/r10k/action/deploy/environment.rb:154
50
+ #: ../lib/r10k/action/deploy/environment.rb:160
51
51
  msgid "Environment %{env_dir} is new, updating all modules"
52
52
  msgstr ""
53
53
 
54
- #: ../lib/r10k/action/deploy/module.rb:78
54
+ #: ../lib/r10k/action/deploy/module.rb:81
55
55
  msgid "Only updating modules in environment(s) %{opt_env} skipping environment %{env_path}"
56
56
  msgstr ""
57
57
 
58
- #: ../lib/r10k/action/deploy/module.rb:80
58
+ #: ../lib/r10k/action/deploy/module.rb:83
59
59
  msgid "Updating modules %{modules} in environment %{env_path}"
60
60
  msgstr ""
61
61
 
@@ -75,15 +75,15 @@ msgstr ""
75
75
  msgid "No config file explicitly given and no default config file could be found, default settings will be used."
76
76
  msgstr ""
77
77
 
78
- #: ../lib/r10k/content_synchronizer.rb:13
78
+ #: ../lib/r10k/content_synchronizer.rb:27
79
79
  msgid "Updating modules with %{pool_size} threads"
80
80
  msgstr ""
81
81
 
82
- #: ../lib/r10k/content_synchronizer.rb:24
82
+ #: ../lib/r10k/content_synchronizer.rb:37
83
83
  msgid "Error during concurrent deploy of a module: %{message}"
84
84
  msgstr ""
85
85
 
86
- #: ../lib/r10k/content_synchronizer.rb:52
86
+ #: ../lib/r10k/content_synchronizer.rb:75
87
87
  msgid "Module thread %{id} exiting: %{message}"
88
88
  msgstr ""
89
89
 
@@ -95,7 +95,7 @@ msgstr ""
95
95
  msgid "Unable to load sources; the supplied configuration does not define the 'sources' key"
96
96
  msgstr ""
97
97
 
98
- #: ../lib/r10k/environment/base.rb:65 ../lib/r10k/environment/base.rb:81 ../lib/r10k/environment/base.rb:90 ../lib/r10k/source/base.rb:69
98
+ #: ../lib/r10k/environment/base.rb:68 ../lib/r10k/environment/base.rb:84 ../lib/r10k/environment/base.rb:93 ../lib/r10k/source/base.rb:83
99
99
  msgid "%{class} has not implemented method %{method}"
100
100
  msgstr ""
101
101
 
@@ -103,15 +103,15 @@ msgstr ""
103
103
  msgid "Improper configuration value given for strip_component setting in %{src} source. Value must be a string, a /regex/, false, or omitted. Got \"%{val}\" (%{type})"
104
104
  msgstr ""
105
105
 
106
- #: ../lib/r10k/environment/with_modules.rb:60
106
+ #: ../lib/r10k/environment/with_modules.rb:57
107
107
  msgid "Environment and %{src} both define the \"%{name}\" module"
108
108
  msgstr ""
109
109
 
110
- #: ../lib/r10k/environment/with_modules.rb:61
110
+ #: ../lib/r10k/environment/with_modules.rb:58
111
111
  msgid "#{msg_error}. The %{src} definition will be ignored"
112
112
  msgstr ""
113
113
 
114
- #: ../lib/r10k/environment/with_modules.rb:71
114
+ #: ../lib/r10k/environment/with_modules.rb:68
115
115
  msgid "Unexpected value for `module_conflicts` setting in %{env} environment: %{val}"
116
116
  msgstr ""
117
117
 
@@ -331,11 +331,15 @@ msgstr ""
331
331
  msgid "Module name (%{title}) must match either 'modulename' or 'owner/modulename'"
332
332
  msgstr ""
333
333
 
334
- #: ../lib/r10k/module/forge.rb:88 ../lib/r10k/module/forge.rb:117
334
+ #: ../lib/r10k/module/forge.rb:89
335
+ msgid "The module %{title} does not appear to have any published releases, cannot determine latest version."
336
+ msgstr ""
337
+
338
+ #: ../lib/r10k/module/forge.rb:92 ../lib/r10k/module/forge.rb:121
335
339
  msgid "The module %{title} does not exist on %{url}."
336
340
  msgstr ""
337
341
 
338
- #: ../lib/r10k/module/forge.rb:192
342
+ #: ../lib/r10k/module/forge.rb:196
339
343
  msgid "Forge module names must match 'owner/modulename', instead got #{title}"
340
344
  msgstr ""
341
345
 
@@ -371,7 +375,7 @@ msgstr ""
371
375
  msgid "Remove the duplicates of the following modules: %{dupes}"
372
376
  msgstr ""
373
377
 
374
- #: ../lib/r10k/puppetfile.rb:276
378
+ #: ../lib/r10k/puppetfile.rb:285
375
379
  msgid "unrecognized declaration '%{method}'"
376
380
  msgstr ""
377
381
 
@@ -454,27 +458,27 @@ msgid ""
454
458
  "Returned: %{data}"
455
459
  msgstr ""
456
460
 
457
- #: ../lib/r10k/source/git.rb:77
461
+ #: ../lib/r10k/source/git.rb:75
458
462
  msgid "Fetching '%{remote}' to determine current branches."
459
463
  msgstr ""
460
464
 
461
- #: ../lib/r10k/source/git.rb:80
465
+ #: ../lib/r10k/source/git.rb:78
462
466
  msgid "Unable to determine current branches for Git source '%{name}' (%{basedir})"
463
467
  msgstr ""
464
468
 
465
- #: ../lib/r10k/source/git.rb:110
469
+ #: ../lib/r10k/source/git.rb:113
466
470
  msgid "Environment %{env_name} contained non-word characters, correcting name to %{corrected_env_name}"
467
471
  msgstr ""
468
472
 
469
- #: ../lib/r10k/source/git.rb:119
473
+ #: ../lib/r10k/source/git.rb:122
470
474
  msgid "Environment %{env_name} contained non-word characters, ignoring it."
471
475
  msgstr ""
472
476
 
473
- #: ../lib/r10k/source/git.rb:138 ../lib/r10k/source/svn.rb:113
477
+ #: ../lib/r10k/source/git.rb:141 ../lib/r10k/source/svn.rb:115
474
478
  msgid "Branch %{branch} filtered out by ignore_branch_prefixes %{ibp}"
475
479
  msgstr ""
476
480
 
477
- #: ../lib/r10k/source/git.rb:149
481
+ #: ../lib/r10k/source/git.rb:152
478
482
  msgid "Branch `%{name}:%{branch}` filtered out by filter_command %{cmd}"
479
483
  msgstr ""
480
484
 
@@ -518,23 +522,23 @@ msgstr ""
518
522
  msgid "pe_license feature is not available, PE only Puppet modules will not be downloadable."
519
523
  msgstr ""
520
524
 
521
- #: ../lib/r10k/util/purgeable.rb:52
522
- msgid "Not purging %{item} due to internal exclusion match: %{exclusion_match}"
525
+ #: ../lib/r10k/util/purgeable.rb:87
526
+ msgid "Not purging %{path} due to internal exclusion match: %{exclusion_match}"
523
527
  msgstr ""
524
528
 
525
- #: ../lib/r10k/util/purgeable.rb:54
526
- msgid "Not purging %{item} due to whitelist match: %{whitelist_match}"
529
+ #: ../lib/r10k/util/purgeable.rb:89
530
+ msgid "Not purging %{path} due to whitelist match: %{allowlist_match}"
527
531
  msgstr ""
528
532
 
529
- #: ../lib/r10k/util/purgeable.rb:71
533
+ #: ../lib/r10k/util/purgeable.rb:133
530
534
  msgid "No unmanaged contents in %{managed_dirs}, nothing to purge"
531
535
  msgstr ""
532
536
 
533
- #: ../lib/r10k/util/purgeable.rb:76
537
+ #: ../lib/r10k/util/purgeable.rb:138
534
538
  msgid "Removing unmanaged path %{path}"
535
539
  msgstr ""
536
540
 
537
- #: ../lib/r10k/util/purgeable.rb:81
541
+ #: ../lib/r10k/util/purgeable.rb:143
538
542
  msgid "Unable to remove unmanaged path: %{path}"
539
543
  msgstr ""
540
544
 
@@ -0,0 +1,4 @@
1
+ ---
2
+ forge:
3
+ baseurl: 'http://private-forge.com'
4
+ authorization_token: 'faketoken'
@@ -0,0 +1,3 @@
1
+ ---
2
+ forge:
3
+ authorization_token: 'faketoken'
@@ -265,6 +265,15 @@ describe R10K::Action::Deploy::Environment do
265
265
  describe "deployment purge level" do
266
266
  let(:purge_levels) { [:deployment] }
267
267
 
268
+
269
+ it "updates the source's cache before it purges environments" do
270
+ deployment.sources.each do |source|
271
+ expect(source).to receive(:reload!).ordered
272
+ end
273
+ expect(deployment).to receive(:purge!).ordered
274
+ subject.call
275
+ end
276
+
268
277
  it "only logs about purging deployment" do
269
278
  expect(subject).to receive(:visit_environment).and_wrap_original do |original, env, &block|
270
279
  expect(env.logger).to_not receive(:debug).with(/purging unmanaged puppetfile content/i)
@@ -182,7 +182,7 @@ describe R10K::Action::Deploy::Module do
182
182
  subject { described_class.new({ config: '/some/nonexistent/path' }, ['mod1', 'mod2'], {}) }
183
183
 
184
184
  let(:cache) { instance_double("R10K::Git::Cache", 'sanitized_dirname' => 'foo', 'cached?' => true, 'sync' => true) }
185
- let(:repo) { instance_double("R10K::Git::StatefulRepository", cache: cache, resolve: 'main') }
185
+ let(:repo) { instance_double("R10K::Git::StatefulRepository", cache: cache, resolve: 'main', tracked_paths: []) }
186
186
 
187
187
  it 'does not sync modules not given' do
188
188
  allow(R10K::Deployment).to receive(:new).and_wrap_original do |original, settings, &block|
@@ -202,14 +202,26 @@ describe R10K::Action::Deploy::Module do
202
202
  allow_any_instance_of(R10K::Source::Git).to receive(:branch_names).and_return([R10K::Environment::Name.new('first', {})])
203
203
 
204
204
  expect(subject).to receive(:visit_environment).and_wrap_original do |original, environment, &block|
205
- pf = environment.puppetfile
206
- expect(pf).to receive(:load) do
207
- pf.add_module('mod1', { git: 'git://remote' })
208
- pf.add_module('mod2', { git: 'git://remote' })
209
- pf.add_module('mod3', { git: 'git://remote' })
205
+ # For this test we want to have realistic Modules and access to
206
+ # their internal Repos to validate the sync. Unfortunately, to
207
+ # do so we do some invasive mocking, effectively implementing
208
+ # our own R10K::Puppetfile#load. We directly update the Puppetfile's
209
+ # internal ModuleLoader and then call `load` on it so it will create
210
+ # the correct loaded_content.
211
+ puppetfile = environment.puppetfile
212
+ loader = puppetfile.loader
213
+ expect(puppetfile).to receive(:load) do
214
+ loader.add_module('mod1', { git: 'git://remote' })
215
+ loader.add_module('mod2', { git: 'git://remote' })
216
+ loader.add_module('mod3', { git: 'git://remote' })
217
+
218
+ allow(loader).to receive(:puppetfile_content).and_return('')
219
+ loaded_content = loader.load
220
+ puppetfile.instance_variable_set(:@loaded_content, loaded_content)
221
+ puppetfile.instance_variable_set(:@loaded, true)
210
222
  end
211
223
 
212
- pf.modules.each do |mod|
224
+ puppetfile.modules.each do |mod|
213
225
  if ['mod1', 'mod2'].include?(mod.name)
214
226
  expect(mod.should_sync?).to be(true)
215
227
  else
@@ -231,7 +243,7 @@ describe R10K::Action::Deploy::Module do
231
243
  subject { described_class.new({ config: '/some/nonexistent/path', environment: 'first' }, ['mod1'], {}) }
232
244
 
233
245
  let(:cache) { instance_double("R10K::Git::Cache", 'sanitized_dirname' => 'foo', 'cached?' => true, 'sync' => true) }
234
- let(:repo) { instance_double("R10K::Git::StatefulRepository", cache: cache, resolve: 'main') }
246
+ let(:repo) { instance_double("R10K::Git::StatefulRepository", cache: cache, resolve: 'main', tracked_paths: []) }
235
247
 
236
248
  it 'only syncs to the given environments' do
237
249
  allow(R10K::Deployment).to receive(:new).and_wrap_original do |original, settings, &block|
@@ -252,15 +264,27 @@ describe R10K::Action::Deploy::Module do
252
264
  R10K::Environment::Name.new('second', {})])
253
265
 
254
266
  expect(subject).to receive(:visit_environment).and_wrap_original do |original, environment, &block|
255
- pf = environment.puppetfile
267
+ puppetfile = environment.puppetfile
256
268
 
257
269
  if environment.name == 'first'
258
- expect(pf).to receive(:load) do
259
- pf.add_module('mod1', { git: 'git://remote' })
260
- pf.add_module('mod2', { git: 'git://remote' })
270
+ # For this test we want to have realistic Modules and access to
271
+ # their internal Repos to validate the sync. Unfortunately, to
272
+ # do so we do some invasive mocking, effectively implementing
273
+ # our own R10K::Puppetfile#load. We directly update the Puppetfile's
274
+ # internal ModuleLoader and then call `load` on it so it will create
275
+ # the correct loaded_content.
276
+ loader = puppetfile.loader
277
+ expect(puppetfile).to receive(:load) do
278
+ loader.add_module('mod1', { git: 'git://remote' })
279
+ loader.add_module('mod2', { git: 'git://remote' })
280
+
281
+ allow(loader).to receive(:puppetfile_content).and_return('')
282
+ loaded_content = loader.load
283
+ puppetfile.instance_variable_set(:@loaded_content, loaded_content)
284
+ puppetfile.instance_variable_set(:@loaded, true)
261
285
  end
262
286
 
263
- pf.modules.each do |mod|
287
+ puppetfile.modules.each do |mod|
264
288
  if mod.name == 'mod1'
265
289
  expect(mod.should_sync?).to be(true)
266
290
  else
@@ -269,7 +293,7 @@ describe R10K::Action::Deploy::Module do
269
293
  expect(mod).to receive(:sync).and_call_original
270
294
  end
271
295
  else
272
- expect(pf).not_to receive(:load)
296
+ expect(puppetfile).not_to receive(:load)
273
297
  end
274
298
 
275
299
  original.call(environment, &block)
@@ -218,42 +218,66 @@ describe R10K::Action::Runner do
218
218
  end
219
219
 
220
220
  describe "configuration authorization" do
221
- context "when license is not present" do
222
- before(:each) do
223
- expect(R10K::Util::License).to receive(:load).and_return(nil)
221
+ context "settings auth" do
222
+ it "sets the configured token as the forge authorization header" do
223
+ options = { config: "spec/fixtures/unit/action/r10k_forge_auth.yaml" }
224
+ runner = described_class.new(options, %w[args yes], action_class)
225
+
226
+ expect(PuppetForge).to receive(:host=).with('http://private-forge.com')
227
+ expect(PuppetForge::Connection).to receive(:authorization=).with('faketoken')
228
+ expect(PuppetForge::Connection).to receive(:authorization).and_return('faketoken')
229
+ expect(R10K::Util::License).not_to receive(:load)
230
+ runner.setup_settings
231
+ runner.setup_authorization
224
232
  end
225
233
 
226
- it "does not set authorization header on connection class" do
227
- expect(PuppetForge::Connection).not_to receive(:authorization=)
228
- runner.setup_authorization
234
+ it 'errors if no custom forge URL is set' do
235
+ options = { config: "spec/fixtures/unit/action/r10k_forge_auth_no_url.yaml" }
236
+ runner = described_class.new(options, %w[args yes], action_class)
237
+ expect(PuppetForge::Connection).not_to receive(:authorization=).with('faketoken')
238
+
239
+ expect { runner.setup_settings }.to raise_error(R10K::Error, /Cannot specify a Forge auth/)
229
240
  end
230
241
  end
231
242
 
232
- context "when license is present but invalid" do
233
- before(:each) do
234
- expect(R10K::Util::License).to receive(:load).and_raise(R10K::Error.new('invalid license'))
235
- end
243
+ context "license auth" do
244
+ context "when license is not present" do
245
+ before(:each) do
246
+ expect(R10K::Util::License).to receive(:load).and_return(nil)
247
+ end
236
248
 
237
- it "issues warning to logger" do
238
- expect(runner.logger).to receive(:warn).with(/invalid license/)
239
- runner.setup_authorization
249
+ it "does not set authorization header on connection class" do
250
+ expect(PuppetForge::Connection).not_to receive(:authorization=)
251
+ runner.setup_authorization
252
+ end
240
253
  end
241
254
 
242
- it "does not set authorization header on connection class" do
243
- expect(PuppetForge::Connection).not_to receive(:authorization=)
244
- runner.setup_authorization
245
- end
246
- end
255
+ context "when license is present but invalid" do
256
+ before(:each) do
257
+ expect(R10K::Util::License).to receive(:load).and_raise(R10K::Error.new('invalid license'))
258
+ end
247
259
 
248
- context "when license is present and valid" do
249
- before(:each) do
250
- mock_license = double('pe-license', :authorization_token => 'test token')
251
- expect(R10K::Util::License).to receive(:load).and_return(mock_license)
260
+ it "issues warning to logger" do
261
+ expect(runner.logger).to receive(:warn).with(/invalid license/)
262
+ runner.setup_authorization
263
+ end
264
+
265
+ it "does not set authorization header on connection class" do
266
+ expect(PuppetForge::Connection).not_to receive(:authorization=)
267
+ runner.setup_authorization
268
+ end
252
269
  end
253
270
 
254
- it "sets authorization header on connection class" do
255
- expect(PuppetForge::Connection).to receive(:authorization=).with('test token')
256
- runner.setup_authorization
271
+ context "when license is present and valid" do
272
+ before(:each) do
273
+ mock_license = double('pe-license', :authorization_token => 'test token')
274
+ expect(R10K::Util::License).to receive(:load).and_return(mock_license)
275
+ end
276
+
277
+ it "sets authorization header on connection class" do
278
+ expect(PuppetForge::Connection).to receive(:authorization=).with('test token')
279
+ runner.setup_authorization
280
+ end
257
281
  end
258
282
  end
259
283
  end
@@ -62,4 +62,18 @@ describe R10K::Git::Cache do
62
62
  subject.cached?
63
63
  end
64
64
  end
65
+
66
+ describe "dirname sanitization" do
67
+ it 'sanitizes cache directory name' do
68
+ expect(subject.sanitized_dirname).to eq('git---some-git-remote')
69
+ end
70
+
71
+ context 'with username and password' do
72
+ subject { subclass.new('https://"user:pa$$w0rd:@some/git/remote') }
73
+
74
+ it 'sanitizes cache directory name' do
75
+ expect(subject.sanitized_dirname).to eq('https---some-git-remote')
76
+ end
77
+ end
78
+ end
65
79
  end
@@ -104,9 +104,16 @@ describe R10K::Module::Forge do
104
104
 
105
105
  it "uses the latest version from the forge when the version is :latest" do
106
106
  subject = described_class.new('branan/eight_hundred', fixture_modulepath, { version: :latest })
107
- expect(subject.v3_module).to receive_message_chain(:current_release, :version).and_return('8.8.8')
107
+ release = double("Module Release", version: '8.8.8')
108
+ expect(subject.v3_module).to receive(:current_release).and_return(release).twice
108
109
  expect(subject.expected_version).to eq '8.8.8'
109
110
  end
111
+
112
+ it "throws when there are no available versions" do
113
+ subject = described_class.new('branan/eight_hundred', fixture_modulepath, { version: :latest })
114
+ expect(subject.v3_module).to receive(:current_release).and_return(nil)
115
+ expect { subject.expected_version }.to raise_error(PuppetForge::ReleaseNotFound)
116
+ end
110
117
  end
111
118
 
112
119
  describe "determining the status" do