berkshelf 3.1.5 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/berkshelf.gemspec +6 -5
  4. data/features/commands/search.feature +2 -2
  5. data/features/commands/vendor.feature +6 -2
  6. data/features/commands/verify.feature +29 -0
  7. data/features/config.feature +13 -48
  8. data/features/step_definitions/filesystem_steps.rb +2 -2
  9. data/features/step_definitions/gem_steps.rb +3 -1
  10. data/features/step_definitions/utility_steps.rb +2 -2
  11. data/generator_files/Vagrantfile.erb +30 -30
  12. data/generator_files/metadata.rb.erb +0 -1
  13. data/lib/berkshelf.rb +5 -2
  14. data/lib/berkshelf/berksfile.rb +41 -41
  15. data/lib/berkshelf/cli.rb +11 -1
  16. data/lib/berkshelf/community_rest.rb +1 -0
  17. data/lib/berkshelf/config.rb +18 -4
  18. data/lib/berkshelf/cookbook_store.rb +1 -1
  19. data/lib/berkshelf/downloader.rb +4 -0
  20. data/lib/berkshelf/errors.rb +0 -1
  21. data/lib/berkshelf/file_syncer.rb +134 -0
  22. data/lib/berkshelf/locations/base.rb +6 -1
  23. data/lib/berkshelf/locations/git.rb +2 -2
  24. data/lib/berkshelf/lockfile.rb +14 -2
  25. data/lib/berkshelf/uploader.rb +10 -17
  26. data/lib/berkshelf/validator.rb +37 -0
  27. data/lib/berkshelf/version.rb +1 -1
  28. data/lib/berkshelf/visualizer.rb +13 -6
  29. data/spec/spec_helper.rb +1 -1
  30. data/spec/support/kitchen.rb +3 -1
  31. data/spec/support/matchers/file_system_matchers.rb +1 -1
  32. data/spec/support/matchers/filepath_matchers.rb +38 -2
  33. data/spec/support/shared_examples/formatter.rb +7 -7
  34. data/spec/unit/berkshelf/berksfile_spec.rb +51 -21
  35. data/spec/unit/berkshelf/cached_cookbook_spec.rb +5 -5
  36. data/spec/unit/berkshelf/cli_spec.rb +1 -1
  37. data/spec/unit/berkshelf/community_rest_spec.rb +12 -12
  38. data/spec/unit/berkshelf/config_spec.rb +4 -4
  39. data/spec/unit/berkshelf/cookbook_generator_spec.rb +2 -2
  40. data/spec/unit/berkshelf/cookbook_store_spec.rb +6 -6
  41. data/spec/unit/berkshelf/core_ext/file_utils_spec.rb +3 -3
  42. data/spec/unit/berkshelf/core_ext/pathname_spec.rb +23 -6
  43. data/spec/unit/berkshelf/dependency_spec.rb +4 -4
  44. data/spec/unit/berkshelf/downloader_spec.rb +5 -1
  45. data/spec/unit/berkshelf/errors_spec.rb +1 -1
  46. data/spec/unit/berkshelf/file_syncer_spec.rb +206 -0
  47. data/spec/unit/berkshelf/init_generator_spec.rb +19 -22
  48. data/spec/unit/berkshelf/installer_spec.rb +6 -6
  49. data/spec/unit/berkshelf/locations/base_spec.rb +17 -8
  50. data/spec/unit/berkshelf/locations/git_spec.rb +34 -34
  51. data/spec/unit/berkshelf/locations/path_spec.rb +3 -3
  52. data/spec/unit/berkshelf/lockfile_parser_spec.rb +1 -1
  53. data/spec/unit/berkshelf/lockfile_spec.rb +50 -36
  54. data/spec/unit/berkshelf/packager_spec.rb +6 -4
  55. data/spec/unit/berkshelf/resolver/graph_spec.rb +3 -3
  56. data/spec/unit/berkshelf/resolver_spec.rb +3 -3
  57. data/spec/unit/berkshelf/shell_spec.rb +30 -24
  58. data/spec/unit/berkshelf/uploader_spec.rb +10 -36
  59. data/spec/unit/berkshelf/validator_spec.rb +30 -0
  60. data/spec/unit/berkshelf/visualizer_spec.rb +17 -2
  61. metadata +34 -15
  62. data/lib/berkshelf/mixin/dsl_eval.rb +0 -58
  63. data/spec/unit/berkshelf/mixin/dsl_eval_spec.rb +0 -55
