r10k 1.2.4 → 1.3.0rc1

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 (57) hide show
  1. checksums.yaml +8 -8
  2. data/{CHANGELOG → CHANGELOG.mkd} +51 -41
  3. data/doc/dynamic-environments/configuration.mkd +1 -1
  4. data/doc/dynamic-environments/git-environments.markdown +19 -0
  5. data/doc/dynamic-environments/usage.mkd +6 -0
  6. data/lib/r10k/cli/deploy.rb +15 -0
  7. data/lib/r10k/cli/ext/logging.rb +0 -1
  8. data/lib/r10k/cli/module/deploy.rb +0 -1
  9. data/lib/r10k/cli/puppetfile.rb +2 -2
  10. data/lib/r10k/cli.rb +2 -16
  11. data/lib/r10k/deployment/environment.rb +9 -79
  12. data/lib/r10k/deployment/source.rb +15 -89
  13. data/lib/r10k/deployment.rb +13 -14
  14. data/lib/r10k/environment/base.rb +42 -0
  15. data/lib/r10k/environment/git.rb +79 -0
  16. data/lib/r10k/environment/svn.rb +73 -0
  17. data/lib/r10k/environment.rb +7 -0
  18. data/lib/r10k/execution.rb +0 -1
  19. data/lib/r10k/git/cache.rb +11 -5
  20. data/lib/r10k/git/repository.rb +1 -8
  21. data/lib/r10k/git/working_dir.rb +11 -34
  22. data/lib/r10k/git.rb +0 -1
  23. data/lib/r10k/instance_cache.rb +32 -0
  24. data/lib/r10k/keyed_factory.rb +39 -0
  25. data/lib/r10k/module/forge.rb +2 -3
  26. data/lib/r10k/module/svn.rb +0 -1
  27. data/lib/r10k/puppetfile.rb +0 -1
  28. data/lib/r10k/registry.rb +3 -31
  29. data/lib/r10k/source/base.rb +60 -0
  30. data/lib/r10k/source/git.rb +195 -0
  31. data/lib/r10k/source/svn.rb +140 -0
  32. data/lib/r10k/source.rb +39 -0
  33. data/lib/r10k/svn/remote.rb +48 -0
  34. data/lib/r10k/svn/working_dir.rb +0 -2
  35. data/lib/r10k/svn.rb +6 -0
  36. data/lib/r10k/task/deployment.rb +1 -2
  37. data/lib/r10k/task.rb +0 -2
  38. data/lib/r10k/task_runner.rb +0 -1
  39. data/lib/r10k/util/core_ext/hash_ext.rb +19 -0
  40. data/lib/r10k/util/subprocess.rb +0 -1
  41. data/lib/r10k/version.rb +1 -1
  42. data/lib/r10k.rb +1 -0
  43. data/spec/unit/deployment/environment_spec.rb +16 -15
  44. data/spec/unit/environment/git_spec.rb +81 -0
  45. data/spec/unit/environment/svn_spec.rb +76 -0
  46. data/spec/unit/git/repository_spec.rb +0 -10
  47. data/spec/unit/git/working_dir_spec.rb +1 -110
  48. data/spec/unit/{registry_spec.rb → instance_cache_spec.rb} +3 -3
  49. data/spec/unit/keyed_factory_spec.rb +51 -0
  50. data/spec/unit/source/git_spec.rb +274 -0
  51. data/spec/unit/source/svn_spec.rb +102 -0
  52. data/spec/unit/source_spec.rb +10 -0
  53. data/spec/unit/svn/remote_spec.rb +21 -0
  54. data/spec/unit/util/core_ext/hash_ext_spec.rb +63 -0
  55. metadata +36 -10
  56. data/lib/r10k/git/alternates.rb +0 -49
  57. data/spec/unit/git/alternates_spec.rb +0 -90
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+ require 'r10k/environment'
3
+
4
+ describe R10K::Environment::SVN do
5
+
6
+ subject do
7
+ described_class.new(
8
+ 'myenv',
9
+ '/some/nonexistent/environmentdir',
10
+ 'svn-dirname',
11
+ {
12
+ :remote => 'https://svn-server.site/svn-repo/trunk'
13
+ }
14
+ )
15
+ end
16
+
17
+ let(:working_dir) { subject.working_dir }
18
+
19
+ describe "storing attributes" do
20
+ it "can return the environment name" do
21
+ expect(subject.name).to eq 'myenv'
22
+ end
23
+
24
+ it "can return the environment basedir" do
25
+ expect(subject.basedir).to eq '/some/nonexistent/environmentdir'
26
+ end
27
+
28
+ it "can return the environment dirname" do
29
+ expect(subject.dirname).to eq 'svn-dirname'
30
+ end
31
+
32
+ it "can return the environment remote" do
33
+ expect(subject.remote).to eq 'https://svn-server.site/svn-repo/trunk'
34
+ end
35
+ end
36
+
37
+ describe "synchronizing the environment" do
38
+ it "updates all modules when creating a new environment" do
39
+ allow(working_dir).to receive(:is_svn?).and_return(false)
40
+ expect(working_dir).to receive(:checkout)
41
+ expect(subject).to receive(:sync_modules)
42
+ subject.sync
43
+ end
44
+
45
+ it "does not update all modules when updating an existing environment" do
46
+ allow(working_dir).to receive(:is_svn?).and_return(true)
47
+ expect(working_dir).to receive(:update)
48
+ expect(subject).to_not receive(:sync_modules)
49
+ subject.sync
50
+ end
51
+ end
52
+
53
+ describe "generating a puppetfile for the environment" do
54
+ let(:puppetfile) { subject.puppetfile }
55
+
56
+ it "creates a puppetfile at the full path to the environment" do
57
+ expect(puppetfile.basedir).to eq '/some/nonexistent/environmentdir/svn-dirname'
58
+ end
59
+
60
+ it "sets the moduledir to 'modules' relative to the environment path" do
61
+ expect(puppetfile.moduledir).to eq '/some/nonexistent/environmentdir/svn-dirname/modules'
62
+ end
63
+
64
+ it "sets the puppetfile path to 'Puppetfile' relative to the environment path" do
65
+ expect(puppetfile.puppetfile_path).to eq '/some/nonexistent/environmentdir/svn-dirname/Puppetfile'
66
+ end
67
+ end
68
+
69
+ describe "enumerating modules" do
70
+ it "loads the Puppetfile and returns modules in that puppetfile" do
71
+ expect(subject.puppetfile).to receive(:load)
72
+ expect(subject.puppetfile).to receive(:modules).and_return [:modules]
73
+ expect(subject.modules).to eq([:modules])
74
+ end
75
+ end
76
+ end
@@ -21,14 +21,4 @@ describe R10K::Git::Repository do
21
21
  })
