r10k 3.5.1 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
@@ -15,6 +15,22 @@ describe R10K::Environment::Git do
15
15
  )
16
16
  end
17
17
 
18
+ describe "initializing" do
19
+ subject do
20
+ described_class.new('name', '/dir', 'ref', {
21
+ :remote => 'url',
22
+ :ref => 'value',
23
+ :puppetfile_name => 'Puppetfile',
24
+ :moduledir => 'modules',
25
+ :modules => { },
26
+ })
27
+ end
28
+
29
+ it "accepts valid base class initialization arguments" do
30
+ expect(subject.name).to eq 'name'
31
+ end
32
+ end
33
+
18
34
  describe "storing attributes" do
19
35
  it "can return the environment name" do
20
36
  expect(subject.name).to eq 'myenv'
@@ -62,9 +78,10 @@ describe R10K::Environment::Git do
62
78
 
63
79
  describe "enumerating modules" do
64
80
  it "loads the Puppetfile and returns modules in that puppetfile" do
81
+ mod = double('A module', :name => 'dbl')
65
82
  expect(subject.puppetfile).to receive(:load)
66
- expect(subject.puppetfile).to receive(:modules).and_return [:modules]
67
- expect(subject.modules).to eq([:modules])
83
+ expect(subject.puppetfile).to receive(:modules).and_return [mod]
84
+ expect(subject.modules).to eq([mod])
68
85
  end
69
86
  end
70
87
 
@@ -2,6 +2,34 @@ require 'spec_helper'
2
2
  require 'r10k/environment/name'
3
3
 
4
4
  describe R10K::Environment::Name do
5
+ describe "strip_component" do
6
+ it "does not modify the given name when no strip_component is given" do
7
+ bn = described_class.new('myenv', source: 'source', prefix: false)
8
+ expect(bn.dirname).to eq 'myenv'
9
+ end
10
+
11
+ it "removes the first occurance of a regex match when a regex is given" do
12
+ bn = described_class.new('myenv', source: 'source', prefix: false, strip_component: '/env/')
13
+ expect(bn.dirname).to eq 'my'
14
+ end
15
+
16
+ it "does not modify the given name when there is no regex match" do
17
+ bn = described_class.new('myenv', source: 'source', prefix: false, strip_component: '/bar/')
18
+ expect(bn.dirname).to eq 'myenv'
19
+ end
20
+
21
+ it "removes the given name's prefix when it matches strip_component" do
22
+ bn = described_class.new('env/prod', source: 'source', prefix: false, strip_component: 'env/')
23
+ expect(bn.dirname).to eq 'prod'
24
+ end
25
+
26
+ it "raises an error when given an integer" do
27
+ expect {
28
+ described_class.new('env/prod', source: 'source', prefix: false, strip_component: 4)
29
+ }.to raise_error(%r{Improper.*"4"})
30
+ end
31
+ end
32
+
5
33
  describe "prefixing" do
6
34
  it "uses the branch name as the dirname when prefixing is off" do
7
35
  bn = described_class.new('mybranch', :source => 'source', :prefix => false)
@@ -16,6 +16,18 @@ describe R10K::Environment::SVN do
16
16
 
17
17
  let(:working_dir) { subject.working_dir }
18
18
 
19
+ describe "initializing" do
20
+ subject do
21
+ described_class.new('name', '/dir', 'ref', {
22
+ :puppetfile_name => 'Puppetfile',
23
+ })
24
+ end
25
+
26
+ it "accepts valid base class initialization arguments" do
27
+ expect(subject.name).to eq 'name'
28
+ end
29
+ end
30
+
19
31
  describe "storing attributes" do
20
32
  it "can return the environment name" do
