berkshelf 3.0.0.beta7 → 3.0.0.beta8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +4 -1
  4. data/CONTRIBUTING.md +1 -1
  5. data/Gemfile +0 -1
  6. data/Guardfile +0 -8
  7. data/README.md +33 -13
  8. data/berkshelf.gemspec +3 -3
  9. data/features/commands/install.feature +16 -88
  10. data/features/commands/search.feature +15 -0
  11. data/features/commands/shelf/show.feature +2 -2
  12. data/features/commands/shelf/uninstall.feature +1 -1
  13. data/features/commands/show.feature +3 -3
  14. data/features/commands/update.feature +29 -1
  15. data/features/commands/upload.feature +172 -7
  16. data/features/commands/vendor.feature +32 -0
  17. data/features/json_formatter.feature +26 -24
  18. data/features/lifecycle.feature +285 -0
  19. data/features/lockfile.feature +9 -7
  20. data/features/step_definitions/chef_server_steps.rb +1 -0
  21. data/features/step_definitions/cli_steps.rb +2 -2
  22. data/features/step_definitions/filesystem_steps.rb +2 -4
  23. data/gem_graph.png +0 -0
  24. data/generator_files/chefignore +0 -2
  25. data/lib/berkshelf.rb +39 -14
  26. data/lib/berkshelf/berksfile.rb +161 -113
  27. data/lib/berkshelf/cached_cookbook.rb +2 -2
  28. data/lib/berkshelf/cli.rb +15 -3
  29. data/lib/berkshelf/commands/shelf.rb +3 -7
  30. data/lib/berkshelf/community_rest.rb +9 -9
  31. data/lib/berkshelf/config.rb +3 -3
  32. data/lib/berkshelf/cookbook_generator.rb +0 -8
  33. data/lib/berkshelf/cookbook_store.rb +1 -2
  34. data/lib/berkshelf/dependency.rb +25 -138
  35. data/lib/berkshelf/downloader.rb +41 -7
  36. data/lib/berkshelf/errors.rb +113 -214
  37. data/lib/berkshelf/formatters/base.rb +42 -0
  38. data/lib/berkshelf/formatters/human.rb +145 -0
  39. data/lib/berkshelf/formatters/json.rb +149 -133
  40. data/lib/berkshelf/formatters/null.rb +8 -18
  41. data/lib/berkshelf/init_generator.rb +1 -1
  42. data/lib/berkshelf/installer.rb +115 -104
  43. data/lib/berkshelf/location.rb +22 -121
  44. data/lib/berkshelf/locations/base.rb +75 -0
  45. data/lib/berkshelf/locations/git.rb +196 -0
  46. data/lib/berkshelf/locations/github.rb +8 -0
  47. data/lib/berkshelf/locations/path.rb +78 -0
  48. data/lib/berkshelf/lockfile.rb +452 -290
  49. data/lib/berkshelf/logger.rb +9 -3
  50. data/lib/berkshelf/mixin/logging.rb +4 -9
  51. data/lib/berkshelf/resolver.rb +12 -12
  52. data/lib/berkshelf/source.rb +13 -1
  53. data/lib/berkshelf/version.rb +1 -1
  54. data/spec/fixtures/cookbooks/example_cookbook-0.5.0/metadata.rb +3 -7
  55. data/spec/fixtures/cookbooks/example_cookbook/metadata.rb +3 -6
  56. data/spec/spec_helper.rb +5 -6
  57. data/spec/support/matchers/file_system_matchers.rb +4 -0
  58. data/spec/support/shared_examples/formatter.rb +11 -0
  59. data/spec/unit/berkshelf/berksfile_spec.rb +25 -28
  60. data/spec/unit/berkshelf/cli_spec.rb +19 -11
  61. data/spec/unit/berkshelf/dependency_spec.rb +4 -164
  62. data/spec/unit/berkshelf/formatters/base_spec.rb +35 -0
  63. data/spec/unit/berkshelf/formatters/human_spec.rb +7 -0
  64. data/spec/unit/berkshelf/formatters/json_spec.rb +7 -0
  65. data/spec/unit/berkshelf/formatters/null_spec.rb +7 -11
  66. data/spec/unit/berkshelf/location_spec.rb +16 -144
  67. data/spec/unit/berkshelf/locations/base_spec.rb +80 -0
  68. data/spec/unit/berkshelf/locations/git_spec.rb +249 -0
  69. data/spec/unit/berkshelf/locations/path_spec.rb +107 -0
  70. data/spec/unit/berkshelf/lockfile_parser_spec.rb +3 -3
  71. data/spec/unit/berkshelf/lockfile_spec.rb +55 -11
  72. data/spec/unit/berkshelf/logger_spec.rb +2 -2
  73. data/spec/unit/berkshelf/mixin/logging_spec.rb +5 -9
  74. data/spec/unit/berkshelf/source_spec.rb +32 -13
  75. data/spec/unit/berkshelf_spec.rb +6 -9
  76. metadata +33 -33
  77. data/.ruby-version +0 -1
  78. data/berkshelf-complete.sh +0 -75
  79. data/lib/berkshelf/formatters.rb +0 -110
  80. data/lib/berkshelf/formatters/human_readable.rb +0 -142
  81. data/lib/berkshelf/git.rb +0 -204
  82. data/lib/berkshelf/locations/git_location.rb +0 -135
  83. data/lib/berkshelf/locations/github_location.rb +0 -55
  84. data/lib/berkshelf/locations/mercurial_location.rb +0 -114
  85. data/lib/berkshelf/locations/path_location.rb +0 -88
  86. data/lib/berkshelf/mercurial.rb +0 -146
  87. data/lib/berkshelf/mixin.rb +0 -7
  88. data/spec/support/mercurial.rb +0 -123
  89. data/spec/unit/berkshelf/formatters_spec.rb +0 -114
  90. data/spec/unit/berkshelf/git_spec.rb +0 -312
  91. data/spec/unit/berkshelf/locations/git_location_spec.rb +0 -126
  92. data/spec/unit/berkshelf/locations/mercurial_location_spec.rb +0 -131
  93. data/spec/unit/berkshelf/locations/path_location_spec.rb +0 -25
  94. data/spec/unit/berkshelf/mercurial_spec.rb +0 -172
