berkshelf 3.0.0.beta1 → 3.0.0.beta2

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.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -1
  3. data/CONTRIBUTING.md +2 -0
  4. data/LICENSE +1 -1
  5. data/README.md +1 -1
  6. data/Thorfile +2 -2
  7. data/berkshelf.gemspec +3 -3
  8. data/features/install_command.feature +36 -8
  9. data/features/json_formatter.feature +93 -3
  10. data/features/licenses.feature +1 -1
  11. data/features/lockfile.feature +0 -12
  12. data/features/outdated_command.feature +124 -0
  13. data/features/show_command.feature +44 -25
  14. data/features/step_definitions/chef/config_steps.rb +2 -2
  15. data/features/step_definitions/chef_server_steps.rb +9 -1
  16. data/features/step_definitions/config_steps.rb +1 -1
  17. data/features/step_definitions/filesystem_steps.rb +7 -0
  18. data/features/support/env.rb +2 -1
  19. data/features/update_command.feature +11 -21
  20. data/features/upload_command.feature +45 -1
  21. data/features/vendor_command.feature +83 -0
  22. data/lib/berkshelf.rb +5 -4
  23. data/lib/berkshelf/api_client/remote_cookbook.rb +13 -0
  24. data/lib/berkshelf/berksfile.rb +155 -23
  25. data/lib/berkshelf/chef.rb +0 -1
  26. data/lib/berkshelf/cli.rb +40 -31
  27. data/lib/berkshelf/dependency.rb +14 -4
  28. data/lib/berkshelf/errors.rb +74 -3
  29. data/lib/berkshelf/formatters.rb +12 -1
  30. data/lib/berkshelf/formatters/human_readable.rb +44 -5
  31. data/lib/berkshelf/formatters/json.rb +50 -8
  32. data/lib/berkshelf/installer.rb +8 -8
  33. data/lib/berkshelf/location.rb +17 -0
  34. data/lib/berkshelf/locations/git_location.rb +7 -17
  35. data/lib/berkshelf/locations/mercurial_location.rb +112 -0
  36. data/lib/berkshelf/lockfile.rb +1 -1
  37. data/lib/berkshelf/mercurial.rb +146 -0
  38. data/lib/berkshelf/version.rb +1 -1
  39. data/spec/config/knife.rb +2 -4
  40. data/spec/fixtures/lockfiles/default.lock +0 -1
  41. data/spec/support/chef_api.rb +9 -2
  42. data/spec/support/mercurial.rb +122 -0
  43. data/spec/support/path_helpers.rb +2 -2
  44. data/spec/unit/berkshelf/berksfile_spec.rb +34 -8
  45. data/spec/unit/berkshelf/dependency_spec.rb +0 -7
  46. data/spec/unit/berkshelf/formatters/null_spec.rb +1 -1
  47. data/spec/unit/berkshelf/locations/mercurial_location_spec.rb +150 -0
  48. data/spec/unit/berkshelf/lockfile_spec.rb +0 -12
  49. data/spec/unit/berkshelf/mercurial_spec.rb +173 -0
  50. metadata +32 -110
  51. data/lib/berkshelf/chef/config.rb +0 -68
  52. data/lib/berkshelf/mixin/config.rb +0 -172
  53. data/spec/fixtures/cookbooks/example_metadata_name/metadata.rb +0 -2
  54. data/spec/fixtures/cookbooks/example_metadata_no_name/metadata.rb +0 -1
  55. data/spec/fixtures/cookbooks/example_no_metadata/recipes/default.rb +0 -1
  56. data/spec/fixtures/cookbooks/nginx-0.100.5/README.md +0 -77
  57. data/spec/fixtures/cookbooks/nginx-0.100.5/attributes/default.rb +0 -65
  58. data/spec/fixtures/cookbooks/nginx-0.100.5/definitions/nginx_site.rb +0 -35
  59. data/spec/fixtures/cookbooks/nginx-0.100.5/files/default/mime.types +0 -73
  60. data/spec/fixtures/cookbooks/nginx-0.100.5/files/ubuntu/mime.types +0 -73
  61. data/spec/fixtures/cookbooks/nginx-0.100.5/libraries/nginxlib.rb +0 -1
  62. data/spec/fixtures/cookbooks/nginx-0.100.5/metadata.rb +0 -91
  63. data/spec/fixtures/cookbooks/nginx-0.100.5/providers/defprovider.rb +0 -1
  64. data/spec/fixtures/cookbooks/nginx-0.100.5/recipes/default.rb +0 -59
  65. data/spec/fixtures/cookbooks/nginx-0.100.5/resources/defresource.rb +0 -1
  66. data/spec/fixtures/cookbooks/nginx-0.100.5/templates/default/nginx.pill.erb +0 -15
  67. data/spec/fixtures/cookbooks/nginx-0.100.5/templates/default/plugins/nginx.rb.erb +0 -66
  68. data/spec/fixtures/lockfile_spec/with_lock/Berksfile +0 -1
  69. data/spec/fixtures/lockfile_spec/without_lock/.gitkeep +0 -0
  70. data/spec/fixtures/reset.pem +0 -27
  71. data/spec/unit/chef/config_spec.rb +0 -81
