--- /dev/null
+---
+branches:
+ only:
+ - master
+notifications:
+ email: false
+language: ruby
+script: 'bundle exec rake spec'
+after_success:
+- git clone -q git://github.com/puppetlabs/ghpublisher.git .forge-releng
+- .forge-releng/publish
+rvm:
+- 1.8.7
+- 1.9.3
+env:
+ matrix:
+ - PUPPET_VERSION=2.6.18
+ - PUPPET_VERSION=2.7.21
+ - PUPPET_VERSION=3.1.1
+ global:
+ - PUBLISHER_LOGIN=puppetlabs
+ - secure: |-
+ ZiIkYd9+CdPzpwSjFPnVkCx1FIlipxpbdyD33q94h2Tj5zXjNb1GXizVy0NR
+ kVxGhU5Ld8y9z8DTqKRgCI1Yymg3H//OU++PKLOQj/X5juWVR4URBNPeBOzu
+ IJBDl1MADKA4i1+jAZPpz4mTvTtKS4pWKErgCSmhSfsY1hs7n6c=
-source :rubygems
+source 'https://rubygems.org'
gem 'rake', '~> 0.8.7'
-gem 'rspec', '~> 1.2.9'
-gem 'mocha', '~> 0.12.7', :require => false
+gem 'rspec', '~> 1.3'
+gem 'mocha', '~> 0.12.9', :require => false
gem 'puppet', '~> 2.7'
GEM
- remote: http://rubygems.org/
+ remote: https://rubygems.org/
specs:
- facter (1.6.13)
+ facter (1.7.2)
metaclass (0.0.1)
- mocha (0.12.7)
+ mocha (0.12.10)
metaclass (~> 0.0.1)
- puppet (2.7.19)
+ puppet (2.7.22)
facter (~> 1.5)
rake (0.8.7)
- rspec (1.2.9)
+ rspec (1.3.2)
PLATFORMS
ruby
DEPENDENCIES
- mocha (~> 0.12.7)
+ mocha (~> 0.12.9)
puppet (~> 2.7)
rake (~> 0.8.7)
- rspec (~> 1.2.9)
+ rspec (~> 1.3)
name 'puppetlabs/vcsrepo'
-version '0.1.1'
+version '0.1.2'
+summary 'Manage repositories from various version control systems'
+description 'Manage repositories from various version control systems'
For sources that use SSH (eg, `username@server:...`)
----------------------------------------------------
-Manage your SSH keys with Puppet and use `require` in your `vcsrepo`
-to ensure they are present. For more information, see the `require`
-metaparameter documentation[1].
+If your SSH key is associated with a user, simply fill the `user` parameter to use his keys.
+
+Example:
+
+ user => 'toto' # will use toto's $HOME/.ssh setup
+
+
+Otherwise, manage your SSH keys with Puppet and use `require` in your `vcsrepo` to ensure they are present.
+For more information, see the `require` metaparameter documentation[1].
More Examples
-------------
vcsrepo { "/path/to/repo":
ensure => present,
provider => hg,
- source => "http://hg.example.com/myrepo"
+ source => "http://hg.example.com/myrepo",
revision => '21ea4598c962'
}
vcsrepo { "/path/to/repo":
ensure => present,
provider => hg,
- source => "http://hg.example.com/myrepo"
+ source => "http://hg.example.com/myrepo",
revision => '1.1.2'
}
+Check out as a user:
+
+ vcsrepo { "/path/to/repo":
+ ensure => present,
+ provider => hg,
+ source => "http://hg.example.com/myrepo",
+ user => 'user'
+ }
+
+Specify an SSH identity key:
+
+ vcsrepo { "/path/to/repo":
+ ensure => present,
+ provider => hg,
+ source => "ssh://hg@hg.example.com/myrepo",
+ identity => "/home/user/.ssh/id_dsa,
+ }
+
For sources that use SSH (eg, `ssh://...`)
------------------------------------------
vcsrepo
=======
+[](https://travis-ci.org/puppetlabs/puppetlabs-vcsrepo)
+
Purpose
-------
end
def revision=(desired)
- bzr('update', '-r', desired, @resource.value(:path))
+ at_path do
+ begin
+ bzr('update', '-r', desired)
+ rescue Puppet::ExecutionFailure
+ bzr('update', '-r', desired, ':parent')
+ end
+ end
+ end
+
+ def latest
+ at_path do
+ bzr('version-info', ':parent')[/^revision-id:\s+(\S+)/, 1]
+ end
+ end
+
+ def latest?
+ at_path do
+ return self.revision == self.latest
+ end
end
private
##TODO modify the commands below so that the su - is included
optional_commands :git => 'git',
- :su => 'su'
+ :su => 'su'
has_features :bare_repositories, :reference_tracking, :ssh_identity, :multiple_remotes, :user
def create
return current unless @resource.value(:revision)
if tag_revision?(@resource.value(:revision))
- canonical = at_path { git_with_identity('show', @resource.value(:revision)).scan(/commit (.*)/).to_s }
+ canonical = at_path { git_with_identity('show', @resource.value(:revision)).scan(/^commit (.*)/).to_s }
else
- canonical = at_path { git_with_identity('rev-parse', @resource.value(:revision)).chomp }
+ # if it's not a tag, look for it as a local ref
+ canonical = at_path { git_with_identity('rev-parse', '--revs-only', @resource.value(:revision)).chomp }
+ if canonical.empty?
+ # git rev-parse executed properly but didn't find the ref;
+ # look for it in the remote
+ remote_ref = at_path { git_with_identity('ls-remote', '--heads', '--tags', @resource.value(:remote), @resource.value(:revision)).chomp }
+ if remote_ref.empty?
+ fail("#{@resource.value(:revision)} is not a local or remote ref")
+ end
+
+ # $ git ls-remote --heads --tags origin feature/cvs
+ # 7d4244b35e72904e30130cad6d2258f901c16f1a refs/heads/feature/cvs
+ canonical = remote_ref.split.first
+ end
end
if current == canonical
working_copy_exists? || bare_exists?
end
+ def update_remote_origin_url
+ current = git_with_identity('config', 'remote.origin.url')
+ unless @resource.value(:source).nil?
+ if current.nil? or current.strip != @resource.value(:source)
+ git_with_identity('config', 'remote.origin.url', @resource.value(:source))
+ end
+ end
+ end
+
def update_references
at_path do
+ update_remote_origin_url
git_with_identity('fetch', @resource.value(:remote))
git_with_identity('fetch', '--tags', @resource.value(:remote))
update_owner_and_excludes
end
if !File.exist?(File.join(@resource.value(:path), '.git'))
args.push(source, path)
- git_with_identity(*args)
+ Dir.chdir("/") do
+ git_with_identity(*args)
+ end
else
notice "Repo has already been cloned"
end
else
# normal init
FileUtils.mkdir(@resource.value(:path))
+ FileUtils.chown(@resource.value(:user), nil, @resource.value(:path)) if @resource.value(:user)
args = ['init']
if @resource.value(:ensure) == :bare
args << '--bare'
create
end
at_path do
+ update_remote_origin_url
git_with_identity('fetch', @resource.value(:remote))
git_with_identity('fetch', '--tags', @resource.value(:remote))
end
if @resource.value(:identity)
Tempfile.open('git-helper') do |f|
f.puts '#!/bin/sh'
- f.puts "exec ssh -oStrictHostKeyChecking=no -oPasswordAuthentication=no -oKbdInteractiveAuthentication=no -oChallengeResponseAuthentication=no -i #{@resource.value(:identity)} $*"
+ f.puts "exec ssh -oStrictHostKeyChecking=no -oPasswordAuthentication=no -oKbdInteractiveAuthentication=no -oChallengeResponseAuthentication=no -oConnectTimeout=120 -i #{@resource.value(:identity)} $*"
f.close
FileUtils.chmod(0755, f.path)
Puppet::Type.type(:vcsrepo).provide(:hg, :parent => Puppet::Provider::Vcsrepo) do
desc "Supports Mercurial repositories"
- optional_commands :hg => 'hg'
- has_features :reference_tracking
+ optional_commands :hg => 'hg',
+ :su => 'su'
+ has_features :reference_tracking, :ssh_identity, :user
def create
if !@resource.value(:source)
def latest
at_path do
begin
- hg('incoming', '--branch', '.', '--newest-first', '--limit', '1')[/^changeset:\s+(?:-?\d+):(\S+)/m, 1]
+ hg_wrapper('incoming', '--branch', '.', '--newest-first', '--limit', '1')[/^changeset:\s+(?:-?\d+):(\S+)/m, 1]
rescue Puppet::ExecutionFailure
# If there are no new changesets, return the current nodeid
self.revision
def revision
at_path do
- current = hg('parents')[/^changeset:\s+(?:-?\d+):(\S+)/m, 1]
+ current = hg_wrapper('parents')[/^changeset:\s+(?:-?\d+):(\S+)/m, 1]
desired = @resource.value(:revision)
if desired
# Return the tag name if it maps to the current nodeid
- mapped = hg('tags')[/^#{Regexp.quote(desired)}\s+\d+:(\S+)/m, 1]
+ mapped = hg_wrapper('tags')[/^#{Regexp.quote(desired)}\s+\d+:(\S+)/m, 1]
if current == mapped
desired
else
def revision=(desired)
at_path do
begin
- hg('pull')
+ hg_wrapper('pull')
rescue
end
begin
- hg('merge')
+ hg_wrapper('merge')
rescue Puppet::ExecutionFailure
# If there's nothing to merge, just skip
end
- hg('update', '--clean', '-r', desired)
+ hg_wrapper('update', '--clean', '-r', desired)
end
update_owner
end
private
def create_repository(path)
- hg('init', path)
+ hg_wrapper('init', path)
end
def clone_repository(revision)
end
args.push(@resource.value(:source),
@resource.value(:path))
- hg(*args)
+ hg_wrapper(*args)
end
def update_owner
end
end
+ def hg_wrapper(*args)
+ if @resource.value(:identity)
+ args += ["--ssh", "ssh -oStrictHostKeyChecking=no -oPasswordAuthentication=no -oKbdInteractiveAuthentication=no -oChallengeResponseAuthentication=no -i #{@resource.value(:identity)}"]
+ end
+ if @resource.value(:user)
+ args.map! { |a| if a =~ /\s/ then "'#{a}'" else a end } # Adds quotes to arguments with whitespaces.
+ su(@resource.value(:user), '-c', "hg #{args.join(' ')}")
+ else
+ hg(*args)
+ end
+ end
end
desc "Supports Subversion repositories"
optional_commands :svn => 'svn',
- :svnadmin => 'svnadmin'
+ :svnadmin => 'svnadmin'
has_features :filesystem_types, :reference_tracking, :basic_auth
args.push('--password', @resource.value(:basic_auth_password))
args.push('--no-auth-cache')
end
+
+ if @resource.value(:force)
+ args.push('--force')
+ end
+
return args
end
@should ||= []
case should
- when :present
- return true unless [:absent, :purged, :held].include?(is)
- when :latest
- if is == :latest
- return true
- else
- return false
- end
- when :bare
- return is == :bare
+ when :present
+ return true unless [:absent, :purged, :held].include?(is)
+ when :latest
+ if is == :latest
+ return true
+ else
+ return false
+ end
+ when :bare
+ return is == :bare
end
end
end
newvalue :bare, :required_features => [:bare_repositories] do
- if !provider.exists?
+ if !provider.exists?
provider.create
end
end
describe "setting the revision property" do
it "should use 'bzr update -r' with the revision" do
- revision = 'somerev'
- provider.expects(:bzr).with('update', '-r', revision, resource.value(:path))
- provider.revision = revision
+ expects_chdir
+ provider.expects(:bzr).with('update', '-r', 'somerev')
+ provider.revision = 'somerev'
end
end
context "with a revision that is a remote branch", :resource => {:revision => 'only/remote'} do
it "should execute 'git clone' and 'git checkout -b'" do
provider.expects(:git).with('clone', resource.value(:source), resource.value(:path))
+ expects_chdir('/')
expects_chdir
provider.expects(:update_submodules)
provider.expects(:git).with('branch', '-a').returns(resource.value(:revision))
context "with a revision that is not a remote branch", :resource => {:revision => 'a-commit-or-tag'} do
it "should execute 'git clone' and 'git reset --hard'" do
provider.expects(:git).with('clone', resource.value(:source), resource.value(:path))
+ expects_chdir('/')
expects_chdir
provider.expects(:update_submodules)
provider.expects(:git).with('branch', '-a').returns(resource.value(:revision))
context "when its SHA is not different than the current SHA" do
it "should return the ref" do
+ provider.expects(:git).with('config', 'remote.origin.url').returns('')
provider.expects(:git).with('fetch', 'origin') # FIXME
provider.expects(:git).with('fetch', '--tags', 'origin')
- provider.expects(:git).with('rev-parse', resource.value(:revision)).returns('currentsha')
+ provider.expects(:git).with('rev-parse', '--revs-only', resource.value(:revision)).returns('currentsha')
provider.expects(:git).with('tag', '-l').returns("Hello")
provider.revision.should == resource.value(:revision)
end
context "when its SHA is different than the current SHA" do
it "should return the current SHA" do
+ provider.expects(:git).with('config', 'remote.origin.url').returns('')
provider.expects(:git).with('fetch', 'origin') # FIXME
provider.expects(:git).with('fetch', '--tags', 'origin')
- provider.expects(:git).with('rev-parse', resource.value(:revision)).returns('othersha')
+ provider.expects(:git).with('rev-parse', '--revs-only', resource.value(:revision)).returns('othersha')
provider.expects(:git).with('tag', '-l').returns("Hello")
provider.revision.should == 'currentsha'
end
end
+
+ context "when its a ref to a remote head" do
+ it "should return the revision" do
+ provider.expects(:git).with('config', 'remote.origin.url').returns('')
+ provider.expects(:git).with('fetch', 'origin') # FIXME
+ provider.expects(:git).with('fetch', '--tags', 'origin')
+ provider.expects(:git).with('tag', '-l').returns("Hello")
+ provider.expects(:git).with('rev-parse', '--revs-only', resource.value(:revision)).returns('')
+ provider.expects(:git).with('ls-remote', '--heads', '--tags', 'origin', resource.value(:revision)).returns("newsha refs/heads/#{resource.value(:revision)}")
+ provider.revision.should == 'currentsha'
+ end
+ end
+
+ context "when its a ref to non existant remote head" do
+ it "should fail" do
+ provider.expects(:git).with('config', 'remote.origin.url').returns('')
+ provider.expects(:git).with('fetch', 'origin') # FIXME
+ provider.expects(:git).with('fetch', '--tags', 'origin')
+ provider.expects(:git).with('tag', '-l').returns("Hello")
+ provider.expects(:git).with('rev-parse', '--revs-only', resource.value(:revision)).returns('')
+ provider.expects(:git).with('ls-remote', '--heads', '--tags', 'origin', resource.value(:revision)).returns('')
+ expect { provider.revision }.should raise_error(Puppet::Error, /not a local or remote ref$/)
+ end
+ end
+
+ context "when the source is modified" do
+ resource_with :source => 'git://git@foo.com/bar.git' do
+ it "should update the origin url" do
+ provider.expects(:git).with('config', 'remote.origin.url').returns('old')
+ provider.expects(:git).with('config', 'remote.origin.url', 'git://git@foo.com/bar.git')
+ provider.expects(:git).with('fetch', 'origin') # FIXME
+ provider.expects(:git).with('fetch', '--tags', 'origin')
+ provider.expects(:git).with('rev-parse', '--revs-only', resource.value(:revision)).returns('currentsha')
+ provider.expects(:git).with('tag', '-l').returns("Hello")
+ provider.revision.should == resource.value(:revision)
+ end
+ end
+ end
end
end
context "updating references" do
it "should use 'git fetch --tags'" do
expects_chdir
+ provider.expects(:git).with('config', 'remote.origin.url').returns('')
provider.expects(:git).with('fetch', 'origin')
provider.expects(:git).with('fetch', '--tags', 'origin')
provider.update_references