@@ -14,11 +14,7 @@ module Berkshelf
14
14
  class DeprecatedError < BerkshelfError; status_code(10); end
15
15
  class InternalError < BerkshelfError; status_code(99); end
16
16
  class ArgumentError < InternalError; end
17
- class AbstractFunction < InternalError
18
- def to_s
19
- 'Function must be implemented on includer'
20
- end
21
- end
17
+ class AbstractFunction < InternalError; end
22
18
 
23
19
  class BerksfileNotFound < BerkshelfError
24
20
  status_code(100)
@@ -34,75 +30,45 @@ module Berkshelf
34
30
  end
35
31
  end
36
32
 
37
- class NoVersionForConstraints < BerkshelfError; status_code(101); end
38
- class DuplicateLocationDefined < BerkshelfError; status_code(102); end
39
- class CookbookNotFound < BerkshelfError; status_code(103); end
40
-
41
- class GitError < BerkshelfError
42
- status_code(104)
33
+ class CookbookNotFound < BerkshelfError
34
+ status_code(103)
43
35
 
44
- # @param [#to_s] stderr
45
- # the error that came from stderr
46
- def initialize(stderr)
47
- @stderr = stderr.to_s
48
- end
49
-
50
- # A common header for all git errors. The #to_s method should
51
- # use this before outputting any specific errors.
52
- #
53
- # @return [String]
54
- def header
55
- 'An error occurred during Git execution:'
36
+ def initialize(name, version, location)
37
+ @name = name
38
+ @version = version
39
+ @location = location
56
40
  end
57
41
 
58
42
  def to_s
