r10k 3.5.1 → 3.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.github/pull_request_template.md +4 -1
  3. data/.github/workflows/docker.yml +4 -1
  4. data/.github/workflows/release.yml +3 -2
  5. data/.github/workflows/rspec_tests.yml +81 -0
  6. data/.travis.yml +8 -1
  7. data/CHANGELOG.mkd +43 -2
  8. data/CODEOWNERS +2 -2
  9. data/README.mkd +13 -4
  10. data/doc/common-patterns.mkd +1 -0
  11. data/doc/dynamic-environments/configuration.mkd +143 -39
  12. data/doc/dynamic-environments/usage.mkd +12 -11
  13. data/doc/puppetfile.mkd +23 -3
  14. data/docker/Gemfile +1 -1
  15. data/docker/Makefile +7 -4
  16. data/docker/docker-compose.yml +18 -0
  17. data/docker/r10k/Dockerfile +4 -3
  18. data/docker/r10k/docker-entrypoint.sh +0 -1
  19. data/docker/r10k/release.Dockerfile +3 -2
  20. data/docker/spec/dockerfile_spec.rb +26 -32
  21. data/integration/tests/git_source/git_source_repeated_remote.rb +68 -0
  22. data/integration/tests/user_scenario/basic_workflow/multi_env_custom_forge_git_module.rb +2 -1
  23. data/integration/tests/user_scenario/basic_workflow/multi_env_custom_forge_git_module_static.rb +2 -1
  24. data/integration/tests/user_scenario/basic_workflow/multi_source_custom_forge_git_module.rb +1 -1
  25. data/integration/tests/user_scenario/basic_workflow/single_env_custom_forge_git_module.rb +2 -1
  26. data/integration/tests/user_scenario/complex_workflow/multi_env_add_change_remove.rb +1 -1
  27. data/integration/tests/user_scenario/complex_workflow/multi_env_remove_re-add.rb +1 -1
  28. data/integration/tests/user_scenario/complex_workflow/multi_env_unamanaged.rb +1 -1
  29. data/lib/r10k/action/deploy/display.rb +9 -3
  30. data/lib/r10k/action/deploy/environment.rb +39 -14
  31. data/lib/r10k/action/deploy/module.rb +4 -1
  32. data/lib/r10k/action/runner.rb +34 -0
  33. data/lib/r10k/cli/deploy.rb +14 -7
  34. data/lib/r10k/cli/puppetfile.rb +5 -5
  35. data/lib/r10k/environment/base.rb +9 -2
  36. data/lib/r10k/environment/git.rb +17 -2
  37. data/lib/r10k/environment/name.rb +22 -4
  38. data/lib/r10k/environment/svn.rb +11 -2
  39. data/lib/r10k/environment/with_modules.rb +28 -20
  40. data/lib/r10k/forge/module_release.rb +2 -2
  41. data/lib/r10k/git.rb +1 -0
  42. data/lib/r10k/git/cache.rb +12 -4
  43. data/lib/r10k/git/rugged/credentials.rb +39 -2
  44. data/lib/r10k/git/stateful_repository.rb +4 -0
  45. data/lib/r10k/initializers.rb +2 -0
  46. data/lib/r10k/module/base.rb +8 -0
  47. data/lib/r10k/module/forge.rb +16 -4
  48. data/lib/r10k/module/git.rb +42 -24
  49. data/lib/r10k/module/local.rb +1 -1
  50. data/lib/r10k/module/svn.rb +14 -11
  51. data/lib/r10k/puppetfile.rb +30 -12
  52. data/lib/r10k/settings.rb +30 -3
  53. data/lib/r10k/source/base.rb +5 -0
  54. data/lib/r10k/source/git.rb +26 -3
  55. data/lib/r10k/source/hash.rb +4 -2
  56. data/lib/r10k/source/svn.rb +5 -1
  57. data/lib/r10k/util/setopts.rb +33 -12
  58. data/lib/r10k/version.rb +1 -1
  59. data/locales/r10k.pot +71 -43
  60. data/r10k.gemspec +1 -1
  61. data/spec/fixtures/unit/action/r10k_creds.yaml +9 -0
  62. data/spec/shared-examples/subprocess-runner.rb +11 -5
  63. data/spec/unit/action/deploy/display_spec.rb +4 -0
  64. data/spec/unit/action/deploy/environment_spec.rb +154 -12
  65. data/spec/unit/action/deploy/module_spec.rb +40 -1
  66. data/spec/unit/action/puppetfile/install_spec.rb +1 -0
  67. data/spec/unit/action/runner_spec.rb +48 -1
  68. data/spec/unit/environment/git_spec.rb +19 -2
  69. data/spec/unit/environment/name_spec.rb +28 -0
  70. data/spec/unit/environment/svn_spec.rb +12 -0
  71. data/spec/unit/environment/with_modules_spec.rb +74 -0
  72. data/spec/unit/forge/module_release_spec.rb +14 -10
  73. data/spec/unit/git/cache_spec.rb +10 -0
  74. data/spec/unit/git/rugged/credentials_spec.rb +79 -2
  75. data/spec/unit/git_spec.rb +3 -3
  76. data/spec/unit/module/forge_spec.rb +6 -0
  77. data/spec/unit/module/git_spec.rb +56 -1
  78. data/spec/unit/module_spec.rb +59 -9
  79. data/spec/unit/puppetfile_spec.rb +61 -7
  80. data/spec/unit/settings_spec.rb +12 -0
  81. data/spec/unit/source/git_spec.rb +49 -1
  82. data/spec/unit/util/setopts_spec.rb +25 -1
  83. metadata +9 -11
  84. data/azure-pipelines.yml +0 -86
