r10k 3.9.0 → 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.
- checksums.yaml +4 -4
- data/.github/pull_request_template.md +1 -1
- data/.github/workflows/rspec_tests.yml +1 -1
- data/.github/workflows/stale.yml +19 -0
- data/CHANGELOG.mkd +24 -0
- data/doc/dynamic-environments/configuration.mkd +13 -6
- data/integration/Rakefile +1 -1
- data/integration/tests/user_scenario/basic_workflow/negative/neg_specify_deleted_forge_module.rb +3 -9
- data/integration/tests/user_scenario/basic_workflow/single_env_purge_unmanaged_modules.rb +8 -14
- data/lib/r10k/action/base.rb +10 -0
- data/lib/r10k/action/deploy/display.rb +42 -9
- data/lib/r10k/action/deploy/environment.rb +70 -41
- data/lib/r10k/action/deploy/module.rb +51 -29
- data/lib/r10k/action/puppetfile/check.rb +3 -1
- data/lib/r10k/action/puppetfile/install.rb +20 -23
- data/lib/r10k/action/puppetfile/purge.rb +8 -2
- data/lib/r10k/action/runner.rb +11 -6
- data/lib/r10k/content_synchronizer.rb +83 -0
- data/lib/r10k/deployment.rb +1 -1
- data/lib/r10k/environment/base.rb +21 -1
- data/lib/r10k/environment/git.rb +0 -3
- data/lib/r10k/environment/svn.rb +4 -6
- data/lib/r10k/environment/with_modules.rb +18 -10
- data/lib/r10k/git/cache.rb +1 -1
- data/lib/r10k/initializers.rb +7 -0
- data/lib/r10k/module.rb +1 -1
- data/lib/r10k/module/base.rb +17 -1
- data/lib/r10k/module/forge.rb +29 -19
- data/lib/r10k/module/git.rb +23 -14
- data/lib/r10k/module/local.rb +1 -0
- data/lib/r10k/module/svn.rb +12 -9
- data/lib/r10k/module_loader/puppetfile.rb +195 -0
- data/lib/r10k/module_loader/puppetfile/dsl.rb +37 -0
- data/lib/r10k/puppetfile.rb +111 -202
- data/lib/r10k/settings.rb +3 -0
- data/lib/r10k/source/base.rb +14 -0
- data/lib/r10k/source/git.rb +19 -6
- data/lib/r10k/source/hash.rb +1 -3
- data/lib/r10k/source/svn.rb +4 -2
- data/lib/r10k/util/cleaner.rb +21 -0
- data/lib/r10k/util/purgeable.rb +70 -8
- data/lib/r10k/version.rb +1 -1
- data/locales/r10k.pot +67 -71
- data/spec/fixtures/unit/action/r10k_forge_auth.yaml +4 -0
- data/spec/fixtures/unit/action/r10k_forge_auth_no_url.yaml +3 -0
- data/spec/fixtures/unit/util/purgeable/managed_one/managed_subdir_1/managed_subdir_2/ignored_1 +0 -0
- data/spec/fixtures/unit/util/purgeable/managed_two/.hidden/unmanaged_3 +0 -0
- data/spec/r10k-mocks/mock_source.rb +1 -1
- data/spec/shared-examples/puppetfile-action.rb +7 -7
- data/spec/unit/action/deploy/display_spec.rb +32 -6
- data/spec/unit/action/deploy/environment_spec.rb +85 -48
- data/spec/unit/action/deploy/module_spec.rb +163 -31
- data/spec/unit/action/puppetfile/check_spec.rb +2 -2
- data/spec/unit/action/puppetfile/install_spec.rb +31 -10
- data/spec/unit/action/puppetfile/purge_spec.rb +25 -5
- data/spec/unit/action/runner_spec.rb +49 -25
- data/spec/unit/git/cache_spec.rb +14 -0
- data/spec/unit/module/forge_spec.rb +23 -14
- data/spec/unit/module/git_spec.rb +8 -8
- data/spec/unit/module_loader/puppetfile_spec.rb +330 -0
- data/spec/unit/module_spec.rb +22 -5
- data/spec/unit/puppetfile_spec.rb +123 -203
- data/spec/unit/settings_spec.rb +6 -2
- data/spec/unit/util/purgeable_spec.rb +40 -14
- metadata +12 -2
@@ -218,42 +218,66 @@ describe R10K::Action::Runner do
|
|
218
218
|
end
|
219
219
|
|
220
220
|
describe "configuration authorization" do
|
221
|
-
context "
|
222
|
-
|
223
|
-
|
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
|
227
|
-
|
228
|
-
runner.
|
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 "
|
233
|
-
|
234
|
-
|
235
|
-
|
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
|
-
|
238
|
-
|
239
|
-
|
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
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
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
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
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
|
-
|
255
|
-
|
256
|
-
|
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
|
data/spec/unit/git/cache_spec.rb
CHANGED
@@ -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
|
@@ -11,15 +11,15 @@ describe R10K::Module::Forge do
|
|
11
11
|
|
12
12
|
describe "implementing the Puppetfile spec" do
|
13
13
|
it "should implement 'branan/eight_hundred', '8.0.0'" do
|
14
|
-
expect(described_class).to be_implement('branan/eight_hundred', '8.0.0')
|
14
|
+
expect(described_class).to be_implement('branan/eight_hundred', { version: '8.0.0' })
|
15
15
|
end
|
16
16
|
|
17
17
|
it "should implement 'branan-eight_hundred', '8.0.0'" do
|
18
|
-
expect(described_class).to be_implement('branan-eight_hundred', '8.0.0')
|
18
|
+
expect(described_class).to be_implement('branan-eight_hundred', { version: '8.0.0' })
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should fail with an invalid title" do
|
22
|
-
expect(described_class).to_not be_implement('branan!eight_hundred', '8.0.0')
|
22
|
+
expect(described_class).to_not be_implement('branan!eight_hundred', { version: '8.0.0' })
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -30,7 +30,7 @@ describe R10K::Module::Forge do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
describe "setting attributes" do
|
33
|
-
subject { described_class.new('branan/eight_hundred', '/moduledir', '8.0.0') }
|
33
|
+
subject { described_class.new('branan/eight_hundred', '/moduledir', { version: '8.0.0' }) }
|
34
34
|
|
35
35
|
it "sets the name" do
|
36
36
|
expect(subject.name).to eq 'eight_hundred'
|
@@ -50,7 +50,7 @@ describe R10K::Module::Forge do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
describe "properties" do
|
53
|
-
subject { described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0') }
|
53
|
+
subject { described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' }) }
|
54
54
|
|
55
55
|
it "sets the module type to :forge" do
|
56
56
|
expect(subject.properties).to include(:type => :forge)
|
@@ -67,7 +67,7 @@ describe R10K::Module::Forge do
|
|
67
67
|
end
|
68
68
|
|
69
69
|
context "when a module is deprecated" do
|
70
|
-
subject { described_class.new('puppetlabs/corosync', fixture_modulepath, :latest) }
|
70
|
+
subject { described_class.new('puppetlabs/corosync', fixture_modulepath, { version: :latest }) }
|
71
71
|
|
72
72
|
it "warns on sync if module is not already insync" do
|
73
73
|
allow(subject).to receive(:status).and_return(:absent)
|
@@ -77,6 +77,7 @@ describe R10K::Module::Forge do
|
|
77
77
|
logger_dbl = double(Log4r::Logger)
|
78
78
|
allow_any_instance_of(described_class).to receive(:logger).and_return(logger_dbl)
|
79
79
|
|
80
|
+
allow(logger_dbl).to receive(:info).with(/Deploying module to.*/)
|
80
81
|
expect(logger_dbl).to receive(:warn).with(/puppet forge module.*puppetlabs-corosync.*has been deprecated/i)
|
81
82
|
|
82
83
|
subject.sync
|
@@ -88,6 +89,7 @@ describe R10K::Module::Forge do
|
|
88
89
|
logger_dbl = double(Log4r::Logger)
|
89
90
|
allow_any_instance_of(described_class).to receive(:logger).and_return(logger_dbl)
|
90
91
|
|
92
|
+
allow(logger_dbl).to receive(:info).with(/Deploying module to.*/)
|
91
93
|
expect(logger_dbl).to_not receive(:warn).with(/puppet forge module.*puppetlabs-corosync.*has been deprecated/i)
|
92
94
|
|
93
95
|
subject.sync
|
@@ -96,20 +98,27 @@ describe R10K::Module::Forge do
|
|
96
98
|
|
97
99
|
describe '#expected_version' do
|
98
100
|
it "returns an explicitly given expected version" do
|
99
|
-
subject = described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0')
|
101
|
+
subject = described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' })
|
100
102
|
expect(subject.expected_version).to eq '8.0.0'
|
101
103
|
end
|
102
104
|
|
103
105
|
it "uses the latest version from the forge when the version is :latest" do
|
104
|
-
subject = described_class.new('branan/eight_hundred', fixture_modulepath, :latest)
|
105
|
-
|
106
|
+
subject = described_class.new('branan/eight_hundred', fixture_modulepath, { version: :latest })
|
107
|
+
release = double("Module Release", version: '8.8.8')
|
108
|
+
expect(subject.v3_module).to receive(:current_release).and_return(release).twice
|
106
109
|
expect(subject.expected_version).to eq '8.8.8'
|
107
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
|
108
117
|
end
|
109
118
|
|
110
119
|
describe "determining the status" do
|
111
120
|
|
112
|
-
subject { described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0') }
|
121
|
+
subject { described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' }) }
|
113
122
|
|
114
123
|
it "is :absent if the module directory is absent" do
|
115
124
|
allow(subject).to receive(:exist?).and_return false
|
@@ -154,7 +163,7 @@ describe R10K::Module::Forge do
|
|
154
163
|
end
|
155
164
|
|
156
165
|
describe "#sync" do
|
157
|
-
subject { described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0') }
|
166
|
+
subject { described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' }) }
|
158
167
|
|
159
168
|
it 'does nothing when the module is in sync' do
|
160
169
|
allow(subject).to receive(:status).and_return :insync
|
@@ -186,7 +195,7 @@ describe R10K::Module::Forge do
|
|
186
195
|
|
187
196
|
describe '#install' do
|
188
197
|
it 'installs the module from the forge' do
|
189
|
-
subject = described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0')
|
198
|
+
subject = described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' })
|
190
199
|
release = instance_double('R10K::Forge::ModuleRelease')
|
191
200
|
expect(R10K::Forge::ModuleRelease).to receive(:new).with('branan-eight_hundred', '8.0.0').and_return(release)
|
192
201
|
expect(release).to receive(:install).with(subject.path)
|
@@ -196,7 +205,7 @@ describe R10K::Module::Forge do
|
|
196
205
|
|
197
206
|
describe '#uninstall' do
|
198
207
|
it 'removes the module path' do
|
199
|
-
subject = described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0')
|
208
|
+
subject = described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' })
|
200
209
|
expect(FileUtils).to receive(:rm_rf).with(subject.path.to_s)
|
201
210
|
subject.uninstall
|
202
211
|
end
|
@@ -204,7 +213,7 @@ describe R10K::Module::Forge do
|
|
204
213
|
|
205
214
|
describe '#reinstall' do
|
206
215
|
it 'uninstalls and then installs the module' do
|
207
|
-
subject = described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0')
|
216
|
+
subject = described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' })
|
208
217
|
expect(subject).to receive(:uninstall)
|
209
218
|
expect(subject).to receive(:install)
|
210
219
|
subject.reinstall
|
@@ -119,14 +119,6 @@ describe R10K::Module::Git do
|
|
119
119
|
allow(mock_repo).to receive(:head).and_return('abc123')
|
120
120
|
end
|
121
121
|
|
122
|
-
context "when option is unrecognized" do
|
123
|
-
let(:opts) { { unrecognized: true } }
|
124
|
-
|
125
|
-
it "raises an error" do
|
126
|
-
expect { test_module(opts) }.to raise_error(ArgumentError, /cannot handle option 'unrecognized'/)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
122
|
describe "desired ref" do
|
131
123
|
context "when no desired ref is given" do
|
132
124
|
it "defaults to master" do
|
@@ -210,6 +202,14 @@ describe R10K::Module::Git do
|
|
210
202
|
expect(mod.desired_ref).to eq(:control_branch)
|
211
203
|
end
|
212
204
|
|
205
|
+
it "warns control branch may be unresolvable" do
|
206
|
+
logger = double("logger")
|
207
|
+
allow_any_instance_of(described_class).to receive(:logger).and_return(logger)
|
208
|
+
expect(logger).to receive(:warn).with(/Cannot track control repo branch.*boolean.*/)
|
209
|
+
|
210
|
+
test_module(branch: :control_branch)
|
211
|
+
end
|
212
|
+
|
213
213
|
context "when default ref is provided and resolvable" do
|
214
214
|
it "uses default ref" do
|
215
215
|
expect(mock_repo).to receive(:resolve).with('default').and_return('abc123')
|
@@ -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
|