diff options
-rw-r--r-- | Modulefile | 2 | ||||
-rw-r--r-- | README.GIT.markdown | 20 | ||||
-rw-r--r-- | README.SVN.markdown | 2 | ||||
-rw-r--r-- | README.markdown | 30 | ||||
-rw-r--r-- | lib/puppet/provider/vcsrepo/git.rb | 78 | ||||
-rw-r--r-- | lib/puppet/type/vcsrepo.rb | 8 | ||||
-rw-r--r-- | spec/unit/puppet/provider/vcsrepo/git_spec.rb | 117 | ||||
-rw-r--r-- | spec/unit/puppet/provider/vcsrepo/svn_spec.rb | 36 |
8 files changed, 261 insertions, 32 deletions
diff --git a/Modulefile b/Modulefile new file mode 100644 index 0000000..4cb86b0 --- /dev/null +++ b/Modulefile @@ -0,0 +1,2 @@ +name 'puppetlabs/vcsrepo' +version '0.0.1' diff --git a/README.GIT.markdown b/README.GIT.markdown new file mode 100644 index 0000000..08545aa --- /dev/null +++ b/README.GIT.markdown @@ -0,0 +1,20 @@ +Using vcsrepo with Git +====================== + +To create a blank repository +---------------------------- + +Define a `vcsrepo` without a `source` or `revision`: + + vcsrepo { "/path/to/repo": + ensure: present + } + +If you're defining this for a central/"official" repository, you'll +probably want to make it a "bare" repository. Do this by setting +`ensure` to `bare` instead of `present`: + + vcsrepo { "/path/to/repo": + ensure: bare + } + diff --git a/README.SVN.markdown b/README.SVN.markdown new file mode 100644 index 0000000..30aaf54 --- /dev/null +++ b/README.SVN.markdown @@ -0,0 +1,2 @@ +Using vcsrepo with Subversion +============================= diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..33fddcb --- /dev/null +++ b/README.markdown @@ -0,0 +1,30 @@ +vcsrepo +======= + +Purpose +------- + +This provides a single type, `vcsrepo`. + +This type can be used to describe: + +* A working copy checked out from a (remote or local) source, at an + arbitrary revision +* A "blank" working copy not associated with a source (when it makes + sense for the VCS being used) +* A "blank" central repository (when the distinction makes sense for the VCS + being used) + +Supported Version Control Systems +--------------------------------- + +This module supports a wide range of VCS types, each represented by a +separate provider. + +For information on how to use this module with a specific VCS, see +`README.<VCS>.markdown`. + +License +------- + +See LICENSE. diff --git a/lib/puppet/provider/vcsrepo/git.rb b/lib/puppet/provider/vcsrepo/git.rb index 670d8de..bdc819e 100644 --- a/lib/puppet/provider/vcsrepo/git.rb +++ b/lib/puppet/provider/vcsrepo/git.rb @@ -1,3 +1,6 @@ +require 'tmpdir' +require 'digest/md5' + Puppet::Type.type(:vcsrepo).provide(:git) do desc "Supports Git repositories" @@ -13,7 +16,14 @@ Puppet::Type.type(:vcsrepo).provide(:git) do end def exists? - File.directory?(@resource.value(:path)) + case @resource.value(:ensure) + when 'present' + working_copy_exists? + when 'bare' + bare_exists? + else + path_exists? + end end def destroy @@ -37,6 +47,22 @@ Puppet::Type.type(:vcsrepo).provide(:git) do private + def bare_exists? + bare_git_config_exists? && !working_copy_exists? + end + + def working_copy_exists? + File.directory?(File.join(@resource.value(:path), '.git')) + end + + def path_exists? + File.directory?(@resource.value(:path)) + end + + def bare_git_config_exists? + File.exist?(File.join(@resource.value(:path), 'config')) + end + def clone_repository(source, path) git('clone', source, path) end @@ -48,9 +74,51 @@ Puppet::Type.type(:vcsrepo).provide(:git) do end def init_repository(path) - FileUtils.mkdir_p(path) + if @resource.value(:ensure) == 'bare' && working_copy_exists? + convert_working_copy_to_bare + elsif @resource.value(:ensure) == 'present' && bare_exists? + convert_bare_to_working_copy + elsif File.directory?(@resource.value(:path)) + raise Puppet::Error, "Could not create repository (non-repository at path)" + else + normal_init + end + end + + # Convert working copy to bare + # + # Moves: + # <path>/.git + # to: + # <path>/ + def convert_working_copy_to_bare + FileUtils.mv(File.join(@resource.value(:path), '.git'), tempdir) + FileUtils.rm_rf(@resource.value(:path)) + FileUtils.cp_r(tempdir, @resource.value(:path)) + end + + # Convert bare to working copy + # + # Moves: + # <path>/ + # to: + # <path>/.git + def convert_bare_to_working_copy + FileUtils.mv(@resource.value(:path), tempdir) + FileUtils.mkdir(@resource.value(:path)) + FileUtils.cp_r(tempdir, File.join(@resource.value(:path), '.git')) + reset('HEAD') + git('checkout', '-f') + end + + def normal_init + FileUtils.mkdir(@resource.value(:path)) + args = ['init'] + if @resource.value(:ensure) == 'bare' + args << '--bare' + end at_path do - git('init') + git(*args) end end @@ -70,4 +138,8 @@ Puppet::Type.type(:vcsrepo).provide(:git) do value end + def tempdir + @tempdir ||= File.join(Dir.tmpdir, 'vcsrepo-' + Digest::MD5.hexdigest(@resource.value(:path))) + end + end diff --git a/lib/puppet/type/vcsrepo.rb b/lib/puppet/type/vcsrepo.rb index 04c48a3..4d5c2a0 100644 --- a/lib/puppet/type/vcsrepo.rb +++ b/lib/puppet/type/vcsrepo.rb @@ -3,7 +3,13 @@ require 'pathname' Puppet::Type.newtype(:vcsrepo) do desc "A local version control repository" - ensurable + ensurable do + defaultvalues + + newvalue :bare do + provider.create + end + end newparam(:path) do desc "Absolute path to repository" diff --git a/spec/unit/puppet/provider/vcsrepo/git_spec.rb b/spec/unit/puppet/provider/vcsrepo/git_spec.rb index a5ed753..f8a7170 100644 --- a/spec/unit/puppet/provider/vcsrepo/git_spec.rb +++ b/spec/unit/puppet/provider/vcsrepo/git_spec.rb @@ -34,12 +34,67 @@ describe provider_class do end end context "when a source is not given" do - it "should execute 'git init'" do + before do @resource.expects(:value).with(:path).returns(@path).at_least_once @resource.expects(:value).with(:source).returns(nil) - Dir.expects(:chdir).with(@path).yields - @provider.expects(:git).with('init') - @provider.create + end + context "when ensure = present" do + before { @resource.expects(:value).with(:ensure).returns('present').at_least_once } + context "when the path does not exist" do + it "should execute 'git init'" do + Dir.expects(:mkdir).with(@path) + Dir.expects(:chdir).with(@path).yields + @provider.expects(:bare_exists?).returns(false) + File.expects(:directory?).with(@path).returns(false) + @provider.expects(:git).with('init') + @provider.create + end + end + context "when the path is a bare repository" do + it "should convert it to a working copy" do + @provider.expects(:bare_exists?).returns(true) + @provider.expects(:convert_bare_to_working_copy) + @provider.create + end + end + context "when the path is not a repository" do + it "should raise an exception" do + File.expects(:directory?).with(@path).returns(true) + @provider.expects(:bare_exists?).returns(false) + proc { + @provider.create + }.should raise_error(Puppet::Error) + end + end + end + context "when ensure = bare" do + before { @resource.expects(:value).with(:ensure).returns('bare').at_least_once } + context "when the path does not exist" do + it "should execute 'git init --bare'" do + Dir.expects(:chdir).with(@path).yields + File.expects(:directory?).with(@path).returns(false) + FileUtils.expects(:mkdir).with(@path) + @provider.expects(:working_copy_exists?).returns(false) + @provider.expects(:git).with('init', '--bare') + @provider.create + end + end + context "when the path is a working copy repository" do + it "should convert it to a bare repository" do + @provider.expects(:working_copy_exists?).returns(true) + @provider.expects(:convert_working_copy_to_bare) + @provider.create + end + end + context "when the path is not a repository" do + it "should raise an exception" do + File.expects(:directory?).with(@path).returns(true) + @provider.expects(:working_copy_exists?).returns(false) + proc { + @provider.create + }.should raise_error(Puppet::Error) + end + end end end end @@ -53,10 +108,54 @@ describe provider_class do end describe "when checking existence" do - it "should check for the directory" do - @resource.expects(:value).with(:path).returns(@path) - File.expects(:directory?).with(@path) - @provider.exists? + context "when ensure = present" do + context "when a working copy exists" do + it "should be true" do + @resource.expects(:value).with(:ensure).returns('present').at_least_once + @provider.expects(:working_copy_exists?).returns(true) + @provider.should be_exists + end + end + context "when a bare repo exists" do + it "should be " do + @resource.expects(:value).with(:ensure).returns('present').at_least_once + @provider.expects(:working_copy_exists?).returns(false) + @provider.should_not be_exists + end + end + end + context "when ensure = bare" do + context "when a working copy exists" do + it "should be false" do + @resource.expects(:value).with(:ensure).returns('bare').at_least_once + @provider.expects(:bare_exists?).returns(false) + @provider.should_not be_exists + end + end + context "when a bare repo exists" do + it "should be true" do + @resource.expects(:value).with(:ensure).returns('bare').at_least_once + @provider.expects(:bare_exists?).returns(true) + @provider.should be_exists + end + end + end + context "when ensure = absent" do + before { @resource.expects(:value).with(:ensure).returns('absent') } + context "when the path exists" do + it "should be true" do + @resource.expects(:value).with(:path).returns(@path) + File.expects(:directory?).with(@path).returns(true) + @provider.should be_exists + end + end + context "when the path does not exist" do + it "should be false" do + @resource.expects(:value).with(:path).returns(@path) + File.expects(:directory?).with(@path).returns(false) + @provider.should_not be_exists + end + end end end @@ -106,7 +205,7 @@ describe provider_class do end end end - + describe "when setting the revision property" do it "should use 'git fetch' and 'git reset'" do @resource.expects(:value).with(:path).returns(@path).at_least_once diff --git a/spec/unit/puppet/provider/vcsrepo/svn_spec.rb b/spec/unit/puppet/provider/vcsrepo/svn_spec.rb index 3af06f2..fc5c37b 100644 --- a/spec/unit/puppet/provider/vcsrepo/svn_spec.rb +++ b/spec/unit/puppet/provider/vcsrepo/svn_spec.rb @@ -10,7 +10,7 @@ describe provider_class do @path = '/tmp/vcsrepo' end - context 'when creating' do + describe 'when creating' do context "when a source is given" do context "and when a revision is given" do it "should execute 'svn checkout' with a revision" do @@ -53,7 +53,7 @@ describe provider_class do end end - context 'when destroying' do + describe 'when destroying' do it "it should remove the directory" do @resource.expects(:value).with(:path).returns(@path).at_least_once FileUtils.expects(:rm_rf).with(@path) @@ -61,7 +61,7 @@ describe provider_class do end end - context "when checking existence" do + describe "when checking existence" do it "should check for the directory" do @resource.expects(:value).with(:path).returns(@path) File.expects(:directory?).with(@path) @@ -69,23 +69,21 @@ describe provider_class do end end - describe "revision property" do - context "when checking" do - it "should use 'svn info'" do - @resource.expects(:value).with(:path).returns(@path) - p fixture(:svn_info)[/^Revision:\s+(\d+)/m, 1] - @provider.expects('svn').with('info').returns(fixture(:svn_info)) - Dir.expects(:chdir).with(@path).yields - @provider.revision.should == '4' - end + describe "when checking the revision property" do + it "should use 'svn info'" do + @resource.expects(:value).with(:path).returns(@path) + @provider.expects('svn').with('info').returns(fixture(:svn_info)) + Dir.expects(:chdir).with(@path).yields + @provider.revision.should == '4' end - context "when setting" do - it "should use 'svn update'" do - @resource.expects(:value).with(:path).returns(@path) - @provider.expects('svn').with('update', '-r', '30') - Dir.expects(:chdir).with(@path).yields - @provider.revision = '30' - end + end + + describe "when setting the revision property" do + it "should use 'svn update'" do + @resource.expects(:value).with(:path).returns(@path) + @provider.expects('svn').with('update', '-r', '30') + Dir.expects(:chdir).with(@path).yields + @provider.revision = '30' end end |