data/r10k.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.license = 'Apache-2.0'
24
24
 
25
25
  s.add_dependency 'colored2', '3.1.2'
26
- s.add_dependency 'cri', ['>= 2.15.10', '< 3.0.0']
26
+ s.add_dependency 'cri', '2.15.10'
27
27
 
28
28
  s.add_dependency 'log4r', '1.1.10'
29
29
  s.add_dependency 'multi_json', '~> 1.10'
@@ -0,0 +1,9 @@
1
+ ---
2
+ git:
3
+ private_key: '/global/config/private/key'
4
+ oauth_token: '/global/config/oauth/token'
5
+ repositories:
6
+ - remote: 'git@myfakegitserver.com:user/repo.git'
7
+ private_key: '/config/private/key'
8
+ - remote: 'https://myfakegitserver.com/user/repo.git'
9
+ oauth_token: '/config/oauth/token'
@@ -32,23 +32,29 @@ shared_examples_for "a subprocess runner" do |fixture_root|
32
32
  end
33
33
  end
34
34
 
35
- describe "running 'ls' with a different working directory" do
35
+ describe "running 'ls' or 'dir' with a different working directory" do
36
36
  subject do
37
- described_class.new(%w[ls]).tap do |o|
38
- o.cwd = fixture_root
37
+ if R10K::Util::Platform.windows?
38
+ described_class.new(%w[cmd /c dir]).tap do |o|
39
+ o.cwd = fixture_root
40
+ end
41
+ else
42
+ described_class.new(%w[ls]).tap do |o|
43
+ o.cwd = fixture_root
44
+ end
39
45
  end
40
46
  end
41
47
 
42
48
  it "returns the contents of the given working directory" do
43
49
  result = subject.run
44
- expect(result.stdout).to eq 'no-execute.sh'
50
+ expect(result.stdout).to match('no-execute.sh')
45
51
  end
46
52
  end
47
53
 
48
54
  describe "running 'false'" do
49
55
  subject { described_class.new(%w[false]) }
50
56
 
51
- it "sets the exit code to 1" do
57
+ it "sets the exit code to 1", unless: R10K::Util::Platform.windows? do
52
58
  result = subject.run
53
59
  expect(result.exit_code).to eq 1
54
60
  end
