r10k 3.5.2 → 3.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) 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/.github/workflows/stale.yml +19 -0
  7. data/.travis.yml +8 -1
  8. data/CHANGELOG.mkd +43 -1
  9. data/CODEOWNERS +2 -2
  10. data/README.mkd +13 -4
  11. data/doc/common-patterns.mkd +1 -0
  12. data/doc/dynamic-environments/configuration.mkd +149 -45
  13. data/doc/dynamic-environments/usage.mkd +12 -11
  14. data/doc/puppetfile.mkd +23 -3
  15. data/docker/Gemfile +1 -1
  16. data/docker/Makefile +7 -4
  17. data/docker/docker-compose.yml +18 -0
  18. data/docker/r10k/Dockerfile +4 -3
  19. data/docker/r10k/docker-entrypoint.sh +0 -1
  20. data/docker/r10k/release.Dockerfile +3 -2
  21. data/docker/spec/dockerfile_spec.rb +26 -32
  22. data/integration/tests/git_source/git_source_repeated_remote.rb +68 -0
  23. data/integration/tests/user_scenario/basic_workflow/multi_env_custom_forge_git_module.rb +2 -1
  24. data/integration/tests/user_scenario/basic_workflow/multi_env_custom_forge_git_module_static.rb +2 -1
  25. data/integration/tests/user_scenario/basic_workflow/multi_source_custom_forge_git_module.rb +1 -1
  26. data/integration/tests/user_scenario/basic_workflow/single_env_custom_forge_git_module.rb +2 -1
  27. data/integration/tests/user_scenario/complex_workflow/multi_env_add_change_remove.rb +1 -1
  28. data/integration/tests/user_scenario/complex_workflow/multi_env_remove_re-add.rb +1 -1
  29. data/integration/tests/user_scenario/complex_workflow/multi_env_unamanaged.rb +1 -1
  30. data/lib/r10k/action/base.rb +8 -1
  31. data/lib/r10k/action/deploy/display.rb +46 -10
  32. data/lib/r10k/action/deploy/environment.rb +98 -50
  33. data/lib/r10k/action/deploy/module.rb +51 -29
  34. data/lib/r10k/action/puppetfile/check.rb +3 -1
  35. data/lib/r10k/action/puppetfile/install.rb +20 -23
  36. data/lib/r10k/action/puppetfile/purge.rb +8 -2
  37. data/lib/r10k/action/runner.rb +34 -0
  38. data/lib/r10k/cli/deploy.rb +14 -7
  39. data/lib/r10k/cli/puppetfile.rb +5 -5
  40. data/lib/r10k/content_synchronizer.rb +83 -0
  41. data/lib/r10k/deployment.rb +1 -1
  42. data/lib/r10k/environment/base.rb +30 -3
  43. data/lib/r10k/environment/git.rb +17 -5
  44. data/lib/r10k/environment/name.rb +22 -4
  45. data/lib/r10k/environment/svn.rb +11 -4
  46. data/lib/r10k/environment/with_modules.rb +46 -30
  47. data/lib/r10k/git.rb +1 -0
  48. data/lib/r10k/git/cache.rb +12 -4
  49. data/lib/r10k/git/rugged/credentials.rb +39 -2
  50. data/lib/r10k/git/stateful_repository.rb +4 -0
  51. data/lib/r10k/initializers.rb +2 -0
  52. data/lib/r10k/module.rb +1 -1
  53. data/lib/r10k/module/base.rb +25 -1
  54. data/lib/r10k/module/forge.rb +29 -11
  55. data/lib/r10k/module/git.rb +54 -27
  56. data/lib/r10k/module/local.rb +2 -1
  57. data/lib/r10k/module/svn.rb +24 -18
  58. data/lib/r10k/puppetfile.rb +75 -72
  59. data/lib/r10k/settings.rb +30 -3
  60. data/lib/r10k/source/base.rb +9 -0
  61. data/lib/r10k/source/git.rb +40 -9
  62. data/lib/r10k/source/hash.rb +5 -5
  63. data/lib/r10k/source/svn.rb +5 -3
  64. data/lib/r10k/util/cleaner.rb +21 -0
  65. data/lib/r10k/util/setopts.rb +33 -12
  66. data/lib/r10k/version.rb +1 -1
  67. data/locales/r10k.pot +103 -83
  68. data/r10k.gemspec +1 -1
  69. data/spec/fixtures/unit/action/r10k_creds.yaml +9 -0
  70. data/spec/r10k-mocks/mock_source.rb +1 -1
  71. data/spec/shared-examples/puppetfile-action.rb +7 -7
  72. data/spec/shared-examples/subprocess-runner.rb +11 -5
  73. data/spec/unit/action/deploy/display_spec.rb +35 -5
  74. data/spec/unit/action/deploy/environment_spec.rb +207 -37
  75. data/spec/unit/action/deploy/module_spec.rb +173 -26
  76. data/spec/unit/action/puppetfile/check_spec.rb +2 -2
  77. data/spec/unit/action/puppetfile/install_spec.rb +32 -10
  78. data/spec/unit/action/puppetfile/purge_spec.rb +25 -5
  79. data/spec/unit/action/runner_spec.rb +48 -1
  80. data/spec/unit/environment/git_spec.rb +19 -2
  81. data/spec/unit/environment/name_spec.rb +28 -0
  82. data/spec/unit/environment/svn_spec.rb +12 -0
  83. data/spec/unit/environment/with_modules_spec.rb +74 -0
  84. data/spec/unit/git/cache_spec.rb +10 -0
  85. data/spec/unit/git/rugged/credentials_spec.rb +79 -2
  86. data/spec/unit/git_spec.rb +3 -3
  87. data/spec/unit/module/forge_spec.rb +21 -13
  88. data/spec/unit/module/git_spec.rb +64 -1
  89. data/spec/unit/module_spec.rb +60 -10
  90. data/spec/unit/puppetfile_spec.rb +98 -30
  91. data/spec/unit/settings_spec.rb +12 -0
  92. data/spec/unit/source/git_spec.rb +49 -1
  93. data/spec/unit/util/purgeable_spec.rb +2 -8
  94. data/spec/unit/util/setopts_spec.rb +25 -1
  95. metadata +12 -11
  96. 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
