berkshelf 1.4.0.rc1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/berkshelf.gemspec +2 -1
- data/features/contingent_command.feature +18 -0
- data/features/cookbook_command.feature +13 -11
- data/features/info_command.feature +39 -0
- data/features/step_definitions/filesystem_steps.rb +32 -0
- data/features/step_definitions/gem_steps.rb +3 -2
- data/features/support/env.rb +2 -0
- data/generator_files/Berksfile.erb +5 -0
- data/generator_files/Vagrantfile.erb +10 -0
- data/generator_files/default_test.rb.erb +11 -0
- data/generator_files/helpers.rb.erb +7 -0
- data/lib/berkshelf.rb +4 -3
- data/lib/berkshelf/berksfile.rb +5 -15
- data/lib/berkshelf/cached_cookbook.rb +18 -0
- data/lib/berkshelf/chef/config.rb +21 -26
- data/lib/berkshelf/cli.rb +40 -5
- data/lib/berkshelf/community_rest.rb +17 -1
- data/lib/berkshelf/cookbook_generator.rb +4 -0
- data/lib/berkshelf/cookbook_source.rb +21 -18
- data/lib/berkshelf/init_generator.rb +13 -3
- data/lib/berkshelf/locations/github_location.rb +1 -1
- data/lib/berkshelf/locations/path_location.rb +1 -1
- data/lib/berkshelf/resolver.rb +10 -6
- data/lib/berkshelf/test.rb +37 -0
- data/lib/berkshelf/version.rb +1 -1
- data/spec/spec_helper.rb +5 -1
- data/spec/unit/berkshelf/community_rest_spec.rb +1 -0
- data/spec/unit/berkshelf/cookbook_source_spec.rb +201 -181
- data/spec/unit/berkshelf/init_generator_spec.rb +40 -1
- data/spec/unit/berkshelf/locations/path_location_spec.rb +10 -0
- data/spec/unit/berkshelf/resolver_spec.rb +6 -7
- data/spec/unit/berkshelf/ui_spec.rb +2 -1
- data/spec/unit/chef/config_spec.rb +79 -4
- metadata +34 -8
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'open-uri'
|
2
2
|
require 'retryable'
|
3
|
+
require 'addressable/uri'
|
3
4
|
|
4
5
|
module Berkshelf
|
5
6
|
# @author Jamie Winsor <reset@riotgames.com>
|
@@ -12,7 +13,11 @@ module Berkshelf
|
|
12
13
|
#
|
13
14
|
# @return [String]
|
14
15
|
def unpack(target, destination = Dir.mktmpdir)
|
15
|
-
|
16
|
+
if is_gzip_file(target)
|
17
|
+
Archive::Tar::Minitar.unpack(Zlib::GzipReader.new(File.open(target, 'rb')), destination)
|
18
|
+
elsif is_tar_file(target)
|
19
|
+
Archive::Tar::Minitar.unpack(target, destination)
|
20
|
+
end
|
16
21
|
destination
|
17
22
|
end
|
18
23
|
|
@@ -29,6 +34,17 @@ module Berkshelf
|
|
29
34
|
def version_from_uri(uri)
|
30
35
|
File.basename(uri.to_s).gsub('_', '.')
|
31
36
|
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def is_gzip_file(path)
|
40
|
+
# You cannot write "\x1F\x8B" because the default encoding of
|
41
|
+
# ruby >= 1.9.3 is UTF-8 and 8B is an invalid in UTF-8.
|
42
|
+
IO.binread(path, 2) == [0x1F, 0x8B].pack("C*")
|
43
|
+
end
|
44
|
+
|
45
|
+
def is_tar_file(path)
|
46
|
+
IO.binread(path, 8, 257) == "ustar \0"
|
47
|
+
end
|
32
48
|
end
|
33
49
|
|
34
50
|
V1_API = 'http://cookbooks.opscode.com/api/v1/cookbooks'.freeze
|
@@ -68,6 +68,7 @@ module Berkshelf
|
|
68
68
|
|
69
69
|
extend Forwardable
|
70
70
|
|
71
|
+
attr_reader :berksfile
|
71
72
|
attr_reader :name
|
72
73
|
attr_reader :options
|
73
74
|
attr_reader :version_constraint
|
@@ -93,11 +94,12 @@ module Berkshelf
|
|
93
94
|
# @option options [String] :tag
|
94
95
|
# same as tag
|
95
96
|
# @option options [String] :locked_version
|
96
|
-
def initialize(name, options = {})
|
97
|
+
def initialize(berksfile, name, options = {})
|
97
98
|
self.class.validate_options(options)
|
98
99
|
|
99
|
-
@
|
100
|
-
@
|
100
|
+
@berksfile = berksfile
|
101
|
+
@name = name
|
102
|
+
@locked_version = Solve::Version.new(options[:locked_version]) if options[:locked_version]
|
101
103
|
@version_constraint = Solve::Constraint.new(options[:locked_version] || options[:constraint] || ">= 0.0.0")
|
102
104
|
|
103
105
|
@cached_cookbook, @location = cached_and_location(options)
|
@@ -115,6 +117,13 @@ module Berkshelf
|
|
115
117
|
end
|
116
118
|
end
|
117
119
|
|
120
|
+
# Determine the CachedCookbook and Location information from the given options.
|
121
|
+
#
|
122
|
+
# @return [Array<CachedCookbook, Location>]
|
123
|
+
def cached_and_location(options = {})
|
124
|
+
from_path(options) || from_cache(options) || from_default(options)
|
125
|
+
end
|
126
|
+
|
118
127
|
# Returns true if the cookbook source has already been downloaded. A cookbook
|
119
128
|
# source is downloaded when a cached cookbook is present.
|
120
129
|
#
|
@@ -178,13 +187,6 @@ module Berkshelf
|
|
178
187
|
|
179
188
|
private
|
180
189
|
|
181
|
-
# Determine the CachedCookbook and Location information from the given options.
|
182
|
-
#
|
183
|
-
# @return [Array<CachedCookbook, Location>]
|
184
|
-
def cached_and_location(options = {})
|
185
|
-
from_path(options) || from_cache(options) || from_default(options)
|
186
|
-
end
|
187
|
-
|
188
190
|
# Attempt to load a CachedCookbook from a local file system path (if the :path
|
189
191
|
# option was given). If one is found, the location and cached_cookbook is
|
190
192
|
# updated. Otherwise, this method will raise a CookbookNotFound exception.
|
@@ -196,12 +198,13 @@ module Berkshelf
|
|
196
198
|
def from_path(options = {})
|
197
199
|
return nil unless options[:path]
|
198
200
|
|
199
|
-
|
200
|
-
|
201
|
+
path = File.expand_path(PathLocation.normalize_path(options[:path]), File.dirname(berksfile.filepath))
|
202
|
+
location = PathLocation.new(name, version_constraint, path: path)
|
203
|
+
cached = CachedCookbook.from_path(location.path)
|
201
204
|
|
202
|
-
[cached, location]
|
203
|
-
rescue IOError
|
204
|
-
raise Berkshelf::CookbookNotFound
|
205
|
+
[ cached, location ]
|
206
|
+
rescue IOError => ex
|
207
|
+
raise Berkshelf::CookbookNotFound, ex
|
205
208
|
end
|
206
209
|
|
207
210
|
# Attempt to load a CachedCookbook from the local CookbookStore. This will save
|
@@ -214,9 +217,9 @@ module Berkshelf
|
|
214
217
|
return nil unless File.exists?(path)
|
215
218
|
|
216
219
|
location = PathLocation.new(name, version_constraint, path: path)
|
217
|
-
cached
|
220
|
+
cached = CachedCookbook.from_path(path, name: name)
|
218
221
|
|
219
|
-
[cached, location]
|
222
|
+
[ cached, location ]
|
220
223
|
end
|
221
224
|
|
222
225
|
# Use the default location, and a nil CachedCookbook. If there is no location
|
@@ -230,7 +233,7 @@ module Berkshelf
|
|
230
233
|
location = Location.init(name, version_constraint, options)
|
231
234
|
end
|
232
235
|
|
233
|
-
[nil, location]
|
236
|
+
[ nil, location ]
|
234
237
|
end
|
235
238
|
|
236
239
|
# The hypothetical location of this CachedCookbook, if it were to exist.
|
@@ -29,6 +29,10 @@ module Berkshelf
|
|
29
29
|
type: :boolean,
|
30
30
|
default: false
|
31
31
|
|
32
|
+
class_option :chef_minitest,
|
33
|
+
type: :boolean,
|
34
|
+
default: false
|
35
|
+
|
32
36
|
class_option :scmversion,
|
33
37
|
type: :boolean,
|
34
38
|
default: false
|
@@ -69,6 +73,12 @@ module Berkshelf
|
|
69
73
|
template "Thorfile.erb", target.join("Thorfile")
|
70
74
|
end
|
71
75
|
|
76
|
+
if options[:chef_minitest]
|
77
|
+
empty_directory target.join("files/default/tests/minitest/support")
|
78
|
+
template "default_test.rb.erb", target.join("files/default/tests/minitest/default_test.rb")
|
79
|
+
template "helpers.rb.erb", target.join("files/default/tests/minitest/support/helpers.rb")
|
80
|
+
end
|
81
|
+
|
72
82
|
if options[:scmversion]
|
73
83
|
create_file target.join("VERSION"), "0.1.0"
|
74
84
|
end
|
@@ -108,7 +118,7 @@ module Berkshelf
|
|
108
118
|
raise InvalidConfiguration.new Config.instance.errors
|
109
119
|
end
|
110
120
|
end
|
111
|
-
|
121
|
+
|
112
122
|
|
113
123
|
# Check for supporting gems for provided options
|
114
124
|
#
|
@@ -138,14 +148,14 @@ module Berkshelf
|
|
138
148
|
|
139
149
|
# Warn if the supporting gem for a default is not installed
|
140
150
|
#
|
141
|
-
# @return [Boolean]
|
151
|
+
# @return [Boolean]
|
142
152
|
def assert_default_supported(option, gem_name = option.to_s)
|
143
153
|
unless options[option]
|
144
154
|
begin
|
145
155
|
Gem::Specification.find_by_name(gem_name)
|
146
156
|
rescue Gem::LoadError
|
147
157
|
Berkshelf.ui.warn "By default, this cookbook was generated to support #{gem_name}, however, #{gem_name} is not installed."
|
148
|
-
Berkshelf.ui.warn "To skip support for #{gem_name}, use --#{option}"
|
158
|
+
Berkshelf.ui.warn "To skip support for #{gem_name}, use --#{option.to_s.gsub('_', '-')}"
|
149
159
|
Berkshelf.ui.warn "To install #{gem_name}: gem install #{gem_name}"
|
150
160
|
return false
|
151
161
|
end
|
data/lib/berkshelf/resolver.rb
CHANGED
@@ -3,16 +3,20 @@ module Berkshelf
|
|
3
3
|
class Resolver
|
4
4
|
extend Forwardable
|
5
5
|
|
6
|
+
# @return [Berkshelf::Berksfile]
|
7
|
+
attr_reader :berksfile
|
8
|
+
# @return [Solve::Graph]
|
6
9
|
attr_reader :graph
|
7
10
|
|
8
|
-
# @param [
|
11
|
+
# @param [Berkshelf::Berksfile] berksfile
|
9
12
|
# @param [Hash] options
|
10
13
|
#
|
11
14
|
# @option options [Array<CookbookSource>, CookbookSource] sources
|
12
|
-
def initialize(
|
13
|
-
@
|
14
|
-
@
|
15
|
-
@
|
15
|
+
def initialize(berksfile, options = {})
|
16
|
+
@berksfile = berksfile
|
17
|
+
@downloader = @berksfile.downloader
|
18
|
+
@graph = Solve::Graph.new
|
19
|
+
@sources = Hash.new
|
16
20
|
|
17
21
|
# Dependencies need to be added AFTER the sources. If they are
|
18
22
|
# not, then one of the dependencies of a source that is added
|
@@ -70,7 +74,7 @@ module Berkshelf
|
|
70
74
|
source.cached_cookbook.dependencies.each do |name, constraint|
|
71
75
|
next if has_source?(name)
|
72
76
|
|
73
|
-
add_source(CookbookSource.new(name, constraint: constraint))
|
77
|
+
add_source(CookbookSource.new(berksfile, name, constraint: constraint))
|
74
78
|
end
|
75
79
|
end
|
76
80
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Berkshelf
|
2
|
+
# Because aruba runs in a sub-process, there's no easy way to share mocks and
|
3
|
+
# stubs across a run (See RiotGames/berkshelf#208). As a work-around, we pass
|
4
|
+
# "special" mocks and stubs into the TEST environment variable. This class
|
5
|
+
# parses and then requires the appropriate mocks during the run.
|
6
|
+
#
|
7
|
+
# @author Seth Vargo <sethvargo@gmail.com>
|
8
|
+
class Mocks
|
9
|
+
require 'rspec/mocks/standalone'
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def env_keys
|
13
|
+
self.instance_methods(false).map { |key| key.to_s.upcase }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(keys)
|
18
|
+
keys.each do |key|
|
19
|
+
self.send(key.downcase.to_sym, ENV[key.to_s])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Trick bundler into thinking gems are missing.
|
24
|
+
#
|
25
|
+
# @param [String] gems
|
26
|
+
# a CSV list of gems to be missing
|
27
|
+
def missing_gems(gems)
|
28
|
+
gems.split(',').each do |gem|
|
29
|
+
Gem::Specification.stub(:find_by_name).with(gem).and_raise(Gem::LoadError)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
unless (keys = Berkshelf::Mocks.env_keys & ENV.keys).empty?
|
36
|
+
Berkshelf::Mocks.new(keys)
|
37
|
+
end
|
data/lib/berkshelf/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# We set this variable to load additional test materials during cucumber
|
2
|
+
# runs, since aruba runs in a subprocess. See lib/berkshelf/test.rb
|
3
|
+
ENV['RUBY_ENV'] ||= 'test'
|
4
|
+
|
1
5
|
require 'rubygems'
|
2
6
|
require 'bundler'
|
3
7
|
require 'spork'
|
@@ -11,7 +15,7 @@ Spork.prefork do
|
|
11
15
|
|
12
16
|
APP_ROOT = File.expand_path('../../', __FILE__)
|
13
17
|
ENV["BERKSHELF_PATH"] = File.join(APP_ROOT, "spec", "tmp", "berkshelf")
|
14
|
-
ENV["BERKSHELF_CHEF_CONFIG"] = File.join(APP_ROOT, "spec", "
|
18
|
+
ENV["BERKSHELF_CHEF_CONFIG"] = File.join(APP_ROOT, "spec", "knife.rb")
|
15
19
|
|
16
20
|
Dir[File.join(APP_ROOT, "spec/support/**/*.rb")].each {|f| require f}
|
17
21
|
|
@@ -15,6 +15,7 @@ describe Berkshelf::CommunityREST, vcr: { record: :new_episodes, serialize_with:
|
|
15
15
|
|
16
16
|
it 'unpacks the tar' do
|
17
17
|
::File.should_receive(:open).with(target, 'rb')
|
18
|
+
::IO.should_receive(:binread).with(target, 2).and_return([0x1F, 0x8B].pack("C*"))
|
18
19
|
Zlib::GzipReader.should_receive(:new).with(file)
|
19
20
|
Archive::Tar::Minitar.should_receive(:unpack).with(gzip_reader, destination)
|
20
21
|
|
@@ -1,267 +1,287 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
describe Berkshelf::CookbookSource do
|
4
|
+
let(:cookbook_name) { "nginx" }
|
5
|
+
let(:berksfile) { double('berksfile', filepath: fixtures_path.join("Berksfile").to_s) }
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
describe "ClassMethods" do
|
8
|
+
subject { Berkshelf::CookbookSource }
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
describe "::initialize" do
|
11
|
+
context "given no location key (i.e. :git, :path, :site)" do
|
12
|
+
let(:source) { subject.new(berksfile, cookbook_name) }
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
end
|
14
|
+
it "sets a nil valie for location" do
|
15
|
+
source.location.should be_nil
|
17
16
|
end
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
context 'given no value for :locked_version' do
|
20
|
+
let(:source) { subject.new(berksfile, cookbook_name) }
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
22
|
+
it 'returns a wildcard match for any version' do
|
23
|
+
expect(source.version_constraint.to_s).to eq('>= 0.0.0')
|
25
24
|
end
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
context 'given a value for :locked_version' do
|
28
|
+
let(:source) { subject.new(berksfile, cookbook_name, locked_version: '1.2.3') }
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
end
|
30
|
+
it 'returns the locked_version as the constraint' do
|
31
|
+
expect(source.version_constraint.to_s).to eq('= 1.2.3')
|
33
32
|
end
|
33
|
+
end
|
34
34
|
|
35
|
-
|
36
|
-
|
35
|
+
context 'given no value for :constraint' do
|
36
|
+
let(:source) { subject.new(berksfile, cookbook_name) }
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
end
|
38
|
+
it 'returns a wildcard match for any version' do
|
39
|
+
expect(source.version_constraint.to_s).to eq('>= 0.0.0')
|
41
40
|
end
|
41
|
+
end
|
42
42
|
|
43
|
-
|
44
|
-
|
43
|
+
context 'given a value for :constraint' do
|
44
|
+
let(:source) { subject.new(berksfile, cookbook_name, constraint: '~> 1.0.84') }
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
end
|
46
|
+
it 'returns a Solve::Constraint for the given version for version_constraint' do
|
47
|
+
expect(source.version_constraint.to_s).to eq('~> 1.0.84')
|
49
48
|
end
|
49
|
+
end
|
50
50
|
|
51
|
-
|
52
|
-
|
51
|
+
context 'given a value for :locked_version and :constraint' do
|
52
|
+
let(:source) { subject.new(berksfile, cookbook_name, constraint: '~> 1.0.84', locked_version: '1.2.3') }
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
end
|
54
|
+
it 'uses the :locked_version' do
|
55
|
+
expect(source.version_constraint.to_s).to eq('= 1.2.3')
|
57
56
|
end
|
57
|
+
end
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
59
|
+
context "given a location key :git" do
|
60
|
+
let(:url) { "git://url_to_git" }
|
61
|
+
let(:source) { subject.new(berksfile, cookbook_name, git: url) }
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
it "initializes a GitLocation for location" do
|
64
|
+
source.location.should be_a(Berkshelf::GitLocation)
|
65
|
+
end
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
end
|
67
|
+
it "points to the given Git URL" do
|
68
|
+
source.location.uri.should eql(url)
|
70
69
|
end
|
70
|
+
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
context "given a location key :path" do
|
73
|
+
context "given a value for path that contains a cookbook" do
|
74
|
+
let(:path) { fixtures_path.join("cookbooks", "example_cookbook").to_s }
|
75
75
|
|
76
|
-
|
77
|
-
|
78
|
-
|
76
|
+
it "initializes a PathLocation for location" do
|
77
|
+
subject.new(berksfile, cookbook_name, path: path).location.should be_a(Berkshelf::PathLocation)
|
78
|
+
end
|
79
79
|
|
80
|
-
|
81
|
-
|
82
|
-
end
|
80
|
+
it "points to the specified path" do
|
81
|
+
subject.new(berksfile, cookbook_name, path: path).location.path.should eql(path)
|
83
82
|
end
|
83
|
+
end
|
84
84
|
|
85
|
-
|
86
|
-
|
85
|
+
context "given a value for path that does not contain a cookbook" do
|
86
|
+
let(:path) { "/does/not/exist" }
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
end
|
88
|
+
it "raises Berkshelf::CookbookNotFound" do
|
89
|
+
lambda {
|
90
|
+
subject.new(berksfile, cookbook_name, path: path)
|
91
|
+
}.should raise_error(Berkshelf::CookbookNotFound)
|
93
92
|
end
|
93
|
+
end
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
101
|
-
|
102
|
-
it "raises BerkshelfError with a messaging containing all of the invalid options" do
|
103
|
-
lambda {
|
104
|
-
subject.new(cookbook_name, invalid_one: "one", invalid_two: "two")
|
105
|
-
}.should raise_error(Berkshelf::BerkshelfError, "Invalid options for Cookbook Source: 'invalid_one', 'invalid_two'.")
|
106
|
-
end
|
95
|
+
context "given an invalid option" do
|
96
|
+
it "raises BerkshelfError with a friendly message" do
|
97
|
+
lambda {
|
98
|
+
subject.new(berksfile, cookbook_name, invalid_opt: "thisisnotvalid")
|
99
|
+
}.should raise_error(Berkshelf::BerkshelfError, "Invalid options for Cookbook Source: 'invalid_opt'.")
|
107
100
|
end
|
108
101
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
102
|
+
it "raises BerkshelfError with a messaging containing all of the invalid options" do
|
103
|
+
lambda {
|
104
|
+
subject.new(berksfile, cookbook_name, invalid_one: "one", invalid_two: "two")
|
105
|
+
}.should raise_error(Berkshelf::BerkshelfError, "Invalid options for Cookbook Source: 'invalid_one', 'invalid_two'.")
|
106
|
+
end
|
107
|
+
end
|
114
108
|
|
115
|
-
|
116
|
-
|
117
|
-
|
109
|
+
describe "::add_valid_option" do
|
110
|
+
before(:each) do
|
111
|
+
@original = subject.class_variable_get :@@valid_options
|
112
|
+
subject.class_variable_set :@@valid_options, []
|
113
|
+
end
|
118
114
|
|
119
|
-
|
120
|
-
|
115
|
+
after(:each) do
|
116
|
+
subject.class_variable_set :@@valid_options, @original
|
117
|
+
end
|
121
118
|
|
122
|
-
|
123
|
-
|
124
|
-
end
|
119
|
+
it "adds an option to the list of valid options" do
|
120
|
+
subject.add_valid_option(:one)
|
125
121
|
|
126
|
-
|
127
|
-
|
128
|
-
|
122
|
+
subject.valid_options.should have(1).item
|
123
|
+
subject.valid_options.should include(:one)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "does not add duplicate options to the list of valid options" do
|
127
|
+
subject.add_valid_option(:one)
|
128
|
+
subject.add_valid_option(:one)
|
129
129
|
|
130
|
-
|
131
|
-
|
132
|
-
end
|
130
|
+
subject.valid_options.should have(1).item
|
131
|
+
subject.valid_options.should include(:one)
|
133
132
|
end
|
133
|
+
end
|
134
134
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
135
|
+
describe "::add_location_key" do
|
136
|
+
before(:each) do
|
137
|
+
@original = subject.class_variable_get :@@location_keys
|
138
|
+
subject.class_variable_set :@@location_keys, {}
|
139
|
+
end
|
140
140
|
|
141
|
-
|
142
|
-
|
143
|
-
|
141
|
+
after(:each) do
|
142
|
+
subject.class_variable_set :@@location_keys, @original
|
143
|
+
end
|
144
144
|
|
145
|
-
|
146
|
-
|
145
|
+
it "adds a location key and the associated class to the list of valid locations" do
|
146
|
+
subject.add_location_key(:git, subject.class)
|
147
147
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
148
|
+
subject.location_keys.should have(1).item
|
149
|
+
subject.location_keys.should include(:git)
|
150
|
+
subject.location_keys[:git].should eql(subject.class)
|
151
|
+
end
|
152
152
|
|
153
|
-
|
154
|
-
|
155
|
-
|
153
|
+
it "does not add duplicate location keys to the list of location keys" do
|
154
|
+
subject.add_location_key(:git, subject.class)
|
155
|
+
subject.add_location_key(:git, subject.class)
|
156
156
|
|
157
|
-
|
158
|
-
|
159
|
-
end
|
157
|
+
subject.location_keys.should have(1).item
|
158
|
+
subject.location_keys.should include(:git)
|
160
159
|
end
|
161
160
|
end
|
161
|
+
end
|
162
162
|
|
163
|
-
|
164
|
-
|
165
|
-
|
163
|
+
context "given a location key :site" do
|
164
|
+
let(:url) { "http://path_to_api/v1" }
|
165
|
+
let(:source) { subject.new(berksfile, cookbook_name, site: url) }
|
166
166
|
|
167
|
-
|
168
|
-
|
169
|
-
|
167
|
+
it "initializes a SiteLocation for location" do
|
168
|
+
source.location.should be_a(Berkshelf::SiteLocation)
|
169
|
+
end
|
170
170
|
|
171
|
-
|
172
|
-
|
173
|
-
end
|
171
|
+
it "points to the specified URI" do
|
172
|
+
source.location.api_uri.to_s.should eql(url)
|
174
173
|
end
|
174
|
+
end
|
175
175
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
end
|
176
|
+
context "given multiple location options" do
|
177
|
+
it "raises with an Berkshelf::BerkshelfError" do
|
178
|
+
lambda {
|
179
|
+
subject.new(berksfile, cookbook_name, site: "something", git: "something")
|
180
|
+
}.should raise_error(Berkshelf::BerkshelfError)
|
182
181
|
end
|
182
|
+
end
|
183
183
|
|
184
|
-
|
185
|
-
|
186
|
-
|
184
|
+
context "given a group option containing a single group" do
|
185
|
+
let(:group) { :production }
|
186
|
+
let(:source) { subject.new(berksfile, cookbook_name, group: group) }
|
187
187
|
|
188
|
-
|
189
|
-
|
190
|
-
end
|
188
|
+
it "assigns the single group to the groups attribute" do
|
189
|
+
source.groups.should include(group)
|
191
190
|
end
|
191
|
+
end
|
192
192
|
|
193
|
-
|
194
|
-
|
195
|
-
|
193
|
+
context "given a group option containing an array of groups" do
|
194
|
+
let(:groups) { [ :development, :test ] }
|
195
|
+
let(:source) { subject.new(berksfile, cookbook_name, group: groups) }
|
196
196
|
|
197
|
-
|
198
|
-
|
199
|
-
end
|
197
|
+
it "assigns all the groups to the group attribute" do
|
198
|
+
source.groups.should eql(groups)
|
200
199
|
end
|
200
|
+
end
|
201
201
|
|
202
|
-
|
203
|
-
|
202
|
+
context "given no group option" do
|
203
|
+
let(:source) { subject.new(berksfile, cookbook_name) }
|
204
204
|
|
205
|
-
|
206
|
-
|
207
|
-
end
|
205
|
+
it "should have the default group assigned" do
|
206
|
+
source.groups.should include(:default)
|
208
207
|
end
|
209
208
|
end
|
210
209
|
end
|
210
|
+
end
|
211
211
|
|
212
|
-
|
212
|
+
subject { Berkshelf::CookbookSource.new(berksfile, cookbook_name) }
|
213
213
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
214
|
+
describe '#add_group' do
|
215
|
+
it "should store strings as symbols" do
|
216
|
+
subject.add_group "foo"
|
217
|
+
subject.groups.should =~ [:default, :foo]
|
218
|
+
end
|
219
219
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
220
|
+
it "should not store duplicate groups" do
|
221
|
+
subject.add_group "bar"
|
222
|
+
subject.add_group "bar"
|
223
|
+
subject.add_group :bar
|
224
|
+
subject.groups.should =~ [:default, :bar]
|
225
|
+
end
|
226
226
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
227
|
+
it "should add multiple groups" do
|
228
|
+
subject.add_group "baz", "quux"
|
229
|
+
subject.groups.should =~ [:default, :baz, :quux]
|
230
|
+
end
|
231
231
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
end
|
232
|
+
it "should handle multiple groups as an array" do
|
233
|
+
subject.add_group ["baz", "quux"]
|
234
|
+
subject.groups.should =~ [:default, :baz, :quux]
|
236
235
|
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "#cached_and_location" do
|
239
|
+
let(:options) { Hash.new }
|
237
240
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
+
before do
|
242
|
+
Berkshelf::CachedCookbook.stub(:from_path).and_return(double('cached_cookbook'))
|
243
|
+
end
|
241
244
|
|
242
|
-
|
245
|
+
context "when given a value for :path" do
|
246
|
+
before do
|
247
|
+
berksfile.stub(filepath: "/rspec/Berksfile")
|
248
|
+
options[:path] = "cookbooks/whatever"
|
243
249
|
end
|
244
250
|
|
245
|
-
it "returns
|
246
|
-
subject.
|
251
|
+
it "returns a PathLocation with a path relative to the Berksfile's filepath" do
|
252
|
+
_, location = subject.cached_and_location(options)
|
247
253
|
|
248
|
-
|
254
|
+
location.path.should eql("/rspec/cookbooks/whatever")
|
249
255
|
end
|
250
256
|
end
|
257
|
+
end
|
251
258
|
|
252
|
-
|
253
|
-
|
254
|
-
|
259
|
+
describe "#downloaded?" do
|
260
|
+
it "returns true if self.cached_cookbook is not nil" do
|
261
|
+
subject.stub(:cached_cookbook) { double('cb') }
|
255
262
|
|
256
|
-
|
257
|
-
|
263
|
+
subject.downloaded?.should be_true
|
264
|
+
end
|
258
265
|
|
259
|
-
|
260
|
-
|
261
|
-
source = CookbookSource.new("artifact", constraint: "= 0.10.0", site: "http://cookbooks.opscode.com/api/v1/cookbooks")
|
266
|
+
it "returns false if self.cached_cookbook is nil" do
|
267
|
+
subject.stub(:cached_cookbook) { nil }
|
262
268
|
|
263
|
-
|
264
|
-
|
269
|
+
subject.downloaded?.should be_false
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe "#to_s" do
|
274
|
+
it "contains the name, constraint, and groups" do
|
275
|
+
source = Berkshelf::CookbookSource.new(berksfile, "artifact", constraint: "= 0.10.0")
|
276
|
+
|
277
|
+
source.to_s.should eql("artifact (= 0.10.0) groups: [:default]")
|
278
|
+
end
|
279
|
+
|
280
|
+
context "given a CookbookSource with an explicit location" do
|
281
|
+
it "contains the name, constraint, groups, and location" do
|
282
|
+
source = Berkshelf::CookbookSource.new(berksfile, "artifact", constraint: "= 0.10.0", site: "http://cookbooks.opscode.com/api/v1/cookbooks")
|
283
|
+
|
284
|
+
source.to_s.should eql("artifact (= 0.10.0) groups: [:default] location: site: 'http://cookbooks.opscode.com/api/v1/cookbooks'")
|
265
285
|
end
|
266
286
|
end
|
267
287
|
end
|