@@ -8,6 +8,10 @@ describe R10K::Action::Deploy::Display do
8
8
  described_class.new({puppetfile: true}, [])
9
9
  end
10
10
 
11
+ it "accepts a modules option" do
12
+ described_class.new({modules: true}, [])
13
+ end
14
+
11
15
  it "accepts a detail option" do
12
16
  described_class.new({detail: true}, [])
13
17
  end
@@ -19,6 +19,10 @@ describe R10K::Action::Deploy::Environment do
19
19
  described_class.new({puppetfile: true}, [])
20
20
  end
21
21
 
22
+ it "can accept a modules option" do
23
+ described_class.new({modules: true}, [])
24
+ end
25
+
22
26
  it "can accept a default_branch_override option" do
23
27
  described_class.new({:'default-branch-override' => 'default_branch_override_name'}, [])
24
28
  end
@@ -27,8 +31,6 @@ describe R10K::Action::Deploy::Environment do
27
31
  described_class.new({:'no-force' => true}, [])
28
32
  end
29
33
 
30
- it "normalizes environment names in the arg vector"
31
-
32
34
  it 'can accept a generate-types option' do
33
35
  described_class.new({ 'generate-types': true }, [])
34
36
  end
@@ -36,6 +38,25 @@ describe R10K::Action::Deploy::Environment do
36
38
  it 'can accept a puppet-path option' do
37
39
  described_class.new({ 'puppet-path': '/nonexistent' }, [])
38
40
  end
41
+
42
+ it 'can accept a private-key option' do
43
+ described_class.new({ 'private-key': '/nonexistent' }, [])
44
+ end
45
+
46
+ it 'can accept a token option' do
47
+ described_class.new({ 'oauth-token': '/nonexistent' }, [])
48
+ end
49
+
50
+ describe "initializing errors" do
51
+ let (:settings) { { deploy: { purge_levels: [:environment],
52
+ purge_whitelist: ['coolfile', 'coolfile2'],
53
+ purge_allowlist: ['anothercoolfile']}}}
54
+
55
+ subject { described_class.new({config: "/some/nonexistent/path"}, [], settings)}
56
+ it 'errors out when both purge_whitelist and purge_allowlist are set' do
57
+ expect{subject}.to raise_error(R10K::Error, /Values found for both purge_whitelist and purge_allowlist./)
58
+ end
59
+ end
39
60
  end
40
61
 
41
62
  describe "when called" do
@@ -52,6 +73,29 @@ describe R10K::Action::Deploy::Environment do
52
73
  )
53
74
  end
54
75
 
76
+ describe "with puppetfile or modules flag" do
77
+ let(:deployment) { R10K::Deployment.new(mock_config) }
78
+ let(:puppetfile) { instance_double("R10K::Puppetfile", modules: []).as_null_object }
79
+
80
+ before do
81
+ expect(R10K::Deployment).to receive(:new).and_return(deployment)
82
+ expect(R10K::Puppetfile).to receive(:new).and_return(puppetfile).at_least(:once)
83
+ end
84
+
85
+ it "syncs the puppetfile when given the puppetfile flag" do
86
+ expect(puppetfile).to receive(:accept).and_return([])
87
+ action = described_class.new({config: "/some/nonexistent/path", puppetfile: true}, [])
88
+ action.call
89
+ end
90
+
91
+ it "syncs the puppetfile when given the modules flag" do
92
+ expect(puppetfile).to receive(:accept).and_return([])
93
+ action = described_class.new({config: "/some/nonexistent/path", modules: true}, [])
94
+ action.call
95
+ end
96
+
97
+ end
98
+
55
99
  describe "with an environment that doesn't exist" do
56
100
  let(:deployment) do
57
101
  R10K::Deployment.new(mock_config)
@@ -71,7 +115,7 @@ describe R10K::Action::Deploy::Environment do
71
115
  end
72
116
 
73
117
  describe "with no-force" do
74
- subject { described_class.new({ config: "/some/nonexistent/path", puppetfile: true, :'no-force' => true}, %w[first]) }
118
+ subject { described_class.new({ config: "/some/nonexistent/path", modules: true, :'no-force' => true}, %w[first]) }
75
119
 