@@ -40,7 +40,7 @@ module Berkshelf
40
40
  #
41
41
  # @return [Bershelf::Chef::Config]
42
42
  def chef_config
43
- Berkshelf::Chef::Config.from_file(chef_config_path)
43
+ Ridley::Chef::Config.from_file(chef_config_path)
44
44
  end
45
45
 
46
46
  def clean_tmp_path
@@ -58,7 +58,7 @@ module Berkshelf
58
58
  Berkshelf.chef_config = chef_config
59
59
 
60
60
  # This fucking sucks...
61
- load 'berkshelf/chef/config.rb'
61
+ # load 'berkshelf/chef/config.rb'
62
62
  load 'berkshelf/config.rb'
63
63
 
64
64
  Berkshelf.config = Berkshelf::Config.new
@@ -269,10 +269,6 @@ describe Berkshelf::Berksfile do
269
269
  end
270
270
  end
271
271
 
272
- describe "#install" do
273
- pending
274
- end
275
-
276
272
  describe '#add_dependency' do
277
273
  let(:name) { 'cookbook_one' }
278
274
  let(:constraint) { '= 1.2.0' }
@@ -335,6 +331,36 @@ describe Berkshelf::Berksfile do
335
331
  end
336
332
  end
337
333
 
334
+ describe '#retrieve_locked' do
335
+ let(:lockfile) { double('lockfile', find: locked) }
336
+ let(:locked) { double('locked', cached_cookbook: cached, locked_version: '1.0.0') }
337
+ let(:cached) { double('cached') }
338
+
339
+ before do
340
+ subject.stub(:validate_cookbook_names!)
341
+ subject.stub(:lockfile).and_return(lockfile)
342
+ end
343
+
344
+ it 'validates cookbook names' do
345
+ expect(subject).to receive(:validate_cookbook_names!).once
346
+ subject.retrieve_locked('bacon')
347
+ end
348
+
349
+ it 'raises an error when the lockfile does not exist' do
350
+ lockfile.stub(:find)
351
+ expect {
352
+ subject.retrieve_locked('bacon')
353
+ }.to raise_error(Berkshelf::LockfileNotFound)
354
+ end
355
+
356
+ it 'raises an error when the cookbook is not downloaded' do
357
+ locked.stub(:cached_cookbook)
358
+ expect {
359
+ subject.retrieve_locked('bacon')
360
+ }.to raise_error(Berkshelf::CookbookNotFound)
361
+ end
362
+ end
363
+
338
364
  describe '#upload' do
339
365
  let(:options) { Hash.new }