@@ -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)
@@ -11,20 +11,26 @@ 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
+ end
24
+ end
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'})
23
29
  end
24
30
  end
25
31
 
26
32
  describe "setting attributes" do
27
- subject { described_class.new('branan/eight_hundred', '/moduledir', '8.0.0') }
33
+ subject { described_class.new('branan/eight_hundred', '/moduledir', { version: '8.0.0' }) }
28
34
 
29
35
  it "sets the name" do
30
36
  expect(subject.name).to eq 'eight_hundred'
@@ -44,7 +50,7 @@ describe R10K::Module::Forge do
44
50
  end
45
51
 
46
52
  describe "properties" do
47
- 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' }) }
48
54
 
49
55
  it "sets the module type to :forge" do
50
56
  expect(subject.properties).to include(:type => :forge)
@@ -61,7 +67,7 @@ describe R10K::Module::Forge do
61
67
  end
62
68
 
63
69
  context "when a module is deprecated" do
64
- subject { described_class.new('puppetlabs/corosync', fixture_modulepath, :latest) }
70
+ subject { described_class.new('puppetlabs/corosync', fixture_modulepath, { version: :latest }) }
65
71
 
66
72
  it "warns on sync if module is not already insync" do
67
73
  allow(subject).to receive(:status).and_return(:absent)
@@ -71,6 +77,7 @@ describe R10K::Module::Forge do
71
77
  logger_dbl = double(Log4r::Logger)
72
78
  allow_any_instance_of(described_class).to receive(:logger).and_return(logger_dbl)
73
79
 
80
+ allow(logger_dbl).to receive(:info).with(/Deploying module to.*/)
74
81
  expect(logger_dbl).to receive(:warn).with(/puppet forge module.*puppetlabs-corosync.*has been deprecated/i)
75
82
 
76
83
  subject.sync
@@ -82,6 +89,7 @@ describe R10K::Module::Forge do
82
89
  logger_dbl = double(Log4r::Logger)
83
90
  allow_any_instance_of(described_class).to receive(:logger).and_return(logger_dbl)
84
91
 
92
+ allow(logger_dbl).to receive(:info).with(/Deploying module to.*/)
85
93
  expect(logger_dbl).to_not receive(:warn).with(/puppet forge module.*puppetlabs-corosync.*has been deprecated/i)
86
94
 
87
95
  subject.sync
@@ -90,12 +98,12 @@ describe R10K::Module::Forge do
90
98
 
91
99
  describe '#expected_version' do
92
100
  it "returns an explicitly given expected version" do
93
- 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' })
94
102
  expect(subject.expected_version).to eq '8.0.0'
95
103
  end
96
104
 
97
105
  it "uses the latest version from the forge when the version is :latest" do
98
- subject = described_class.new('branan/eight_hundred', fixture_modulepath, :latest)
106
+ subject = described_class.new('branan/eight_hundred', fixture_modulepath, { version: :latest })
99
107
  expect(subject.v3_module).to receive_message_chain(:current_release, :version).and_return('8.8.8')
100
108
  expect(subject.expected_version).to eq '8.8.8'
101
109
  end
@@ -103,7 +111,7 @@ describe R10K::Module::Forge do
103
111
 
104
112
  describe "determining the status" do
105
113
 