59
- [
60
- header,
61
- "",
62
- " " + @stderr.to_s.split("\n").map(&:strip).join("\n "),
63
- ""
64
- ].join("\n")
43
+ if @version
44
+ "Cookbook '#{@name}' (#{@version}) not found #{@location}!"
45
+ else
46
+ "Cookbook '#{@name}' not found #{@location}!"
47
+ end
65
48
  end
66
49
  end
67
50
 
68
- class AmbiguousGitRef < GitError
69
- def initialize(ref)
70
- @ref = ref
71
- end
72
-
73
- def to_s
74
- [
75
- header,
76
- "",
77
- " Ambiguous Git ref: '#{@ref}'",
78
- "",
79
- ].join("\n")
80
- end
81
- end
51
+ class DuplicateDependencyDefined < BerkshelfError
52
+ status_code(105)
82
53
 
83
- class InvalidGitRef < GitError
84
- def initialize(ref)
85
- @ref = ref
54
+ def initialize(name)
55
+ @name = name
86
56
  end
87
57
 
88
58
  def to_s
89
- [
90
- header,
91
- "",
92
- " Invalid Git ref: '#{@ref}'",
93
- "",
94
- ].join("\n")
59
+ out = "Your Berksfile contains multiple entries named "
60
+ out << "'#{@name}'. Please remove duplicate dependencies, or put them in "
61
+ out << "different groups."
62
+ out
95
63
  end
96
64
  end
97
65
 
98
- class DuplicateDependencyDefined < BerkshelfError; status_code(105); end
99
-
100
66
  class NoSolutionError < BerkshelfError
101
67
  status_code(106)
102
68
 
103
69
  attr_reader :demands
104
70
 
105
- # @param [Array<Berkshelf::Dependency>] demands
71
+ # @param [Array<Dependency>] demands
106
72
  def initialize(demands)
107
73
  @demands = demands
108
74
  end
@@ -113,79 +79,6 @@ module Berkshelf
113
79
  end
114
80
 
115
81
  class CookbookSyntaxError < BerkshelfError; status_code(107); end
116
-
117
- class MercurialError < BerkshelfError
118
- status_code(108);
119
- end
120
-
121
- class InvalidHgURI < BerkshelfError
122
- status_code(110)
123
-
124
- # @param [String] uri
125
- def initialize(uri)
126
- @uri = uri
127
- end
128
-
129
- def to_s
130
- "'#{@uri}' is not a valid Mercurial URI"
131
- end
132
- end
133
-
134
- class InvalidGitURI < BerkshelfError
135
- status_code(110)
136
-
137
- # @param [String] uri
138
- def initialize(uri)
139
- @uri = uri
140
- end
141
-
142
- def to_s
143
- "'#{@uri}' is not a valid Git URI"
144
- end
145
- end
146
-
147
- class InvalidGitHubIdentifier < BerkshelfError
148
- status_code(110)
149
-
150
- # @param [String] repo_identifier
151
- def initialize(repo_identifier)
152
- @repo_identifier = repo_identifier
153
- end
154
-
155
- def to_s
156
- "'#{@repo_identifier}' is not a valid GitHub identifier - should not end in '.git'"
157
- end
158
- end
159
-
160
- class UnknownGitHubProtocol < BerkshelfError
161
- status_code(110)
162
-
163
- # @param [String] protocol
164
- def initialize(protocol)
165
- @protocol = protocol
166
- end
167
-
168
- def to_s
169
- "'#{@protocol}' is not supported for the 'github' location key - please use 'git' instead"
170
- end
171
- end
172
-
173
- class MercurialNotFound < BerkshelfError
174
- status_code(111)
175
-
176
- def to_s
177
- 'Could not find a Mercurial executable in your path - please add it and try again'
178
- end
179
- end
180
-
181
- class GitNotFound < BerkshelfError
182
- status_code(110)
183
-
184
- def to_s
185
- 'Could not find a Git executable in your path - please add it and try again'
186
- end
187
- end
188
-
189
82
  class ConstraintNotSatisfied < BerkshelfError; status_code(111); end
190
83
  class BerksfileReadError < BerkshelfError
191
84
  status_code(113)