21
33
  expect(subject.name).to eq 'myenv'
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+ require 'r10k/environment'
3
+
4
+ describe R10K::Environment::WithModules do
5
+ subject do
6
+ described_class.new(
7
+ 'release42',
8
+ '/some/nonexistent/environmentdir',
9
+ 'prefix_release42',
10
+ {
11
+ :type => 'bare',
12
+ :modules => {
13
+ 'puppetlabs-stdlib' => { local: true },
14
+ 'puppetlabs-concat' => { local: true },
15
+ 'puppetlabs-exec' => { local: true },
16
+ }
17
+ }.merge(subject_params)
18
+ )
19
+ end
20
+
21
+ # Default no additional params
22
+ let(:subject_params) { {} }
23
+
24
+ describe "dealing with module conflicts" do
25
+ context "with no module conflicts" do
26
+ it "validates when there are no conflicts" do
27
+ mod = instance_double('R10K::Module::Base', name: 'nonconflict', origin: :puppetfile)
28
+ expect(subject.module_conflicts?(mod)).to eq false
29
+ end
30
+ end
31
+
32
+ context "with module conflicts and default behavior" do
33
+ it "does not raise an error" do
34
+ mod = instance_double('R10K::Module::Base', name: 'stdlib', origin: :puppetfile)
35
+ expect(subject.logger).to receive(:warn).with(/Puppetfile.*both define.*ignored/i)
36
+ expect(subject.module_conflicts?(mod)).to eq true
37
+ end
38
+ end
39
+
40
+ context "with module conflicts and 'error' behavior" do
41
+ let(:subject_params) {{ :module_conflicts => 'error' }}
42
+ it "raises an error" do
43
+ mod = instance_double('R10K::Module::Base', name: 'stdlib', origin: :puppetfile)
44
+ expect { subject.module_conflicts?(mod) }.to raise_error(R10K::Error, /Puppetfile.*both define.*/i)
45
+ end
46
+ end
47
+
48
+ context "with module conflicts and 'override' behavior" do
49
+ let(:subject_params) {{ :module_conflicts => 'override' }}
50
+ it "does not raise an error" do
51
+ mod = instance_double('R10K::Module::Base', name: 'stdlib', origin: :puppetfile)
52
+ expect(subject.logger).to receive(:debug).with(/Puppetfile.*both define.*ignored/i)
53
+ expect(subject.module_conflicts?(mod)).to eq true
54
+ end
55
+ end
56
+
57
+ context "with module conflicts and invalid configuration" do
58
+ let(:subject_params) {{ :module_conflicts => 'batman' }}
59
+ it "raises an error" do
60
+ mod = instance_double('R10K::Module::Base', name: 'stdlib', origin: :puppetfile)
61
+ expect { subject.module_conflicts?(mod) }.to raise_error(R10K::Error, /Unexpected value.*module_conflicts.*/i)
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "modules method" do
67
+ it "returns the configured modules, and Puppetfile modules" do
68
+ puppetfile_mod = instance_double('R10K::Module::Base', name: 'zebra')
69
+ expect(subject.puppetfile).to receive(:modules).and_return [puppetfile_mod]
70
+ returned_modules = subject.modules
71
+ expect(returned_modules.map(&:name).sort).to eq(%w[concat exec stdlib zebra])
72
+ end
73
+ end
74
+ end
@@ -166,33 +166,37 @@ describe R10K::Forge::ModuleRelease do
166
166
  end
167
167
 
168
168
  describe "#cleanup_unpack_path" do
169
- it "ignores the unpack_path if it doesn't exist" do
170
- expect(unpack_path).to receive(:exist?).and_return false
171
- expect(unpack_path).to_not receive(:parent)
169
+ it "ignores the unpack_path if the parent doesn't exist" do
170
+ parent = instance_double('Pathname')
171
+ expect(parent).to receive(:exist?).and_return false
172
+ expect(parent).to_not receive(:rmtree)
173
+ expect(unpack_path).to receive(:parent).and_return(parent)
172
174
  subject.cleanup_unpack_path
173
175
  end
174
176
 
175
177
  it "removes the containing directory of unpack_path if it exists" do
176
178
  parent = instance_double('Pathname')
177
179
  expect(parent).to receive(:rmtree)
178
- expect(unpack_path).to receive(:exist?).and_return true
179
- expect(unpack_path).to receive(:parent).and_return(parent)
180
+ expect(parent).to receive(:exist?).and_return true
181
+ expect(unpack_path).to receive(:parent).and_return(parent).exactly(2).times
180
182
  subject.cleanup_unpack_path
181
183
  end
182
184
  end
183
185
 
184
186
  describe "#cleanup_download_path" do
185
- it "ignores the download_path if it doesn't exist" do
186
- expect(download_path).to receive(:exist?).and_return false
187
- expect(download_path).to_not receive(:parent)
187
+ it "ignores the download_path if the parent doesn't exist" do
188
+ parent = instance_double('Pathname')
189
+ expect(parent).to receive(:exist?).and_return false
190
+ expect(parent).to_not receive(:rmtree)
191
+ expect(download_path).to receive(:parent).and_return(parent)
188
192
  subject.cleanup_download_path
189
193
  end
190
194
 
191
195
  it "removes the containing directory of download_path if it exists" do
192
196
  parent = instance_double('Pathname')