@@ -7,9 +7,9 @@ describe FileUtils do
7
7
  let(:options) { double('options') }
8
8
 
9
9
  it 'replaces mv with cp_r and rm_rf' do
10
- subject.stub(:windows?) { true }
11
- FileUtils.should_receive(:cp_r).with(src, dest, options)
12
- FileUtils.should_receive(:rm_rf).with(src)
10
+ allow(subject).to receive(:windows?) { true }
11
+ expect(FileUtils).to receive(:cp_r).with(src, dest, options)
12
+ expect(FileUtils).to receive(:rm_rf).with(src)
13
13
 
14
14
  FileUtils.mv(src, dest, options)
15
15
  end
@@ -10,17 +10,26 @@ describe Pathname do
10
10
 
11
11
  context "when the path contains a metadata.json file" do
12
12
  before { FileUtils.touch(metadata_json) }
13
- its(:cookbook?) { should be_true }
13
+
14
+ it "is a cookbook" do
15
+ expect(subject.cookbook?).to be(true)
16
+ end
14
17
  end
15
18
 
16
19
  context "when the path contains a metadata.rb file" do
17
20
  before { FileUtils.touch(metadata_rb) }
18
- its(:cookbook?) { should be_true }
21
+
22
+ it "is a cookbook" do
23
+ expect(subject.cookbook?).to be(true)
24
+ end
19
25
  end
20
26
 
21
27
  context "when the path does not contain a metadata.json or metadata.rb file" do
22
28
  before { FileUtils.rm_f(metadata_rb) && FileUtils.rm_f(metadata_json) }
23
- its(:cookbook?) { should be_false }
29
+
30
+ it "is not a cookbook" do
31
+ expect(subject.cookbook?).to be(false)
32
+ end
24
33
  end
25
34
  end
26
35
 
@@ -30,17 +39,25 @@ describe Pathname do
30
39
  subject { Pathname.new(cookbook_path) }
31
40
 
32
41
  context "when in the root of a cookbook" do
33
- its(:cookbook_root) { should eql(root_path) }
42
+ it "has the correct root" do
43
+ expect(subject.cookbook_root).to eq(root_path)
44
+ end
34
45
  end
35
46
 
36
47
  context "when in the structure of a cookbook" do
37
48
  let(:cookbook_path) { root_path.join("recipes") }
38
- its(:cookbook_root) { should eql(root_path) }
49
+
50
+ it "has the correct root" do
51
+ expect(subject.cookbook_root).to eq(root_path)
52
+ end
39
53
  end
40
54
 
41
55
  context "when not within the structure of a cookbook" do
42
56
  let(:cookbook_path) { "/" }
43
- its(:cookbook_root) { should be_nil }
57
+
58
+ it "has the correct root" do
59
+ expect(subject.cookbook_root).to be(nil)
60
+ end
44
61
  end
45
62
  end
46
63
  end
@@ -121,13 +121,13 @@ describe Berkshelf::Dependency do
121
121
 
122
122
  describe '#installed?' do
123
123
  it 'returns true if self.cached_cookbook is not nil' do
124
- subject.stub(:cached_cookbook) { double('cb') }
125
- expect(subject.installed?).to be_true
124
+ allow(subject).to receive(:cached_cookbook) { double('cb') }
125
+ expect(subject.installed?).to be(true)
126
126
  end
127
127
 
128
128
  it 'returns false if self.cached_cookbook is nil' do
129
- subject.stub(:cached_cookbook) { nil }
130
- expect(subject.installed?).to be_false
129
+ allow(subject).to receive(:cached_cookbook) { nil }
130
+ expect(subject.installed?).to be(false)
131
131
  end
132
132
  end
133
133
  end
@@ -5,7 +5,7 @@ describe Berkshelf::Downloader do
5
5
  subject { described_class.new(berksfile) }
6
6
 
7
7
  describe "#download" do
8
- pending
8
+ skip
9
9
  end
10
10
 
11
11
  describe "#try_download" do