@@ -197,7 +90,6 @@ module Berkshelf
197
90
  @error_backtrace = original_error.backtrace
198
91
  end
199
92
 
200
-
201
93
  def status_code
202
94
  @original_error.respond_to?(:status_code) ? @original_error.status_code : 113
203
95
  end
@@ -219,9 +111,9 @@ module Berkshelf
219
111
  class MismatchedCookbookName < BerkshelfError
220
112
  status_code(114)
221
113
 
222
- # @param [Berkshelf::Dependency] dependency
114
+ # @param [Dependency] dependency
223
115
  # the dependency with the expected name
224
- # @param [Berkshelf::CachedCookbook] cached_cookbook
116
+ # @param [CachedCookbook] cached_cookbook
225
117
  # the cached_cookbook with the mismatched name
226
118
  def initialize(dependency, cached_cookbook)
227
119
  @dependency = dependency
@@ -229,17 +121,18 @@ module Berkshelf
229
121
  end
230
122
 
231
123
  def to_s
232
- [
233
- "In your Berksfile, you have:",
234
- "",
235
- " cookbook '#{@dependency.name}'",
236
- "",
237
- "But that cookbook is actually named '#{@cached_cookbook.cookbook_name}'",
238
- "",
239
- "This can cause potentially unwanted side-effects in the future",
240
- "",
241
- "NOTE: If you don't explicitly set the `name` attribute in the metadata, the name of the directory will be used!",
242
- ].join("\n")
124
+ out = "In your Berksfile, you have:\n"
125
+ out << "\n"
126
+ out << " cookbook '#{@dependency.name}'\n"
127
+ out << "\n"
128
+ out << "But that cookbook is actually named '#{@cached_cookbook.cookbook_name}'\n"
129
+ out << "\n"
130
+ out << "This can cause potentially unwanted side-effects in the future.\n"
131
+ out << "\n"
132
+ out << "NOTE: If you do not explicitly set the 'name' attribute in the "
133
+ out << "metadata, the name of the directory will be used instead. This "
134
+ out << "is often a cause of confusion for dependency solving."
135
+ out
243
136
  end
244
137
  end
245
138
 
@@ -251,51 +144,79 @@ module Berkshelf
251
144
  end
252
145
 
253
146
  def to_s
254
- [
255
- 'Invalid configuration:',
256
- @errors.map { |key, errors| errors.map { |error| " #{key} #{error}" } },
257
- ].join("\n")
147
+ out = "Invalid configuration:\n"
148
+ @errors.each do |key, errors|
149
+ errors.each do |error|
150
+ out << " #{key} #{error}\n"
151
+ end
152
+ end
153
+
154
+ out.strip
258
155
  end
259
156
  end
260
157
 
261
- class ConfigExists < BerkshelfError; status_code(116); end
262
- class ConfigurationError < BerkshelfError; status_code(117); end
263
- class InsufficientPrivledges < BerkshelfError; status_code(119); end
158
+ class InsufficientPrivledges < BerkshelfError
159
+ status_code(119)
160
+
161
+ def initialize(path)
162
+ @path = path
163
+ end
164
+
165
+ def to_s
166
+ "You do not have permission to write to '#{@path}'! Please chown the " \
167
+ "path to the current user, chmod the permissions to include the " \
168
+ "user, or choose a different path."
169
+ end
170
+ end
264
171
 
265
172
  class DependencyNotFound < BerkshelfError
266
173
  status_code(120)
267
174
 
268
- # @param [String, Array<String>] cookbooks
269
- # the list of cookbooks that were not defined
270
- def initialize(cookbooks)
271
- @cookbooks = Array(cookbooks)
175
+ # @param [String, Array<String>] names
176
+ # the list of cookbook names that were not defined
177
+ def initialize(names)
178
+ @names = Array(names)
272
179
  end
273
180
 
274
181
  def to_s