193
197
  expect(parent).to receive(:rmtree)
194
- expect(download_path).to receive(:exist?).and_return true
195
- expect(download_path).to receive(:parent).and_return(parent)
198
+ expect(parent).to receive(:exist?).and_return true
199
+ expect(download_path).to receive(:parent).and_return(parent).exactly(2).times
196
200
  subject.cleanup_download_path
197
201
  end
198
202
  end
@@ -3,6 +3,16 @@ require 'r10k/git/cache'
3
3
 
4
4
  describe R10K::Git::Cache do
5
5
 
6
+ describe 'the default cache_root' do
7
+ it 'is in the right location in linux', unless: R10K::Util::Platform.windows? do
8
+ expect(described_class.defaults[:cache_root]).to match(/\.r10k\/git/)
9
+ end
10
+
11
+ it 'is in the right location for windows', if: R10K::Util::Platform.windows? do
12
+ expect(described_class.defaults[:cache_root]).to match(/[^.]r10k\/git/)
13
+ end
14
+ end
15
+
6
16
  let(:subclass) do
7
17
  Class.new(described_class) do
8
18
  def self.bare_repository
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe R10K::Git::Rugged::Credentials, :unless => R10K::Util::Platform.jruby? do
3
+ describe R10K::Git::Rugged::Credentials, :unless => R10K::Util::Platform.jruby? || R10K::Util::Platform.windows? do
4
4
  before(:all) do
5
5
  require 'r10k/git/rugged/credentials'
6
6
  require 'rugged/credentials'
@@ -10,7 +10,7 @@ describe R10K::Git::Rugged::Credentials, :unless => R10K::Util::Platform.jruby?
10
10
 
11
11
  subject { described_class.new(repo) }
12
12
 
13
- after(:all) { R10K::Git.settings.reset! }
13
+ after(:each) { R10K::Git.settings.reset! }
14
14
 
15
15
  describe "determining the username" do
16
16
  before { R10K::Git.settings[:username] = "moderns" }
@@ -39,6 +39,7 @@ describe R10K::Git::Rugged::Credentials, :unless => R10K::Util::Platform.jruby?
39
39
 
40
40
  it "prefers a per-repository SSH private key" do
41
41
  allow(File).to receive(:readable?).with("/etc/puppetlabs/r10k/ssh/tessier-ashpool-id_rsa").and_return true
42
+ R10K::Git.settings[:private_key] = "/etc/puppetlabs/r10k/ssh/id_rsa"
42
43
  R10K::Git.settings[:repositories] = [{ remote: "ssh://git@tessier-ashpool.freeside/repo.git",
43
44
  private_key: "/etc/puppetlabs/r10k/ssh/tessier-ashpool-id_rsa"}]
44
45
  creds = subject.get_ssh_key_credentials("ssh://git@tessier-ashpool.freeside/repo.git", nil)
@@ -78,6 +79,82 @@ describe R10K::Git::Rugged::Credentials, :unless => R10K::Util::Platform.jruby?
78
79
  end
79
80
  end
80
81
 
