Update .travis.yml
[puppet_vcsrepo.git] / spec / unit / puppet / provider / vcsrepo / git_spec.rb
1 require 'spec_helper'
2
3 describe Puppet::Type.type(:vcsrepo).provider(:git_provider) do
4   def branch_a_list(include_branch = nil?)
5     <<branches
6 end
7 #{"*  master" unless  include_branch.nil?}
8 #{"*  " + include_branch unless !include_branch}
9    remote/origin/master
10    remote/origin/foo
11
12 branches
13     end
14   let(:resource) { Puppet::Type.type(:vcsrepo).new({
15     :name     => 'test',
16     :ensure   => :present,
17     :provider => :git,
18     :revision => '2634',
19     :source   => 'git@repo',
20     :path     => '/tmp/test',
21     :force    => false
22   })}
23
24   let(:provider) { resource.provider }
25
26   before :each do
27     Puppet::Util.stubs(:which).with('git').returns('/usr/bin/git')
28   end
29
30   context 'creating' do
31     context "with a revision that is a remote branch" do
32       it "should execute 'git clone' and 'git checkout -b'" do
33         resource[:revision] = 'only/remote'
34         Dir.expects(:chdir).with('/').at_least_once.yields
35         Dir.expects(:chdir).with('/tmp/test').at_least_once.yields
36         provider.expects(:git).with('clone', resource.value(:source), resource.value(:path))
37         provider.expects(:update_submodules)
38         provider.expects(:update_remote_url).with("origin", resource.value(:source)).returns false
39         provider.expects(:git).with('branch', '-a').returns(branch_a_list(resource.value(:revision)))
40         provider.expects(:git).with('checkout', '--force', resource.value(:revision))
41         provider.create
42       end
43     end
44
45     context "with a remote not named 'origin'" do
46       it "should execute 'git clone --origin not_origin" do
47         resource[:remote] = 'not_origin'
48         Dir.expects(:chdir).with('/').at_least_once.yields
49         Dir.expects(:chdir).with('/tmp/test').at_least_once.yields
50         provider.expects(:git).with('clone', '--origin', 'not_origin', resource.value(:source), resource.value(:path))
51         provider.expects(:update_submodules)
52         provider.expects(:update_remote_url).with("not_origin", resource.value(:source)).returns false
53         provider.expects(:git).with('branch', '-a').returns(branch_a_list(resource.value(:revision)))
54         provider.expects(:git).with('checkout', '--force', resource.value(:revision))
55         provider.create
56       end
57     end
58
59     context "with shallow clone enable" do
60       it "should execute 'git clone --depth 1'" do
61         resource[:revision] = 'only/remote'
62         resource[:depth] = 1
63         Dir.expects(:chdir).with('/').at_least_once.yields
64         Dir.expects(:chdir).with('/tmp/test').at_least_once.yields
65         provider.expects(:git).with('clone', '--depth', '1', resource.value(:source), resource.value(:path))
66         provider.expects(:update_submodules)
67         provider.expects(:update_remote_url).with("origin", resource.value(:source)).returns false
68         provider.expects(:git).with('branch', '-a').returns(branch_a_list(resource.value(:revision)))
69         provider.expects(:git).with('checkout', '--force', resource.value(:revision))
70         provider.create
71       end
72     end
73
74     context "with a revision that is not a remote branch" do
75       it "should execute 'git clone' and 'git reset --hard'" do
76         resource[:revision] = 'a-commit-or-tag'
77         Dir.expects(:chdir).with('/').at_least_once.yields
78         Dir.expects(:chdir).with('/tmp/test').at_least_once.yields
79         provider.expects(:git).with('clone', resource.value(:source), resource.value(:path))
80         provider.expects(:update_submodules)
81         provider.expects(:update_remote_url).with("origin", resource.value(:source)).returns false
82         provider.expects(:git).with('branch', '-a').returns(branch_a_list(resource.value(:revision)))
83         provider.expects(:git).with('checkout', '--force', resource.value(:revision))
84         provider.create
85       end
86
87       it "should execute 'git clone' and submodule commands" do
88         resource.delete(:revision)
89         provider.expects(:git).with('clone', resource.value(:source), resource.value(:path))
90         provider.expects(:update_submodules)
91         provider.expects(:update_remotes)
92         provider.create
93       end
94     end
95
96     context "with an ensure of bare" do
97       context "with revision" do
98         it "should raise an error" do
99           resource[:ensure] = :bare
100           expect { provider.create }.to raise_error Puppet::Error, /cannot set a revision.+bare/i
101         end
102       end
103       context "without revision" do
104         it "should just execute 'git clone --bare'" do
105           resource[:ensure] = :bare
106           resource.delete(:revision)
107           provider.expects(:git).with('clone', '--bare', resource.value(:source), resource.value(:path))
108           provider.expects(:update_remotes)
109           provider.create
110         end
111       end
112     end
113
114     context "when a source is not given" do
115       context "when the path does not exist" do
116         it "should execute 'git init'" do
117           resource[:ensure] = :present
118           resource.delete(:source)
119           expects_mkdir
120           expects_chdir
121           expects_directory?(false)
122
123           provider.expects(:bare_exists?).returns(false)
124           provider.expects(:git).with('init')
125           provider.create
126         end
127       end
128
129       context "when the path is a bare repository" do
130         it "should convert it to a working copy" do
131           resource[:ensure] = :present
132           resource.delete(:source)
133           provider.expects(:bare_exists?).returns(true)
134           provider.expects(:convert_bare_to_working_copy)
135           provider.create
136         end
137       end
138
139       context "when the path is not empty and not a repository" do
140         it "should raise an exception" do
141           provider.expects(:path_exists?).returns(true)
142           provider.expects(:path_empty?).returns(false)
143           expect { provider.create }.to raise_error(Puppet::Error)
144         end
145       end
146     end
147
148     context "when the path does not exist" do
149       it "should execute 'git init --bare'" do
150         resource[:ensure] = :bare
151         resource.delete(:source)
152         resource.delete(:revision)
153         expects_chdir
154         expects_mkdir
155         expects_directory?(false)
156         provider.expects(:working_copy_exists?).returns(false)
157         provider.expects(:git).with('init', '--bare')
158         provider.create
159       end
160     end
161
162     context "when the path is a working copy repository" do
163       it "should convert it to a bare repository" do
164         resource[:ensure] = :bare
165         resource.delete(:source)
166         resource.delete(:revision)
167         provider.expects(:working_copy_exists?).returns(true)
168         provider.expects(:convert_working_copy_to_bare)
169         provider.create
170       end
171       it "should clone overtop it using force" do
172         resource[:force] = true
173         Dir.expects(:chdir).with('/').at_least_once.yields
174         Dir.expects(:chdir).with('/tmp/test').at_least_once.yields
175         provider.expects(:path_exists?).returns(true)
176         provider.expects(:path_empty?).returns(false)
177         provider.destroy
178         provider.expects(:git).with('clone',resource.value(:source), resource.value(:path))
179         provider.expects(:update_submodules)
180         provider.expects(:update_remote_url).with("origin", resource.value(:source)).returns false
181         provider.expects(:git).with('branch', '-a').returns(branch_a_list(resource.value(:revision)))
182         provider.expects(:git).with('checkout', '--force', resource.value(:revision))
183         provider.create
184       end
185     end
186
187     context "when the path is not empty and not a repository" do
188       it "should raise an exception" do
189         provider.expects(:path_exists?).returns(true)
190         provider.expects(:path_empty?).returns(false)
191         provider.expects(:working_copy_exists?).returns(false)
192         expect { provider.create }.to raise_error(Puppet::Error)
193       end
194     end
195   end
196
197
198   context 'destroying' do
199     it "it should remove the directory" do
200       #expects_rm_rf
201       provider.destroy
202     end
203   end
204
205   context "checking the revision property" do
206     before do
207       expects_chdir('/tmp/test')
208       resource[:revision] = 'currentsha'
209       resource.delete(:source)
210       provider.stubs(:git).with('config', 'remote.origin.url').returns('')
211       provider.stubs(:git).with('fetch', 'origin') # FIXME
212       provider.stubs(:git).with('fetch', '--tags', 'origin')
213       provider.stubs(:git).with('rev-parse', 'HEAD').returns('currentsha')
214       provider.stubs(:git).with('branch', '-a').returns(branch_a_list(resource.value(:revision)))
215       provider.stubs(:git).with('tag', '-l').returns("Hello")
216     end
217
218     context "when its SHA is not different than the current SHA" do
219       it "should return the ref" do
220         provider.expects(:git).with('rev-parse', resource.value(:revision)).returns('currentsha')
221         provider.expects(:update_remotes)
222         expect(provider.revision).to eq(resource.value(:revision))
223       end
224     end
225
226     context "when its SHA is different than the current SHA" do
227       it "should return the current SHA" do
228         provider.expects(:git).with('rev-parse', resource.value(:revision)).returns('othersha')
229         provider.expects(:update_remotes)
230         expect(provider.revision).to eq(resource.value(:revision))
231       end
232     end
233
234     context "when its a ref to a remote head" do
235       it "should return the revision" do
236         provider.stubs(:git).with('branch', '-a').returns("  remotes/origin/#{resource.value(:revision)}")
237         provider.expects(:git).with('rev-parse', "origin/#{resource.value(:revision)}").returns("newsha")
238         provider.expects(:update_remotes)
239         expect(provider.revision).to eq(resource.value(:revision))
240       end
241     end
242
243     context "when its a ref to non existant remote head" do
244       it "should fail" do
245         provider.expects(:git).with('branch', '-a').returns(branch_a_list)
246         provider.expects(:git).with('rev-parse', '--revs-only', resource.value(:revision)).returns('')
247         provider.expects(:update_remotes)
248         expect { provider.revision }.to raise_error(Puppet::Error, /not a local or remote ref$/)
249       end
250     end
251
252     context "when the source is modified" do
253       it "should update the origin url" do
254         resource[:source] = 'git://git@foo.com/bar.git'
255         provider.expects(:git).with('config', '-l').returns("remote.origin.url=git://git@foo.com/foo.git\n")
256         provider.expects(:git).with('remote', 'set-url', 'origin', 'git://git@foo.com/bar.git')
257         provider.expects(:git).with('remote','update')
258         provider.expects(:git).with('rev-parse', resource.value(:revision)).returns('currentsha')
259         expect(provider.revision).to eq(resource.value(:revision))
260       end
261     end
262
263     context "when multiple sources are modified" do
264       it "should update the urls" do
265         resource[:source] = {"origin" => "git://git@foo.com/bar.git", "new_remote" => "git://git@foo.com/baz.git"}
266         provider.expects(:git).at_least_once.with('config', '-l').returns("remote.origin.url=git://git@foo.com/foo.git\n", "remote.origin.url=git://git@foo.com/bar.git\n")
267         provider.expects(:git).with('remote', 'set-url', 'origin', 'git://git@foo.com/bar.git')
268         provider.expects(:git).with('remote', 'add', 'new_remote', 'git://git@foo.com/baz.git')
269         provider.expects(:git).with('remote','update')
270         provider.expects(:git).with('rev-parse', resource.value(:revision)).returns('currentsha')
271         expect(provider.revision).to eq(resource.value(:revision))
272       end
273     end
274
275   end
276
277   context "setting the revision property" do
278     before do
279       expects_chdir
280     end
281     context "when it's an existing local branch" do
282       it "should use 'git fetch' and 'git reset'" do
283         resource[:revision] = 'feature/foo'
284         provider.expects(:update_submodules)
285         provider.expects(:git).with('branch', '-a').at_least_once.returns(branch_a_list(resource.value(:revision)))
286         provider.expects(:git).with('checkout', '--force', resource.value(:revision))
287         provider.expects(:git).with('reset', '--hard',  "origin/#{resource.value(:revision)}")
288         provider.revision = resource.value(:revision)
289       end
290     end
291     context "when it's a remote branch" do
292       it "should use 'git fetch' and 'git reset'" do
293         resource[:revision] = 'only/remote'
294         provider.expects(:update_submodules)
295         provider.expects(:git).with('branch', '-a').at_least_once.returns(resource.value(:revision))
296         provider.expects(:git).with('checkout', '--force', resource.value(:revision))
297         provider.expects(:git).with('reset', '--hard',  "origin/#{resource.value(:revision)}")
298         provider.revision = resource.value(:revision)
299       end
300     end
301     context "when it's a commit or tag" do
302       it "should use 'git fetch' and 'git reset'" do
303         resource[:revision] = 'a-commit-or-tag'
304         provider.expects(:git).with('branch', '-a').at_least_once.returns(fixture(:git_branch_a))
305         provider.expects(:git).with('checkout', '--force', resource.value(:revision))
306         provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_a))
307         provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_a))
308         provider.expects(:git).with('submodule', 'update', '--init', '--recursive')
309         provider.revision = resource.value(:revision)
310       end
311     end
312   end
313
314   context "updating references" do
315     it "should use 'git fetch --tags'" do
316       resource.delete(:source)
317       expects_chdir
318       provider.expects(:git).with('config', '-l').returns("remote.origin.url=git://git@foo.com/foo.git\n")
319       provider.expects(:git).with('fetch', 'origin')
320       provider.expects(:git).with('fetch', '--tags', 'origin')
321       provider.update_references
322     end
323   end
324
325   describe 'latest?' do
326     context 'when true' do
327       it do
328         provider.expects(:revision).returns('testrev')
329         provider.expects(:latest_revision).returns('testrev')
330         expect(provider.latest?).to be_truthy
331       end
332     end
333     context 'when false' do
334       it do
335         provider.expects(:revision).returns('master')
336         provider.expects(:latest_revision).returns('testrev')
337         expect(provider.latest?).to be_falsey
338       end
339     end
340   end
341
342   describe 'convert_working_copy_to_bare' do
343     it do
344       FileUtils.expects(:mv).returns(true)
345       FileUtils.expects(:rm_rf).returns(true)
346       FileUtils.expects(:mv).returns(true)
347
348       provider.instance_eval { convert_working_copy_to_bare }
349     end
350   end
351
352     describe 'convert_bare_to_working_copy' do
353     it do
354       FileUtils.expects(:mv).returns(true)
355       FileUtils.expects(:mkdir).returns(true)
356       FileUtils.expects(:mv).returns(true)
357       provider.expects(:commits_in?).returns(true)
358       # If you forget to stub these out you lose 3 hours of rspec work.
359       provider.expects(:reset).with('HEAD').returns(true)
360       provider.expects(:git_with_identity).returns(true)
361       provider.expects(:update_owner_and_excludes).returns(true)
362
363       provider.instance_eval { convert_bare_to_working_copy }
364     end
365   end
366
367 end