76
120
  it "tries to preserve local modifications" do
77
121
  expect(subject.force).to equal(false)
@@ -162,6 +206,44 @@ describe R10K::Action::Deploy::Environment do
162
206
  end
163
207
  end
164
208
 
209
+ describe 'extracting credentials' do
210
+ let(:deployment) do
211
+ R10K::Deployment.new(mock_config)
212
+ end
213
+
214
+ end
215
+
216
+ describe "Purging white/allowlist" do
217
+
218
+ let(:settings) { { deploy: { purge_levels: [:environment], purge_allowlist: ['coolfile', 'coolfile2'] } } }
219
+
220
+ let(:deployment) do
221
+ R10K::Deployment.new(mock_config.merge(settings))
222
+ end
223
+
224
+ before do
225
+ expect(R10K::Deployment).to receive(:new).and_return(deployment)
226
+ end
227
+
228
+ subject { described_class.new({ config: "/some/nonexistent/path", modules: true }, %w[PREFIX_first], settings) }
229
+
230
+ it "reads in the purge_allowlist setting and purges accordingly" do
231
+ expect(subject.logger).to receive(:debug).with(/purging unmanaged content for environment/i)
232
+ expect(subject.instance_variable_get(:@user_purge_allowlist)).to eq(['coolfile', 'coolfile2'])
233
+ subject.call
234
+ end
235
+
236
+ describe "purge_whitelist" do
237
+ let (:settings) { { deploy: { purge_levels: [:environment], purge_whitelist: ['coolfile', 'coolfile2'] } } }
238
+
239
+ it "reads in the purge_whitelist setting and still sets it to purge_allowlist and purges accordingly" do
240
+ expect(subject.logger).to receive(:debug).with(/purging unmanaged content for environment/i)
241
+ expect(subject.instance_variable_get(:@user_purge_allowlist)).to eq(['coolfile', 'coolfile2'])
242
+ subject.call
243
+ end
244
+ end
245
+ end
246
+
165
247
  describe "purge_levels" do
166
248
  let(:settings) { { deploy: { purge_levels: purge_levels } } }
167
249
 
@@ -173,7 +255,7 @@ describe R10K::Action::Deploy::Environment do
173
255
  expect(R10K::Deployment).to receive(:new).and_return(deployment)
174
256
  end
175
257
 
176
- subject { described_class.new({ config: "/some/nonexistent/path", puppetfile: true }, %w[PREFIX_first], settings) }
258
+ subject { described_class.new({ config: "/some/nonexistent/path", modules: true }, %w[PREFIX_first], settings) }
177
259
 
178
260
  describe "deployment purge level" do
179
261
  let(:purge_levels) { [:deployment] }
@@ -219,6 +301,7 @@ describe R10K::Action::Deploy::Environment do
219
301
  end
220
302
  end
221
303
  end
304
+
222
305
  describe "generate-types" do
223
306
  let(:deployment) do
