berkshelf 3.0.0.beta1 → 3.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
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