275
- list = @cookbooks.collect { |cookbook| "'#{cookbook}'" }.join(', ')
276
-
277
- if @cookbooks.size == 1
278
- "Could not find cookbook #{list}. Make sure it is in your " \
279
- "Berksfile, then run `berks install` to download and install the " \
280
- "missing dependencies."
182
+ if @names.size == 1
183
+ "Dependency '#{@names.first}' was not found. Please make sure it is " \
184
+ "in your Berksfile, and then run `berks install` to download and " \
185
+ "install the missing dependencies."
281
186
  else
282
- "Could not find cookbooks #{list}. Make sure they are in your " \
283
- "Berksfile, then run `berks install` to download and install the " \
284
- "missing dependencies."
187
+ out = "The following dependencies were not found:\n"
188
+ @names.each do |name|
189
+ out << " * #{name}\n"
190
+ end
191
+ out << "\n"
192
+ out << "Please make sure they are in your Berksfile, and then run "
193
+ out << "`berks install` to download and install the missing "
194
+ out << "dependencies."
195
+ out
285
196
  end
286
197
  end
287
198
  end
288
199
 
289
- class ValidationFailed < BerkshelfError; status_code(121); end
290
- class InvalidVersionConstraint < BerkshelfError; status_code(122); end
291
- class CommunitySiteError < BerkshelfError; status_code(123); end
200
+ class CommunitySiteError < BerkshelfError
201
+ status_code(123)
202
+
203
+ def initialize(uri, message)
204
+ @uri = uri
205
+ @message = message
206
+ end
207
+
208
+ def to_s
209
+ "An unexpected error occurred retrieving #{@message} from the cookbook " \
210
+ "site at '#{@api_uri}'."
211
+ end
212
+ end
292
213
 
293
214
  class CookbookValidationFailure < BerkshelfError
294
215
  status_code(124)
295
216
 
296
- # @param [Berkshelf::Location] location
217
+ # @param [Location] location
297
218
  # the location (or any subclass) raising this validation error
298
- # @param [Berkshelf::CachedCookbook] cached_cookbook
219
+ # @param [CachedCookbook] cached_cookbook
299
220
  # the cached_cookbook that does not satisfy the constraint
300
221
  def initialize(dependency, cached_cookbook)
301
222
  @dependency = dependency
@@ -307,10 +228,7 @@ module Berkshelf
307
228
  end
308
229
  end
309
230
 
310
- class ClientKeyFileNotFound < BerkshelfError; status_code(125); end
311
-
312
231
  class UploadFailure < BerkshelfError; end
313
-
314
232
  class FrozenCookbook < UploadFailure
315
233
  status_code(126)
316
234
 
@@ -320,18 +238,18 @@ module Berkshelf
320
238
  end
321
239
 
322
240
  def to_s
323
- "The cookbook #{@cookbook.cookbook_name} (#{@cookbook.version})" <<
324
- " already exists and is frozen on the Chef Server. Use the --force" <<
325
- " option to override."
241
+ "The cookbook #{@cookbook.cookbook_name} (#{@cookbook.version}) " \
242
+ "already exists and is frozen on the Chef Server. Use the --force " \
243
+ "option to override."
326
244
  end
327
245
  end
328
246
 
329
247
  class OutdatedDependency < BerkshelfError
330
248
  status_code(128)
331
249
 
332
- # @param [Berkshelf::Dependency] locked_dependency
250
+ # @param [Dependency] locked_dependency
333
251
  # the locked dependency
334
- # @param [Berkshelf::Dependency] dependency
252
+ # @param [Dependency] dependency
335
253
  # the dependency that is outdated
336
254
  def initialize(locked, dependency)
337
255
  @locked = locked
@@ -384,7 +302,7 @@ module Berkshelf
384
302
  # Raised when a cookbook or its recipes contain a space or invalid
385
303
  # character in the path.
386
304
  #
387
- # @param [Berkshelf::CachedCookbook] cookbook
305
+ # @param [CachedCookbook] cookbook
388
306
  # the cookbook that failed validation
389
307
  # @param [Array<#to_s>] files
390
308
  # the list of files that were not valid
@@ -407,25 +325,6 @@ module Berkshelf
407
325
  end
408
326
  end
409
327
 