@@ -35,5 +35,9 @@ describe Berkshelf::Downloader do
35
35
  expect(rest).to receive(:download).with(name, version)
36
36
  subject.try_download(source, name, version)
37
37
  end
38
+
39
+ it "supports the 'file_store' location type" do
40
+ skip
41
+ end
38
42
  end
39
43
  end
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Berkshelf::BerkshelfError do
4
- pending
4
+ skip
5
5
  end
@@ -0,0 +1,206 @@
1
+ require 'spec_helper'
2
+
3
+ module Berkshelf
4
+ describe FileSyncer do
5
+ describe '#glob' do
6
+ before do
7
+ FileUtils.mkdir_p(File.join(tmp_path, 'folder'))
8
+ FileUtils.mkdir_p(File.join(tmp_path, '.hidden_folder'))
9
+
10
+ FileUtils.touch(File.join(tmp_path, 'folder', 'file'))
11
+ FileUtils.touch(File.join(tmp_path, '.hidden_file'))
12
+ end
13
+
14
+ let(:list) do
15
+ described_class
16
+ .glob("#{tmp_path}/**/*")
17
+ .map { |item| item.sub("#{tmp_path}/", '') }
18
+ end
19
+
20
+ it 'includes regular files' do
21
+ expect(list).to include('folder')
22
+ expect(list).to include('folder/file')
23
+ end
24
+
25
+ it 'ignores .' do
26
+ expect(list).to_not include('.')
27
+ end
28
+
29
+ it 'ignores ..' do
30
+ expect(list).to_not include('..')
31
+ end
32
+
33
+ it 'includes hidden files' do
34
+ expect(list).to include('.hidden_file')
35
+ end
36
+
37
+ it 'includes hidden folders' do
38
+ expect(list).to include('.hidden_folder')
39
+ end
40
+ end
41
+
42
+ describe '#sync' do
43
+ let(:source) do
44
+ source = File.join(tmp_path, 'source')
45
+ FileUtils.mkdir_p(source)
46
+
47
+ FileUtils.touch(File.join(source, 'file_a'))
48
+ FileUtils.touch(File.join(source, 'file_b'))
49
+ FileUtils.touch(File.join(source, 'file_c'))
50
+
51
+ FileUtils.mkdir_p(File.join(source, 'folder'))
52
+ FileUtils.touch(File.join(source, 'folder', 'file_d'))
53
+ FileUtils.touch(File.join(source, 'folder', 'file_e'))
54
+
55
+ FileUtils.mkdir_p(File.join(source, '.dot_folder'))
56
+ FileUtils.touch(File.join(source, '.dot_folder', 'file_f'))
57
+
58
+ FileUtils.touch(File.join(source, '.file_g'))
59
+ source
60
+ end
61
+
62
+ let(:destination) { File.join(tmp_path, 'destination') }
63
+
64
+ context 'when the destination is empty' do
65
+ it 'syncs the directories' do
66
+ described_class.sync(source, destination)
67
+
68
+ expect("#{destination}/file_a").to be_a_file
69
+ expect("#{destination}/file_b").to be_a_file
70
+ expect("#{destination}/file_c").to be_a_file
71
+ expect("#{destination}/folder/file_d").to be_a_file
72
+ expect("#{destination}/folder/file_e").to be_a_file
73
+ expect("#{destination}/.dot_folder/file_f").to be_a_file
74
+ expect("#{destination}/.file_g").to be_a_file
75
+ end
76
+ end
77
+
78
+ context 'when the directory exists' do
79
+ before { FileUtils.mkdir_p(destination) }
80
+
81
+ it 'deletes existing files and folders' do
82
+ FileUtils.mkdir_p("#{destination}/existing_folder")
83
+ FileUtils.mkdir_p("#{destination}/.existing_folder")
84
+ FileUtils.touch("#{destination}/existing_file")
85
+ FileUtils.touch("#{destination}/.existing_file")
86
+
87
+ described_class.sync(source, destination)
88
+
89
+ expect("#{destination}/file_a").to be_a_file
90
+ expect("#{destination}/file_b").to be_a_file
91
+ expect("#{destination}/file_c").to be_a_file
92
+ expect("#{destination}/folder/file_d").to be_a_file
93
+ expect("#{destination}/folder/file_e").to be_a_file
94
+ expect("#{destination}/.dot_folder/file_f").to be_a_file
95
+ expect("#{destination}/.file_g").to be_a_file
96
+
97
+ expect("#{destination}/existing_folder").to_not be_a_directory
98
+ expect("#{destination}/.existing_folder").to_not be_a_directory
99
+ expect("#{destination}/existing_file").to_not be_a_file
100
+ expect("#{destination}/.existing_file").to_not be_a_file
101
+ end
102
+ end
103
+
104
+ context 'with deeply nested paths and symlinks' do
105
+ let(:source) do
106
+ source = File.join(tmp_path, 'source')
107
+ FileUtils.mkdir_p(source)
108
+
109
+ FileUtils.mkdir_p(File.join(source, 'bin'))
110
+ FileUtils.touch(File.join(source, 'bin', 'apt'))
111
+ FileUtils.touch(File.join(source, 'bin', 'yum'))
112
+
113
+ FileUtils.touch(File.join(source, 'LICENSE'))
114
+
115
+ FileUtils.mkdir_p(File.join(source, 'include'))
116
+ FileUtils.mkdir_p(File.join(source, 'include', 'linux'))
117
+ FileUtils.touch(File.join(source, 'include', 'linux', 'init.ini'))
118
+
119
+ FileUtils.mkdir_p(File.join(source, 'source'))
120
+ FileUtils.mkdir_p(File.join(source, 'source', 'bin'))
121
+ FileUtils.touch(File.join(source, 'source', 'bin', 'apt'))
122
+ FileUtils.touch(File.join(source, 'source', 'bin', 'yum'))
123
+ FileUtils.touch(File.join(source, 'source', 'LICENSE'))
124
+
125
+ FileUtils.mkdir_p(File.join(source, 'empty_directory'))
126
+
127
+ FileUtils.mkdir_p(File.join(source, 'links'))
128
+ FileUtils.touch(File.join(source, 'links', 'home.html'))
129
+ FileUtils.ln_s("./home.html", "#{source}/links/index.html")
130
+ FileUtils.ln_s("./home.html", "#{source}/links/default.html")
131
+ FileUtils.ln_s("../source/bin/apt", "#{source}/links/apt")
132
+
133
+ FileUtils.ln_s('/foo/bar', "#{source}/root")
134
+
135
+ source
136
+ end
137
+
138
+ it 'copies relative and absolute symlinks' do
139
+ described_class.sync(source, destination)
140
+
141
+ expect("#{destination}/bin").to be_a_directory
142
+ expect("#{destination}/bin/apt").to be_a_file
143
+ expect("#{destination}/bin/yum").to be_a_file
144
+
145
+ expect("#{destination}/LICENSE").to be_a_file
146
+
147
+ expect("#{destination}/include").to be_a_directory
148
+ expect("#{destination}/include/linux").to be_a_directory
149
+ expect("#{destination}/include/linux/init.ini").to be_a_file
150
+
151
+ expect("#{destination}/source").to be_a_directory
152
+ expect("#{destination}/source/bin").to be_a_directory
153
+ expect("#{destination}/source/bin/apt").to be_a_file
154
+ expect("#{destination}/source/bin/yum").to be_a_file
155
+ expect("#{destination}/source/LICENSE").to be_a_file
156
+
157
+ expect("#{destination}/empty_directory").to be_a_directory
158
+
159
+ expect("#{destination}/links").to be_a_directory
160
+ expect("#{destination}/links/home.html").to be_a_file
161
+ expect("#{destination}/links/index.html").to be_a_symlink_to("./home.html")
162
+ expect("#{destination}/links/default.html").to be_a_symlink_to("./home.html")
163
+ expect("#{destination}/links/apt").to be_a_symlink_to("../source/bin/apt")
164
+
165
+ expect("#{destination}/root").to be_a_symlink_to('/foo/bar')
166
+ end
167
+ end
168
+
169
+ context 'when :exclude is given' do
170
+ it 'does not copy files and folders that match the pattern' do
171
+ described_class.sync(source, destination, exclude: '.dot_folder')
172
+
173
+ expect("#{destination}/file_a").to be_a_file
174
+ expect("#{destination}/file_b").to be_a_file
175
+ expect("#{destination}/file_c").to be_a_file
176
+ expect("#{destination}/folder/file_d").to be_a_file
177
+ expect("#{destination}/folder/file_e").to be_a_file
178
+ expect("#{destination}/.dot_folder").to_not be_a_directory
179
+ expect("#{destination}/.dot_folder/file_f").to_not be_a_file
180
+ expect("#{destination}/.file_g").to be_a_file
181
+ end
182
+
183
+ it 'removes existing files and folders in destination' do
184
+ FileUtils.mkdir_p("#{destination}/existing_folder")
185
+ FileUtils.touch("#{destination}/existing_file")
186
+ FileUtils.mkdir_p("#{destination}/.dot_folder")
187
+ FileUtils.touch("#{destination}/.dot_folder/file_f")
188
+
189
+ described_class.sync(source, destination, exclude: '.dot_folder')
190
+
191
+ expect("#{destination}/file_a").to be_a_file
192
+ expect("#{destination}/file_b").to be_a_file
193
+ expect("#{destination}/file_c").to be_a_file
194
+ expect("#{destination}/folder/file_d").to be_a_file
195
+ expect("#{destination}/folder/file_e").to be_a_file
196
+ expect("#{destination}/.dot_folder").to_not be_a_directory
197
+ expect("#{destination}/.dot_folder/file_f").to_not be_a_file
198
+ expect("#{destination}/.file_g").to be_a_file
199
+
200
+ expect("#{destination}/existing_folder").to_not be_a_directory
201
+ expect("#{destination}/existing_file").to_not be_a_file
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
@@ -6,7 +6,7 @@ describe Berkshelf::InitGenerator do
6
6
  let(:kitchen_generator) { double('kitchen-generator', invoke_all: nil) }