82
+ describe "generating token credentials" do
83
+ it 'errors if token file does not exist' do
84
+ R10K::Git.settings[:oauth_token] = "/missing/token/file"
85
+ expect(File).to receive(:readable?).with("/missing/token/file").and_return false
86
+ R10K::Git.settings[:repositories] = [{remote: "https://tessier-ashpool.freeside/repo.git"}]
87
+ expect {
88
+ subject.get_plaintext_credentials("https://tessier-ashpool.freeside/repo.git", nil)
89
+ }.to raise_error(R10K::Git::GitError, /cannot load OAuth token/)
90
+ end
91
+
92
+ it 'errors if the token on stdin is not a valid OAuth token' do
93
+ allow($stdin).to receive(:read).and_return("<bad>token")
94
+ R10K::Git.settings[:oauth_token] = "-"
95
+ R10K::Git.settings[:repositories] = [{remote: "https://tessier-ashpool.freeside/repo.git"}]
96
+ expect {
97
+ subject.get_plaintext_credentials("https://tessier-ashpool.freeside/repo.git", nil)
98
+ }.to raise_error(R10K::Git::GitError, /invalid characters/)
99
+ end
100
+
101
+ it 'errors if the token in the file is not a valid OAuth token' do
102
+ token_file = Tempfile.new('token')
103
+ token_file.write('my bad \ntoken')
104
+ token_file.close
105
+ R10K::Git.settings[:oauth_token] = token_file.path
106
+ R10K::Git.settings[:repositories] = [{remote: "https://tessier-ashpool.freeside/repo.git"}]
107
+ expect {
108
+ subject.get_plaintext_credentials("https://tessier-ashpool.freeside/repo.git", nil)
109
+ }.to raise_error(R10K::Git::GitError, /invalid characters/)
110
+ end
111
+
112
+ it 'prefers per-repo token file' do
113
+ token_file = Tempfile.new('token')
114
+ token_file.write('my_token')
115
+ token_file.close
116
+ R10K::Git.settings[:oauth_token] = "/do/not/use"
117
+ R10K::Git.settings[:repositories] = [{remote: "https://tessier-ashpool.freeside/repo.git",
118
+ oauth_token: token_file.path }]
119
+ creds = subject.get_plaintext_credentials("https://tessier-ashpool.freeside/repo.git", nil)
120
+ expect(creds).to be_a_kind_of(Rugged::Credentials::UserPassword)
121
+ expect(creds.instance_variable_get(:@password)).to eq("my_token")
122
+ expect(creds.instance_variable_get(:@username)).to eq("x-oauth-token")
123
+ end
124
+
125
+ it 'uses the token from a file as a password' do
126
+ token_file = Tempfile.new('token')
127
+ token_file.write('my_token')
128
+ token_file.close
129
+ R10K::Git.settings[:oauth_token] = token_file.path
130
+ R10K::Git.settings[:repositories] = [{remote: "https://tessier-ashpool.freeside/repo.git"}]
131
+ creds = subject.get_plaintext_credentials("https://tessier-ashpool.freeside/repo.git", nil)
132
+ expect(creds).to be_a_kind_of(Rugged::Credentials::UserPassword)
133
+ expect(creds.instance_variable_get(:@password)).to eq("my_token")
134
+ expect(creds.instance_variable_get(:@username)).to eq("x-oauth-token")
135
+ end
136
+
137
+ it 'uses the token from stdin as a password' do
138
+ allow($stdin).to receive(:read).and_return("my_token")
139
+ R10K::Git.settings[:oauth_token] = '-'
140
+ R10K::Git.settings[:repositories] = [{remote: "https://tessier-ashpool.freeside/repo.git"}]
141
+ creds = subject.get_plaintext_credentials("https://tessier-ashpool.freeside/repo.git", nil)
142
+ expect(creds).to be_a_kind_of(Rugged::Credentials::UserPassword)
143
+ expect(creds.instance_variable_get(:@password)).to eq("my_token")
144
+ expect(creds.instance_variable_get(:@username)).to eq("x-oauth-token")
145
+ end
146
+
147
+ it 'only reads the token in once' do
148
+ expect($stdin).to receive(:read).and_return("my_token").once
149
+ R10K::Git.settings[:oauth_token] = '-'
150
+ R10K::Git.settings[:repositories] = [{remote: "https://tessier-ashpool.freeside/repo.git"}]
151
+ creds = subject.get_plaintext_credentials("https://tessier-ashpool.freeside/repo.git", nil)
152
+ expect(creds.instance_variable_get(:@password)).to eq("my_token")
153
+ creds = subject.get_plaintext_credentials("https://tessier-ashpool.freeside/repo.git", nil)
154
+ expect(creds.instance_variable_get(:@password)).to eq("my_token")
155
+ end
156
+ end
157
+
81
158
  describe "generating default credentials" do
82
159
  it "generates the rugged default credential type" do
83
160
  creds = subject.get_default_credentials("https://azurediamond:hunter2@tessier-ashpool.freeside/repo.git", "azurediamond")
@@ -11,7 +11,7 @@ describe R10K::Git do
11
11
  expect(described_class.default_name).to eq :shellgit
12
12
  end
13
13
 
14
- context 'under c-based rubies', :unless => R10K::Util::Platform.jruby? do
14
+ context 'under c-based rubies with rugged available', :unless => R10K::Util::Platform.jruby? || R10K::Util::Platform.windows? do
15
15
  it 'returns rugged when the git executable is absent and the rugged library is present' do
16
16
  expect(R10K::Features).to receive(:available?).with(:shellgit).and_return false
17
17
  expect(R10K::Features).to receive(:available?).with(:rugged).and_return true
@@ -53,7 +53,7 @@ describe R10K::Git do
53
53
  }.to raise_error(R10K::Error, "Git provider 'shellgit' is not functional.")
54
54
  end
55
55
 
