berkshelf 5.6.5 → 6.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 33e876c1bf17b5d4b7f9476c516e1650ee94ec06
4
- data.tar.gz: 60ec3493e1c2588b9d57a1b9955b9835e41dcc0c
3
+ metadata.gz: c31585edab49dfddf07f23af1d5d14dd998bd856
4
+ data.tar.gz: f9ce9ff33e601797b53c0355da9464c230894130
5
5
  SHA512:
6
- metadata.gz: 76b01e75c80bd1babc5cc47713f7d24b61853eaa64657b806ce5a5b1eb7139da9d90529d4837d570f3ae2ce56f7674ec91b0c86e464b13e7d33838b9895e8a74
7
- data.tar.gz: 47b2910e768383ca4ed83d6e9bf1bfa4a539b8e4688484549c11d6f497b7ddfd63f8bdd004ec913383076c40de237d419fc4dd5e1a425e6e1ed893c3272a7c0a
6
+ metadata.gz: 899e6e73d3e9431e4662b07c3b118b99f60fd970dd54f3bc963bdc8e0e5d4a4379736ad4ea183b5f2e9e5eb924c0f66dc8ad946b6bc11aef837e5865e0d4bfea
7
+ data.tar.gz: 99a42e0ba55c5daf4909743b31c9bf2b80a75ba73c112e0e987ca3f255c4876760ce3bb47974c2360b16e980d69f3fc846a9a11af81f02f2f477a0469c2a16aa
@@ -1,14 +1,22 @@
1
1
  # Change Log
2
2
 
