cookbook-omnifetch 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +1 -0
- data/Gemfile +3 -0
- data/LICENSE +201 -0
- data/README.md +45 -0
- data/Rakefile +2 -0
- data/cookbook-omnifetch.gemspec +39 -0
- data/lib/cookbook-omnifetch.rb +137 -0
- data/lib/cookbook-omnifetch/artifactserver.rb +122 -0
- data/lib/cookbook-omnifetch/base.rb +77 -0
- data/lib/cookbook-omnifetch/exceptions.rb +106 -0
- data/lib/cookbook-omnifetch/git.rb +183 -0
- data/lib/cookbook-omnifetch/github.rb +8 -0
- data/lib/cookbook-omnifetch/integration.rb +46 -0
- data/lib/cookbook-omnifetch/path.rb +86 -0
- data/lib/cookbook-omnifetch/version.rb +3 -0
- data/spec/fixtures/cookbooks/example_cookbook-0.5.0/README.md +12 -0
- data/spec/fixtures/cookbooks/example_cookbook-0.5.0/metadata.rb +3 -0
- data/spec/fixtures/cookbooks/example_cookbook-0.5.0/recipes/default.rb +8 -0
- data/spec/fixtures/cookbooks/example_cookbook/.gitignore +2 -0
- data/spec/fixtures/cookbooks/example_cookbook/.kitchen.yml +26 -0
- data/spec/fixtures/cookbooks/example_cookbook/Berksfile +1 -0
- data/spec/fixtures/cookbooks/example_cookbook/Berksfile.lock +3 -0
- data/spec/fixtures/cookbooks/example_cookbook/README.md +12 -0
- data/spec/fixtures/cookbooks/example_cookbook/metadata.rb +3 -0
- data/spec/fixtures/cookbooks/example_cookbook/recipes/default.rb +8 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/unit/artifactserver_spec.rb +51 -0
- data/spec/unit/base_spec.rb +81 -0
- data/spec/unit/git_spec.rb +258 -0
- data/spec/unit/path_spec.rb +108 -0
- metadata +144 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'cookbook-omnifetch/exceptions'
|
2
|
+
|
3
|
+
module CookbookOmnifetch
|
4
|
+
|
5
|
+
class MissingConfiguration < OmnifetchError; end
|
6
|
+
|
7
|
+
class NullValue; end
|
8
|
+
|
9
|
+
class Integration
|
10
|
+
|
11
|
+
def self.configurables
|
12
|
+
@configurables ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.configurable(name)
|
16
|
+
configurables << name
|
17
|
+
|
18
|
+
attr_writer name
|
19
|
+
|
20
|
+
define_method(name) do
|
21
|
+
value = instance_variable_get("@#{name}".to_sym)
|
22
|
+
case value
|
23
|
+
when NullValue
|
24
|
+
raise MissingConfiguration, "`#{name}` is not configured"
|
25
|
+
when Proc
|
26
|
+
value.call
|
27
|
+
else
|
28
|
+
value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
configurable :cache_path
|
35
|
+
configurable :storage_path
|
36
|
+
configurable :shell_out_class
|
37
|
+
configurable :cached_cookbook_class
|
38
|
+
|
39
|
+
def initialize
|
40
|
+
self.class.configurables.each do |configurable|
|
41
|
+
instance_variable_set("@#{configurable}".to_sym, NullValue.new)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'cookbook-omnifetch/base'
|
2
|
+
|
3
|
+
module CookbookOmnifetch
|
4
|
+
class PathLocation < BaseLocation
|
5
|
+
# Technically path locations are always installed, but this method
|
6
|
+
# intentionally returns +false+ to force validation of the cookbook at the
|
7
|
+
# path.
|
8
|
+
#
|
9
|
+
# @see BaseLocation#installed?
|
10
|
+
def installed?
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
# The installation for a path location is actually just a noop
|
15
|
+
#
|
16
|
+
# @see BaseLocation#install
|
17
|
+
def install
|
18
|
+
validate_cached!(expanded_path)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @see BaseLocation#cached_cookbook
|
22
|
+
def cached_cookbook
|
23
|
+
@cached_cookbook ||= CookbookOmnifetch.cached_cookbook_class.from_path(expanded_path)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns true if the location is a metadata location. By default, no
|
27
|
+
# locations are the metadata location.
|
28
|
+
#
|
29
|
+
# @return [Boolean]
|
30
|
+
def metadata?
|
31
|
+
!!options[:metadata]
|
32
|
+
end
|
33
|
+
|
34
|
+
def install_path
|
35
|
+
relative_path
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return this PathLocation's path relative to the associated Berksfile. It
|
39
|
+
# is actually the path reative to the associated Berksfile's parent
|
40
|
+
# directory.
|
41
|
+
#
|
42
|
+
# @return [Pathname]
|
43
|
+
# the relative path relative to the target
|
44
|
+
def relative_path
|
45
|
+
# TODO: this requires Berkshelf::Dependency to provide a delegate (ish) method that does
|
46
|
+
#
|
47
|
+
# def relative_paths_root
|
48
|
+
# File.dirname(berksfile.filepath)
|
49
|
+
# end
|
50
|
+
@relative_path ||= expanded_path.relative_path_from(Pathname.new(dependency.relative_paths_root))
|
51
|
+
end
|
52
|
+
|
53
|
+
# The fully expanded path of this cookbook on disk, relative to the
|
54
|
+
# Berksfile.
|
55
|
+
#
|
56
|
+
# @return [Pathname]
|
57
|
+
def expanded_path
|
58
|
+
# TODO: this requires Berkshelf::Dependency to provide a delegate (ish) method that does
|
59
|
+
#
|
60
|
+
# def relative_paths_root
|
61
|
+
# File.dirname(berksfile.filepath)
|
62
|
+
# end
|
63
|
+
@expanded_path ||= Pathname.new File.expand_path(options[:path], dependency.relative_paths_root)
|
64
|
+
end
|
65
|
+
|
66
|
+
def ==(other)
|
67
|
+
other.is_a?(PathLocation) &&
|
68
|
+
other.metadata? == metadata? &&
|
69
|
+
other.relative_path == relative_path
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_lock
|
73
|
+
out = " path: #{relative_path}\n"
|
74
|
+
out << " metadata: true\n" if metadata?
|
75
|
+
out
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_s
|
79
|
+
"source at #{relative_path}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def inspect
|
83
|
+
"#<CookbookOmnifetch::PathLocation metadata: #{metadata?}, path: #{relative_path}>"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
---
|
2
|
+
driver_plugin: vagrant
|
3
|
+
|
4
|
+
platforms:
|
5
|
+
- name: ubuntu-12.04
|
6
|
+
driver_config:
|
7
|
+
box: canonical-ubuntu-12.04
|
8
|
+
box_url: http://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box
|
9
|
+
require_chef_omnibus: true
|
10
|
+
- name: ubuntu-10.04
|
11
|
+
driver_config:
|
12
|
+
box: opscode-ubuntu-10.04
|
13
|
+
box_url: http://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-10.04_chef-11.2.0.box
|
14
|
+
- name: centos-6.3
|
15
|
+
driver_config:
|
16
|
+
box: opscode-centos-6.3
|
17
|
+
box_url: http://opscode-vm.s3.amazonaws.com/vagrant/opscode_centos-6.3_chef-11.2.0.box
|
18
|
+
- name: centos-5.8
|
19
|
+
driver_config:
|
20
|
+
box: opscode-centos-5.8
|
21
|
+
box_url: http://opscode-vm.s3.amazonaws.com/vagrant/opscode_centos-5.8_chef-11.2.0.box
|
22
|
+
|
23
|
+
suites:
|
24
|
+
- name: default
|
25
|
+
run_list: []
|
26
|
+
attributes: {}
|
@@ -0,0 +1 @@
|
|
1
|
+
site :opscode
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'cookbook-omnifetch'
|
2
|
+
|
3
|
+
module Fixtures
|
4
|
+
|
5
|
+
def fixtures_path
|
6
|
+
spec_root.join('fixtures')
|
7
|
+
end
|
8
|
+
|
9
|
+
def spec_root
|
10
|
+
Pathname.new(File.expand_path(File.dirname(__FILE__)))
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
module MockShellOut; end
|
16
|
+
module MockCachedCookbook; end
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
|
20
|
+
config.raise_errors_for_deprecations!
|
21
|
+
|
22
|
+
config.include Fixtures
|
23
|
+
|
24
|
+
config.expect_with :rspec do |c|
|
25
|
+
c.syntax = [:expect]
|
26
|
+
end
|
27
|
+
config.mock_with :rspec do |c|
|
28
|
+
c.syntax = [:expect, :should]
|
29
|
+
end
|
30
|
+
|
31
|
+
config.filter_run :focus => true
|
32
|
+
|
33
|
+
config.run_all_when_everything_filtered = true
|
34
|
+
|
35
|
+
config.before(:suite) do
|
36
|
+
CookbookOmnifetch.configure do |c|
|
37
|
+
c.cache_path = File.expand_path('~/.berkshelf')
|
38
|
+
c.storage_path = Pathname.new(File.expand_path('~/.berkshelf/cookbooks'))
|
39
|
+
c.shell_out_class = MockShellOut
|
40
|
+
c.cached_cookbook_class = MockCachedCookbook
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'cookbook-omnifetch/artifactserver'
|
3
|
+
|
4
|
+
module CookbookOmnifetch
|
5
|
+
describe ArtifactserverLocation do
|
6
|
+
|
7
|
+
let(:cookbook_name) { "nginx" }
|
8
|
+
|
9
|
+
let(:cookbook_version) { "1.5.23" }
|
10
|
+
|
11
|
+
let(:constraint) { double("Constraint") }
|
12
|
+
|
13
|
+
let(:dependency) { double("Dependency", name: cookbook_name, constraint: constraint) }
|
14
|
+
|
15
|
+
let(:options) { {artifactserver: "https://cookbooks.opscode.com/api/v1", version: cookbook_version } }
|
16
|
+
|
17
|
+
subject(:public_repo_location) { ArtifactserverLocation.new(dependency, options) }
|
18
|
+
|
19
|
+
it "has a URI" do
|
20
|
+
expect(public_repo_location.uri).to eq("https://cookbooks.opscode.com/api/v1")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "has a repo host" do
|
24
|
+
expect(public_repo_location.repo_host).to eq("cookbooks.opscode.com")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "has an exact version" do
|
28
|
+
expect(public_repo_location.cookbook_version).to eq("1.5.23")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "has a cache key containing the site URI and version" do
|
32
|
+
expect(public_repo_location.cache_key).to eq("nginx-1.5.23-cookbooks.opscode.com")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "sets the install location as the cache path plus cache key" do
|
36
|
+
expected_install_path = Pathname.new('~/.berkshelf/cookbooks').expand_path.join("nginx-1.5.23-cookbooks.opscode.com")
|
37
|
+
expect(public_repo_location.install_path).to eq(expected_install_path)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "considers the cookbook installed if it exists in the main cache" do
|
41
|
+
expect(public_repo_location.install_path).to receive(:exist?).and_return(true)
|
42
|
+
expect(public_repo_location.installed?).to be true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "considers the cookbook not installed if it doesn't exist in the main cache" do
|
46
|
+
expect(public_repo_location.install_path).to receive(:exist?).and_return(false)
|
47
|
+
expect(public_repo_location.installed?).to be false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'cookbook-omnifetch/base'
|
3
|
+
|
4
|
+
module CookbookOmnifetch
|
5
|
+
describe BaseLocation do
|
6
|
+
let(:constraint) { double('constraint') }
|
7
|
+
let(:dependency) { double('dependency', name: 'cookbook', version_constraint: constraint) }
|
8
|
+
|
9
|
+
subject { described_class.new(dependency) }
|
10
|
+
|
11
|
+
describe '#installed?' do
|
12
|
+
it 'is an abstract function' do
|
13
|
+
expect { subject.installed? }.to raise_error(AbstractFunction)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#install' do
|
18
|
+
it 'is an abstract function' do
|
19
|
+
expect { subject.install }.to raise_error(AbstractFunction)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#cached_cookbook' do
|
24
|
+
it 'is an abstract function' do
|
25
|
+
expect { subject.cached_cookbook }.to raise_error(AbstractFunction)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#to_lock' do
|
30
|
+
it 'is an abstract function' do
|
31
|
+
expect { subject.to_lock }.to raise_error(AbstractFunction)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#validate_cached!' do
|
36
|
+
context 'when the path is not a cookbook' do
|
37
|
+
before { CookbookOmnifetch.stub(:cookbook?).and_return(false) }
|
38
|
+
|
39
|
+
it 'raises an error' do
|
40
|
+
expect {
|
41
|
+
subject.validate_cached!('/foo/bar')
|
42
|
+
}.to raise_error(NotACookbook)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when the path is a cookbook' do
|
47
|
+
let(:cookbook) do
|
48
|
+
double('cookbook',
|
49
|
+
cookbook_name: 'cookbook',
|
50
|
+
version: '0.1.0',
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
before do
|
55
|
+
CookbookOmnifetch.stub(:cookbook?).and_return(true)
|
56
|
+
MockCachedCookbook.stub(:from_path).and_return(cookbook)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'raises an error if the constraint does not satisfy' do
|
60
|
+
constraint.stub(:satisfies?).with('0.1.0').and_return(false)
|
61
|
+
expect {
|
62
|
+
subject.validate_cached!(cookbook)
|
63
|
+
}.to raise_error(CookbookValidationFailure)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'raises an error if the names do not match' do
|
67
|
+
constraint.stub(:satisfies?).with('0.1.0').and_return(true)
|
68
|
+
cookbook.stub(:cookbook_name).and_return('different_name')
|
69
|
+
expect {
|
70
|
+
subject.validate_cached!(cookbook)
|
71
|
+
}.to raise_error(MismatchedCookbookName)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'returns true when the validation succeeds' do
|
75
|
+
constraint.stub(:satisfies?).with('0.1.0').and_return(true)
|
76
|
+
expect(subject.validate_cached!(cookbook)).to be true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,258 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'cookbook-omnifetch/git'
|
3
|
+
|
4
|
+
module CookbookOmnifetch
|
5
|
+
describe GitLocation do
|
6
|
+
let(:dependency) { double(name: 'bacon') }
|
7
|
+
|
8
|
+
subject do
|
9
|
+
described_class.new(dependency, git: 'https://repo.com', branch: 'ham',
|
10
|
+
tag: 'v1.2.3', ref: 'abc123', revision: 'defjkl123456', rel: 'hi')
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '.initialize' do
|
14
|
+
it 'sets the uri' do
|
15
|
+
instance = described_class.new(dependency, git: 'https://repo.com')
|
16
|
+
expect(instance.uri).to eq('https://repo.com')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'sets the branch' do
|
20
|
+
instance = described_class.new(dependency,
|
21
|
+
git: 'https://repo.com', branch: 'magic_new_feature')
|
22
|
+
expect(instance.branch).to eq('magic_new_feature')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'sets the tag' do
|
26
|
+
instance = described_class.new(dependency,
|
27
|
+
git: 'https://repo.com', tag: 'v1.2.3')
|
28
|
+
expect(instance.tag).to eq('v1.2.3')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'adds the ref' do
|
32
|
+
instance = described_class.new(dependency,
|
33
|
+
git: 'https://repo.com', ref: 'abc123')
|
34
|
+
expect(instance.ref).to eq('abc123')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'sets the revision' do
|
38
|
+
instance = described_class.new(dependency,
|
39
|
+
git: 'https://repo.com', revision: 'abcde12345')
|
40
|
+
expect(instance.revision).to eq('abcde12345')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'sets the rel' do
|
44
|
+
instance = described_class.new(dependency,
|
45
|
+
git: 'https://repo.com', rel: 'internal/path')
|
46
|
+
expect(instance.rel).to eq('internal/path')
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'rev_parse' do
|
50
|
+
def rev_parse(instance)
|
51
|
+
instance.instance_variable_get(:@rev_parse)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'uses the :ref option with priority' do
|
55
|
+
instance = described_class.new(dependency,
|
56
|
+
git: 'https://repo.com', ref: 'abc123', branch: 'magic_new_feature')
|
57
|
+
expect(rev_parse(instance)).to eq('abc123')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'uses the :branch option with priority' do
|
61
|
+
instance = described_class.new(dependency,
|
62
|
+
git: 'https://repo.com', branch: 'magic_new_feature', tag: 'v1.2.3')
|
63
|
+
expect(rev_parse(instance)).to eq('magic_new_feature')
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'uses the :tag option' do
|
67
|
+
instance = described_class.new(dependency,
|
68
|
+
git: 'https://repo.com', tag: 'v1.2.3')
|
69
|
+
expect(rev_parse(instance)).to eq('v1.2.3')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'uses "master" when none is given' do
|
73
|
+
instance = described_class.new(dependency, git: 'https://repo.com')
|
74
|
+
expect(rev_parse(instance)).to eq('master')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#cache_key" do
|
80
|
+
|
81
|
+
it "concatenates the name and revision" do
|
82
|
+
subject.stub(:revision).and_return("abcdef123456")
|
83
|
+
expect(subject.cache_key).to eq("bacon-abcdef123456")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '#installed?' do
|
88
|
+
it 'returns false when there is no revision' do
|
89
|
+
subject.stub(:revision).and_return(nil)
|
90
|
+
expect(subject.installed?).to be false
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns false when the install_path does not exist' do
|
94
|
+
subject.stub(:revision).and_return('abcd1234')
|
95
|
+
subject.stub(:install_path).and_return(double(exist?: false))
|
96
|
+
expect(subject.installed?).to be false
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'returns true when the location is installed' do
|
100
|
+
subject.stub(:revision).and_return('abcd1234')
|
101
|
+
subject.stub(:install_path).and_return(double(exist?: true))
|
102
|
+
expect(subject.installed?).to be true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#install' do
|
107
|
+
before do
|
108
|
+
File.stub(:chmod)
|
109
|
+
FileUtils.stub(:cp_r)
|
110
|
+
subject.stub(:validate_cached!)
|
111
|
+
subject.stub(:git)
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'when the repository is cached' do
|
115
|
+
it 'pulls a new version' do
|
116
|
+
Dir.stub(:chdir) { |args, &b| b.call } # Force eval the chdir block
|
117
|
+
|
118
|
+
subject.stub(:cached?).and_return(true)
|
119
|
+
expect(subject).to receive(:git).with(
|
120
|
+
'fetch --force --tags https://repo.com "refs/heads/*:refs/heads/*"'
|
121
|
+
)
|
122
|
+
subject.install
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'when the revision is not cached' do
|
127
|
+
it 'clones the repository' do
|
128
|
+
Dir.stub(:chdir) { |args, &b| b.call } # Force eval the chdir block
|
129
|
+
|
130
|
+
cache_path = subject.send(:cache_path)
|
131
|
+
subject.stub(:cached?).and_return(false)
|
132
|
+
expect(subject).to receive(:git).with(
|
133
|
+
%|clone https://repo.com "#{cache_path}" --bare --no-hardlinks|
|
134
|
+
)
|
135
|
+
subject.install
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#cached_cookbook' do
|
141
|
+
it 'returns nil if the cookbook is not installed' do
|
142
|
+
subject.stub(:installed?).and_return(false)
|
143
|
+
expect(subject.cached_cookbook).to be_nil
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'returns the cookbook at the install_path' do
|
147
|
+
subject.stub(:installed?).and_return(true)
|
148
|
+
MockCachedCookbook.stub(:from_path)
|
149
|
+
|
150
|
+
expect(MockCachedCookbook).to receive(:from_path).once
|
151
|
+
subject.cached_cookbook
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe '#==' do
|
156
|
+
let(:other) { subject.dup }
|
157
|
+
|
158
|
+
it 'returns true when everything matches' do
|
159
|
+
expect(subject).to eq(other)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'returns false when the other location is not an GitLocation' do
|
163
|
+
other.stub(:is_a?).and_return(false)
|
164
|
+
expect(subject).to_not eq(other)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'returns false when the uri is different' do
|
168
|
+
other.stub(:uri).and_return('different')
|
169
|
+
expect(subject).to_not eq(other)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'returns false when the branch is different' do
|
173
|
+
other.stub(:branch).and_return('different')
|
174
|
+
expect(subject).to_not eq(other)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'returns false when the tag is different' do
|
178
|
+
other.stub(:tag).and_return('different')
|
179
|
+
expect(subject).to_not eq(other)
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'returns false when the ref is different' do
|
183
|
+
other.stub(:ref).and_return('different')
|
184
|
+
expect(subject).to_not eq(other)
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'returns false when the rel is different' do
|
188
|
+
other.stub(:rel).and_return('different')
|
189
|
+
expect(subject).to_not eq(other)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '#to_s' do
|
194
|
+
it 'prefers the tag' do
|
195
|
+
expect(subject.to_s).to eq('https://repo.com (at v1.2.3/hi)')
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'prefers the branch' do
|
199
|
+
subject.stub(:tag).and_return(nil)
|
200
|
+
expect(subject.to_s).to eq('https://repo.com (at ham/hi)')
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'falls back to the ref' do
|
204
|
+
subject.stub(:tag).and_return(nil)
|
205
|
+
subject.stub(:branch).and_return(nil)
|
206
|
+
expect(subject.to_s).to eq('https://repo.com (at abc123/hi)')
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'does not use the rel if missing' do
|
210
|
+
subject.stub(:rel).and_return(nil)
|
211
|
+
expect(subject.to_s).to eq('https://repo.com (at v1.2.3)')
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe '#to_lock' do
|
216
|
+
it 'includes all the information' do
|
217
|
+
expect(subject.to_lock).to eq <<-EOH.gsub(/^ {8}/, '')
|
218
|
+
git: https://repo.com
|
219
|
+
revision: defjkl123456
|
220
|
+
ref: abc123
|
221
|
+
branch: ham
|
222
|
+
tag: v1.2.3
|
223
|
+
rel: hi
|
224
|
+
EOH
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'does not include the branch if missing' do
|
228
|
+
subject.stub(:branch).and_return(nil)
|
229
|
+
expect(subject.to_lock).to_not include('branch')
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'does not include the tag if missing' do
|
233
|
+
subject.stub(:tag).and_return(nil)
|
234
|
+
expect(subject.to_lock).to_not include('tag')
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'does not include the rel if missing' do
|
238
|
+
subject.stub(:rel).and_return(nil)
|
239
|
+
expect(subject.to_lock).to_not include('rel')
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe '#git' do
|
244
|
+
before { described_class.send(:public, :git) }
|
245
|
+
|
246
|
+
it 'raises an error if Git is not installed' do
|
247
|
+
CookbookOmnifetch.stub(:which).and_return(false)
|
248
|
+
expect { subject.git('foo') }.to raise_error(GitNotInstalled)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'raises an error if the command fails' do
|
252
|
+
shell_out = double('shell_out', success?: false, stderr: nil)
|
253
|
+
MockShellOut.stub(:shell_out).and_return(shell_out)
|
254
|
+
expect { subject.git('foo') }.to raise_error(GitCommandError)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|