106
- subject { described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0') }
114
+ subject { described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' }) }
107
115
 
108
116
  it "is :absent if the module directory is absent" do
109
117
  allow(subject).to receive(:exist?).and_return false
@@ -148,7 +156,7 @@ describe R10K::Module::Forge do
148
156
  end
149
157
 
150
158
  describe "#sync" do
151
- subject { described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0') }
159
+ subject { described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' }) }
152
160
 
153
161
  it 'does nothing when the module is in sync' do
154
162
  allow(subject).to receive(:status).and_return :insync
@@ -180,7 +188,7 @@ describe R10K::Module::Forge do
180
188
 
181
189
  describe '#install' do
182
190
  it 'installs the module from the forge' do
183
- subject = described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0')
191
+ subject = described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' })
184
192
  release = instance_double('R10K::Forge::ModuleRelease')
185
193
  expect(R10K::Forge::ModuleRelease).to receive(:new).with('branan-eight_hundred', '8.0.0').and_return(release)
186
194
  expect(release).to receive(:install).with(subject.path)
@@ -190,7 +198,7 @@ describe R10K::Module::Forge do
190
198
 
191
199
  describe '#uninstall' do
192
200
  it 'removes the module path' do
193
- subject = described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0')
201
+ subject = described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' })
194
202
  expect(FileUtils).to receive(:rm_rf).with(subject.path.to_s)
195
203
  subject.uninstall
196
204
  end
@@ -198,7 +206,7 @@ describe R10K::Module::Forge do
198
206
 
199
207
  describe '#reinstall' do
200
208
  it 'uninstalls and then installs the module' do
201
- subject = described_class.new('branan/eight_hundred', fixture_modulepath, '8.0.0')
209
+ subject = described_class.new('branan/eight_hundred', fixture_modulepath, { version: '8.0.0' })
202
210
  expect(subject).to receive(:uninstall)
203
211
  expect(subject).to receive(:install)
204
212
  subject.reinstall
@@ -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
 
@@ -210,6 +210,14 @@ describe R10K::Module::Git do
210
210
  expect(mod.desired_ref).to eq(:control_branch)
211
211
  end
212
212
 
213
+ it "warns control branch may be unresolvable" do
214
+ logger = double("logger")
215
+ allow_any_instance_of(described_class).to receive(:logger).and_return(logger)
216
+ expect(logger).to receive(:warn).with(/Cannot track control repo branch.*boolean.*/)
217
+
218
+ test_module(branch: :control_branch)
219
+ end
220
+
213
221
  context "when default ref is provided and resolvable" do
214
222
  it "uses default ref" do
215
223
  expect(mock_repo).to receive(:resolve).with('default').and_return('abc123')
@@ -268,6 +276,61 @@ describe R10K::Module::Git do
268
276
  end
269
277
  end
270
278
  end
279
+
280
+ context "when using default_branch_override" do
281
+ before(:each) do
282
+ allow(mock_repo).to receive(:resolve).with(mock_env.ref).and_return(nil)
283
+ end
284
+
285
+ context "and the default branch override is resolvable" do
286
+ it "uses the override" do
287
+ expect(mock_repo).to receive(:resolve).with('default_override').and_return('5566aabb')
288
+ mod = test_module({branch: :control_branch,
289
+ default_branch: 'default',
290
+ default_branch_override: 'default_override'},
291
+ mock_env)
292
+ expect(mod.properties).to include(expected: 'default_override')
293
+ end
294
+ end
295
+
296
+ context "and the default branch override is not resolvable" do
297
+ context "and default branch is provided" do
298
+ it "falls back to the default" do
299
+ expect(mock_repo).to receive(:resolve).with('default_override').and_return(nil)
300
+ expect(mock_repo).to receive(:resolve).with('default').and_return('5566aabb')
301
+ mod = test_module({branch: :control_branch,
302
+ default_branch: 'default',
303
+ default_branch_override: 'default_override'},
304
+ mock_env)
305
+ expect(mod.properties).to include(expected: 'default')
306
+ end
307
+ end
308
+
309
+ context "and default branch is not provided" do
310
+ it "raises the appropriate error" do
311
+ expect(mock_repo).to receive(:resolve).with('default_override').and_return(nil)
312
+ mod = test_module({branch: :control_branch,
313
+ default_branch_override: 'default_override'},
314
+ mock_env)
315
+
316
+ expect { mod.properties }.to raise_error(ArgumentError, /unable to manage.*or resolve the default branch override.*no default provided/i)
317
+ end
318
+ end
319
+
320
+ context "and default branch is not resolvable" do
321
+ it "raises the appropriate error" do
322
+ expect(mock_repo).to receive(:resolve).with('default_override').and_return(nil)
323
+ expect(mock_repo).to receive(:resolve).with('default').and_return(nil)
324
+ mod = test_module({branch: :control_branch,
325
+ default_branch: 'default',
326
+ default_branch_override: 'default_override'},
327
+ mock_env)
328
+
329
+ expect { mod.properties }.to raise_error(ArgumentError, /unable to manage.*or resolve the default branch override.*or resolve default/i)
330
+ end
331
+ end
332
+ end
333
+ end
271
334
  end
272
335
  end
273
336
  end