buildpack-packager 2.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +5 -0
  5. data/LICENSE +176 -0
  6. data/README.md +180 -0
  7. data/Rakefile +6 -0
  8. data/bin/buildpack-packager +79 -0
  9. data/buildpack-packager.gemspec +33 -0
  10. data/doc/disconnected_environments.md +50 -0
  11. data/lib/buildpack/manifest_dependency.rb +14 -0
  12. data/lib/buildpack/manifest_validator.rb +88 -0
  13. data/lib/buildpack/packager.rb +55 -0
  14. data/lib/buildpack/packager/default_versions_presenter.rb +38 -0
  15. data/lib/buildpack/packager/dependencies_presenter.rb +41 -0
  16. data/lib/buildpack/packager/manifest_schema.yml +67 -0
  17. data/lib/buildpack/packager/package.rb +139 -0
  18. data/lib/buildpack/packager/table_presentation.rb +21 -0
  19. data/lib/buildpack/packager/version.rb +5 -0
  20. data/lib/buildpack/packager/zip_file_excluder.rb +31 -0
  21. data/lib/kwalify/parser/yaml-patcher.rb +70 -0
  22. data/spec/buildpack/packager_spec.rb +7 -0
  23. data/spec/fixtures/buildpack-with-uri-credentials/VERSION +1 -0
  24. data/spec/fixtures/buildpack-with-uri-credentials/manifest.yml +36 -0
  25. data/spec/fixtures/buildpack-without-uri-credentials/VERSION +1 -0
  26. data/spec/fixtures/buildpack-without-uri-credentials/manifest.yml +36 -0
  27. data/spec/fixtures/manifests/manifest_invalid-md6.yml +18 -0
  28. data/spec/fixtures/manifests/manifest_invalid-md6_and_defaults.yml +21 -0
  29. data/spec/fixtures/manifests/manifest_valid.yml +19 -0
  30. data/spec/helpers/cache_directory_helpers.rb +15 -0
  31. data/spec/helpers/fake_binary_hosting_helpers.rb +21 -0
  32. data/spec/helpers/file_system_helpers.rb +35 -0
  33. data/spec/integration/bin/buildpack_packager/download_caching_spec.rb +85 -0
  34. data/spec/integration/bin/buildpack_packager_spec.rb +378 -0
  35. data/spec/integration/buildpack/directory_name_spec.rb +89 -0
  36. data/spec/integration/buildpack/packager_spec.rb +454 -0
  37. data/spec/integration/default_versions_spec.rb +170 -0
  38. data/spec/integration/output_spec.rb +70 -0
  39. data/spec/spec_helper.rb +12 -0
  40. data/spec/unit/buildpack/packager/zip_file_excluder_spec.rb +68 -0
  41. data/spec/unit/manifest_dependency_spec.rb +41 -0
  42. data/spec/unit/manifest_validator_spec.rb +35 -0
  43. data/spec/unit/packager/package_spec.rb +196 -0
  44. metadata +235 -0