224
307
  R10K::Deployment.new(
@@ -248,7 +331,7 @@ describe R10K::Action::Deploy::Environment do
248
331
  described_class.new(
249
332
  {
250
333
  config: '/some/nonexistent/path',
251
- puppetfile: true,
334
+ modules: true,
252
335
  'generate-types': true
253
336
  },
254
337
  %w[first second]
@@ -302,7 +385,7 @@ describe R10K::Action::Deploy::Environment do
302
385
  described_class.new(
303
386
  {
304
387
  config: '/some/nonexistent/path',
305
- puppetfile: true,
388
+ modules: true,
306
389
  'generate-types': false
307
390
  },
308
391
  %w[first]
@@ -331,6 +414,33 @@ describe R10K::Action::Deploy::Environment do
331
414
  expect(subject.instance_variable_get(:@puppet_path)).to eq('/nonexistent')
332
415
  end
333
416
  end
417
+
418
+ describe 'with puppet-conf' do
419
+
420
+ subject { described_class.new({ config: '/some/nonexistent/path', 'puppet-conf': '/nonexistent' }, []) }
421
+
422
+ it 'sets puppet_conf' do
423
+ expect(subject.instance_variable_get(:@puppet_conf)).to eq('/nonexistent')
424
+ end
425
+ end
426
+
427
+ describe 'with private-key' do
428
+
429
+ subject { described_class.new({ config: '/some/nonexistent/path', 'private-key': '/nonexistent' }, []) }
430
+
431
+ it 'sets private_key' do
432
+ expect(subject.instance_variable_get(:@private_key)).to eq('/nonexistent')
433
+ end
434
+ end
435
+
436
+ describe 'with oauth-token' do
437
+
438
+ subject { described_class.new({ config: '/some/nonexistent/path', 'oauth-token': '/nonexistent' }, []) }
439
+
440
+ it 'sets oauth_token' do
441
+ expect(subject.instance_variable_get(:@oauth_token)).to eq('/nonexistent')
442
+ end
443
+ end
334
444
  end
335
445
 
336
446
  describe "write_environment_info!" do
@@ -349,9 +459,25 @@ describe R10K::Action::Deploy::Environment do
349
459
 
350
460
  let(:mock_stateful_repo_1) { instance_double("R10K::Git::StatefulRepository", :head => "123456") }
351
461
  let(:mock_stateful_repo_2) { instance_double("R10K::Git::StatefulRepository", :head => "654321") }
352
- let(:mock_git_module_1) { instance_double("R10K::Module::Git", :name => "my_cool_module", :version => "1.0", :repo => mock_stateful_repo_1) }
353
- let(:mock_git_module_2) { instance_double("R10K::Module::Git", :name => "my_lame_module", :version => "0.0.1", :repo => mock_stateful_repo_2) }
354
- let(:mock_forge_module_1) { double(:name => "their_shiny_module", :version => "2.0.0") }
462
+ let(:mock_git_module_1) do
463
+ instance_double("R10K::Module::Git",
464
+ :name => "my_cool_module",
465
+ :properties => {
466
+ :type => :git,
467
+ :expected => "1.0",
468
+ :actual => mock_stateful_repo_1.head
469
+ })
470
+ end
471
+ let(:mock_git_module_2) do
472
+ instance_double("R10K::Module::Git",
473
+ :name => "my_uncool_module",
474
+ :properties => {
475
+ :type => :git,
476
+ :expected => "0.0.1",
477
+ :actual => mock_stateful_repo_2.head
478
+ })
479
+ end
480
+ let(:mock_forge_module_1) { double(:name => "their_shiny_module", :properties => { :expected => "2.0.0" }) }
355
481
  let(:mock_puppetfile) { instance_double("R10K::Puppetfile", :modules => [mock_git_module_1, mock_git_module_2, mock_forge_module_1]) }
356
482
 
357
483
  before(:all) do
@@ -364,9 +490,8 @@ describe R10K::Action::Deploy::Environment do
364
490
  Dir.delete(@tmp_path)
365
491
  end
366
492
 
367
- it "writes the .r10k-deploy file correctly" do
493
+ it "writes the .r10k-deploy file correctly if all goes well" do
368
494
  allow(R10K::Puppetfile).to receive(:new).and_return(mock_puppetfile)
369
- allow(mock_forge_module_1).to receive(:repo).and_raise(NoMethodError)
370
495
 
371
496
  fake_env = Fake_Environment.new(@tmp_path, {:name => "my_cool_environment", :signature => "pablo picasso"})
372
497
  allow(fake_env).to receive(:modules).and_return(mock_puppetfile.modules)
@@ -383,13 +508,30 @@ describe R10K::Action::Deploy::Environment do
383
508
  expect(r10k_deploy['module_deploys'][0]['name']).to eq("my_cool_module")
384
509
  expect(r10k_deploy['module_deploys'][0]['version']).to eq("1.0")
385
510
  expect(r10k_deploy['module_deploys'][0]['sha']).to eq("123456")
386
- expect(r10k_deploy['module_deploys'][1]['name']).to eq("my_lame_module")
511
+ expect(r10k_deploy['module_deploys'][1]['name']).to eq("my_uncool_module")
387
512
  expect(r10k_deploy['module_deploys'][1]['version']).to eq("0.0.1")
388
513
  expect(r10k_deploy['module_deploys'][1]['sha']).to eq("654321")
389
514
  expect(r10k_deploy['module_deploys'][2]['name']).to eq("their_shiny_module")
390
515
  expect(r10k_deploy['module_deploys'][2]['version']).to eq("2.0.0")
391
516
  expect(r10k_deploy['module_deploys'][2]['sha']).to eq(nil)
517
+ end
518
+
519
+ it "writes the .r10k-deploy file correctly if there's a failure" do
520
+ allow(R10K::Puppetfile).to receive(:new).and_return(mock_puppetfile)
392
521
 
522
+ fake_env = Fake_Environment.new(@tmp_path, {:name => "my_cool_environment", :signature => "pablo picasso"})
523
+ allow(fake_env).to receive(:modules).and_return(mock_puppetfile.modules)
524
+ allow(mock_forge_module_1).to receive(:properties).and_raise(StandardError)
525
+ subject.send(:write_environment_info!, fake_env, "2019-01-01 23:23:22 +0000", true)
526
+
527
+ file_contents = File.read("#{@tmp_path}/.r10k-deploy.json")
528
+ r10k_deploy = JSON.parse(file_contents)
529
+
530
+ expect(r10k_deploy['name']).to eq("my_cool_environment")
531
+ expect(r10k_deploy['signature']).to eq("pablo picasso")
532
+ expect(r10k_deploy['started_at']).to eq("2019-01-01 23:23:22 +0000")
533
+ expect(r10k_deploy['deploy_success']).to eq(true)
534
+ expect(r10k_deploy['module_deploys'].length).to eq(0)
393
535
  end
394
536
  end
395
537
  end
@@ -26,9 +26,21 @@ describe R10K::Action::Deploy::Module do
26
26
  described_class.new({ 'puppet-path': '/nonexistent' }, [])
27
27
  end
28
28
 
29
+ it 'can accept a puppet-conf option' do
30
+ described_class.new({ 'puppet-conf': '/nonexistent' }, [])
31
+ end
32
+
29
33
  it 'can accept a cachedir option' do
30
34
  described_class.new({ cachedir: '/nonexistent' }, [])
31
35
  end
36
+
37
+ it 'can accept a private-key option' do
38
+ described_class.new({ 'private-key': '/nonexistent' }, [])
39
+ end
40
+
41
+ it 'can accept a token option' do
42
+ described_class.new({ 'oauth-token': '/nonexistent' }, [])
43
+ end
32
44
  end
33
45
 
34
46
  describe "with no-force" do
@@ -128,12 +140,39 @@ describe R10K::Action::Deploy::Module do
128
140
  end
129
141
  end
130
142
 
143
+ describe 'with puppet-conf' do
144
+
145
+ subject { described_class.new({ config: '/some/nonexistent/path', 'puppet-conf': '/nonexistent' }, []) }
146
+
147
+ it 'sets puppet_conf' do
148
+ expect(subject.instance_variable_get(:@puppet_conf)).to eq('/nonexistent')
149
+ end
150
+ end
151
+
131
152
  describe 'with cachedir' do
132
153
 
133
154
  subject { described_class.new({ config: '/some/nonexistent/path', cachedir: '/nonexistent' }, []) }
134
155
 
135
- it 'sets puppet_path' do
156
+ it 'sets cachedir' do
136
157
  expect(subject.instance_variable_get(:@cachedir)).to eq('/nonexistent')
137
158
  end
138
159
  end
160
+
161
+ describe 'with private-key' do
162
+
163
+ subject { described_class.new({ config: '/some/nonexistent/path', 'private-key': '/nonexistent' }, []) }
164
+
165
+ it 'sets private_key' do
166
+ expect(subject.instance_variable_get(:@private_key)).to eq('/nonexistent')
167
+ end
168
+ end
169
+
170
+ describe 'with oauth-token' do
171
+
172
+ subject { described_class.new({ config: '/some/nonexistent/path', 'oauth-token': '/nonexistent' }, []) }
173
+
174
+ it 'sets token_path' do
175
+ expect(subject.instance_variable_get(:@oauth_token)).to eq('/nonexistent')
176
+ end
177
+ end
139
178
  end
@@ -27,6 +27,7 @@ describe R10K::Action::Puppetfile::Install do
27
27
  before do
28
28
  allow(puppetfile).to receive(:purge!)
29
29
  allow(puppetfile).to receive(:modules).and_return(modules)
30
+ allow(puppetfile).to receive(:modules_by_vcs_cachedir).and_return({none: modules})
30
31
  end
31
32
 
32
33
  it "syncs each module in the Puppetfile" do
@@ -10,11 +10,12 @@ describe R10K::Action::Runner do
10
10
  Class.new do
11
11
  attr_reader :opts
12
12
  attr_reader :argv
13
+ attr_reader :settings
13
14
 
14
15
  def initialize(opts, argv, settings = {})
15
16
  @opts = opts
16
17
  @argv = argv
17
- @settings = {}
18
+ @settings = settings
18
19
  end
19
20
 
20
21
  def call
@@ -170,6 +171,52 @@ describe R10K::Action::Runner do
170
171
  end
171
172
  end
172
173
 
174
+ describe "configuring git credentials" do
175
+ it 'errors if both token and key paths are passed' do
176
+ runner = described_class.new({ 'oauth-token': '/nonexistent',
177
+ 'private-key': '/also/fake' }, %w[args yes], action_class)
178
+ expect{ runner.call }.to raise_error(R10K::Error, /Cannot specify both/)
179
+ end
180
+
181
+ it 'saves the sshkey path in settings hash' do
182
+ runner = described_class.new({ 'private-key': '/my/ssh/key' }, %w[args yes], action_class)
183
+ runner.call
184
+ expect(runner.instance.settings[:git][:private_key]).to eq('/my/ssh/key')
185
+ end
186
+
187
+ it 'overrides per-repo sshkey in settings hash' do
188
+ runner = described_class.new({ config: "spec/fixtures/unit/action/r10k_creds.yaml",
189
+ 'private-key': '/my/ssh/key' },
190
+ %w[args yes],
191
+ action_class)
192
+ runner.call
193
+ expect(runner.instance.settings[:git][:private_key]).to eq('/my/ssh/key')
194
+ expect(runner.instance.settings[:git][:repositories].count).to eq(2)
195
+ runner.instance.settings[:git][:repositories].each do |repo_settings|
196
+ expect(repo_settings[:private_key]).to eq('/my/ssh/key')
197
+ end
198
+ end
199
+
200
+ it 'saves the token path in settings hash' do
201
+ runner = described_class.new({ 'oauth-token': '/my/token/path' }, %w[args yes], action_class)
202
+ runner.call
203
+ expect(runner.instance.settings[:git][:oauth_token]).to eq('/my/token/path')
204
+ end
205
+
206
+ it 'overrides per-repo oauth token in settings hash' do
207
+ runner = described_class.new({ config: "spec/fixtures/unit/action/r10k_creds.yaml",
208
+ 'oauth-token': '/my/token' },
209
+ %w[args yes],
210
+ action_class)
211
+ runner.call
212
+ expect(runner.instance.settings[:git][:oauth_token]).to eq('/my/token')
213
+ expect(runner.instance.settings[:git][:repositories].count).to eq(2)
214
+ runner.instance.settings[:git][:repositories].each do |repo_settings|
215
+ expect(repo_settings[:oauth_token]).to eq('/my/token')
216
+ end
217
+ end
218
+ end
219
+
173
220
  describe "configuration authorization" do
174
221
  context "when license is not present" do
175
222
  before(:each) do