vara 0.17.1

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.
@@ -0,0 +1,87 @@
1
+ module Vara
2
+ module Metadata
3
+ # "Struct" representing the information about the compiled_packages field in metadata.yml
4
+ # @example entry from metadata.yml
5
+ # compiled_package:
6
+ # name: cf
7
+ # file: cf-170-bosh-vsphere-esxi-ubuntu-2366.tgz
8
+ # version: "170"
9
+ # md5: 048f9e546bb2bb490f44cd9ea074b22a
10
+ # url: https://s3-us-west-1.amazonaws.com/releng-artifacts/cf-170-build-99/cf-170-bosh-vsphere-esxi-ubuntu-2366.tgz
11
+ class CompiledPackages
12
+ # The name field of the YAML. Typically the name of the contained release.
13
+ # @return [String]
14
+ attr_reader :name
15
+
16
+ # The version field of the YAML. Typically the version of the contained release.
17
+ # @return [String]
18
+ attr_reader :version
19
+
20
+ # The filename of the compiled package
21
+ # @return [String]
22
+ attr_reader :basename
23
+
24
+ # Checksum of the compiled_packages tarball
25
+ # @return [String]
26
+ attr_reader :md5
27
+
28
+ # SHA1 Checksum is not supported for compiled_packages
29
+ # @return nil
30
+ attr_reader :sha1
31
+
32
+ # Infers the metadata given a compiled packages file on disk
33
+ # @param path_to_compiled_packages [String] The path to the compiled packages file on disk
34
+ # @return [Vara::CompiledPackagesMetadata]
35
+ def self.from_file(path_to_compiled_packages)
36
+ md5 = Digest::MD5.file(path_to_compiled_packages).hexdigest
37
+ basename = File.basename(path_to_compiled_packages)
38
+
39
+ name, rest = basename.split('-', 2)
40
+ version = rest.gsub(/-bosh.*$/, '')
41
+
42
+ new(name, version, basename, md5)
43
+ end
44
+
45
+ # @param name [String]
46
+ # @param version [String]
47
+ # @param file [String]
48
+ # @param md5 [String]
49
+ # @param url [String]
50
+ def initialize(name, version, file, md5, url = nil)
51
+ @name = name
52
+ @version = version
53
+ @basename = file
54
+ @md5 = md5
55
+ @url = url
56
+ end
57
+
58
+ # The blobstore URL for the compiled_package.
59
+ # @raise [RuntimeError] if the URL is not set.
60
+ # @return [String]
61
+ def url
62
+ @url || fail("URL unknown for compiled_packages #{name}")
63
+ end
64
+
65
+ # @return [nil] the interface for downloader requires this method
66
+ def aws
67
+ nil
68
+ end
69
+
70
+ # If the URL is set, a markdown-style URL with the basename attribute.
71
+ # Otherwise, just the basename.
72
+ # @return [String]
73
+ def to_s
74
+ @url ? "[#{basename}](#{@url})" : basename
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
81
+ # All rights reserved.
82
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
83
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
84
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
85
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
86
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
87
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,86 @@
1
+ require 'ostruct'
2
+
3
+ module Vara
4
+ module Metadata
5
+ # "Struct" representing the information about a single release in metadata.yml's releases array
6
+ # @example entry from metadata.yml
7
+ # releases:
8
+ # - file: cf-170.tgz
9
+ # name: cf
10
+ # version: '170'
11
+ # md5: 8a0700de688b4fdd270b41c4a4de9d0e
12
+ # url: https://releng-artifacts.s3.amazonaws.com/cf-170.tgz
13
+ class Release
14
+ # @return [String] Name of the release
15
+ attr_reader :name
16
+
17
+ # @return [String] Version of the release
18
+ attr_reader :version
19
+
20
+ # @return [String] The name of the release file
21
+ attr_reader :basename
22
+
23
+ # @return [String] The md5 of the release file's content
24
+ attr_reader :md5
25
+
26
+ # @return [String] The sha1 of the release file's content
27
+ attr_reader :sha1
28
+
29
+ # @return [OpenStruct] The AWS Configuration
30
+ attr_reader :aws
31
+
32
+ # Infers the metadata given a release file on disk
33
+ # @param release_tarball_path [String] The path to the release file on disk
34
+ # @return [Vara::ReleaseMetadata]
35
+ def self.from_file(release_tarball_path)
36
+ md5 = Digest::MD5.file(release_tarball_path).hexdigest
37
+ sha1 = Digest::SHA1.file(release_tarball_path).hexdigest
38
+ basename = File.basename(release_tarball_path)
39
+
40
+ release_parts = basename.gsub(/\.tgz$/, '')
41
+ name, version = release_parts.split('-', 2)
42
+
43
+ new(name: name, version: version, file: basename, md5: md5, sha1: sha1)
44
+ end
45
+
46
+ # @param name [String]
47
+ # @param version [String]
48
+ # @param file [String]
49
+ # @param md5 [String]
50
+ # @param url [String]
51
+ def initialize(name:, version:, file:, md5:, sha1:, url: nil, aws: nil)
52
+ @name = name
53
+ @version = version
54
+ @basename = file
55
+ @md5 = md5
56
+ @sha1 = sha1
57
+ @url = url
58
+ @aws = OpenStruct.new(aws) if aws
59
+ end
60
+
61
+ def url
62
+ if @url
63
+ @url
64
+ elsif @aws
65
+ "#{aws.bucket_name}/#{aws.filename}"
66
+ end
67
+ end
68
+
69
+ # If the URL is set, a markdown-style URL with the basename attribute.
70
+ # Otherwise, just the basename.
71
+ # @return [String]
72
+ def to_s
73
+ @url ? "[#{basename}](#{@url})" : basename
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
80
+ # All rights reserved.
81
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
82
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
83
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
84
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
85
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
86
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,84 @@
1
+ module Vara
2
+ module Metadata
3
+ # "Struct" representing the information about the stemcell field in metadata.yml
4
+ # @note Unlike Vara::ReleaseMetadata and Vara::CompiledPackagesMetadata, this class does not have a settable URL
5
+ # because there is an inferred URL from the global BOSH stemcell blobstore.
6
+ # @example entry from metadata.yml
7
+ # stemcell:
8
+ # name: bosh-vsphere-esxi-ubuntu
9
+ # version: '2366'
10
+ # file: bosh-stemcell-2366-vsphere-esxi-ubuntu.tgz
11
+ # md5: 0fbdcd100f716d127f821b1b4335135a
12
+ class Stemcell
13
+ # @return [String] the name of the stemcell.
14
+ attr_reader :name
15
+
16
+ # @return [String] the version of the stemcell.
17
+ attr_reader :version
18
+
19
+ # @return [String] the filename of the stemcell
20
+ attr_reader :basename
21
+
22
+ # @return [String] md5 checksum of the stemcell
23
+ attr_reader :md5
24
+
25
+ # @return [String] sha1 checksum of the stemcell
26
+ attr_reader :sha1
27
+
28
+ # Infers the metadata given a stemcell file on disk
29
+ # @param path_to_stemcell [String] The path to the stemcell file on disk
30
+ # @return [Vara::StemcellMetadata]
31
+ def self.from_file(path_to_stemcell)
32
+ md5 = Digest::MD5.file(path_to_stemcell).hexdigest
33
+ sha1 = Digest::SHA1.file(path_to_stemcell).hexdigest
34
+ basename = File.basename(path_to_stemcell)
35
+
36
+ stemcell_parts = basename.gsub(/^bosh-stemcell-/, '').gsub(/\.tgz$/, '')
37
+
38
+ raw_version, iaas, hypervisor, os = stemcell_parts.split('-')
39
+ version = raw_version.tr('_', '.')
40
+
41
+ name = ['bosh', iaas, hypervisor, os].join('-')
42
+
43
+ new(name: name, version: version, file: basename, md5: md5, sha1: sha1)
44
+ end
45
+
46
+ # @param name [String]
47
+ # @param version [String]
48
+ # @param file [String]
49
+ # @param md5 [String]
50
+ def initialize(name:, version:, file:, md5:, sha1:)
51
+ @name = name
52
+ @version = version
53
+ @basename = file
54
+ @md5 = md5
55
+ @sha1 = sha1
56
+ end
57
+
58
+ # @return [String] the inferred blobstore URL of the stemcell, assuming it is a BOSH public stemcell
59
+ def url
60
+ iaas = basename.gsub(/.*\d-(\w+)-.*/, '\1')
61
+ "http://bosh-jenkins-artifacts.cf-app.com/bosh-stemcell/#{iaas}/#{basename}"
62
+ end
63
+
64
+ # @return [nil] the interface for downloader requires this method
65
+ def aws
66
+ nil
67
+ end
68
+
69
+ # @return [String] a markdown-style URL with the basename attribute.
70
+ def to_s
71
+ "[#{basename}](#{url})"
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
78
+ # All rights reserved.
79
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
80
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
81
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
82
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
83
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
84
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,79 @@
1
+ require 'vara/git_inspector'
2
+
3
+ module Vara
4
+ class PrereleaseVersioner
5
+ PRERELEASE_VERSION_PLACEHOLDER = '$PRERELEASE_VERSION$'.freeze
6
+ PRODUCT_VERSION_KEY = 'product_version'.freeze
7
+ TO_VERSION_KEY = 'to_version'.freeze
8
+ MIGRATIONS_KEY = 'migrations'.freeze
9
+ MIGRATIONS_RULES_KEY = 'rules'.freeze
10
+ MIGRATIONS_RULES_TO_KEY = 'to'.freeze
11
+
12
+ # @param product_directory_path [String]
13
+ # @param cycle [String] cycle (e.g. alpha, beta, etc.) to use in expanded prerelease version value
14
+ def initialize(product_directory_path, cycle)
15
+ @product_directory_path = product_directory_path
16
+ @cycle = cycle
17
+ end
18
+
19
+ # @param new_prerelease_version [String] explicit value to override the prerelease version. Use with caution.
20
+ # @return [void]
21
+ def override_prerelease_version!(new_prerelease_version)
22
+ @prerelease_version = new_prerelease_version
23
+ end
24
+
25
+ # @param metadata_hash [Hash] Hash contents of full product metadata
26
+ # @return [Hash] product metadata with product version value updated if necessary
27
+ def update_metadata(metadata_hash)
28
+ return metadata_hash unless metadata_hash.fetch(PRODUCT_VERSION_KEY).include?(PRERELEASE_VERSION_PLACEHOLDER)
29
+ metadata_hash[PRODUCT_VERSION_KEY].gsub!(PRERELEASE_VERSION_PLACEHOLDER, prerelease_version)
30
+ metadata_hash
31
+ end
32
+
33
+ # @param migrations_hash [Hash] Hash contents of full content migrations
34
+ # @return [Hash] content migrations with product version value updated if necessary
35
+ def update_content_migrations(migrations_hash)
36
+ migrations_hash[TO_VERSION_KEY].gsub!(PRERELEASE_VERSION_PLACEHOLDER, prerelease_version) if migrations_hash.key?(TO_VERSION_KEY)
37
+ migrations_hash.fetch(MIGRATIONS_KEY, []).each do |migration|
38
+ migration.fetch(MIGRATIONS_RULES_KEY, []).each do |rule|
39
+ next unless updates_product_version?(rule)
40
+ rule[MIGRATIONS_RULES_TO_KEY].gsub!(PRERELEASE_VERSION_PLACEHOLDER, prerelease_version)
41
+ end
42
+ end
43
+ migrations_hash
44
+ end
45
+
46
+ private
47
+
48
+ attr_reader :product_directory_path, :cycle
49
+
50
+ def updates_product_version?(rule_hash)
51
+ rule_hash['type'] == 'update' && rule_hash['selector'] == 'product_version'
52
+ end
53
+
54
+ def prerelease_version
55
+ @prerelease_version ||= ".#{cycle}.#{commit_number}.#{short_sha}"
56
+ end
57
+
58
+ def commit_number
59
+ git_inspector.commit_count
60
+ end
61
+
62
+ def short_sha
63
+ git_inspector.short_sha
64
+ end
65
+
66
+ def git_inspector
67
+ @git_inspector ||= GitInspector.new(product_directory_path)
68
+ end
69
+ end
70
+ end
71
+
72
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
73
+ # All rights reserved.
74
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
75
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
76
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
77
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
78
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
79
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,98 @@
1
+ require 'vara/product_metadata'
2
+ require 'vara/product_resource_downloader'
3
+ require 'vara/product_artifact_zipper'
4
+ require 'vara/product_contents'
5
+ require 'vara/md5_creator'
6
+ require 'vara/materials'
7
+
8
+ module Vara
9
+ class Product
10
+ METADATA_DIR = 'metadata'.freeze
11
+ METADATA_PARTS_DIR = 'metadata_parts'.freeze
12
+
13
+ attr_reader :base_dir
14
+
15
+ def initialize(base_dir)
16
+ @base_dir = base_dir
17
+ end
18
+
19
+ def metadata_file
20
+ @metadata_file ||= find_metadata_file || fail('No metadata file found.')
21
+ end
22
+
23
+ def build
24
+ if metadata.explicit_stemcell? && metadata.stemcell_criteria?
25
+ fail 'binaries.yml includes both stemcell and stemcell criteria keys'
26
+ end
27
+
28
+ ProductArtifactZipper.new(path, ProductContents.from_metadata_path(metadata_file)).zip!
29
+
30
+ MD5Creator.md5(path)
31
+
32
+ Materials.build(metadata_file, path).save_to(bom_path)
33
+
34
+ path
35
+ end
36
+
37
+ def path
38
+ File.join(base_dir, "#{filename_components.join('-')}.pivotal")
39
+ end
40
+
41
+ def bom_path
42
+ "#{path}.yml"
43
+ end
44
+
45
+ def md5_path
46
+ "#{path}.md5"
47
+ end
48
+
49
+ def stemcell_version
50
+ metadata.stemcell_metadata.version
51
+ end
52
+
53
+ def metadata_ref
54
+ `cd #{base_dir} && git log -1 --format=format:%h`
55
+ end
56
+
57
+ def releases
58
+ metadata.releases_metadata.map do |release_metadata|
59
+ {
60
+ 'name' => release_metadata['name'],
61
+ 'version' => release_metadata['version']
62
+ }
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def metadata
69
+ ProductMetadata.from_file(metadata_file)
70
+ end
71
+
72
+ def filename_components
73
+ [metadata.name, metadata.product_version]
74
+ end
75
+
76
+ def find_metadata_file
77
+ files = Dir.glob(File.join(base_dir, METADATA_DIR, '*.yml')).sort
78
+
79
+ case files.size
80
+ when 0 then
81
+ nil
82
+ when 1 then
83
+ files.first
84
+ else
85
+ fail("Found: #{files.map { |f| File.basename(f) }}. Vara supports one .yml file under metadata/")
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
92
+ # All rights reserved.
93
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
94
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
95
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
96
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
97
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
98
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,32 @@
1
+ module Vara
2
+ class ProductArtifactValidator
3
+ def self.validate_file_checksum(file_metadata, file_name)
4
+ fail "No checksum for file #{file_name}!" unless file_metadata.md5 || file_metadata.sha1
5
+
6
+ validate_md5(file_metadata, file_name) if file_metadata.md5
7
+
8
+ validate_sha1(file_metadata, file_name) if file_metadata.sha1
9
+ end
10
+
11
+ def self.validate_sha1(file_metadata, file_name)
12
+ sha1_got = Digest::SHA1.file(file_name).hexdigest
13
+ sha1_expected = file_metadata.sha1
14
+ fail "sha1 mismatch for file #{file_name}, expected #{sha1_expected}, got #{sha1_got}" if sha1_got != sha1_expected
15
+ end
16
+
17
+ def self.validate_md5(file_metadata, file_name)
18
+ md5_got = Digest::MD5.file(file_name).hexdigest
19
+ md5_expected = file_metadata.md5
20
+ fail "md5 mismatch for file #{file_name}, expected #{md5_expected}, got #{md5_got}" if md5_got != md5_expected
21
+ end
22
+ end
23
+ end
24
+
25
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
26
+ # All rights reserved.
27
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
28
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
29
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
32
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.