buildpack-packager 2.3.4

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 (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