7
7
 
8
8
  before do
9
- Kitchen::Generator::Init.stub(:new).with(any_args()).and_return(kitchen_generator)
9
+ allow(Kitchen::Generator::Init).to receive(:new).with(any_args()).and_return(kitchen_generator)
10
10
  FileUtils.mkdir_p(target)
11
11
  File.open(File.join(target, 'metadata.rb'), 'w') do |f|
12
12
  f.write("name 'some_cookbook'")
@@ -25,13 +25,12 @@ describe Berkshelf::InitGenerator do
25
25
  file '.gitignore'
26
26
  file 'Berksfile'
27
27
  file 'Gemfile' do
28
- contains "gem 'berkshelf'"
28
+ contains %(gem 'berkshelf')
29
29
  end
30
30
  file 'Vagrantfile' do
31
- contains 'recipe[some_cookbook::default]'
32
- contains ' config.omnibus.chef_version = :latest'
33
- contains 'config.vm.box = "chef/ubuntu-14.04"'
34
- contains 'config.vm.box_url = "https://vagrantcloud.com/chef/ubuntu-14.04/version/1/provider/virtualbox.box"'
31
+ contains %(recipe[some_cookbook::default])
32
+ contains %(config.omnibus.chef_version = 'latest')
33
+ contains %(config.vm.box = 'chef/ubuntu-14.04')
35
34
  end