56
- context 'under c-based rubies', :unless => R10K::Util::Platform.jruby? do
56
+ context 'under c-based rubies with rugged available', :unless => R10K::Util::Platform.jruby? || R10K::Util::Platform.windows? do
57
57
  it "sets the current provider if the provider exists and is functional" do
58
58
  expect(R10K::Features).to receive(:available?).with(:rugged).and_return true
59
59
  described_class.provider = :rugged
@@ -71,7 +71,7 @@ describe R10K::Git do
71
71
  end
72
72
 
73
73
  describe "retrieving the current provider" do
74
- context 'under c-based rubies', :unless => R10K::Util::Platform.jruby? do
74
+ context 'under c-based rubies', :unless => R10K::Util::Platform.jruby? || R10K::Util::Platform.windows? do
75
75
  it "uses the default if a provider has not been set" do
76
76
  expect(described_class).to receive(:default_name).and_return :rugged
77
77
  expect(described_class.provider).to eq(R10K::Git::Rugged)
@@ -23,6 +23,12 @@ describe R10K::Module::Forge do
23
23
  end
24
24
  end
25
25
 
26
+ describe "implementing the standard options interface" do
27
+ it "should implement {type: forge}" do
28
+ expect(described_class).to be_implement('branan-eight_hundred', {type: 'forge', version: '8.0.0', source: 'not implemented'})
29
+ end
30
+ end
31
+
26
32
  describe "setting attributes" do
27
33
  subject { described_class.new('branan/eight_hundred', '/moduledir', '8.0.0') }
28
34
 
@@ -123,7 +123,7 @@ describe R10K::Module::Git do
123
123
  let(:opts) { { unrecognized: true } }
124
124
 
125
125
  it "raises an error" do
126
- expect { test_module(opts) }.to raise_error(ArgumentError, /unhandled options.*unrecognized/i)
126
+ expect { test_module(opts) }.to raise_error(ArgumentError, /cannot handle option 'unrecognized'/)
127
127
  end
128
128
  end
129
129
 
@@ -268,6 +268,61 @@ describe R10K::Module::Git do
268
268
  end
269
269
  end
270
270
  end
271
+
272
+ context "when using default_branch_override" do
273
+ before(:each) do
274
+ allow(mock_repo).to receive(:resolve).with(mock_env.ref).and_return(nil)
275
+ end
276
+
277
+ context "and the default branch override is resolvable" do
278
+ it "uses the override" do
279
+ expect(mock_repo).to receive(:resolve).with('default_override').and_return('5566aabb')
280
+ mod = test_module({branch: :control_branch,
281
+ default_branch: 'default',
282
+ default_branch_override: 'default_override'},
283
+ mock_env)
284
+ expect(mod.properties).to include(expected: 'default_override')
285
+ end
286
+ end
287
+
288
+ context "and the default branch override is not resolvable" do
289
+ context "and default branch is provided" do
290
+ it "falls back to the default" do
291
+ expect(mock_repo).to receive(:resolve).with('default_override').and_return(nil)
292
+ expect(mock_repo).to receive(:resolve).with('default').and_return('5566aabb')
293
+ mod = test_module({branch: :control_branch,
294
+ default_branch: 'default',
295
+ default_branch_override: 'default_override'},
296
+ mock_env)
297
+ expect(mod.properties).to include(expected: 'default')
298
+ end
299
+ end
300
+
301
+ context "and default branch is not provided" do
302
+ it "raises the appropriate error" do
303
+ expect(mock_repo).to receive(:resolve).with('default_override').and_return(nil)
304
+ mod = test_module({branch: :control_branch,
305
+ default_branch_override: 'default_override'},
306
+ mock_env)
307
+
308
+ expect { mod.properties }.to raise_error(ArgumentError, /unable to manage.*or resolve the default branch override.*no default provided/i)
309
+ end
310
+ end
311
+
312
+ context "and default branch is not resolvable" do
313
+ it "raises the appropriate error" do
314
+ expect(mock_repo).to receive(:resolve).with('default_override').and_return(nil)
315
+ expect(mock_repo).to receive(:resolve).with('default').and_return(nil)
316
+ mod = test_module({branch: :control_branch,
317
+ default_branch: 'default',
318
+ default_branch_override: 'default_override'},
319
+ mock_env)
320
+
321
+ expect { mod.properties }.to raise_error(ArgumentError, /unable to manage.*or resolve the default branch override.*or resolve default/i)
322
+ end
323
+ end
324
+ end
325
+ end
271
326
  end
272
327
  end
273
328
  end