340
366
  let(:chef_config) do
@@ -428,8 +454,8 @@ describe Berkshelf::Berksfile do
428
454
  describe "#apply" do
429
455
  let(:env_name) { 'berkshelf-test' }
430
456
  let(:server_url) { Berkshelf::RSpec::ChefServer.server_url }
431
- let(:client_name) { 'reset' }
432
- let(:client_key) { fixtures_path.join('reset.pem').to_s }
457
+ let(:client_name) { 'berkshelf' }
458
+ let(:client_key) { fixtures_path.join('../config/berkshelf.pem').to_s }
433
459
  let(:ridley) { Ridley.new(server_url: server_url, client_name: client_name, client_key: client_key) }
434
460
 
435
461
  before do
@@ -525,14 +551,14 @@ describe Berkshelf::Berksfile do
525
551
  Dir.stub(:glob).and_return(['/there are/spaces/in this/recipes/default.rb'])
526
552
  expect {
527
553
  subject.validate_files!(cookbook)
528
- }.to raise_error(Berkshelf::InvalidCookbookFiles)
554
+ }.to raise_error
529
555
  end
530
556
 
531
557
  it 'does not raise an error when the cookbook is valid' do
532
558
  Dir.stub(:glob).and_return(['/there-are/no-spaces/in-this/recipes/default.rb'])
533
559
  expect {
534
560
  subject.validate_files!(cookbook)
535
- }.to_not raise_error(Berkshelf::InvalidCookbookFiles)
561
+ }.to_not raise_error
536
562
  end
537
563
 
538
564
  it 'does not raise an exception with spaces in the path' do
@@ -214,13 +214,6 @@ describe Berkshelf::Dependency do
214
214
  end
215
215
  end
216
216
 
217
- it 'includes the constraint' do
218
- subject.version_constraint = '~> 1.0.0'
219
-
220
- expect(hash).to have_key(:constraint)
221
- expect(hash[:constraint]).to eq('~> 1.0.0')
222
- end
223
-
224
217
  it 'includes the locked version' do
225
218
  subject.stub(cached_cookbook: double('cached', version: '1.2.3'))
226
219
 
@@ -7,7 +7,7 @@ describe Berkshelf::Formatters::Null do
7
7
  it "does not raise an error for :#{meth}" do
8
8
  expect {
9
9
  subject.send(meth)
10
- }.to_not raise_error(Berkshelf::AbstractFunction)
10
+ }.to_not raise_error
11
11
  end
12
12
 
13
13
  it "returns nil for :#{meth}" do