22
22
  end
23
23
  end
24
-
25
- describe "tags" do
26
- let(:tags) { %w[0.1.1 0.1.2 0.1.3 0.1.4 0.2.0 0.3.0 2.0.0] }
27
- let(:output) { tags.map {|x| x + "\n"}.join }
28
-
29
- it "returns a list of tags for this repo" do
30
- expect(subject).to receive(:git).with(%w[tag -l], anything).and_return(double(:stdout => output))
31
- expect(subject.tags).to eq(tags)
32
- end
33
- end
34
24
  end
@@ -2,120 +2,11 @@ require 'spec_helper'
2
2
  require 'r10k/git'
3
3
 
4
4
  describe R10K::Git::WorkingDir do
5
- include_context "fail on execution"
6
5
 
7
6
  describe "initializing" do
8
7
  it "generates a new cache for the remote" do
9
- wd = described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir')
8
+ wd = described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/tmp')
10
9
  wd.cache.should be_kind_of R10K::Git::Cache
11
10
  end
12
-
13
- it "uses the provided ref as the dirname when no dirname is given" do
14
- wd = described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir')
15
- expect(wd.dirname).to eq('master')
16
- end
17
-
18
- it "uses an explicit dirname when given" do
19
- wd = described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir', 'mydir')
20
- expect(wd.dirname).to eq('mydir')
21
- end
22
- end
23
-
24
- describe "synchronizing the working directory" do
25
- subject { described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir') }
26
- it "clones the repository when the repository doesn't exist" do
27
- expect(subject).to receive(:cloned?).and_return false
28
- expect(subject).to receive(:clone)
29
- subject.sync
30
- end
31
-
32
- it "updates the repository when the repository already exists" do
33
- expect(subject).to receive(:cloned?).and_return true
34
- expect(subject).to receive(:update)
35
- subject.sync
36
- end
37
- end
38
-
39
- describe "when cloning a new repository" do
40
- subject { described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir') }
41
-
42
- before do
43
- allow(subject).to receive(:cloned?).and_return false
44
- end
45
-
46
- it "updates the cache before cloning" do
47
- expect(subject.cache).to receive(:sync)
48
- allow(subject).to receive(:git)
49
- allow(subject).to receive(:checkout)
50
- subject.sync
51
- end
52
-
53
- it "clones the repository and uses the cache git dir as an object reference" do
54
- allow(subject.cache).to receive(:sync)
55
- expect(subject).to receive(:git).with(['clone', '--reference', subject.cache.git_dir,
56
- 'git://github.com/adrienthebo/r10k-fixture-repo',
57
- '/some/nonexistent/dir/master'])
58
- expect(subject).to receive(:git).with(['remote', 'add', 'cache', subject.cache.git_dir],
59
- an_instance_of(Hash))
60
-
61
- expect(subject).to receive(:git).with(['fetch', 'cache'], an_instance_of(Hash))
62
- allow(subject).to receive(:checkout)
63
- subject.sync
64
- end
65
-
66
- it 'checks out the specific ref after the clone' do
67
- allow(subject.cache).to receive(:sync)
68
- allow(subject).to receive(:git)
69
- expect(subject).to receive(:checkout)
70
- subject.sync
71
- end
72
- end
73
-
74
- describe "updating an existing repository" do
75
- subject { described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir') }
76
-
77
- before do
78
- allow(subject).to receive(:cloned?).and_return true
79
- end
80
-
81
- it "updates the remotes when they are out of sync" do
82
- allow(subject).to receive(:ref_needs_fetch?).and_return false
83
- allow(subject).to receive(:needs_checkout?).and_return false
84
-
85
- expect(subject).to receive(:update_remotes?).and_return true
86
- expect(subject).to receive(:update_remotes)
87
-
88
- subject.sync
89
- end
90
-
91
- it "updates the cache when the ref requires an update" do
92
- allow(subject).to receive(:update_remotes?).and_return false
93
-
94
- expect(subject).to receive(:ref_needs_fetch?).and_return true
95
- expect(subject).to receive(:fetch_from_cache)
96
- expect(subject).to receive(:checkout).with(an_instance_of(R10K::Git::Ref))
97
-
98
- subject.sync
99
- end
100
-
101
- it "checks out the ref when the wrong commit is checked out" do
102
- allow(subject).to receive(:update_remotes?).and_return false
103
- allow(subject).to receive(:ref_needs_fetch?).and_return false
104
-
105
- expect(subject).to receive(:needs_checkout?).and_return true
106
- expect(subject).to receive(:checkout).with(an_instance_of(R10K::Git::Ref))
107
-
108
- subject.sync
109
- end
110
-
111
- it "doesn't update the repo when everything is in sync" do
112
- allow(subject).to receive(:update_remotes?).and_return false
113
- allow(subject).to receive(:ref_needs_fetch?).and_return false
114
- allow(subject).to receive(:needs_checkout?).and_return false
115
-
116
- expect(subject).to_not receive(:checkout)
117
-
118
- subject.sync
119
- end
120
11
  end
121
12
  end
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
- require 'r10k/registry'
3
+ require 'r10k/instance_cache'
4
4
 
5
- describe R10K::Registry do
5
+ describe R10K::InstanceCache do
6
6
 
7
- describe "setting up a new registry" do
7
+ describe "setting up a new instance cache" do
8
8
  let(:klass) do
9
9
  dubs = double('test class')
10
10
  allow(dubs).to receive(:new) { |*args| args }
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+ require 'r10k/keyed_factory'
3
+
4
+ describe R10K::KeyedFactory do
5
+
6
+ let(:registered) { Class.new }
7
+
8
+ describe "registering implementations" do
9
+ it "can register new implementations" do
10
+ subject.register(:klass, registered)
11
+ expect(subject.retrieve(:klass)).to eq registered
12
+ end
13
+
14
+ it "raises an error when a duplicate implementation is registered" do
15
+ subject.register(:klass, registered)
16
+
17
+ expect {
18
+ subject.register(:klass, registered)
19
+ }.to raise_error(R10K::KeyedFactory::DuplicateImplementationError)
20
+ end
21
+
22
+ it "can register classes with nil as a key" do
23
+ subject.register(nil, registered)
24
+ expect(subject.retrieve(nil)).to eq registered
25
+ end
26
+ end
27
+
28
+ describe "generating instances" do
29
+ before do
30
+ subject.register(:klass, registered)
31
+ end
32
+
33
+ it "generates an instance with the associated class" do
34
+ instance = subject.generate(:klass)
35
+ expect(instance).to be_a_kind_of registered
36
+ end
37
+
38
+ it "can generate a class with nil as a key" do
39
+ other = Class.new
40
+ subject.register(nil, other)
41
+ instance = subject.generate(nil)
42
+ expect(instance).to be_a_kind_of other
43
+ end
44
+
45
+ it "raises an error if no implementation was registered with the given key" do
46
+ expect {
47
+ subject.generate(:foo)
48
+ }.to raise_error(R10K::KeyedFactory::UnknownImplementationError)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,274 @@
1
+ require 'spec_helper'
2
+ require 'r10k/source'
3
+
4
+ describe R10K::Source::Git do
5
+
6
+ subject do
7
+ described_class.new('mysource', '/some/nonexistent/dir',
8
+ {:remote => 'https://git-server/repo.git'})
9
+ end
10
+
11
+ it "stores the name" do
12
+ expect(subject.name).to eq 'mysource'
13
+ end
14
+
15
+ it "stores the basedir" do
16
+ expect(subject.basedir).to eq '/some/nonexistent/dir'
17
+ end
18
+
19
+ describe "preloading" do
20
+ it "fetches the git cache" do
21
+ expect(subject.cache).to receive(:sync)
22
+ subject.preload!
23
+ end
24
+ end
25
+
26
+ describe "lazily generating environments" do
27
+ it "returns an empty list of environments when the cache has not been created" do
28
+ allow(subject.cache).to receive(:cached?).and_return false
29
+ expect(subject.environments).to be_empty
30
+ end
31
+
32
+ it "generates environments when the cache is present and environments have not been loaded" do
33
+ allow(subject.cache).to receive(:cached?).and_return true
34
+ allow(subject).to receive(:generate_environments).and_return %w[hi]
35
+ expect(subject.environments).to have(1).items
36
+ end
37
+
38
+ it "doesn't recreate environments if they have already been loaded" do
39
+ allow(subject.cache).to receive(:cached?).and_return true
40
+ allow(subject).to receive(:generate_environments).once.and_return %w[hi]
41
+ expect(subject.environments).to have(1).items
42
+ expect(subject.environments).to have(1).items
43
+ end
44
+ end
45
+
46
+ describe "eagerly generating environments" do
47
+ before do
48
+ allow(subject.cache).to receive(:branches).and_return %w[master]
49
+ end
50
+
51
+ let(:master_env) { subject.generate_environments.first }
52
+
53
+ it "creates an environment for each branch" do
54
+ expect(subject.generate_environments).to have(1).items
55
+ end
56
+
57
+ it "copies the source remote to the environment" do
58
+ expect(master_env.remote).to eq subject.remote
59
+ end
60
+
61
+ it "uses the branch name as the directory by default" do
62
+ expect(master_env.dirname).to eq 'master'
63
+ end
64
+ end
65
+ end
66
+
67
+ describe R10K::Source::Git, "handling invalid branch names" do
68
+ %w[correct_and_warn correct].each do |setting|
69
+ describe "when invalid is #{setting}" do
70
+ subject do
71
+ described_class.new('/some/nonexistent/dir', 'mysource', {
72
+ :remote => 'https://git-server/repo.git',
73
+ :invalid_branches => setting
74
+ })
75
+ end
76
+
77
+ before do
78
+ allow(subject.cache).to receive(:branches).and_return ['master', 'invalid-branch']
79
+ end
80
+
81
+ it "creates an environment for each branch" do
82
+ expect(subject.generate_environments).to have(2).items
83
+ end
84
+
85
+ it "removes invalid characters from branch names" do
86
+ invalid_env = subject.generate_environments.last
87
+ expect(invalid_env.dirname).to eq 'invalid_branch'
88
+ end
89
+ end
90
+ end
91
+
92
+ describe "when invalid is 'error'" do
93
+ subject do
94
+ described_class.new('/some/nonexistent/dir', 'mysource', {
95
+ :remote => 'https://git-server/repo.git',
96
+ :invalid_branches => 'error',
97
+ })
98
+ end
99
+
100
+ before do
101
+ allow(subject.cache).to receive(:branches).and_return ['master', 'invalid-branch']
102
+ end
103
+
104
+ it "only creates an environment for valid branches" do
105
+ expect(subject.generate_environments).to have(1).items
106
+ end
107
+ end
108
+ end
109
+
110
+ # Since prefixing is an immutable property of a source, it's easier to create
111
+ # a new context and duplicate stubs in a single location rather than packing a
112
+ # single test with all the stubs that entirely recreate the source.
113
+ describe R10K::Source::Git, 'when prefixing is enabled' do
114
+ subject do
115
+ described_class.new(
116
+ 'prefixed',
117
+ '/some/nonexistent/dir',
118
+ {
119
+ :prefix => true,
120
+ :remote => 'https://git-server/repo.git',
121
+ })
122
+ end
123
+
124
+ describe "generating prefixed environments" do
125
+ before do
126
+ allow(subject.cache).to receive(:cached?).and_return true
127
+ allow(subject.cache).to receive(:branches).and_return %w[master other]
128
+ end
129
+
130
+ let(:environments) { subject.environments }
131
+
132
+ it "creates an environment for each branch" do
133
+ expect(subject.environments).to have(2).items
134
+ end
135
+
136
+ it "prefixes the source name to environments when prefixing is enabled" do
137
+ expect(environments[0].dirname).to eq 'prefixed_master'
138
+ expect(environments[1].dirname).to eq 'prefixed_other'
139
+ end
140
+ end
141
+ end
142
+
143
+ describe R10K::Source::Git, 'registering as a source' do
144
+ it "registers with the :git key" do
145
+ expect(R10K::Source.retrieve(:git)).to eq described_class
146
+ end
147
+
148
+ it "registers with the nil key" do
149
+ expect(R10K::Source.retrieve(nil)).to eq described_class
150
+ end
151
+ end
152
+
153
+ describe R10K::Source::Git::BranchName do
154
+ describe "prefixing" do
155
+ it "uses the branch name as the dirname when prefixing is off" do
156
+ bn = described_class.new('mybranch', {:prefix => false, :sourcename => 'foo'})
157
+ expect(bn.dirname).to eq 'mybranch'
158
+ end
159
+
160
+ it "prepends the source name when prefixing is on" do
161
+ bn = described_class.new('mybranch', {:prefix => true, :sourcename => 'foo'})
162
+ expect(bn.dirname).to eq 'foo_mybranch'
163
+ end
164
+ end
165
+
166
+ describe "determining the validate behavior with :invalid" do
167
+ [
168
+ ['correct_and_warn', {:validate => true, :correct => true}],
169
+ ['correct', {:validate => false, :correct => true}],
170
+ ['error', {:validate => true, :correct => false}],
171
+ ].each do |(setting, outcome)|
172
+ it "treats #{setting} as #{outcome.inspect}" do
173
+ bn = described_class.new('mybranch', {:invalid => setting})
174
+ expect(bn.validate?).to eq outcome[:validate]
175
+ expect(bn.correct?).to eq outcome[:correct]
176
+ end
177
+ end
178
+ end
179
+
180
+ describe "determining if a branch is a valid environment name" do
181
+ invalid_cases = [
182
+ 'hyphenated-branch',
183
+ 'dotted.branch',
184
+ 'slashed/branch',
185
+ 'at@branch',
186
+ 'http://branch'
187
+ ]
188
+
189
+ valid_cases = [
190
+ 'my_branchname',
191
+ 'my_issue_346',
192
+ ]
193
+
194
+ describe "and validate is false" do
195
+ invalid_cases.each do |branch|
196
+ it "is valid if the branch is #{branch}" do
197
+ bn = described_class.new(branch, {:validate => false})
198
+ expect(bn).to be_valid
199
+ end
200
+ end
201
+
202
+ valid_cases.each do |branch|
203
+ it "is valid if the branch is #{branch}" do
204
+ bn = described_class.new(branch, {:validate => false})
205
+ expect(bn).to be_valid
206
+ end
207
+ end
208
+ end
209
+
210
+ describe "and validate is true" do
211
+ invalid_cases.each do |branch|
212
+ it "is invalid if the branch is #{branch}" do
213
+ bn = described_class.new(branch, {:validate => true})
214
+ expect(bn).to_not be_valid
215
+ end
216
+ end
217
+
218
+ valid_cases.each do |branch|
219
+ it "is valid if the branch is #{branch}" do
220
+ bn = described_class.new(branch, {:validate => true})
221
+ expect(bn).to be_valid
222
+ end
223
+ end
224
+
225
+ end
226
+ end
227
+
228
+ describe "correcting branch names" do
229
+ invalid_cases = [
230
+ 'hyphenated-branch',
231
+ 'dotted.branch',
232
+ 'slashed/branch',
233
+ 'at@branch',
234
+ 'http://branch'
235
+ ]
236
+
237
+ valid_cases = [
238
+ 'my_branchname',
239
+ 'my_issue_346',
240
+ ]
241
+
242
+ describe "and correct is false" do
243
+ invalid_cases.each do |branch|
244
+ it "doesn't modify #{branch}" do
245
+ bn = described_class.new(branch.dup, {:correct => false})
246
+ expect(bn.dirname).to eq branch
247
+ end
248
+ end
249
+
250
+ valid_cases.each do |branch|
251
+ it "doesn't modify #{branch}" do
252
+ bn = described_class.new(branch.dup, {:correct => false})
253
+ expect(bn.dirname).to eq branch
254
+ end
255
+ end
256
+ end
257
+
258
+ describe "and correct is true" do
259
+ invalid_cases.each do |branch|
260
+ it "replaces invalid characters in #{branch} with underscores" do
261
+ bn = described_class.new(branch.dup, {:correct => true})
262
+ expect(bn.dirname).to eq branch.gsub(/\W/, '_')
263
+ end
264
+ end
265
+
266
+ valid_cases.each do |branch|
267
+ it "doesn't modify #{branch}" do
268
+ bn = described_class.new(branch.dup, {:correct => true})
269
+ expect(bn.dirname).to eq branch
270
+ end
271
+ end
272
+ end
273
+ end
274
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+ require 'r10k/source'
3
+
4
+ describe R10K::Source::SVN do
5
+
6
+ subject do
7
+ described_class.new('mysource', '/some/nonexistent/dir',
8
+ {:remote => 'https://svn-server.site/repo'})
9
+ end
10
+
11
+ it "stores the name" do
12
+ expect(subject.name).to eq 'mysource'
13
+ end
14
+
15
+ it "stores the basedir" do
16
+ expect(subject.basedir).to eq '/some/nonexistent/dir'
17
+ end
18
+
19
+
20
+ describe "lazily generating environments" do
21
+ it "generates environments when they have not been loaded" do
22
+ expect(subject).to receive(:generate_environments).and_return %w[hi]
23
+ expect(subject.environments).to eq %w[hi]
24
+ end
25
+
26
+ it "doesn't recreate environments if they have already been loaded" do
27
+ expect(subject).to receive(:generate_environments).once.and_return %w[hi]
28
+ subject.environments
29
+ subject.environments
30
+ end
31
+ end
32
+
33
+ describe "eagerly generating environments" do
34
+ before do
35
+ allow(subject.svn_remote).to receive(:branches).and_return %w[apache dns robobutler]
36
+ end
37
+
38
+ let(:environments) { subject.generate_environments }
39
+
40
+ it "creates an environment for each branch and the trunk" do
41
+ expect(environments[0].name).to eq 'production'
42
+ expect(environments[1].name).to eq 'apache'
43
+ expect(environments[2].name).to eq 'dns'
44
+ expect(environments[3].name).to eq 'robobutler'
45
+ end
46
+
47
+ it "maps trunk to production" do
48
+ expect(environments[0].remote).to eq 'https://svn-server.site/repo/trunk'
49
+ end
50
+
51
+ it "sets the remote for branch environments to subdirectories of the branches/ directory" do
52
+ expect(environments[1].remote).to eq 'https://svn-server.site/repo/branches/apache'
53
+ expect(environments[2].remote).to eq 'https://svn-server.site/repo/branches/dns'
54
+ expect(environments[3].remote).to eq 'https://svn-server.site/repo/branches/robobutler'
55
+ end
56
+
57
+ it "uses the branch name as the directory by default" do
58
+ expect(environments[0].dirname).to eq 'production'
59
+ expect(environments[1].dirname).to eq 'apache'
60
+ expect(environments[2].dirname).to eq 'dns'
61
+ expect(environments[3].dirname).to eq 'robobutler'
62
+ end
63
+ end
64
+ end
65
+
66
+ describe R10K::Source::SVN, 'when prefixing is enabled' do
67
+ subject do
68
+ described_class.new(
69
+ 'mysource',
70
+ '/some/nonexistent/dir',
71
+ {
72
+ :remote => 'https://svn-server.site/repo',
73
+ :prefix => true
74
+ }
75
+ )
76
+ end
77
+
78
+ describe "generating prefixed environments" do
79
+ before do
80
+ allow(subject.svn_remote).to receive(:branches).and_return %w[apache dns robobutler]
81
+ end
82
+
83
+ let(:environments) { subject.generate_environments }
84
+
85
+ it "creates an environment for each branch and the trunk" do
86
+ expect(environments).to have(4).items
87
+ end
88
+
89
+ it "prefixes the source name to environments" do
90
+ expect(environments[0].dirname).to eq 'mysource_production'
91
+ expect(environments[1].dirname).to eq 'mysource_apache'
92
+ expect(environments[2].dirname).to eq 'mysource_dns'
93
+ expect(environments[3].dirname).to eq 'mysource_robobutler'
94
+ end
95
+ end
96
+ end
97
+
98
+ describe R10K::Source::SVN, 'registering as a source' do
99
+ it "registers with the :svn key" do
100
+ expect(R10K::Source.retrieve(:svn)).to eq described_class
101
+ end
102
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ require 'r10k/source'
3
+
4
+ describe R10K::Source do
5
+ it "implementds methods for a keyed factory" do
6
+ expect(described_class).to respond_to :register
7
+ expect(described_class).to respond_to :retrieve
8
+ expect(described_class).to respond_to :generate
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ require 'r10k'
2
+ require 'r10k/svn'
3
+
4
+ describe R10K::SVN::Remote do
5
+ subject { described_class.new('https://svn-server.site/repo') }
6
+
7
+ it "generates the trunk URL by appending '/trunk' to the base URL" do
8
+ expect(subject.trunk).to eq 'https://svn-server.site/repo/trunk'
9
+ end
10
+
11
+ describe "retrieving branches" do
12
+ let(:branches) do
13
+ %[apache/\ndns/\nrobobutler/\nstaging/\n]
14
+ end
15
+
16
+ it "enumerates the /branches directory of the base URL" do
17
+ allow(subject).to receive(:svn).with(['ls', 'https://svn-server.site/repo/branches']).and_return(branches)
18
+ expect(subject.branches).to eq(%w[apache dns robobutler staging])
19
+ end
20
+ end
21
+ end