3
- ## [5.6.5](https://github.com/berkshelf/berkshelf/tree/5.6.4) (2017-05-04)
4
- [Full Changelog](https://github.com/berkshelf/berkshelf/compare/v5.6.4...5.6.5)
3
+ ## [6.0.0](https://github.com/berkshelf/berkshelf/tree/6.0.0) (2017-05-17)
4
+ [Full Changelog](https://github.com/berkshelf/berkshelf/compare/v5.6.5...6.0.0)
5
5
 
6
6
  **Merged pull requests:**
7
7
 
8
- - Handle Windows backslashes in trusted_certs path [\#1689](https://github.com/berkshelf/berkshelf/pull/1689) ([jeremymv2](https://github.com/jeremymv2))
8
+ - Minor refactor on the default artifactory options and support artifactory\_api\_key in knife.rb [\#1691](https://github.com/berkshelf/berkshelf/pull/1691) ([coderanger](https://github.com/coderanger))
9
+ - Artifactory support [\#1690](https://github.com/berkshelf/berkshelf/pull/1690) ([coderanger](https://github.com/coderanger))
9
10
 
10
- ## [5.6.4](https://github.com/berkshelf/berkshelf/tree/5.6.4) (2017-03-14)
11
- [Full Changelog](https://github.com/berkshelf/berkshelf/compare/v5.6.3...5.6.4)
11
+ ## [v5.6.5](https://github.com/berkshelf/berkshelf/tree/v5.6.5) (2017-05-04)
12
+ [Full Changelog](https://github.com/berkshelf/berkshelf/compare/v5.6.4...v5.6.5)
13
+
14
+ **Merged pull requests:**
15
+
16
+ - handle Windows backslashes in trusted\_certs path [\#1689](https://github.com/berkshelf/berkshelf/pull/1689) ([jeremymv2](https://github.com/jeremymv2))
17
+
18
+ ## [v5.6.4](https://github.com/berkshelf/berkshelf/tree/v5.6.4) (2017-03-14)
19
+ [Full Changelog](https://github.com/berkshelf/berkshelf/compare/v5.6.3...v5.6.4)
12
20
 
13
21
  **Merged pull requests:**
14
22
 
@@ -1426,4 +1434,4 @@
1426
1434
 
1427
1435
 
1428
1436
 
1429
- \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
1437
+ \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
data/Gemfile CHANGED
@@ -45,6 +45,7 @@ group :development do
45
45
  gem "dep_selector", ">= 1.0"
46
46
  gem "fuubar", ">= 2.0"
47
47
  gem "rspec", ">= 3.0"
48
+ gem "rspec-its", ">= 1.2"
48
49
  gem "test-kitchen", ">= 1.2"
49
50
  gem "webmock", ">= 1.11"
50
51
  gem "yard", ">= 0.8"
@@ -20,7 +20,7 @@ GIT
20
20
  PATH
21
21
  remote: .
22
22
  specs:
23
- berkshelf (5.6.5)
23
+ berkshelf (6.0.0)
24
24
  addressable (~> 2.3, >= 2.3.4)
25
25
  berkshelf-api-client (>= 2.0.2, < 4.0)
26
26
  buff-config (~> 2.0)
@@ -40,9 +40,8 @@ PATH
40
40
  GEM
41
41
  remote: https://rubygems.org/
42
42
  specs:
43
- activesupport (4.2.7.1)
43
+ activesupport (4.2.8)
44
44
  i18n (~> 0.7)
45
- json (~> 1.7, >= 1.7.7)
46
45
  minitest (~> 5.1)
47
46
  thread_safe (~> 0.3, >= 0.3.4)
48
47
  tzinfo (~> 1.1)
@@ -50,7 +49,7 @@ GEM
50
49
  public_suffix (~> 2.0, >= 2.0.2)
51
50
  archive (0.0.6)
52
51
  ffi (~> 1.9.3)
53
- artifactory (2.6.0)
52
+ artifactory (2.8.1)
54
53
  aruba (0.14.2)
55
54
  childprocess (~> 0.5.6)
56
55
  contracts (~> 0.9)
@@ -85,7 +84,7 @@ GEM
85
84
  fuzzyurl
86
85
  mixlib-config (~> 2.0)
87
86
  mixlib-shellout (~> 2.0)
88
- chef-zero (5.3.0)
87
+ chef-zero (13.0.0)
89
88
  ffi-yajl (~> 2.2)
90
89
  hashie (>= 2.0, < 4.0)
91
90
  mixlib-log (~> 1.3)
@@ -97,7 +96,7 @@ GEM
97
96
  coderay (1.1.1)
98
97
  coercible (1.0.0)
99
98
  descendants_tracker (~> 0.0.1)
100
- contracts (0.14.0)
99
+ contracts (0.16.0)
101
100
  coolline (0.5.0)
102
101
  unicode_utils (~> 1.4)
103
102
  crack (0.4.3)
@@ -120,7 +119,7 @@ GEM
120
119
  descendants_tracker (0.0.4)
121
120
  thread_safe (~> 0.3, >= 0.3.1)
122
121
  diff-lcs (1.3)
123
- domain_name (0.5.20161129)
122
+ domain_name (0.5.20170404)
124
123
  unf (>= 0.0.5, < 1.0.0)
125
124
  equalizer (0.0.11)
126
125
  erubis (2.7.0)
@@ -128,7 +127,7 @@ GEM
128
127
  multipart-post (>= 1.2, < 3)
129
128
  faraday-http-cache (2.0.0)
130
129
  faraday (~> 0.8)
131
- ffi (1.9.17)
130
+ ffi (1.9.18)
132
131
  ffi-yajl (2.3.0)
133
132
  libyajl2 (~> 1.2)
134
133
  formatador (0.2.5)
@@ -136,7 +135,7 @@ GEM
136
135
  rspec-core (~> 3.0)
137
136
  ruby-progressbar (~> 1.4)
138
137
  fuzzyurl (0.9.0)
139
- gherkin (4.0.0)
138
+ gherkin (4.1.3)
140
139
  github_changelog_generator (1.14.3)
141
140
  activesupport
142
141
  faraday-http-cache
@@ -145,13 +144,13 @@ GEM
145
144
  rainbow (>= 2.1)
146
145
  rake (>= 10.0)
147
146
  retriable (~> 2.1)
148
- grape (0.19.1)
147
+ grape (0.19.2)
149
148
  activesupport
150
149
  builder
151
150
  hashie (>= 2.1.0)
152
151
  multi_json (>= 1.3.2)
153
152
  multi_xml (>= 0.5.2)
154
- mustermann-grape (~> 0.4.0)
153
+ mustermann-grape (~> 1.0.0)
155
154
  rack (>= 1.3.0)
156
155
  rack-accept
157
156
  virtus (>= 1.0.0)
@@ -177,22 +176,22 @@ GEM
177
176
  guard (~> 2.1)
178
177
  guard-compat (~> 1.1)
179
178
  rspec (>= 2.99.0, < 4.0)
180
- hashdiff (0.3.2)
179
+ hashdiff (0.3.4)
181
180
  hashie (3.5.5)
182
181
  hitimes (1.2.4)
183
- http (2.2.0)
182
+ http (2.2.2)
184
183
  addressable (~> 2.3)
185
184
  http-cookie (~> 1.0)
186
185
  http-form_data (~> 1.0.1)
187
186
  http_parser.rb (~> 0.6.0)
188
187
  http-cookie (1.0.3)
189
188
  domain_name (~> 0.5)
190
- http-form_data (1.0.1)
189
+ http-form_data (1.0.2)
191
190
  http_parser.rb (0.6.0)
192
191
  httpclient (2.8.3)
193
- i18n (0.8.0)
192
+ i18n (0.8.1)
194
193
  ice_nine (0.11.2)
195
- json (1.8.6)
194
+ json (2.1.0)
196
195
  libnotify (0.8.4)
197
196
  ffi (>= 1.0.11)
198
197
  libyajl2 (1.2.0)
@@ -200,10 +199,10 @@ GEM
200
199
  rb-fsevent (~> 0.9, >= 0.9.4)
201
200
  rb-inotify (~> 0.9, >= 0.9.7)
202
201
  ruby_dep (~> 1.2)
203
- lumberjack (1.0.11)
202
+ lumberjack (1.0.12)
204
203
  method_source (0.8.2)
205
204
  minitar (0.6.1)
206
- minitest (5.10.1)
205
+ minitest (5.10.2)
207
206
  mixlib-archive (0.4.1)
208
207
  mixlib-log
209
208
  mixlib-authentication (1.4.1)
@@ -218,19 +217,18 @@ GEM
218
217
  mixlib-shellout (2.2.7)
219
218
  mixlib-versioning (1.1.0)
220
219
  molinillo (0.5.7)
221
- msgpack (1.0.3)
220
+ msgpack (1.1.0)
222
221
  multi_json (1.12.1)
223
222
  multi_test (0.1.2)
224
223
  multi_xml (0.6.0)
225
224
  multipart-post (2.0.0)
226
- mustermann (0.4.0)
227
- tool (~> 0.2)
228
- mustermann-grape (0.4.0)
229
- mustermann (= 0.4.0)
225
+ mustermann (1.0.0)
226
+ mustermann-grape (1.0.0)
227
+ mustermann (~> 1.0.0)
230
228
  nenv (0.3.0)
231
229
  net-scp (1.2.1)
232
230
  net-ssh (>= 2.6.5)
233
- net-ssh (4.0.1)
231
+ net-ssh (4.1.0)
234
232
  net-ssh-gateway (1.3.0)
235
233
  net-ssh (>= 2.6.5)
236
234
  nio4r (2.0.0)
@@ -244,10 +242,11 @@ GEM
244
242
  method_source (~> 0.8.1)
245
243
  slop (~> 3.4)
246
244
  public_suffix (2.0.5)
247
- rack (2.0.1)
245
+ rack (2.0.3)
248
246
  rack-accept (0.4.5)
249
247
  rack (>= 0.4)
250
- rainbow (2.2.1)
248
+ rainbow (2.2.2)
249
+ rake
251
250
  rake (12.0.0)
252
251
  rb-fsevent (0.9.8)
253
252
  rb-inotify (0.9.8)
@@ -279,19 +278,22 @@ GEM
279
278
  retryable (~> 2.0)
280
279
  semverse (~> 2.0)
281
280
  varia_model (~> 0.6)
282
- rspec (3.5.0)
283
- rspec-core (~> 3.5.0)
284
- rspec-expectations (~> 3.5.0)
285
- rspec-mocks (~> 3.5.0)
286
- rspec-core (3.5.4)
287
- rspec-support (~> 3.5.0)
288
- rspec-expectations (3.5.0)
281
+ rspec (3.6.0)
282
+ rspec-core (~> 3.6.0)
283
+ rspec-expectations (~> 3.6.0)
284
+ rspec-mocks (~> 3.6.0)
285
+ rspec-core (3.6.0)
286
+ rspec-support (~> 3.6.0)
287
+ rspec-expectations (3.6.0)
289
288
  diff-lcs (>= 1.2.0, < 2.0)
290
- rspec-support (~> 3.5.0)
291
- rspec-mocks (3.5.0)
289
+ rspec-support (~> 3.6.0)
290
+ rspec-its (1.2.0)
291
+ rspec-core (>= 3.0.0)
292
+ rspec-expectations (>= 3.0.0)
293
+ rspec-mocks (3.6.0)
292
294
  diff-lcs (>= 1.2.0, < 2.0)
293
- rspec-support (~> 3.5.0)
294
- rspec-support (3.5.0)
295
+ rspec-support (~> 3.6.0)
296
+ rspec-support (3.6.0)
295
297
  ruby-progressbar (1.8.1)
296
298
  ruby_dep (1.5.0)
297
299
  safe_yaml (1.0.4)
@@ -305,24 +307,23 @@ GEM
305
307
  molinillo (>= 0.5)
306
308
  semverse (>= 1.1, < 3.0)
307
309
  terminal-notifier-guard (1.5.3)
308
- test-kitchen (1.15.0)
310
+ test-kitchen (1.16.0)
309
311
  mixlib-install (>= 1.2, < 3.0)
310
312
  mixlib-shellout (>= 1.2, < 3.0)
311
313
  net-scp (~> 1.1)
312
314
  net-ssh (>= 2.9, < 5.0)
313
315
  net-ssh-gateway (~> 1.2)
314
316
  safe_yaml (~> 1.0)
315
- thor (~> 0.18)
317
+ thor (~> 0.19, < 0.19.2)
316
318
  thor (0.19.1)
317
- thread_safe (0.3.5)
319
+ thread_safe (0.3.6)
318
320
  timers (4.0.4)
319
321
  hitimes
320
- tool (0.2.3)
321
- tzinfo (1.2.2)
322
+ tzinfo (1.2.3)
322
323
  thread_safe (~> 0.1)
323
324
  unf (0.1.4)
324
325
  unf_ext
325
- unf_ext (0.0.7.2)
326
+ unf_ext (0.0.7.4)
326
327
  unicode_utils (1.4.0)
327
328
  uuidtools (2.1.5)
328
329
  varia_model (0.6.0)
@@ -334,7 +335,7 @@ GEM
334
335
  descendants_tracker (~> 0.0, >= 0.0.3)
335
336
  equalizer (~> 0.0, >= 0.0.9)
336
337
  wdm (0.1.1)
337
- webmock (2.3.2)
338
+ webmock (3.0.1)
338
339
  addressable (>= 2.3.6)
339
340
  crack (>= 0.3.2)
340
341
  hashdiff
@@ -342,7 +343,7 @@ GEM
342
343
  websocket-extensions (>= 0.1.0)
343
344
  websocket-extensions (0.1.2)
344
345
  win32console (1.3.2)
345
- yard (0.9.8)
346
+ yard (0.9.9)
346
347
 
347
348
  PLATFORMS
348
349
  ruby
@@ -368,6 +369,7 @@ DEPENDENCIES
368
369
  rb-inotify
369
370
  rb-notifu (>= 0.0.4)
370
371
  rspec (>= 3.0)
372
+ rspec-its (>= 1.2)
371
373
  terminal-notifier-guard (~> 1.5.3)
372
374
  test-kitchen (>= 1.2)
373
375
  wdm
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
27
27
  s.name = "berkshelf"
28
28
  s.require_paths = ["lib"]
29
29
  s.version = Berkshelf::VERSION
30
- s.required_ruby_version = ">= 2.2.0"
30
+ s.required_ruby_version = ">= 2.3.3"
31
31
  s.required_rubygems_version = ">= 2.0.0"
32
32
 
33
33
  s.add_dependency "addressable", "~> 2.3", ">= 2.3.4"
@@ -0,0 +1,70 @@
1
+ Feature: Installing cookbooks from an Artifactory server
2
+ This integration test uses some environment variables to configure which
3
+ Artifactory server to talk to, as there is no ArtifactoryZero to test against.
4
+ If those aren't present, we skip the tests.
5
+
6
+ $TEST_BERKSHELF_ARTIFACTORY - URL to the Chef virtual repository.
7
+ $TEST_BERKSHELF_ARTIFACTORY_API_KEY - API key to use.
8
+
9
+ Scenario: when the cookbook exists
10
+ Given I have a Berksfile pointing at an authenticated Artifactory server with:
11
+ """
12
+ cookbook 'poise', '2.7.2'
13
+ """
14
+ When I successfully run `berks install`
15
+ Then the output should contain:
16
+ """
17
+ Installing poise (2.7.2)
18
+ """
19
+ And the cookbook store should have the cookbooks:
20
+ | poise | 2.7.2 |
21
+
22
+ Scenario: when the cookbook does not exist
23
+ Given I have a Berksfile pointing at an authenticated Artifactory server with:
24
+ """
25
+ cookbook '1234567890'
26
+ """
27
+ When I run `berks install`
28
+ Then the output should contain:
29
+ """
30
+ Unable to find a solution for demands: 1234567890 (>= 0.0.0)
31
+ """
32
+ And the exit status should be "NoSolutionError"
33
+
34
+ Scenario: when the cookbook exists, but the version does not
35
+ Given I have a Berksfile pointing at an authenticated Artifactory server with:
36
+ """
37
+ cookbook 'poise', '0.0.0'
38
+ """
39
+ When I run `berks install`
40
+ Then the output should contain:
41
+ """
42
+ Unable to find a solution for demands: poise (= 0.0.0)
43
+ """
44
+ And the exit status should be "NoSolutionError"
45
+
46
+ Scenario: when the API key is not present:
47
+ Given I have a Berksfile pointing at an Artifactory server with:
48
+ """
49
+ cookbook 'poise'
50
+ """
51
+ When I run `berks install`
52
+ Then the output should contain:
53
+ """
54
+ Unable to find a solution for demands: poise (>= 0.0.0)
55
+ """
56
+ And the exit status should be "NoSolutionError"
57
+
58
+ Scenario: when the API key is given in $ARTIFACTORY_API_KEY:
59
+ Given I have a Berksfile pointing at an Artifactory server with:
60
+ """
61
+ cookbook 'poise', '2.7.2'
62
+ """
63
+ And the environment variable ARTIFACTORY_API_KEY is $TEST_BERKSHELF_ARTIFACTORY_API_KEY
64
+ When I successfully run `berks install`
65
+ Then the output should contain:
66
+ """
67
+ Installing poise (2.7.2)
68
+ """
69
+ And the cookbook store should have the cookbooks:
70
+ | poise | 2.7.2 |
@@ -37,3 +37,18 @@ Given /^I have a Berksfile at "(.+)" pointing at the local Berkshelf API with:$/
37
37
  """
38
38
  }
39
39
  end
40
+
41
+ Given /I have a Berksfile pointing at an( authenticated)? Artifactory server with:/ do |authenticated, content|
42
+ if ENV['TEST_BERKSHELF_ARTIFACTORY']
43
+ steps %Q{
44
+ Given a file named "Berksfile" with:
45
+ """
46
+ source artifactory: '#{ENV['TEST_BERKSHELF_ARTIFACTORY']}'#{authenticated ? ", api_key: '#{ENV['TEST_BERKSHELF_ARTIFACTORY_API_KEY']}'" : ''}
47
+
48
+ #{content}
49
+ """
50
+ }
51
+ else
52
+ skip_this_scenario
53
+ end
54
+ end
@@ -5,3 +5,7 @@ end
5
5
  Given /^the environment variable (.+) is "(.+)"$/ do |variable, value|
6
6
  set_environment_variable(variable, value)
7
7
  end
8
+
9
+ Given /^the environment variable (.+) is \$TEST_BERKSHELF_ARTIFACTORY_API_KEY$/ do |variable|
10
+ set_environment_variable(variable, ENV['TEST_BERKSHELF_ARTIFACTORY_API_KEY'])
11
+ end
@@ -44,7 +44,7 @@ Then /^the cookbook store should have the cookbooks:$/ do |cookbooks|
44
44
  cookbooks.raw.each do |name, version|
45
45
  expect(cookbook_store.storage_path).to have_structure {
46
46
  directory "#{name}-#{version}" do
47
- file "metadata.rb" do
47
+ file "metadata.{rb,json}" do
48
48
  contains version
49
49
  end
50
50
  end
@@ -56,7 +56,7 @@ Then /^the cookbook store should have the git cookbooks:$/ do |cookbooks|
56
56
  cookbooks.raw.each do |name, version, sha1|
57
57
  expect(cookbook_store.storage_path).to have_structure {
58
58
  directory "#{name}-#{sha1}" do
59
- file "metadata.rb" do
59
+ file "metadata.{rb,json}" do
60
60
  contains version
61
61
  end
62
62
  end
@@ -14,10 +14,16 @@ class Hash
14
14
  end
15
15
  end
16
16
 
17
+ # Pending Ridley allowing newer Faraday and Celluloid.
18
+ def clean_json_output(output)
19
+ output.gsub(/^.+warning: constant ::Fixnum is deprecated$/, '') \
20
+ .gsub(/^.*forwarding to private method Celluloid::PoolManager#url_prefix$/, '')
21
+ end
22
+
17
23
  Then /^the output should contain JSON:$/ do |data|
18
24
  parsed = ERB.new(data).result
19
25
  target = JSON.pretty_generate(JSON.parse(parsed).sort_by_key)
20
- actual = JSON.pretty_generate(JSON.parse(all_commands.map { |c| c.output }.join("\n")).sort_by_key)
26
+ actual = JSON.pretty_generate(JSON.parse(all_commands.map { |c| clean_json_output(c.output) }.join("\n")).sort_by_key)
21
27
 
22
28
  expect(actual).to eq(target)
23
29
  end
@@ -191,11 +191,15 @@ module Berkshelf
191
191
  # @param [String] api_url
192
192
  # url for the api to add
193
193
  #
194
+ # @param [Hash] options
195
+ # extra source options
196
+ #
194
197
  # @raise [InvalidSourceURI]
195
198
  #
196
199
  # @return [Array<Source>]
197
- def source(api_url)
198
- @sources[api_url] = Source.new(api_url)
200
+ def source(api_url, **options)
201
+ source = Source.new(api_url, **options)
202
+ @sources[source.uri.to_s] = source
199
203
  end
200
204
  expose :source
201
205
 
@@ -115,6 +115,11 @@ module Berkshelf
115
115
  def find(name, version)
116
116
  response = get("cookbooks/#{name}/versions/#{self.class.uri_escape_version(version)}")
117
117
 
118
+ # Artifactory responds with a 200 and blank body for unknown cookbooks.
119
+ if response.status == 200 && response.body.to_s == ''
120
+ response.env.status = 404
121
+ end
122
+
118
123
  case response.status
119
124
  when (200..299)
120
125
  response.body
@@ -131,6 +136,11 @@ module Berkshelf
131
136
  def latest_version(name)
132
137
  response = get("cookbooks/#{name}")
133
138
 
139
+ # Artifactory responds with a 200 and blank body for unknown cookbooks.
140
+ if response.status == 200 && response.body.to_s == ''
141
+ response.env.status = 404
142
+ end
143
+
134
144
  case response.status
135
145
  when (200..299)
136
146
  self.class.version_from_uri response.body["latest_version"]
@@ -63,17 +63,18 @@ module Berkshelf
63
63
 
64
64
  case remote_cookbook.location_type
65
65
  when :opscode, :supermarket
66
- CommunityREST.new(remote_cookbook.location_path).download(name, version)
66
+ options = {}
67
+ if source.type == :artifactory
68
+ options[:headers] = {'X-Jfrog-Art-Api' => source.options[:api_key]}
69
+ end
70
+ CommunityREST.new(remote_cookbook.location_path, options).download(name, version)
67
71
  when :chef_server
68
72
  # @todo Dynamically get credentials for remote_cookbook.location_path
69
- ssl_options = { verify: Berkshelf::Config.instance.ssl.verify }
70
- ssl_options[:cert_store] = ssl_policy.store if ssl_policy.store
71
-
72
73
  credentials = {
73
74
  server_url: remote_cookbook.location_path,
74
- client_name: Berkshelf::Config.instance.chef.node_name,
75
- client_key: Berkshelf::Config.instance.chef.client_key,
76
- ssl: ssl_options,
75
+ client_name: source.options[:client_name] || Berkshelf::Config.instance.chef.node_name,
76
+ client_key: source.options[:client_key] || Berkshelf::Config.instance.chef.client_key,
77
+ ssl: source.options[:ssl],
77
78
  }
78
79
  # @todo Something scary going on here - getting an instance of Kitchen::Logger from test-kitchen
79
80
  # https://github.com/opscode/test-kitchen/blob/master/lib/kitchen.rb#L99
@@ -6,11 +6,42 @@ module Berkshelf
6
6
  class Source
7
7
  include Comparable
8
8
 
9
- attr_accessor :source
9
+ attr_accessor :type
10
+ attr_accessor :uri_string
11
+ attr_accessor :options
10
12
 
11
13
  # @param [String, Berkshelf::SourceURI] source
12
- def initialize(source)
13
- @source = source
14
+ def initialize(source, **options)
15
+ @options = {timeout: api_timeout, open_timeout: [(api_timeout / 10), 3].max, ssl: {}}
16
+ @options.update(options)
17
+ case source
18
+ when String
19
+ # source "https://supermarket.chef.io/"
20
+ @type = :supermarket
21
+ @uri_string = source
22
+ when :chef_server
23
+ # source :chef_server
24
+ @type = :chef_server
25
+ @uri_string = options[:url] || Berkshelf::Config.instance.chef.chef_server_url
26
+ when Hash
27
+ # source type: uri, option: value, option: value
28
+ source = source.dup
29
+ @type, @uri_string = source.shift
30
+ @options.update(source)
31
+ end
32
+ # Default options for some source types.
33
+ case @type
34
+ when :chef_server
35
+ @options[:client_name] ||= Berkshelf::Config.instance.chef.node_name
36
+ @options[:client_key] ||= Berkshelf::Config.instance.chef.client_key
37
+ when :artifactory
38
+ @options[:api_key] ||= Berkshelf::Config.instance.chef.artifactory_api_key || ENV['ARTIFACTORY_API_KEY']
39
+ end
40
+ # Set some default SSL options.
41
+ Berkshelf::Config.instance.ssl.each do |key, value|
42
+ @options[:ssl][key.to_sym] = value unless @options[:ssl].include?(key.to_sym)
43
+ end
44
+ @options[:ssl][:cert_store] = ssl_policy.store if ssl_policy.store
14
45
  @universe = nil
15
46
  end
16
47
 
@@ -19,35 +50,21 @@ module Berkshelf
19
50
  end
20
51
 
21
52
  def api_client
22
- @api_client ||= begin
23
- ssl_options = { verify: Berkshelf::Config.instance.ssl.verify }
24
- ssl_options[:cert_store] = ssl_policy.store if ssl_policy.store
25
-
26
- if source == :chef_server
27
- APIClient.chef_server(
28
- ssl: ssl_options,
29
- timeout: api_timeout,
30
- open_timeout: [(api_timeout / 10), 3].max,
31
- client_name: Berkshelf::Config.instance.chef.node_name,
32
- server_url: Berkshelf::Config.instance.chef.chef_server_url,
33
- client_key: Berkshelf::Config.instance.chef.client_key
34
- )
35
- else
36
- APIClient.new(uri,
37
- timeout: api_timeout,
38
- open_timeout: [(api_timeout / 10), 3].max,
39
- ssl: Berkshelf::Config.instance.ssl
40
- )
41
- end
42
- end
53
+ @api_client ||= case type
54
+ when :chef_server
55
+ APIClient.chef_server(server_url: uri.to_s, **options)
56
+ when :artifactory
57
+ # Don't accidentally mutate the options.
58
+ client_options = options.dup
59
+ api_key = client_options.delete(:api_key)
60
+ APIClient.new(uri, headers: {'X-Jfrog-Art-Api' => api_key}, **client_options)
61
+ else
62
+ APIClient.new(uri, **options)
63
+ end
43
64
  end
44
65
 
45
66
  def uri
46
- @uri ||= if source == :chef_server
47
- SourceURI.parse(Berkshelf::Config.instance.chef.chef_server_url)
48
- else
49
- SourceURI.parse(source)
50
- end
67
+ @uri ||= SourceURI.parse(uri_string)
51
68
  end
52
69
 
53
70
  # Forcefully obtain the universe from the API endpoint and assign it to {#universe}. This
@@ -116,20 +133,24 @@ module Berkshelf
116
133
  end
117
134
 
118
135
  def to_s
119
- "#{uri}"
136
+ if type == :supermarket
137
+ "#{uri}"
138
+ else
139
+ "#{type}: #{uri}"
140
+ end
120
141
  end
121
142
 
122
143
  def inspect
123
- "#<#{self.class.name} uri: #{@uri.to_s.inspect}>"
144
+ "#<#{self.class.name} #{type}: #{uri.to_s.inspect}, #{options.map {|k, v| "#{k}: #{v.inspect}" }.join(', ')}>"
124
145
  end
125
146
 
126
147
  def hash
127
- @uri.host.hash
148
+ [type, uri_string, options].hash
128
149
  end
129
150
 
130
151
  def ==(other)
131
152
  return false unless other.is_a?(self.class)
132
- uri == other.uri
153
+ type == other.type && uri == other.uri
133
154
  end
134
155
 
135
156
  private
@@ -1,3 +1,3 @@
1
1
  module Berkshelf
2
- VERSION = "5.6.5"
2
+ VERSION = "6.0.0"
3
3
  end
@@ -7,6 +7,7 @@ BERKS_SPEC_DATA = File.expand_path("../data", __FILE__)
7
7
  require "rspec"
8
8
  require "cleanroom/rspec"
9
9
  require "webmock/rspec"
10
+ require "rspec/its"
10
11
  require "berkshelf/api/rspec" unless windows?
11
12
 
12
13
  Dir["spec/support/**/*.rb"].each { |f| require File.expand_path(f) }
@@ -23,11 +23,12 @@ module Berkshelf
23
23
  end
24
24
 
25
25
  def matches?(root)
26
- unless root.join(@name).exist?
26
+ path = Pathname.glob(root.join(@name)).first
27
+ unless path.exist?
27
28
  throw :failure, root.join(@name)
28
29
  end
29
30
 
30
- contents = File.read(root.join(@name))
31
+ contents = File.read(path)
31
32
 
32
33
  @contents.each do |string|
33
34
  unless contents.include?(string)
@@ -38,23 +38,49 @@ module Berkshelf
38
38
  let(:version) { "1.0.0" }
39
39
 
40
40
  it "supports the 'opscode' location type" do
41
+ allow(source).to receive(:type) { :supermarket }
41
42
  allow(remote_cookbook).to receive(:location_type) { :opscode }
42
43
  allow(remote_cookbook).to receive(:location_path) { "http://api.opscode.com" }
43
44
  rest = double("community-rest")
44
- expect(CommunityREST).to receive(:new).with("http://api.opscode.com") { rest }
45
+ expect(CommunityREST).to receive(:new).with("http://api.opscode.com", {}) { rest }
45
46
  expect(rest).to receive(:download).with(name, version)
46
47
  subject.try_download(source, name, version)
47
48
  end
48
49
 
49
50
  it "supports the 'supermarket' location type" do
51
+ allow(source).to receive(:type) { :supermarket }
50
52
  allow(remote_cookbook).to receive(:location_type) { :supermarket }
51
53
  allow(remote_cookbook).to receive(:location_path) { "http://api.supermarket.com" }
52
54
  rest = double("community-rest")
53
- expect(CommunityREST).to receive(:new).with("http://api.supermarket.com") { rest }
55
+ expect(CommunityREST).to receive(:new).with("http://api.supermarket.com", {}) { rest }
54
56
  expect(rest).to receive(:download).with(name, version)
55
57
  subject.try_download(source, name, version)
56
58
  end
57
59
 
60
+ context "with an artifactory source" do
61
+ it "supports the 'opscode' location type" do
62
+ allow(source).to receive(:type) { :artifactory }
63
+ allow(source).to receive(:options) { {api_key: 'secret'} }
64
+ allow(remote_cookbook).to receive(:location_type) { :opscode }
65
+ allow(remote_cookbook).to receive(:location_path) { "http://artifactory/" }
66
+ rest = double("community-rest")
67
+ expect(CommunityREST).to receive(:new).with("http://artifactory/", {headers: {'X-Jfrog-Art-Api' => 'secret'}}) { rest }
68
+ expect(rest).to receive(:download).with(name, version)
69
+ subject.try_download(source, name, version)
70
+ end
71
+
72
+ it "supports the 'supermarket' location type" do
73
+ allow(source).to receive(:type) { :artifactory }
74
+ allow(source).to receive(:options) { {api_key: 'secret'} }
75
+ allow(remote_cookbook).to receive(:location_type) { :supermarket }
76
+ allow(remote_cookbook).to receive(:location_path) { "http://artifactory/" }
77
+ rest = double("community-rest")
78
+ expect(CommunityREST).to receive(:new).with("http://artifactory/", {headers: {'X-Jfrog-Art-Api' => 'secret'}}) { rest }
79
+ expect(rest).to receive(:download).with(name, version)
80
+ subject.try_download(source, name, version)
81
+ end
82
+ end
83
+
58
84
  describe "chef_server location type" do
59
85
  let(:chef_server_url) { "http://configured-chef-server/" }
60
86
  let(:ridley_client) do
@@ -91,6 +117,7 @@ module Berkshelf
91
117
  allow(subject).to receive(:ssl_policy).and_return(ssl_policy)
92
118
  allow(remote_cookbook).to receive(:location_type) { :chef_server }
93
119
  allow(remote_cookbook).to receive(:location_path) { chef_server_url }
120
+ allow(source).to receive(:options) { {read_timeout: 30, open_timeout: 3, ssl: {verify: true, cert_store: cert_store}} }
94
121
  end
95
122
 
96
123
  it "uses the berkshelf config and provides a custom cert_store" do
@@ -106,6 +133,44 @@ module Berkshelf
106
133
  expect(Ridley).to receive(:open).with(credentials) { ridley_client }
107
134
  subject.try_download(source, name, version)
108
135
  end
136
+
137
+ context "with a source option for client_name" do
138
+ before do
139
+ allow(source).to receive(:options) { {client_name: "other-client", read_timeout: 30, open_timeout: 3, ssl: {verify: true, cert_store: cert_store}} }
140
+ end
141
+ it "uses the override" do
142
+ credentials = {
143
+ server_url: chef_server_url,
144
+ client_name: "other-client",
145
+ client_key: chef_config.client_key,
146
+ ssl: {
147
+ verify: berkshelf_config.ssl.verify,
148
+ cert_store: cert_store,
149
+ },
150
+ }
151
+ expect(Ridley).to receive(:open).with(credentials) { ridley_client }
152
+ subject.try_download(source, name, version)
153
+ end
154
+ end
155
+
156
+ context "with a source option for client_key" do
157
+ before do
158
+ allow(source).to receive(:options) { {client_key: "other-key", read_timeout: 30, open_timeout: 3, ssl: {verify: true, cert_store: cert_store}} }
159
+ end
160
+ it "uses the override" do
161
+ credentials = {
162
+ server_url: chef_server_url,
163
+ client_name: chef_config.node_name,
164
+ client_key: "other-key",
165
+ ssl: {
166
+ verify: berkshelf_config.ssl.verify,
167
+ cert_store: cert_store,
168
+ },
169
+ }
170
+ expect(Ridley).to receive(:open).with(credentials) { ridley_client }
171
+ subject.try_download(source, name, version)
172
+ end
173
+ end
109
174
  end
110
175
 
111
176
  it "supports the 'file_store' location type" do
@@ -2,9 +2,152 @@ require "spec_helper"
2
2
 
3
3
  module Berkshelf
4
4
  describe Source do
5
- describe "#universe"
6
- describe "#cookbook"
7
- describe "#versions"
5
+ let(:arguments) { [] }
6
+ let(:config) { Config.new }
7
+ subject(:instance) { described_class.new(*arguments) }
8
+ before do
9
+ allow(Berkshelf::Config).to receive(:instance).and_return(config)
10
+ end
11
+
12
+ describe "#type" do
13
+ subject { instance.type }
14
+
15
+ context "with a string argument" do
16
+ let(:arguments) { ['https://example.com'] }
17
+ it { is_expected.to eq :supermarket }
18
+ end
19
+
20
+ context "with a string argument and options" do
21
+ let(:arguments) { ['https://example.com', {key: 'value'}] }
22
+ it { is_expected.to eq :supermarket }
23
+ end
24
+
25
+ context "with a symbol argument" do
26
+ let(:arguments) { [:chef_server] }
27
+ it { is_expected.to eq :chef_server }
28
+ end
29
+
30
+ context "with a symbol argument and options" do
31
+ let(:arguments) { [:chef_server, {key: 'value'}] }
32
+ it { is_expected.to eq :chef_server }
33
+ end
34
+
35
+ context "with a hash argument" do
36
+ let(:arguments) { [{artifactory: 'https://example.com/api/chef/chef-virtual'}] }
37
+ it { is_expected.to eq :artifactory }
38
+ end
39
+
40
+ context "with a hash argument and connected options" do
41
+ let(:arguments) { [{artifactory: 'https://example.com/api/chef/chef-virtual', key: 'value'}] }
42
+ it { is_expected.to eq :artifactory }
43
+ end
44
+
45
+ context "with a hash argument and disconnected options" do
46
+ let(:arguments) { [{artifactory: 'https://example.com/api/chef/chef-virtual'}, {key: 'value'}] }
47
+ it { is_expected.to eq :artifactory }
48
+ end
49
+ end
50
+
51
+ describe "#uri" do
52
+ subject { instance.uri.to_s }
53
+
54
+ context "with a string argument" do
55
+ let(:arguments) { ['https://example.com'] }
56
+ it { is_expected.to eq 'https://example.com' }
57
+ end
58
+
59
+ context "with a string argument and options" do
60
+ let(:arguments) { ['https://example.com', {key: 'value'}] }
61
+ it { is_expected.to eq 'https://example.com' }
62
+ end
63
+
64
+ context "with a symbol argument" do
65
+ let(:arguments) { [:chef_server] }
66
+ before { config.chef.chef_server_url = 'https://chefserver/' }
67
+ it { is_expected.to eq 'https://chefserver/' }
68
+ end
69
+
70
+ context "with a symbol argument and options" do
71
+ let(:arguments) { [:chef_server, {key: 'value'}] }
72
+ before { config.chef.chef_server_url = 'https://chefserver/' }
73
+ it { is_expected.to eq 'https://chefserver/' }
74
+ end
75
+
76
+ context "with a hash argument" do
77
+ let(:arguments) { [{artifactory: 'https://example.com/api/chef/chef-virtual'}] }
78
+ it { is_expected.to eq 'https://example.com/api/chef/chef-virtual' }
79
+ end
80
+
81
+ context "with a hash argument and connected options" do
82
+ let(:arguments) { [{artifactory: 'https://example.com/api/chef/chef-virtual', key: 'value'}] }
83
+ it { is_expected.to eq 'https://example.com/api/chef/chef-virtual' }
84
+ end
85
+
86
+ context "with a hash argument and disconnected options" do
87
+ let(:arguments) { [{artifactory: 'https://example.com/api/chef/chef-virtual'}, {key: 'value'}] }
88
+ it { is_expected.to eq 'https://example.com/api/chef/chef-virtual' }
89
+ end
90
+
91
+ context "with an invalid URI" do
92
+ let(:arguments) { ['ftp://example.com'] }
93
+ it { expect { subject }.to raise_error InvalidSourceURI }
94
+ end
95
+ end
96
+
97
+ describe "#options" do
98
+ subject { instance.options }
99
+
100
+ context "with a string argument" do
101
+ let(:arguments) { ['https://example.com'] }
102
+
103
+ it { is_expected.to be_a(Hash) }
104
+ # Check all baseline values.
105
+ its([:timeout]) { is_expected.to eq 30 }
106
+ its([:open_timeout]) { is_expected.to eq 3 }
107
+ its([:ssl, :verify]) { is_expected.to be true }
108
+ its([:ssl, :ca_file]) { is_expected.to be_nil }
109
+ its([:ssl, :ca_path]) { is_expected.to be_nil }
110
+ its([:ssl, :client_cert]) { is_expected.to be_nil }
111
+ its([:ssl, :client_key]) { is_expected.to be_nil }
112
+ its([:ssl, :cert_store]) { is_expected.to be_a(OpenSSL::X509::Store) }
113
+ end
114
+
115
+ context "with a string argument and options" do
116
+ let(:arguments) { ['https://example.com', {key: 'value'}] }
117
+ its([:key]) { is_expected.to eq 'value' }
118
+ end
119
+
120
+ context "with a symbol argument" do
121
+ let(:arguments) { [:chef_server] }
122
+ it { is_expected.to be_a(Hash) }
123
+ end
124
+
125
+ context "with a symbol argument and options" do
126
+ let(:arguments) { [:chef_server, {key: 'value'}] }
127
+ its([:key]) { is_expected.to eq 'value' }
128
+ end
129
+
130
+ context "with a hash argument" do
131
+ let(:arguments) { [{artifactory: 'https://example.com/api/chef/chef-virtual'}] }
132
+ it { is_expected.to be_a(Hash) }
133
+ end
134
+
135
+ context "with a hash argument and connected options" do
136
+ let(:arguments) { [{artifactory: 'https://example.com/api/chef/chef-virtual', key: 'value'}] }
137
+ its([:key]) { is_expected.to eq 'value' }
138
+ end
139
+
140
+ context "with a hash argument and disconnected options" do
141
+ let(:arguments) { [{artifactory: 'https://example.com/api/chef/chef-virtual'}, {key: 'value'}] }
142
+ its([:key]) { is_expected.to eq 'value' }
143
+ end
144
+
145
+ context "with an artifactory source and the API key in the Chef config" do
146
+ let(:arguments) { [{artifactory: 'https://example.com/api/chef/chef-virtual'}] }
147
+ before { config.chef.artifactory_api_key = 'secret' }
148
+ its([:api_key]) { is_expected.to eq 'secret' }
149
+ end
150
+ end
8
151
 
9
152
  describe "#==" do
10
153
  it "is the same if the uri matches" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: berkshelf
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.6.5
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie Winsor
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2017-05-04 00:00:00.000000000 Z
15
+ date: 2017-05-17 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: addressable
@@ -284,6 +284,7 @@ files:
284
284
  - berkshelf.gemspec
285
285
  - bin/berks
286
286
  - docs/berkshelf_for_newcomers.md
287
+ - features/artifactory.feature
287
288
  - features/berksfile.feature
288
289
  - features/commands/apply.feature
289
290
  - features/commands/contingent.feature
@@ -471,7 +472,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
471
472
  requirements:
472
473
  - - ">="
473
474
  - !ruby/object:Gem::Version
474
- version: 2.2.0
475
+ version: 2.3.3
475
476
  required_rubygems_version: !ruby/object:Gem::Requirement
476
477
  requirements:
477
478
  - - ">="
@@ -479,11 +480,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
479
480
  version: 2.0.0
480
481
  requirements: []
481
482
  rubyforge_project:
482
- rubygems_version: 2.5.1
483
+ rubygems_version: 2.6.11
483
484
  signing_key:
484
485
  specification_version: 4
485
486
  summary: Manages a Cookbook's, or an Application's, Cookbook dependencies
486
487
  test_files:
488
+ - features/artifactory.feature
487
489
  - features/berksfile.feature
488
490
  - features/commands/apply.feature
489
491
  - features/commands/contingent.feature