summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerdar Sutay <serdar@opscode.com>2014-10-10 15:28:28 -0700
committerSerdar Sutay <serdar@opscode.com>2014-10-10 15:28:28 -0700
commit685042c1ea839cef2ad7fe440df1fc0955535581 (patch)
treeedb81ca9f83619055d3ebd56cfb00fa0afcee003
parent0b44df383395482d96e317babf0546068c30b7ec (diff)
parenteb9b7d065feb003192fcf9295e9a3fc4f8ffe8f3 (diff)
downloadchef-685042c1ea839cef2ad7fe440df1fc0955535581.tar.gz
Merge pull request #2079 from jbence/CHEF-2065
Use exact match to locate remote git-reference
-rw-r--r--lib/chef/provider/git.rb64
-rw-r--r--spec/unit/provider/git_spec.rb46
2 files changed, 88 insertions, 22 deletions
diff --git a/lib/chef/provider/git.rb b/lib/chef/provider/git.rb
index c8e615c1f9..2ef119e839 100644
--- a/lib/chef/provider/git.rb
+++ b/lib/chef/provider/git.rb
@@ -64,7 +64,7 @@ class Chef
a.failure_message Chef::Exceptions::UnresolvableGitReference,
"Unable to parse SHA reference for '#{@new_resource.revision}' in repository '#{@new_resource.repository}'. " +
"Verify your (case-sensitive) repository URL and revision.\n" +
- "`git ls-remote` output: #{@resolved_reference}"
+ "`git ls-remote '#{@new_resource.repository}' '#{rev_search_pattern}'` output: #{@resolved_reference}"
end
end
@@ -240,35 +240,55 @@ class Chef
# annotated tags, we have to search for "revision*" and
# post-process. Special handling for 'HEAD' to ignore a tag
# named 'HEAD'.
- rev_pattern = case @new_resource.revision
- when '', 'HEAD'
- 'HEAD'
- else
- @new_resource.revision + '*'
- end
- command = git("ls-remote \"#{@new_resource.repository}\" \"#{rev_pattern}\"")
- @resolved_reference = shell_out!(command, run_options).stdout
- ref_lines = @resolved_reference.split("\n")
- refs = ref_lines.map { |line| line.split("\t") }
- # first try for ^{} indicating the commit pointed to by an
- # annotated tag
- tagged_commit = refs.find { |m| m[1].end_with?("#{@new_resource.revision}^{}") }
+ @resolved_reference = git_ls_remote(rev_search_pattern)
+ refs = @resolved_reference.split("\n").map { |line| line.split("\t") }
+ # First try for ^{} indicating the commit pointed to by an
+ # annotated tag.
# It is possible for a user to create a tag named 'HEAD'.
# Using such a degenerate annotated tag would be very
# confusing. We avoid the issue by disallowing the use of
# annotated tags named 'HEAD'.
- if tagged_commit && rev_pattern != 'HEAD'
- tagged_commit[0]
+ if rev_search_pattern != 'HEAD'
+ found = find_revision(refs, @new_resource.revision, '^{}')
else
- found = refs.find { |m| m[1].end_with?(@new_resource.revision) }
- if found
- found[0]
- else
- nil
- end
+ found = refs_search(refs, 'HEAD')
+ end
+ found = find_revision(refs, @new_resource.revision) if found.empty?
+ found.size == 1 ? found.first[0] : nil
+ end
+
+ def find_revision(refs, revision, suffix="")
+ found = refs_search(refs, rev_match_pattern('refs/tags/', revision) + suffix)
+ found = refs_search(refs, rev_match_pattern('refs/heads/', revision) + suffix) if found.empty?
+ found = refs_search(refs, revision + suffix) if found.empty?
+ found
+ end
+
+ def rev_match_pattern(prefix, revision)
+ if revision.start_with?(prefix)
+ revision
+ else
+ prefix + revision
end
end
+ def rev_search_pattern
+ if ['', 'HEAD'].include? @new_resource.revision
+ 'HEAD'
+ else
+ @new_resource.revision + '*'
+ end
+ end
+
+ def git_ls_remote(rev_pattern)
+ command = git(%Q(ls-remote "#{@new_resource.repository}" "#{rev_pattern}"))
+ shell_out!(command, run_options).stdout
+ end
+
+ def refs_search(refs, pattern)
+ refs.find_all { |m| m[1] == pattern }
+ end
+
private
def run_options(run_opts={})
diff --git a/spec/unit/provider/git_spec.rb b/spec/unit/provider/git_spec.rb
index ff1c0b0398..02d155efbd 100644
--- a/spec/unit/provider/git_spec.rb
+++ b/spec/unit/provider/git_spec.rb
@@ -106,6 +106,52 @@ describe Chef::Provider::Git do
@provider.target_revision.should eql("663c22a5e41f5ae3193460cca044ed1435029f53")
end
+ it "converts resource.revision from a tag to a SHA using an exact match" do
+ @resource.revision "v1.0"
+ @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
+ "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/releases/v1.0\n" +
+ "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n")
+ @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ @provider.target_revision.should eql("503c22a5e41f5ae3193460cca044ed1435029f53")
+ end
+
+ it "converts resource.revision from a tag to a SHA, matching tags first, then heads" do
+ @resource.revision "v1.0"
+ @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
+ "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
+ "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
+ @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ @provider.target_revision.should eql("663c22a5e41f5ae3193460cca044ed1435029f53")
+ end
+
+ it "converts resource.revision from a tag to a SHA, matching heads if no tags match" do
+ @resource.revision "v1.0"
+ @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
+ "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.1\n" +
+ "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
+ @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ @provider.target_revision.should eql("503c22a5e41f5ae3193460cca044ed1435029f53")
+ end
+
+ it "converts resource.revision from a tag to a SHA, matching tags first, then heads, then revision" do
+ @resource.revision "refs/pulls/v1.0"
+ @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
+ "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
+ "805c22a5e41f5ae3193460cca044ed1435029f53\trefs/pulls/v1.0\n" +
+ "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
+ @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"refs/pulls/v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ @provider.target_revision.should eql("805c22a5e41f5ae3193460cca044ed1435029f53")
+ end
+
+ it "converts resource.revision from a tag to a SHA, using full path if provided" do
+ @resource.revision "refs/heads/v1.0"
+ @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
+ "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
+ "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
+ @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"refs/heads/v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ @provider.target_revision.should eql("503c22a5e41f5ae3193460cca044ed1435029f53")
+ end
+
it "raises an invalid remote reference error if you try to deploy from ``origin'' and assertions are run" do
@resource.revision "origin/"
@provider.action = :checkout