@@ -0,0 +1,150 @@
1
+ require 'spec_helper'
2
+
3
+ describe Berkshelf::MercurialLocation do
4
+
5
+ include Berkshelf::RSpec::Mercurial
6
+
7
+ let(:cookbook_uri) { mercurial_origin_for('fake_cookbook', is_cookbook: true, tags: ["1.0.0"], branches: ["mybranch"]) }
8
+ let(:constraint) { double('comp-vconstraint', satisfies?: true) }
9
+ let(:dependency) { double('dep', name: "berkshelf-cookbook-fixture", version_constraint: constraint) }
10
+ let(:storage_path) { Berkshelf::CookbookStore.instance.storage_path }
11
+
12
+ describe '.initialize' do
13
+ it 'raises InvalidHgURI if given an invalid URI for options[:hg]' do
14
+ expect {
15
+ described_class.new(dependency, hg: '/something/on/disk')
16
+ }.to raise_error(Berkshelf::InvalidHgURI)
17
+ end
18
+ end
19
+
20
+ describe '.tmpdir' do
21
+ it 'creates a temporary directory within the Berkshelf temporary directory' do
22
+ expect(described_class.tmpdir).to include(Berkshelf.tmp_dir)
23
+ end
24
+ end
25
+
26
+ subject { described_class.new(dependency, hg: cookbook_uri) }
27
+
28
+ describe '#download' do
29
+
30
+ before() do
31
+ # recreate the fake repo
32
+ clean_tmp_path
33
+ FileUtils.mkdir_p(storage_path)
34
+ cookbook_uri
35
+ end
36
+
37
+ context 'when a local revision is present' do
38
+ let(:cached) { double('cached') }
39
+
40
+ before do
41
+ Berkshelf::Mercurial.stub(:rev_parse).and_return('abcd1234')
42
+ described_class.any_instance.stub(:cached?).and_return(true)
43
+ described_class.any_instance.stub(:validate_cached).with(cached).and_return(cached)
44
+ Berkshelf::CachedCookbook.stub(:from_store_path).with(any_args()).and_return(cached)
45
+ end
46
+
47
+ it 'returns the cached cookbook' do
48
+ expect(subject.download).to eq(cached)
49
+ end
50
+ end
51
+
52
+ it 'returns an instance of Berkshelf::CachedCookbook' do
53
+ expect(subject.download).to be_a(Berkshelf::CachedCookbook)
54
+ end
55
+
56
+ it 'downloads the cookbook to the given destination' do
57
+ cached_cookbook = subject.download
58
+ rev = subject.rev
59
+
60
+ expect(storage_path).to have_structure {
61
+ directory "#{cached_cookbook.cookbook_name}-#{rev}" do
62
+ file 'metadata.rb'
63
+ end
64
+ }
65
+ end
66
+
67
+ context 'given no ref/branch/tag options is given' do
68
+ subject { described_class.new(dependency, hg: cookbook_uri) }
69
+
70
+ it 'sets the branch attribute to the default revision of the cloned repo' do
71
+ subject.download
72
+ expect(subject.branch).to_not be_nil
73
+ end
74
+ end
75
+
76
+ context 'given a repo that does not exist' do
77
+ before { dependency.stub(name: "doesnot_exist") }
78
+ subject { described_class.new(dependency, hg: 'http://thisdoesntexist.org/notarepo') }
79
+
80
+ it 'raises a MercurailError' do
81
+ Berkshelf::Mercurial.stub(:hg).and_raise(Berkshelf::MercurialError.new(''))
82
+ expect {
83
+ subject.download
84
+ }.to raise_error(Berkshelf::MercurialError)
85
+ end
86
+ end
87
+
88
+ context 'given a hg repo that does not contain a cookbook' do
89
+ let(:fake_remote) { mercurial_origin_for('not_a_cookbook', is_cookbook: false) }
90
+ subject { described_class.new(dependency, hg: fake_remote) }
91
+
92
+ it 'raises a CookbookNotFound error' do
93
+ expect {
94
+ subject.download
95
+ }.to raise_error(Berkshelf::CookbookNotFound)
96
+ end
97
+ end
98
+
99
+ context 'given the content at the repo does not satisfy the version constraint' do
100
+ before { constraint.stub(satisfies?: false) }
101
+ subject do
102
+ described_class.new(dependency,
103
+ hg: cookbook_uri
104
+ )
105
+ end
106
+
107
+ it 'raises a CookbookValidationFailure error' do
108
+ expect {
109
+ subject.download
110
+ }.to raise_error(Berkshelf::CookbookValidationFailure)
111
+ end
112
+ end
113
+
114
+ context 'given a value for tag' do
115
+ let(:tag) { '1.0.0' }
116
+
117
+ subject do
118
+ described_class.new(dependency,
119
+ hg: cookbook_uri,
120
+ tag: tag
121
+ )
122
+ end
123
+ let(:cached) { subject.download }
124
+ let(:sha) { subject.rev }
125
+ let(:expected_path) { storage_path.join("#{cached.cookbook_name}-#{sha}") }
126
+
127
+ it 'returns a cached cookbook with a path that contains the ref' do
128
+ expect(cached.path).to eq(expected_path)
129
+ end
130
+ end
131
+
132
+ context 'give a value for branch' do
133
+ let(:branch) { 'mybranch' }
134
+
135
+ subject do
136
+ described_class.new(dependency,
137
+ hg: cookbook_uri,
138
+ branch: branch
139
+ )
140
+ end
141
+ let(:cached) { subject.download }
142
+ let(:sha) { subject.rev }
143
+ let(:expected_path) { storage_path.join("#{cached.cookbook_name}-#{sha}") }
144
+
145
+ it 'returns a cached cookbook with a path that contains the ref' do
146
+ expect(cached.path).to eq(expected_path)
147
+ end
148
+ end
149
+ end
150
+ end
@@ -100,18 +100,6 @@ describe Berkshelf::Lockfile do
100
100
  end