410
- # Raised when a CachedCookbook has a license file that isn't allowed
411
- # by the Berksfile.
412
- #
413
- # @param [Berkshelf::CachedCookbook] cookbook
414
- # the cookbook that failed license validation
415
- class LicenseNotAllowed < BerkshelfError
416
- status_code(133)
417
-
418
- def initialize(cookbook)
419
- @cookbook = cookbook
420
- end
421
-
422
- def to_s
423
- msg = "'#{@cookbook.cookbook_name}' has a license of '#{@cookbook.metadata.license}', but"
424
- msg << " '#{@cookbook.metadata.license}' is not in your list of allowed licenses"
425
- msg
426
- end
427
- end
428
-
429
328
  class LicenseNotFound < BerkshelfError
430
329
  status_code(134)
431
330
 
@@ -437,7 +336,7 @@ module Berkshelf
437
336
 
438
337
  def to_s
439
338
  "Unknown license: '#{license}'\n" +
440
- "Available licenses: #{Berkshelf::CookbookGenerator::LICENSES.join(', ')}"
339
+ "Available licenses: #{CookbookGenerator::LICENSES.join(', ')}"
441
340
  end
442
341
  end
443
342
 
@@ -480,16 +379,15 @@ module Berkshelf
480
379
  class InvalidSourceURI < BerkshelfError
481
380
  status_code(137)
482
381
 
483
- attr_reader :reason
484
-
485
382
  def initialize(url, reason = nil)
486
383
  @url = url
487
384
  @reason = reason
488
385
  end
489
386
 
490
387
  def to_s
491
- msg = "'#{@url}' is not a valid Berkshelf source URI."
492
- msg + " #{reason}." unless reason.nil?
388
+ msg = "'#{@url}' is not a valid Berkshelf source URI."
389
+ msg << " #{@reason}." unless @reason.nil?
390
+ msg
493
391
  end
494
392
  end
495
393
 
@@ -513,11 +411,11 @@ module Berkshelf
513
411
  end
514
412
 
515
413
  def to_s
516
- "#{@path} does not appear to be a valid cookbook. Does it have a `metadata.rb`?"
414
+ "The resource at '#{@path}' does not appear to be a valid cookbook. " \
415
+ "Does it have a metadata.rb?"
517
416
  end
518
417
  end
519
418
 
520
- class InvalidLockFile < BerkshelfError; status_code(142); end
521
419
  class PackageError < BerkshelfError; status_code(143); end
522
420
 
523
421
  class LockfileOutOfSync < BerkshelfError
@@ -532,25 +430,26 @@ module Berkshelf
532
430
  status_code(145)
533
431
 
534
432
  def initialize(dependency)
535
- name = dependency.name
536
- version = dependency.locked_version
433
+ @name = dependency.name
434
+ @version = dependency.locked_version
435
+ end
537
436
 
538
- super "The cookbook '#{name} (#{version})' is not installed. Please " \
539
- "run `berks install` to download and install the missing " \
540
- "dependency."
437
+ def to_s
438
+ "The cookbook '#{@name} (#{@version})' is not installed. Please run " \
439
+ "`berks install` to download and install the missing dependency."
541
440
  end
542
441
  end
543
442
 
544
443
  class NoAPISourcesDefined < BerkshelfError
545
444
  status_code(146)
546
445
 
547
- def initialize
548
- super "Your Berksfile does not define any API sources! You must define " \
549
- "at least one source in order to download cookbooks. To add the " \
550
- "default Berkshelf API server, add the following code to the top of " \
551
- "your Berksfile:" \
552
- "\n\n" \
553
- " source 'https://api.berkshelf.com'"
446
+ def to_s
447
+ "Your Berksfile does not define any API sources! You must define " \
448
+ "at least one source in order to download cookbooks. To add the " \
449
+ "default Berkshelf API server, add the following code to the top of " \
450
+ "your Berksfile:" \
451
+ "\n\n" \
452
+ " source 'https://api.berkshelf.com'"
554
453
  end
555
454
  end
556
455
  end