36
35
  file 'chefignore'
37
36
  }
@@ -175,54 +174,52 @@ describe Berkshelf::InitGenerator do
175
174
  end
176
175
  end
177
176
 
178
- context "given the 'vagrant.omnibus.enabled' option set to false" do
177
+ context "given the 'vagrant.omnibus.version' option set" do
179
178
  before do
180
- Berkshelf::Config.instance.vagrant.omnibus.enabled = false
179
+ Berkshelf::Config.instance.vagrant.omnibus.version = "11.4.4"
181
180
  capture(:stdout) {
182
181
  Berkshelf::InitGenerator.new([target]).invoke_all
183
182
  }
184
183
  end
185
184
 
186
- it "generates a Vagrantfile without the 'config.omnibus.chef_version' value set" do
185
+ it "generates a Vagrantfile with the 'config.omnibus.chef_version' value set" do
187
186
  expect(target).to have_structure {
188
187
  file 'Vagrantfile' do
189
- contains "#config.omnibus.chef_version"
188
+ contains "config.omnibus.chef_version = '11.4.4'"
190
189
  end
191
190
  }
192
191
  end
193
192
  end
194
193
 
195
- context "given the 'vagrant.omnibus.version' option set" do
194
+ context "given the 'vagrant.omnibus.version' option set to 'latest'" do
196
195
  before do
