summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Modulefile2
-rw-r--r--README.GIT.markdown20
-rw-r--r--README.SVN.markdown2
-rw-r--r--README.markdown30
-rw-r--r--lib/puppet/provider/vcsrepo/git.rb78
-rw-r--r--lib/puppet/type/vcsrepo.rb8
-rw-r--r--spec/unit/puppet/provider/vcsrepo/git_spec.rb117
-rw-r--r--spec/unit/puppet/provider/vcsrepo/svn_spec.rb36
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