@@ -0,0 +1,378 @@
1
+ require 'spec_helper'
2
+ require 'tmpdir'
3
+ require 'yaml'
4
+ require 'open3'
5
+
6
+ describe 'buildpack_packager binary' do
7
+ def create_manifests
8
+ create_manifest
9
+ create_full_manifest
10
+ end
11
+
12
+ def create_manifest
13
+ File.open(File.join(buildpack_dir, 'manifest.yml'), 'w') do |manifest_file|
14
+ manifest_file.write <<-MANIFEST
15
+ ---
16
+ language: sample
17
+
18
+ url_to_dependency_map:
19
+ - match: fake_name(\d+\.\d+(\.\d+)?)
20
+ name: fake_name
21
+ version: $1
22
+
23
+ dependencies:
24
+ - name: fake_name
25
+ version: 1.2
26
+ uri: file://#{file_location}
27
+ md5: #{md5}
28
+ modules: ["one", "two", "three"]
29
+ cf_stacks:
30
+ - lucid64
31
+ - cflinuxfs2
32
+
33
+ exclude_files:
34
+ - .gitignore
35
+ - lib/ephemeral_junkpile
36
+ MANIFEST
37
+ end
38
+
39
+ files_to_include << 'manifest.yml'
40
+ end
41
+
42
+ def create_full_manifest
43
+ File.open(File.join(buildpack_dir, 'manifest-including-default-versions.yml'), 'w') do |manifest_file|
44
+ manifest_file.write <<-MANIFEST
45
+ ---
46
+ language: sample
47
+
48
+ url_to_dependency_map:
49
+ - match: fake_name(\d+\.\d+(\.\d+)?)
50
+ name: fake_name
51
+ version: $1
52
+
53
+ default_versions:
54
+ - name: fake_name
55
+ version: 1.2
56
+
57
+ dependencies:
58
+ - name: fake_name
59
+ version: 1.2
60
+ uri: file://#{file_location}
61
+ md5: #{md5}
62
+ cf_stacks:
63
+ - lucid64
64
+ - cflinuxfs2
65
+ - name: fake_name
66
+ version: 1.1
67
+ uri: file://#{deprecated_file_location}
68
+ md5: #{deprecated_md5}
69
+ cf_stacks:
70
+ - lucid64
71
+ - cflinuxfs2
72
+
73
+ exclude_files:
74
+ - .gitignore
75
+ - lib/ephemeral_junkpile
76
+ MANIFEST
77
+ end
78
+
79
+ files_to_include << 'manifest-including-default-versions.yml'
80
+ end
81
+
82
+ def create_invalid_manifest
83
+ File.open(File.join(buildpack_dir, 'manifest.yml'), 'w') do |manifest_file|
84
+ manifest_file.write <<-MANIFEST
85
+ ---
86
+ language: sample
87
+ dependencies:
88
+ - name: fake_name
89
+ version: 1.2
90
+ uri: file://#{file_location}
91
+ md5: md5
92
+ cf_stacks: [cflinuxfs2]
93
+ MANIFEST
94
+ end
95
+
96
+ files_to_include << 'manifest.yml'
97
+ end
98
+
99
+ let(:tmp_dir) { Dir.mktmpdir }
100
+ let(:buildpack_dir) { File.join(tmp_dir, 'sample-buildpack-root-dir') }
101
+ let(:remote_dependencies_dir) { File.join(tmp_dir, 'remote_dependencies') }
102
+ let(:file_location) { "#{remote_dependencies_dir}/dep1.txt" }
103
+ let(:md5) { Digest::MD5.file(file_location).hexdigest }
104
+ let(:deprecated_file_location) { "#{remote_dependencies_dir}/dep2.txt" }
105
+ let(:deprecated_md5) { Digest::MD5.file(deprecated_file_location).hexdigest }
106
+
107
+ let(:files_to_include) do
108
+ [
109
+ 'VERSION',
110
+ 'README.md',
111
+ 'lib/sai.to',
112
+ 'lib/rash'
113
+ ]
114
+ end
115
+
116
+ let(:files_to_exclude) do
117
+ [
118
+ '.gitignore',
119
+ 'lib/ephemeral_junkpile'
120
+ ]
121
+ end
122
+
123
+ let(:files) { files_to_include + files_to_exclude }
124
+
125
+ let(:dependencies) do
126
+ ['dep1.txt', 'dep2.txt']
127
+ end
128
+
129
+ before do
130
+ make_fake_files(
131
+ remote_dependencies_dir,
132
+ dependencies
133
+ )
134
+
135
+ make_fake_files(
136
+ buildpack_dir,
137
+ files
138
+ )
139
+
140
+ `echo "1.2.3" > #{File.join(buildpack_dir, 'VERSION')}`
141
+ end
142
+
143
+ after do
144
+ FileUtils.remove_entry tmp_dir
145
+ end
146
+
147
+ describe 'flags' do
148
+ describe '--list flag' do
149
+ let(:flags) { '--list' }
150
+
151
+ before do
152
+ create_manifests
153
+ end
154
+
155
+ context 'default manifest' do
156
+ it 'emits a table of contents' do
157
+ output = run_packager_binary(buildpack_dir, flags)
158
+ stdout = output.first
159
+
160
+ expect(stdout).to match(/fake_name.*1\.2/)
161
+ expect(stdout).to match(/------/) # it's a table!
162
+ end
163
+
164
+ context 'and there are modules' do
165
+ it 'emit a table for modules' do
166
+ output = run_packager_binary(buildpack_dir, flags)
167
+ stdout = output.first
168
+
169
+ expect(stdout).to match /modules/
170
+ expect(stdout).to match /one, three, two/
171
+ end
172
+ end
173
+ end
174
+
175
+ context 'custom manifest' do
176
+ let(:flags) { '--list --use-custom-manifest=manifest-including-default-versions.yml' }
177
+
178
+ it 'emits a table of contents' do
179
+ output = run_packager_binary(buildpack_dir, flags)
180
+ stdout = output.first
181
+
182
+ expect(stdout).to match(/fake_name.*1\.1/)
183
+ expect(stdout).to match(/fake_name.*1\.2/)
184
+ expect(stdout).to match(/------/) # it's a table!
185
+ end
186
+
187
+ context 'and there are no modules' do
188
+ it 'ensures there is no modules column' do
189
+ output = run_packager_binary(buildpack_dir, flags)
190
+ stdout = output.first
191
+
192
+ expect(stdout).to_not match /modules/
193
+ end
194
+ end
195
+ end
196
+ end
197
+
198
+ describe '--defaults flag' do
199
+ let(:flags) { '--defaults' }
200
+
201
+ before do
202
+ create_manifests
203
+ end
204
+
205
+ context 'default manifest with no default_versions' do
206
+ it 'emits an empty table' do
207
+ output = run_packager_binary(buildpack_dir, flags)
208
+ stdout = output.first
209
+
210
+ expect(stdout).to match(/ name | version/)
211
+ expect(stdout).to match(/------/) # it's a table!
212
+ expect(stdout.split("\m").length).to eq(2)
213
+ end
214
+ end
215
+
216
+ context 'custom manifest with default_versions' do
217
+ let(:flags) { '--defaults --use-custom-manifest=manifest-including-default-versions.yml' }
218
+
219
+ it 'emits a table of the manifest specified default dependency versions' do
220
+ output = run_packager_binary(buildpack_dir, flags)
221
+ stdout = output.first
222
+
223
+ expect(stdout).to match(/ name | version/)
224
+ expect(stdout).to match(/fake_name.*1\.2/)
225
+ expect(stdout).to match(/------/) # it's a table!
226
+ end
227
+ end
228
+ end
229
+
230
+ describe '--use-custom-manifest' do
231
+ let(:flags) { '--uncached' }
232
+
233
+ before do
234
+ create_manifests
235
+ end
236
+
237
+ context 'with the flag' do
238
+ let(:flags) { '--uncached --use-custom-manifest=manifest-including-default-versions.yml' }
239
+
240
+ it 'uses the specified manifest' do
241
+ run_packager_binary(buildpack_dir, flags)
242
+
243
+ manifest_location = File.join(Dir.mktmpdir, 'manifest.yml')
244
+ zip_file_path = File.join(buildpack_dir, 'sample_buildpack-v1.2.3.zip')
245
+
246
+ Zip::File.open(zip_file_path) do |zip_file|
247
+ generated_manifest = zip_file.find { |file| file.name == 'manifest.yml' }
248
+ generated_manifest.extract(manifest_location)
249
+ end
250
+
251
+ manifest_contents = File.read(manifest_location)
252
+
253
+ expect(manifest_contents).to eq(File.read(File.join(buildpack_dir, 'manifest-including-default-versions.yml')))
254
+ end
255
+ end
256
+
257
+ context 'without the flag' do
258
+ it 'uses the skinny manifest' do
259
+ run_packager_binary(buildpack_dir, flags)
260
+
261
+ manifest_location = File.join(Dir.mktmpdir, 'manifest.yml')
262
+ zip_file_path = File.join(buildpack_dir, 'sample_buildpack-v1.2.3.zip')
263
+
264
+ Zip::File.open(zip_file_path) do |zip_file|
265
+ generated_manifest = zip_file.find { |file| file.name == 'manifest.yml' }
266
+ generated_manifest.extract(manifest_location)
267
+ end
268
+
269
+ manifest_contents = File.read(manifest_location)
270
+
271
+ expect(manifest_contents).to eq(File.read(File.join(buildpack_dir, 'manifest.yml')))
272
+ end
273
+ end
274
+ end
275
+ end
276
+
277
+ context 'without a manifest' do
278
+ let(:flags) { '--uncached' }
279
+
280
+ specify do
281
+ output, status = run_packager_binary(buildpack_dir, flags)
282
+
283
+ expect(output).to include('Could not find manifest.yml')
284
+ expect(status).not_to be_success
285
+ end
286
+ end
287
+
288
+ context 'with an invalid manifest' do
289
+ let(:flags) { '--uncached' }
290
+
291
+ before do
292
+ create_invalid_manifest
293
+ end
294
+
295
+ specify do
296
+ output, status = run_packager_binary(buildpack_dir, flags)
297
+
298
+ expect(output).to include('conform to the schema')
299
+ expect(status).not_to be_success
300
+ end
301
+ end
302
+
303
+ describe 'usage' do
304
+ context 'without a flag' do
305
+ let(:flags) { '' }
306
+ specify do
307
+ output, status = run_packager_binary(buildpack_dir, flags)
308
+
309
+ expect(output).to include('USAGE: buildpack-packager < --cached | --uncached | --list | --defaults >')
310
+ expect(status).not_to be_success
311
+ end
312
+ end
313
+
314
+ context 'with an invalid flag' do
315
+ let(:flags) { 'beast' }
316
+
317
+ it 'reports proper usage' do
318
+ output, status = run_packager_binary(buildpack_dir, flags)
319
+
320
+ expect(output).to include('USAGE: buildpack-packager < --cached | --uncached | --list | --defaults >')
321
+ expect(status).not_to be_success
322
+ end
323
+ end
324
+ end
325
+
326
+ context 'with a manifest' do
327
+ before do
328
+ create_manifest
329
+ end
330
+
331
+ describe 'the zip file contents' do
332
+ context 'an uncached buildpack' do
333
+ let(:flags) { '--uncached' }
334
+
335
+ specify do
336
+ output, status = run_packager_binary(buildpack_dir, flags)
337
+
338
+ zip_file_path = File.join(buildpack_dir, 'sample_buildpack-v1.2.3.zip')
339
+ zip_contents = get_zip_contents(zip_file_path)
340
+
341
+ expect(zip_contents).to match_array(files_to_include)
342
+ expect(status).to be_success
343
+ end
344
+ end
345
+
346
+ context 'an cached buildpack' do
347
+ let(:flags) { '--cached' }
348
+
349
+ specify do
350
+ _, status = run_packager_binary(buildpack_dir, flags)
351
+
352
+ zip_file_path = File.join(buildpack_dir, 'sample_buildpack-cached-v1.2.3.zip')
353
+ zip_contents = get_zip_contents(zip_file_path)
354
+
355
+ dependencies_in_manifest = YAML.load_file(File.join(buildpack_dir, 'manifest.yml'))['dependencies']
356
+
357
+ dependencies_with_translation = dependencies_in_manifest
358
+ .map { |dep| "file://#{remote_dependencies_dir}/#{dep['uri'].split('/').last}" }
359
+ .map { |path| path.gsub(/[:\/]/, '_') }
360
+
361
+ deps_with_path = dependencies_with_translation.map { |dep| "dependencies/#{dep}" }
362
+
363
+ expect(zip_contents).to match_array(files_to_include + deps_with_path)
364
+ expect(status).to be_success
365
+ end
366
+
367
+ context 'vendored dependencies with invalid checksums' do
368
+ let(:md5) { 'InvalidMD5_123' }
369
+
370
+ specify do
371
+ stdout, status = run_packager_binary(buildpack_dir, flags)
372
+ expect(status).not_to be_success
373
+ end
374
+ end
375
+ end
376
+ end
377
+ end
378
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+ require 'buildpack/packager'
3
+
4
+ module Buildpack
5
+ describe Packager do
6
+ let(:fake_file_uri) do
7
+ location = File.join(Dir.mktmpdir, 'fake.file')
8
+ File.write(location, 'fake text')
9
+ "file://#{location}"
10
+ end
11
+
12
+ let(:md5) { Digest::MD5.file(fake_file_uri.gsub(/file:\/\//, '')).hexdigest }
13
+
14
+ let(:manifest) do
15
+ {
16
+ language: 'fake',
17
+ exclude_files: [],
18
+ dependencies: [
19
+ {
20
+ 'name' => 'fake',
21
+ 'uri' => fake_file_uri,
22
+ 'md5' => md5
23
+ }
24
+ ]
25
+ }
26
+ end
27
+
28
+ let(:mode) { :uncached }
29
+ let(:cache_dir) { '' }
30
+
31
+ let(:root_dir) do
32
+ dir_name = Dir.mktmpdir('fake-buildpack')
33
+ File.write(File.join(dir_name, 'mock.txt'), 'fake!')
34
+ dir_name
35
+ end
36
+
37
+ let(:options) do
38
+ {
39
+ root_dir: root_dir,
40
+ manifest_path: 'manifest.yml',
41
+ mode: mode,
42
+ force_download: false,
43
+ cache_dir: cache_dir
44
+ }
45
+ end
46
+
47
+ before do
48
+ @pwd ||= Dir.pwd
49
+ Dir.chdir(root_dir)
50
+ end
51
+
52
+ after do
53
+ Dir.chdir(@pwd)
54
+ end
55
+
56
+ describe 'directory naming structure' do
57
+ before do
58
+ allow_any_instance_of(Packager::Package).to receive(:buildpack_version).and_return('1.0.0')
59
+ allow_any_instance_of(Packager::Package).to receive(:manifest).and_return(manifest)
60
+ allow(FileUtils).to receive(:cp)
61
+ Packager.package(options)
62
+ end
63
+
64
+ context 'directory has no space' do
65
+ let(:root_dir) do
66
+ dir_name = Dir.mktmpdir('nospace')
67
+ File.write(File.join(dir_name, 'mock.txt'), "don't read this")
68
+ dir_name
69
+ end
70
+
71
+ it 'puts the zip file in the right place' do
72
+ expect(File.exist?(File.join(root_dir, 'fake_buildpack-v1.0.0.zip'))).to be(true)
73
+ end
74
+ end
75
+
76
+ context 'directory has a space' do
77
+ let(:root_dir) do
78
+ dir_name = Dir.mktmpdir('a space')
79
+ File.write(File.join(dir_name, 'mock.txt'), "don't read this")
80
+ dir_name
81
+ end
82
+
83
+ it 'it puts the zip file in the right place' do
84
+ expect(File.exist?(File.join(root_dir, 'fake_buildpack-v1.0.0.zip'))).to be(true)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end