197
- Berkshelf::Config.instance.vagrant.omnibus.enabled = true
198
- Berkshelf::Config.instance.vagrant.omnibus.version = "11.4.4"
196
+ Berkshelf::Config.instance.vagrant.omnibus.version = "latest"
199
197
  capture(:stdout) {
200
198
  Berkshelf::InitGenerator.new([target]).invoke_all
201
199
  }
202
200
  end
203
201
 
204
- it "generates a Vagrantfile with the 'config.omnibus.chef_version' value set" do
202
+ it "generates a Vagrantfile with the 'config.omnibus.chef_version' value set to :latest" do
205
203
  expect(target).to have_structure {
206
204
  file 'Vagrantfile' do
207
- contains " config.omnibus.chef_version = \"11.4.4\""
205
+ contains " config.omnibus.chef_version = 'latest'"
208
206
  end
209
207
  }
210
208
  end
211
209
  end
212
210
 
213
- context "given the 'vagrant.omnibus.version' option set to 'latest'" do
211
+ context "given the 'vagrant.vm.box_url' option set" do
214
212
  before do
215
- Berkshelf::Config.instance.vagrant.omnibus.enabled = true
216
- Berkshelf::Config.instance.vagrant.omnibus.version = "latest"
213
+ Berkshelf::Config.instance.vagrant.vm.box_url = "https://vagrantcloud.com/chef/ubuntu-14.04/version/1/provider/virtualbox.box"
217
214
  capture(:stdout) {
218
215
  Berkshelf::InitGenerator.new([target]).invoke_all
219
216
  }
220
217
  end
221
218
 
222
- it "generates a Vagrantfile with the 'config.omnibus.chef_version' value set to :latest" do
219
+ it "generates a Vagrantfile with the 'config.vm.box_url' value set" do
223
220
  expect(target).to have_structure {
224
221
  file 'Vagrantfile' do
225
- contains " config.omnibus.chef_version = :latest"
222
+ contains "config.vm.box_url = 'https://vagrantcloud.com/chef/ubuntu-14.04/version/1/provider/virtualbox.box'"
226
223
  end
227
224
  }
228
225
  end
@@ -230,8 +227,8 @@ describe Berkshelf::InitGenerator do
230
227
 
231
228
  context 'with the chef_minitest option true' do
232
229
  before(:each) do
233
- Berkshelf::Resolver.stub(:resolve) { resolver }
234
- pending 'Runs fine with no mock for the HTTP call on the first pass, subsequent passes throw errors'
230
+ allow(Berkshelf::Resolver).to receive(:resolve) { resolver }
231
+ skip 'Runs fine with no mock for the HTTP call on the first pass, subsequent passes throw errors'
235
232
  capture(:stdout) {
236
233
  Berkshelf::InitGenerator.new([target], chef_minitest: true).invoke_all
237
234
  }
@@ -10,11 +10,11 @@ describe Berkshelf::Installer do
10
10
  let(:source_two) { double('two', uri: 'https://api.chef.org') }
11
11
  let(:sources) { [ source_one, source_two ] }
12
12
 
13
- before { berksfile.stub(sources: sources) }
13
+ before { allow(berksfile).to receive_messages(sources: sources) }
14
14
 
15
15
  it "sends the message #universe on each source" do
16
- source_one.should_receive(:build_universe)
17
- source_two.should_receive(:build_universe)
16
+ expect(source_one).to receive(:build_universe)
17
+ expect(source_two).to receive(:build_universe)
18
18
 
19
19
  subject.build_universe
20
20
  end
@@ -22,15 +22,15 @@ describe Berkshelf::Installer do
22
22
 
23
23
  describe "#run" do
24
24
  context 'when a lockfile is not present' do
25
- pending
25
+ skip
26
26
  end
27
27
 
28
28
  context 'when a value for :except is given' do
29
- pending
29
+ skip
30
30
  end
31
31
 
32
32
  context 'when a value for :only is given' do
33
- pending
33
+ skip
34
34
  end
35
35
  end
36
36
  end