101
101
  end
102
102
 
103
- describe '#to_s' do
104
- it 'returns a pretty-formatted string' do
105
- expect(subject.to_s).to eq '#<Berkshelf::Lockfile Berksfile.lock>'
106
- end
107
- end
108
-
109
- describe '#inspect' do
110
- it 'returns a pretty-formatted, detailed string' do
111
- expect(subject.inspect).to eq("#<#{described_class} Berksfile.lock, dependencies: [#<Berkshelf::Dependency: build-essential (>= 0.0.0), locked_version: 1.1.2, groups: [:default], location: default>, #<Berkshelf::Dependency: chef-client (>= 0.0.0), locked_version: 2.1.4, groups: [:default], location: default>]>")
112
- end
113
- end
114
-
115
103
  describe '#to_hash' do
116
104
  let(:hash) { subject.to_hash }
117
105
 
@@ -0,0 +1,173 @@
1
+ require 'spec_helper'
2
+
3
+ describe Berkshelf::Mercurial do
4
+
5
+ include Berkshelf::RSpec::Mercurial
6
+
7
+ let(:hg) { Berkshelf::Mercurial }
8
+
9
+ describe '.find_hg' do
10
+ it 'finds hg' do
11
+ expect(described_class.find_hg).to_not be_nil
12
+ end
13
+
14
+ it 'raises an error if mercurial cannot be not found' do
15
+ ENV.should_receive(:[]).with('PATH').and_return(String.new)
16
+
17
+ expect {
18
+ described_class.find_hg
19
+ }.to raise_error(Berkshelf::MercurialNotFound)
20
+ end
21
+ end
22
+
23
+ describe '.clone' do
24
+ let(:target) { clone_path('nginx') }
25
+
26
+ it 'clones the repository to the target path' do
27
+ origin_uri = mercurial_origin_for('nginx')
28
+
29
+ described_class.clone(origin_uri, target)
30
+
31
+ expect(target).to exist
32
+ expect(target).to be_directory
33
+ end
34
+ end
35
+
36
+ describe '.checkout' do
37
+ let(:repo_path) { clone_path('nginx') }
38
+ let(:repo) {
39
+ origin_uri = mercurial_origin_for('nginx', tags: ['1.0.1', '1.0.2'], branches: ['topic', 'next_topic'])
40
+ hg.clone(origin_uri, repo_path)
41
+ }
42
+
43
+ shared_examples 'able to checkout hg rev' do |test_rev|
44
+ it 'checks out the specified rev of the given repository' do
45
+ hg.checkout(repo, rev)
46
+
47
+ Dir.chdir repo_path do
48
+ test_rev ||= rev
49
+ expect(%x[hg id -r #{test_rev}].split(' ').first).to eq(%x[hg id -i].strip)
50
+ end
51
+ end
52
+ end
53
+
54
+ context 'with sha commit id' do
55
+ let(:rev) { id_for_rev('nginx', '1.0.1') }
56
+
57
+ it_behaves_like 'able to checkout hg rev'
58
+ end
59
+
60
+ context 'with tags' do
61
+ let(:rev) { '1.0.1' }
62
+
63
+ it_behaves_like 'able to checkout hg rev'
64
+
65
+ context 'after checking out another tag' do
66
+ let(:other_tag) { '1.0.2' }
67
+ before do
68
+ hg.checkout(repo, other_tag)
69
+ Dir.chdir repo_path do
70
+ shell_out "echo 'uncommitted change' >> content_file"
71
+ end
72
+ end
73
+
74
+ it_behaves_like 'able to checkout hg rev'
75
+ end
76
+ end
77
+
78
+ context 'with branches' do
79
+ let(:rev) { 'topic' }
80
+
81
+ it_behaves_like 'able to checkout hg rev', 'topic'
82
+
83
+ context 'after checking out another branch' do
84
+ let(:other_branch) { 'next_topic' }
85
+ before do
86
+ hg.checkout(repo, other_branch)
87
+ Dir.chdir repo_path do
88
+ shell_out "echo 'uncommitted change' >> content_file"
89
+ end
90
+ end
91
+
92
+ it_behaves_like 'able to checkout hg rev', 'topic'
93
+ end
94
+ end
95
+ end
96
+
97
+ describe '.rev_parse' do
98
+ let(:repo_path) { clone_path('nginx') }
99
+
100
+ before(:each) do
101
+ origin_uri = mercurial_origin_for('nginx', tags: ['1.1.1'])
102
+ described_class.clone(origin_uri, repo_path)
103
+ described_class.checkout(repo_path, id_for_rev('nginx', '1.1.1'))
104
+ end
105
+
106
+ it 'returns the ref for HEAD' do
107
+ rev = described_class.rev_parse(repo_path)
108
+ ref = id_for_rev('nginx', '1.1.1')
109
+
110
+ expect(rev).to eql(ref)
111
+ end
112
+ end
113
+
114
+ let(:https_uri) { 'https://hghub.com/reset/' }
115
+ let(:http_uri) { 'http://hghub.com/reset/' }
116
+ let(:invalid_uri) { '/something/on/disk' }
117
+
118
+ describe '.validate_uri' do
119
+ context 'given an invalid URI' do
120
+ it 'returns false' do
121
+ expect(described_class.validate_uri(invalid_uri)).to be_false
122
+ end
123
+ end
124
+
125
+ context 'given a HTTP URI' do
126
+ it 'returns true' do
127
+ expect(described_class.validate_uri(http_uri)).to be_true
128
+ end
129
+ end
130
+
131
+ context 'given a valid HTTPS URI' do
132
+ it 'returns true' do
133
+ expect(described_class.validate_uri(https_uri)).to be_true
134
+ end
135
+ end
136
+
137
+ context 'given an integer' do
138
+ it 'returns false' do
139
+ expect(described_class.validate_uri(123)).to be_false
140
+ end
141
+ end
142
+ end
143
+
144
+ describe '.validate_uri!' do
145
+ context 'given an invalid URI' do
146
+ it 'raises InvalidHgURI' do
147
+ expect {
148
+ described_class.validate_uri!(invalid_uri)
149
+ }.to raise_error(Berkshelf::InvalidHgURI)
150
+ end
151
+ end
152
+
153
+ context 'given a HTTP URI' do
154
+ it 'raises InvalidHgURI' do
155
+ expect(described_class.validate_uri!(http_uri)).to be_true
156
+ end
157
+ end
158
+
159
+ context 'given a valid HTTPS URI' do
160
+ it 'returns true' do
161
+ expect(described_class.validate_uri!(https_uri)).to be_true
162
+ end
163
+ end
164
+
165
+ context 'given an integer' do
166
+ it 'raises InvalidHgURI' do
167
+ expect {
168
+ described_class.validate_uri!(123)
169
+ }.to raise_error(Berkshelf::InvalidHgURI)
170
+ end
171
+ end
172
+ end
173
+ end