Merge pull request #46 from Paulche/master
authorAaron Stone <aaron@serendipity.cx>
Wed, 17 Jul 2013 21:25:51 +0000 (14:25 -0700)
committerAaron Stone <aaron@serendipity.cx>
Wed, 17 Jul 2013 21:25:51 +0000 (14:25 -0700)
Enable unlimited nesting for submodule updating

1  2 
lib/puppet/provider/vcsrepo/git.rb
spec/unit/puppet/provider/vcsrepo/git_spec.rb

@@@ -5,7 -5,7 +5,7 @@@ Puppet::Type.type(:vcsrepo).provide(:gi
  
    ##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'
  
    def update_submodules
      at_path do
-       git_with_identity('submodule', 'init')
-       git_with_identity('submodule', 'update')
-       git_with_identity('submodule', 'foreach', 'git', 'submodule', 'init')
-       git_with_identity('submodule', 'foreach', 'git', 'submodule', 'update')
+       git_with_identity('submodule', 'update', '--init', '--recursive')
      end
    end
  
        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)
@@@ -8,7 -8,6 +8,7 @@@ describe_provider :vcsrepo, :git, :reso
          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))
@@@ -19,7 -18,6 +19,7 @@@
          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
  
          provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_a))
          provider.expects(:git).with('checkout', '--force', resource.value(:revision))
          provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_a))
-         provider.expects(:git).with('submodule', 'init')
-         provider.expects(:git).with('submodule', 'update')
          provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_a))
-         provider.expects(:git).with('submodule', 'foreach', 'git', 'submodule', 'init')
-         provider.expects(:git).with('submodule', 'foreach', 'git', 'submodule', 'update')
+         provider.expects(:git).with('submodule', 'update', '--init', '--recursive')
          provider.revision = resource.value(:revision)
        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