berkshelf 0.4.0.rc4 → 0.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 +2 -0
- data/Guardfile +6 -3
- data/features/default_locations.feature +122 -0
- data/features/install.feature +20 -4
- data/features/lockfile.feature +1 -6
- data/features/update.feature +2 -3
- data/generator_files/Berksfile.erb +2 -0
- data/generator_files/gitignore.erb +6 -0
- data/lib/berkshelf.rb +6 -10
- data/lib/berkshelf/berksfile.rb +203 -14
- data/lib/berkshelf/cached_cookbook.rb +5 -1
- data/lib/berkshelf/cli.rb +4 -0
- data/lib/berkshelf/cookbook_source.rb +49 -91
- data/lib/berkshelf/cookbook_store.rb +2 -0
- data/lib/berkshelf/downloader.rb +71 -51
- data/lib/berkshelf/errors.rb +7 -3
- data/lib/berkshelf/formatters.rb +6 -6
- data/lib/berkshelf/location.rb +171 -0
- data/lib/berkshelf/locations/chef_api_location.rb +252 -0
- data/lib/berkshelf/locations/git_location.rb +76 -0
- data/lib/berkshelf/locations/path_location.rb +38 -0
- data/lib/berkshelf/locations/site_location.rb +150 -0
- data/lib/berkshelf/lockfile.rb +2 -2
- data/lib/berkshelf/resolver.rb +12 -15
- data/lib/berkshelf/uploader.rb +2 -9
- data/lib/berkshelf/version.rb +1 -1
- data/spec/fixtures/lockfile_spec/without_lock/.gitkeep +0 -0
- data/spec/support/chef_api.rb +7 -1
- data/spec/unit/berkshelf/berksfile_spec.rb +157 -12
- data/spec/unit/berkshelf/cached_cookbook_spec.rb +19 -0
- data/spec/unit/berkshelf/cookbook_generator_spec.rb +1 -0
- data/spec/unit/berkshelf/cookbook_source_spec.rb +25 -35
- data/spec/unit/berkshelf/cookbook_store_spec.rb +3 -3
- data/spec/unit/berkshelf/downloader_spec.rb +171 -43
- data/spec/unit/berkshelf/formatters_spec.rb +13 -16
- data/spec/unit/berkshelf/{cookbook_source/location_spec.rb → location_spec.rb} +10 -10
- data/spec/unit/berkshelf/{cookbook_source → locations}/chef_api_location_spec.rb +4 -4
- data/spec/unit/berkshelf/{cookbook_source → locations}/git_location_spec.rb +8 -8
- data/spec/unit/berkshelf/{cookbook_source → locations}/path_location_spec.rb +5 -5
- data/spec/unit/berkshelf/{cookbook_source → locations}/site_location_spec.rb +17 -3
- data/spec/unit/berkshelf/lockfile_spec.rb +26 -17
- data/spec/unit/berkshelf/resolver_spec.rb +6 -5
- data/spec/unit/berkshelf/uploader_spec.rb +6 -4
- metadata +27 -31
- data/lib/berkshelf/cookbook_source/chef_api_location.rb +0 -256
- data/lib/berkshelf/cookbook_source/git_location.rb +0 -78
- data/lib/berkshelf/cookbook_source/location.rb +0 -167
- data/lib/berkshelf/cookbook_source/path_location.rb +0 -40
- data/lib/berkshelf/cookbook_source/site_location.rb +0 -149
- data/lib/berkshelf/dsl.rb +0 -45
- data/lib/berkshelf/tx_result.rb +0 -12
- data/lib/berkshelf/tx_result_set.rb +0 -37
- data/spec/fixtures/lockfile_spec/without_lock/Berksfile.lock +0 -5
- data/spec/unit/berkshelf/dsl_spec.rb +0 -42
- data/spec/unit/berkshelf/tx_result_set_spec.rb +0 -77
- data/spec/unit/berkshelf/tx_result_spec.rb +0 -21
@@ -87,8 +87,8 @@ module Berkshelf
|
|
87
87
|
|
88
88
|
describe "#cookbooks" do
|
89
89
|
before(:each) do
|
90
|
-
|
91
|
-
|
90
|
+
generate_cookbook(subject.storage_path, "nginx", "0.101.2")
|
91
|
+
generate_cookbook(subject.storage_path, "mysql", "1.2.6")
|
92
92
|
end
|
93
93
|
|
94
94
|
it "returns a list of CachedCookbooks" do
|
@@ -97,7 +97,7 @@ module Berkshelf
|
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
-
it "
|
100
|
+
it "contains a CachedCookbook for every cookbook in the storage path" do
|
101
101
|
subject.cookbooks.should have(2).items
|
102
102
|
end
|
103
103
|
|
@@ -2,81 +2,209 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Berkshelf
|
4
4
|
describe Downloader do
|
5
|
+
describe "ClassMethods" do
|
6
|
+
subject { Downloader }
|
7
|
+
|
8
|
+
describe "::initialize" do
|
9
|
+
context "when no value for locations is given" do
|
10
|
+
it "sets the @locations instance variable to a blank array" do
|
11
|
+
downloader = subject.new(double('store'))
|
12
|
+
|
13
|
+
downloader.instance_variable_get(:@locations).should be_a(Array)
|
14
|
+
downloader.instance_variable_get(:@locations).should have(0).items
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when an explicit value of locations is given" do
|
19
|
+
let(:locations) do
|
20
|
+
[
|
21
|
+
{
|
22
|
+
type: :chef_api,
|
23
|
+
value: double('capi'),
|
24
|
+
options: double('capi_opts')
|
25
|
+
},
|
26
|
+
{
|
27
|
+
type: :chef_api,
|
28
|
+
value: double('capi2'),
|
29
|
+
options: double('capi_opts2')
|
30
|
+
}
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
it "sets the @locations instance variable to the given locations" do
|
35
|
+
downloader = subject.new(double('store'), locations: locations)
|
36
|
+
|
37
|
+
downloader.instance_variable_get(:@locations).should eql(locations)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
5
43
|
subject { Downloader.new(CookbookStore.new(tmp_path)) }
|
6
|
-
let(:source) { CookbookSource.new("sparkle_motion") }
|
7
44
|
|
8
|
-
describe "#
|
9
|
-
|
10
|
-
|
45
|
+
describe "#download" do
|
46
|
+
let(:source) { double('source', name: "artifact", version_constraint: "= 0.10.0") }
|
47
|
+
let(:location) { double('location') }
|
48
|
+
let(:cached_cookbook) { double('cached') }
|
49
|
+
|
50
|
+
context "when the source has a location" do
|
51
|
+
before(:each) do
|
52
|
+
source.stub(:location).and_return(location)
|
53
|
+
location.should_receive(:download).with(subject.storage_path).and_return(cached_cookbook)
|
54
|
+
source.should_receive(:cached_cookbook=).with(cached_cookbook)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "sends 'download' to the source's location and sets the source's cached_cookbook to the result" do
|
58
|
+
subject.download(source).should be_true
|
59
|
+
end
|
60
|
+
|
61
|
+
it "returns an Array containing the cached_cookbook and location used to download" do
|
62
|
+
result = subject.download(source)
|
11
63
|
|
12
|
-
|
64
|
+
result.should be_a(Array)
|
65
|
+
result[0].should eql(cached_cookbook)
|
66
|
+
result[1].should eql(location)
|
67
|
+
end
|
13
68
|
end
|
14
69
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
70
|
+
context "when the source does not have a location" do
|
71
|
+
before(:each) do
|
72
|
+
source.stub(:location).and_return(nil)
|
73
|
+
subject.stub(:locations).and_return([{type: :chef_api, value: :knife, options: Hash.new}])
|
74
|
+
end
|
75
|
+
|
76
|
+
it "sends the 'download' message to the default location" do
|
77
|
+
Location.should_receive(:init).with(source.name, source.version_constraint, chef_api: :knife).and_return(location)
|
78
|
+
location.should_receive(:download).with(subject.storage_path).and_return(cached_cookbook)
|
79
|
+
source.should_receive(:cached_cookbook=).with(cached_cookbook)
|
80
|
+
|
81
|
+
subject.download(source)
|
82
|
+
end
|
19
83
|
end
|
20
84
|
end
|
21
85
|
|
22
|
-
describe "#
|
23
|
-
|
86
|
+
describe "#locations" do
|
87
|
+
let(:type) { :site }
|
88
|
+
let(:value) { double('value') }
|
89
|
+
let(:options) { double('options') }
|
90
|
+
|
91
|
+
it "returns an array of Hashes representing locations" do
|
92
|
+
subject.add_location(type, value, options)
|
93
|
+
|
94
|
+
subject.locations.each { |l| l.should be_a(Hash) }
|
95
|
+
end
|
24
96
|
|
25
|
-
|
26
|
-
subject.
|
97
|
+
context "when no locations are explicitly added" do
|
98
|
+
subject { Downloader.new(double('store')) }
|
27
99
|
|
28
|
-
|
100
|
+
it "returns an array of default locations" do
|
101
|
+
subject.locations.should eql(Downloader::DEFAULT_LOCATIONS)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "when locations are explicitly added" do
|
106
|
+
let(:locations) do
|
107
|
+
[
|
108
|
+
{
|
109
|
+
type: :chef_api,
|
110
|
+
value: double('capi'),
|
111
|
+
options: double('capi_opts')
|
112
|
+
},
|
113
|
+
{
|
114
|
+
type: :chef_api,
|
115
|
+
value: double('capi2'),
|
116
|
+
options: double('capi_opts2')
|
117
|
+
}
|
118
|
+
]
|
119
|
+
end
|
120
|
+
|
121
|
+
subject { Downloader.new(double('store'), locations: locations) }
|
122
|
+
|
123
|
+
it "contains only the locations passed to the initializer" do
|
124
|
+
subject.locations.should eql(locations)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "does not include the array of default locations" do
|
128
|
+
subject.locations.should_not include(Downloader::DEFAULT_LOCATIONS)
|
129
|
+
end
|
29
130
|
end
|
30
131
|
end
|
31
132
|
|
32
|
-
describe "#
|
33
|
-
let(:
|
34
|
-
let(:
|
133
|
+
describe "#add_location" do
|
134
|
+
let(:type) { :site }
|
135
|
+
let(:value) { double('value') }
|
136
|
+
let(:options) { double('options') }
|
137
|
+
|
138
|
+
it "adds a hash to the end of the array of locations" do
|
139
|
+
subject.add_location(type, value, options)
|
35
140
|
|
36
|
-
|
37
|
-
subject.enqueue source_one
|
38
|
-
subject.enqueue source_two
|
141
|
+
subject.locations.should have(1).item
|
39
142
|
end
|
40
143
|
|
41
|
-
it "
|
42
|
-
subject.
|
144
|
+
it "adds a hash with a type, value, and options key" do
|
145
|
+
subject.add_location(type, value, options)
|
43
146
|
|
44
|
-
subject.
|
147
|
+
subject.locations.last.should have_key(:type)
|
148
|
+
subject.locations.last.should have_key(:value)
|
149
|
+
subject.locations.last.should have_key(:options)
|
45
150
|
end
|
46
151
|
|
47
|
-
it "
|
48
|
-
subject.
|
49
|
-
subject.download_all
|
152
|
+
it "sets the value of the given 'value' to the value of the key 'value'" do
|
153
|
+
subject.add_location(type, value, options)
|
50
154
|
|
51
|
-
subject.
|
155
|
+
subject.locations.last[:value].should eql(value)
|
52
156
|
end
|
53
157
|
|
54
|
-
it "
|
55
|
-
|
158
|
+
it "sets the value of the given 'type' to the value of the key 'type'" do
|
159
|
+
subject.add_location(type, value, options)
|
56
160
|
|
57
|
-
|
161
|
+
subject.locations.last[:type].should eql(type)
|
58
162
|
end
|
59
|
-
end
|
60
163
|
|
61
|
-
|
62
|
-
|
63
|
-
let(:bad_source) { CookbookSource.new("donowaytexists") }
|
164
|
+
it "sets the value of the given 'options' to the value of the key 'options'" do
|
165
|
+
subject.add_location(type, value, options)
|
64
166
|
|
65
|
-
|
66
|
-
subject.download(source).should be_a(TXResult)
|
167
|
+
subject.locations.last[:options].should eql(options)
|
67
168
|
end
|
68
169
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
170
|
+
it "raises a DuplicateLocationDefined error if a location of the given type and value was already added" do
|
171
|
+
subject.add_location(type, value, options)
|
172
|
+
|
173
|
+
lambda {
|
174
|
+
subject.add_location(type, value, options)
|
175
|
+
}.should raise_error(DuplicateLocationDefined)
|
73
176
|
end
|
74
177
|
|
75
|
-
context "
|
76
|
-
|
77
|
-
|
178
|
+
context "adding multiple locations" do
|
179
|
+
let(:type_2) { :site }
|
180
|
+
let(:value_2) { double('value_2') }
|
181
|
+
let(:options_2) { double('options_2') }
|
182
|
+
|
183
|
+
it "adds locations in the order they are added" do
|
184
|
+
subject.add_location(type, value, options)
|
185
|
+
subject.add_location(type_2, value_2, options_2)
|
186
|
+
|
187
|
+
subject.locations.should have(2).items
|
188
|
+
|
189
|
+
subject.locations[0][:value].should eql(value)
|
190
|
+
subject.locations[1][:value].should eql(value_2)
|
78
191
|
end
|
79
192
|
end
|
80
193
|
end
|
194
|
+
|
195
|
+
describe "#has_location?" do
|
196
|
+
let(:type) { :site }
|
197
|
+
let(:value) { double('value') }
|
198
|
+
|
199
|
+
it "returns true if a source of the given type and value was already added" do
|
200
|
+
subject.add_location(type, value)
|
201
|
+
|
202
|
+
subject.has_location?(type, value).should be_true
|
203
|
+
end
|
204
|
+
|
205
|
+
it "returns false if a source of the given type and value was not added" do
|
206
|
+
subject.has_location?(type, value).should be_false
|
207
|
+
end
|
208
|
+
end
|
81
209
|
end
|
82
210
|
end
|
@@ -1,24 +1,21 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
module Berkshelf
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
describe Formatters::AbstractFormatter do
|
5
|
+
subject do
|
6
|
+
Class.new do
|
7
|
+
include Formatters::AbstractFormatter
|
8
|
+
end.new
|
7
9
|
end
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
lambda { subject.upload("my_coobook","1.2.3","http://chef_server") }.should raise_error(MethodNotImplmentedError)
|
18
|
-
lambda { subject.shims_written("/Users/jcocktosten") }.should raise_error(MethodNotImplmentedError)
|
19
|
-
lambda { subject.msg("something you should know") }.should raise_error(MethodNotImplmentedError)
|
20
|
-
lambda { subject.error("whoa this is bad") }.should raise_error(MethodNotImplmentedError)
|
21
|
-
end
|
11
|
+
it "has abstract methods for all the messaging modes" do
|
12
|
+
lambda { subject.install("my_coobook","1.2.3","http://community") }.should raise_error(AbstractFunction)
|
13
|
+
lambda { subject.use("my_coobook","1.2.3") }.should raise_error(AbstractFunction)
|
14
|
+
lambda { subject.use("my_coobook","1.2.3","http://community") }.should raise_error(AbstractFunction)
|
15
|
+
lambda { subject.upload("my_coobook","1.2.3","http://chef_server") }.should raise_error(AbstractFunction)
|
16
|
+
lambda { subject.shims_written("/Users/jcocktosten") }.should raise_error(AbstractFunction)
|
17
|
+
lambda { subject.msg("something you should know") }.should raise_error(AbstractFunction)
|
18
|
+
lambda { subject.error("whoa this is bad") }.should raise_error(AbstractFunction)
|
22
19
|
end
|
23
20
|
end
|
24
21
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Berkshelf
|
2
|
-
describe
|
2
|
+
describe Location do
|
3
3
|
describe "ClassMethods Module" do
|
4
4
|
subject do
|
5
5
|
Class.new do
|
6
|
-
include
|
6
|
+
include Location
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
@@ -88,7 +88,7 @@ module Berkshelf
|
|
88
88
|
end
|
89
89
|
|
90
90
|
describe "ModuleFunctions" do
|
91
|
-
subject {
|
91
|
+
subject { Location }
|
92
92
|
|
93
93
|
describe "::init" do
|
94
94
|
let(:name) { "artifact" }
|
@@ -97,25 +97,25 @@ module Berkshelf
|
|
97
97
|
it "returns an instance of SiteLocation given a site: option key" do
|
98
98
|
result = subject.init(name, constraint, site: "http://site/value")
|
99
99
|
|
100
|
-
result.should be_a(
|
100
|
+
result.should be_a(SiteLocation)
|
101
101
|
end
|
102
102
|
|
103
103
|
it "returns an instance of PathLocation given a path: option key" do
|
104
104
|
result = subject.init(name, constraint, path: "/Users/reset/code")
|
105
105
|
|
106
|
-
result.should be_a(
|
106
|
+
result.should be_a(PathLocation)
|
107
107
|
end
|
108
108
|
|
109
109
|
it "returns an instance of GitLocation given a git: option key" do
|
110
110
|
result = subject.init(name, constraint, git: "git://github.com/something.git")
|
111
111
|
|
112
|
-
result.should be_a(
|
112
|
+
result.should be_a(GitLocation)
|
113
113
|
end
|
114
114
|
|
115
115
|
it "returns an instance of SiteLocation when no option key is given that matches a registered location_key" do
|
116
116
|
result = subject.init(name, constraint)
|
117
117
|
|
118
|
-
result.should be_a(
|
118
|
+
result.should be_a(SiteLocation)
|
119
119
|
end
|
120
120
|
|
121
121
|
context "given two location_keys" do
|
@@ -133,7 +133,7 @@ module Berkshelf
|
|
133
133
|
|
134
134
|
subject do
|
135
135
|
Class.new do
|
136
|
-
include
|
136
|
+
include Location
|
137
137
|
end.new(name, constraint)
|
138
138
|
end
|
139
139
|
|
@@ -142,10 +142,10 @@ module Berkshelf
|
|
142
142
|
end
|
143
143
|
|
144
144
|
describe "#download" do
|
145
|
-
it "raises a
|
145
|
+
it "raises a AbstractFunction if not defined" do
|
146
146
|
lambda {
|
147
147
|
subject.download(double('destination'))
|
148
|
-
}.should raise_error(
|
148
|
+
}.should raise_error(AbstractFunction)
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
module Berkshelf
|
4
|
-
describe
|
4
|
+
describe ChefAPILocation do
|
5
5
|
let(:test_chef_api) { "https://chefserver:8081" }
|
6
6
|
|
7
7
|
describe "ClassMethods" do
|
8
|
-
subject {
|
8
|
+
subject { ChefAPILocation }
|
9
9
|
let(:valid_uri) { test_chef_api }
|
10
10
|
let(:invalid_uri) { "notauri" }
|
11
11
|
let(:constraint) { double('constraint') }
|
@@ -110,7 +110,7 @@ module Berkshelf
|
|
110
110
|
end
|
111
111
|
|
112
112
|
subject do
|
113
|
-
loc =
|
113
|
+
loc = ChefAPILocation.new("nginx",
|
114
114
|
double('constraint', satisfies?: true),
|
115
115
|
chef_api: :knife
|
116
116
|
)
|
@@ -229,7 +229,7 @@ module Berkshelf
|
|
229
229
|
|
230
230
|
describe "#to_s" do
|
231
231
|
subject do
|
232
|
-
|
232
|
+
ChefAPILocation.new('nginx',
|
233
233
|
double('constraint'),
|
234
234
|
chef_api: :knife
|
235
235
|
)
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
module Berkshelf
|
4
|
-
describe
|
4
|
+
describe GitLocation do
|
5
5
|
let(:complacent_constraint) { double('comp-vconstraint', satisfies?: true) }
|
6
6
|
|
7
7
|
describe "ClassMethods" do
|
8
|
-
subject {
|
8
|
+
subject { GitLocation }
|
9
9
|
|
10
10
|
describe "::initialize" do
|
11
11
|
it "raises InvalidGitURI if given an invalid Git URI for options[:git]" do
|
@@ -16,7 +16,7 @@ module Berkshelf
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
subject {
|
19
|
+
subject { GitLocation.new("artifact", complacent_constraint, git: "git://github.com/RiotGames/artifact-cookbook.git") }
|
20
20
|
|
21
21
|
describe "#download" do
|
22
22
|
it "returns an instance of Berkshelf::CachedCookbook" do
|
@@ -40,7 +40,7 @@ module Berkshelf
|
|
40
40
|
end
|
41
41
|
|
42
42
|
context "given no ref/branch/tag options is given" do
|
43
|
-
subject {
|
43
|
+
subject { GitLocation.new("nginx", complacent_constraint, git: "git://github.com/opscode-cookbooks/nginx.git") }
|
44
44
|
|
45
45
|
it "sets the branch attribute to the HEAD revision of the cloned repo" do
|
46
46
|
subject.download(tmp_path)
|
@@ -50,7 +50,7 @@ module Berkshelf
|
|
50
50
|
end
|
51
51
|
|
52
52
|
context "given a git repo that does not exist" do
|
53
|
-
subject {
|
53
|
+
subject { GitLocation.new("doesnot_exist", complacent_constraint, git: "git://github.com/RiotGames/thisrepo_does_not_exist.git") }
|
54
54
|
|
55
55
|
it "raises a GitError" do
|
56
56
|
lambda {
|
@@ -60,7 +60,7 @@ module Berkshelf
|
|
60
60
|
end
|
61
61
|
|
62
62
|
context "given a git repo that does not contain a cookbook" do
|
63
|
-
subject {
|
63
|
+
subject { GitLocation.new("doesnot_exist", complacent_constraint, git: "git://github.com/RiotGames/berkshelf.git") }
|
64
64
|
|
65
65
|
it "raises a CookbookNotFound error" do
|
66
66
|
lambda {
|
@@ -71,7 +71,7 @@ module Berkshelf
|
|
71
71
|
|
72
72
|
context "given the content at the Git repo does not satisfy the version constraint" do
|
73
73
|
subject do
|
74
|
-
|
74
|
+
GitLocation.new("nginx",
|
75
75
|
double('constraint', satisfies?: false),
|
76
76
|
git: "git://github.com/opscode-cookbooks/nginx.git"
|
77
77
|
)
|
@@ -86,7 +86,7 @@ module Berkshelf
|
|
86
86
|
|
87
87
|
context "given a value for ref that is a tag or branch and not a commit hash" do
|
88
88
|
subject do
|
89
|
-
|
89
|
+
GitLocation.new("artifact",
|
90
90
|
complacent_constraint,
|
91
91
|
git: "git://github.com/RiotGames/artifact-cookbook.git",
|
92
92
|
ref: "0.9.8"
|