dependabot-docker_compose 0.297.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.
- checksums.yaml +7 -0
- data/lib/dependabot/docker_compose/file_fetcher.rb +67 -0
- data/lib/dependabot/docker_compose/file_parser.rb +76 -0
- data/lib/dependabot/docker_compose/file_updater.rb +106 -0
- data/lib/dependabot/docker_compose/metadata_finder.rb +39 -0
- data/lib/dependabot/docker_compose/package_manager.rb +53 -0
- data/lib/dependabot/docker_compose/requirement.rb +43 -0
- data/lib/dependabot/docker_compose/tag.rb +144 -0
- data/lib/dependabot/docker_compose/update_checker.rb +479 -0
- data/lib/dependabot/docker_compose/version.rb +84 -0
- data/lib/dependabot/docker_compose.rb +19 -0
- data/lib/dependabot/shared/shared_file_fetcher.rb +99 -0
- data/lib/dependabot/shared/shared_file_parser.rb +80 -0
- data/lib/dependabot/shared/shared_file_updater.rb +261 -0
- data/lib/dependabot/shared/utils/credentials_finder.rb +101 -0
- data/lib/dependabot/shared/utils/helpers.rb +19 -0
- metadata +285 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e8800055af3f3a9fc1a7b056288ea510770fd65dcf8933eb69a66a4aed591914
|
4
|
+
data.tar.gz: 05c25842d1a91b7fc0cddff8e51b0687d5ff0f1cb200276409e25671cf245f46
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c8f586a6ee7a26cb2e0e92abca5e23a0304537236df1fac702a667dfb8117494ce16d3d3243e20b4003e181c129e998381c7e5cca72da98ffaab7f2ff5aaf9b1
|
7
|
+
data.tar.gz: 72d33eae6923a14d9ffc8f12ab9cfdf0cddab97ce91afa51a39be2bf8fa618bbb678cdc6408166f54745d3c5305800be91d5328c6c2a9eef8d421cfc7664499e
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "dependabot/shared/shared_file_fetcher"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module DockerCompose
|
8
|
+
class FileFetcher < Dependabot::Shared::SharedFileFetcher
|
9
|
+
FILENAME_REGEX = /(docker-)?compose(-[\w]+)?(?>\.[\w-]+)?\.ya?ml/i
|
10
|
+
|
11
|
+
sig { override.returns(T::Array[DependencyFile]) }
|
12
|
+
def fetch_files
|
13
|
+
fetched_files = []
|
14
|
+
fetched_files += correctly_encoded_docker_compose_files if allow_beta_ecosystems?
|
15
|
+
|
16
|
+
return fetched_files if fetched_files.any?
|
17
|
+
|
18
|
+
raise_appropriate_error
|
19
|
+
end
|
20
|
+
|
21
|
+
sig { override.returns(Regexp) }
|
22
|
+
def self.filename_regex
|
23
|
+
FILENAME_REGEX
|
24
|
+
end
|
25
|
+
|
26
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
27
|
+
def docker_compose_files
|
28
|
+
@docker_compose_files ||=
|
29
|
+
T.let(repo_contents(raise_errors: false)
|
30
|
+
.select { |f| f.type == "file" && f.name.match?(FILENAME_REGEX) }
|
31
|
+
.map { |f| fetch_file_from_host(f.name) }, T.nilable(T::Array[DependencyFile]))
|
32
|
+
end
|
33
|
+
|
34
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
35
|
+
def correctly_encoded_docker_compose_files
|
36
|
+
docker_compose_files.select { |f| T.must(f.content).valid_encoding? }
|
37
|
+
end
|
38
|
+
|
39
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
40
|
+
def incorrectly_encoded_docker_compose_files
|
41
|
+
docker_compose_files.reject { |f| T.must(f.content).valid_encoding? }
|
42
|
+
end
|
43
|
+
|
44
|
+
sig { override.returns(String) }
|
45
|
+
def self.required_files_message
|
46
|
+
"Repo must contain a docker-compose.yaml file."
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
sig { override.returns(String) }
|
52
|
+
def default_file_name
|
53
|
+
"docker-compose.yml"
|
54
|
+
end
|
55
|
+
|
56
|
+
sig { override.returns(String) }
|
57
|
+
def file_type
|
58
|
+
"Docker Compose"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
Dependabot::FileFetchers.register(
|
65
|
+
"docker_compose",
|
66
|
+
Dependabot::DockerCompose::FileFetcher
|
67
|
+
)
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "yaml"
|
5
|
+
require "dependabot/shared/shared_file_parser"
|
6
|
+
require "dependabot/docker_compose/package_manager"
|
7
|
+
|
8
|
+
module Dependabot
|
9
|
+
module DockerCompose
|
10
|
+
class FileParser < Dependabot::Shared::SharedFileParser
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
FROM_IMAGE = %r{^(?:#{REGISTRY}/)?#{IMAGE}(?:#{TAG})?(?:#{DIGEST})?(?:#{NAME})?}
|
14
|
+
|
15
|
+
sig { returns(Ecosystem) }
|
16
|
+
def ecosystem
|
17
|
+
@ecosystem ||= T.let(
|
18
|
+
Ecosystem.new(
|
19
|
+
name: ECOSYSTEM,
|
20
|
+
package_manager: DockerPackageManager.new
|
21
|
+
),
|
22
|
+
T.nilable(Ecosystem)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
sig { override.returns(T::Array[Dependabot::Dependency]) }
|
27
|
+
def parse
|
28
|
+
dependency_set = DependencySet.new
|
29
|
+
|
30
|
+
composefiles.each do |composefile|
|
31
|
+
yaml = YAML.safe_load(T.must(composefile.content))
|
32
|
+
yaml["services"].each do |_, service|
|
33
|
+
parsed_from_image = T.must(FROM_IMAGE.match(service["image"])).named_captures
|
34
|
+
parsed_from_image["registry"] = nil if parsed_from_image["registry"] == "docker.io"
|
35
|
+
|
36
|
+
version = version_from(parsed_from_image)
|
37
|
+
next unless version
|
38
|
+
|
39
|
+
dependency_set << build_dependency(composefile, parsed_from_image, version)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
dependency_set.dependencies
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
sig { override.returns(String) }
|
49
|
+
def package_manager
|
50
|
+
"docker_compose"
|
51
|
+
end
|
52
|
+
|
53
|
+
sig { override.returns(String) }
|
54
|
+
def file_type
|
55
|
+
"docker-compose.yml"
|
56
|
+
end
|
57
|
+
|
58
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
59
|
+
def composefiles
|
60
|
+
dependency_files
|
61
|
+
end
|
62
|
+
|
63
|
+
sig { override.void }
|
64
|
+
def check_required_files
|
65
|
+
return if dependency_files.any?
|
66
|
+
|
67
|
+
raise "No #{file_type}!"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Dependabot::FileParsers.register(
|
74
|
+
"docker_compose",
|
75
|
+
Dependabot::DockerCompose::FileParser
|
76
|
+
)
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "dependabot/shared/shared_file_updater"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module DockerCompose
|
8
|
+
class FileUpdater < Dependabot::Shared::SharedFileUpdater
|
9
|
+
extend T::Sig
|
10
|
+
extend T::Helpers
|
11
|
+
|
12
|
+
YAML_REGEXP = /(docker-)?compose(?>\.[\w-]+)?\.ya?ml/i
|
13
|
+
IMAGE_REGEX = /image:\s*/
|
14
|
+
|
15
|
+
sig { override.returns(T::Array[Regexp]) }
|
16
|
+
def self.updated_files_regex
|
17
|
+
[YAML_REGEXP]
|
18
|
+
end
|
19
|
+
|
20
|
+
sig { override.returns(String) }
|
21
|
+
def file_type
|
22
|
+
"Docker compose"
|
23
|
+
end
|
24
|
+
|
25
|
+
sig { override.returns(Regexp) }
|
26
|
+
def yaml_file_pattern
|
27
|
+
YAML_REGEXP
|
28
|
+
end
|
29
|
+
|
30
|
+
sig { override.returns(Regexp) }
|
31
|
+
def container_image_regex
|
32
|
+
IMAGE_REGEX
|
33
|
+
end
|
34
|
+
|
35
|
+
sig { override.params(escaped_declaration: String).returns(Regexp) }
|
36
|
+
def build_old_declaration_regex(escaped_declaration)
|
37
|
+
%r{#{IMAGE_REGEX}\s+(docker\.io/)?#{escaped_declaration}(?=\s|$)}
|
38
|
+
end
|
39
|
+
|
40
|
+
sig { override.returns(T::Array[Dependabot::DependencyFile]) }
|
41
|
+
def updated_dependency_files
|
42
|
+
updated_files = []
|
43
|
+
dependency_files.each do |file|
|
44
|
+
next unless requirement_changed?(file, T.must(dependency))
|
45
|
+
|
46
|
+
updated_files << updated_file(
|
47
|
+
file: file,
|
48
|
+
content: T.must(updated_dockerfile_content(file))
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
updated_files.reject! { |f| dependency_files.include?(f) }
|
53
|
+
raise "No files changed!" if updated_files.none?
|
54
|
+
|
55
|
+
updated_files
|
56
|
+
end
|
57
|
+
|
58
|
+
sig do
|
59
|
+
override.params(previous_content: String, old_source: T::Hash[Symbol, T.nilable(String)],
|
60
|
+
new_source: T::Hash[Symbol, T.nilable(String)]).returns(String)
|
61
|
+
end
|
62
|
+
def update_digest_and_tag(previous_content, old_source, new_source)
|
63
|
+
old_digest = old_source[:digest]
|
64
|
+
new_digest = new_source[:digest]
|
65
|
+
|
66
|
+
old_tag = old_source[:tag]
|
67
|
+
new_tag = new_source[:tag]
|
68
|
+
|
69
|
+
old_declaration =
|
70
|
+
if private_registry_url(old_source)
|
71
|
+
"#{private_registry_url(old_source)}/"
|
72
|
+
else
|
73
|
+
""
|
74
|
+
end
|
75
|
+
old_declaration += T.must(dependency).name
|
76
|
+
old_declaration +=
|
77
|
+
if specified_with_tag?(old_source)
|
78
|
+
":#{old_tag}"
|
79
|
+
else
|
80
|
+
""
|
81
|
+
end
|
82
|
+
old_declaration +=
|
83
|
+
if old_digest&.start_with?("sha256:")
|
84
|
+
"@#{old_digest}"
|
85
|
+
else
|
86
|
+
""
|
87
|
+
end
|
88
|
+
|
89
|
+
escaped_declaration = Regexp.escape(old_declaration)
|
90
|
+
|
91
|
+
old_declaration_regex = build_old_declaration_regex(escaped_declaration)
|
92
|
+
|
93
|
+
previous_content.gsub(old_declaration_regex) do |old_dec|
|
94
|
+
old_dec
|
95
|
+
.gsub(":#{old_tag}", ":#{new_tag}")
|
96
|
+
.gsub(old_digest.to_s, new_digest.to_s)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
Dependabot::FileUpdaters.register(
|
104
|
+
"docker_compose",
|
105
|
+
Dependabot::DockerCompose::FileUpdater
|
106
|
+
)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "dependabot/metadata_finders"
|
5
|
+
require "dependabot/metadata_finders/base"
|
6
|
+
require "dependabot/shared_helpers"
|
7
|
+
require "sorbet-runtime"
|
8
|
+
|
9
|
+
module Dependabot
|
10
|
+
module DockerCompose
|
11
|
+
class MetadataFinder < Dependabot::MetadataFinders::Base
|
12
|
+
extend T::Sig
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
sig { override.returns(T.nilable(Dependabot::Source)) }
|
17
|
+
def look_up_source
|
18
|
+
return if dependency.requirements.empty?
|
19
|
+
|
20
|
+
new_source = dependency.requirements.first&.fetch(:source)
|
21
|
+
return unless new_source && new_source[:registry] && new_source[:tag]
|
22
|
+
|
23
|
+
image_ref = "#{new_source[:registry]}/#{dependency.name}:#{new_source[:tag]}"
|
24
|
+
image_details_output = SharedHelpers.run_shell_command("regctl image inspect #{image_ref}")
|
25
|
+
image_details = JSON.parse(image_details_output)
|
26
|
+
image_source = image_details.dig("config", "Labels", "org.opencontainers.image.source")
|
27
|
+
return unless image_source
|
28
|
+
|
29
|
+
Dependabot::Source.from_url(image_source)
|
30
|
+
rescue StandardError => e
|
31
|
+
Dependabot.logger.warn("Error looking up Docker Compose source: #{e.message}")
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Dependabot::MetadataFinders
|
39
|
+
.register("docker_compose", Dependabot::DockerCompose::MetadataFinder)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# typed: strong
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "sorbet-runtime"
|
5
|
+
require "dependabot/docker_compose/version"
|
6
|
+
require "dependabot/ecosystem"
|
7
|
+
require "dependabot/docker_compose/requirement"
|
8
|
+
|
9
|
+
module Dependabot
|
10
|
+
module DockerCompose
|
11
|
+
ECOSYSTEM = "docker_compose"
|
12
|
+
|
13
|
+
SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
|
14
|
+
|
15
|
+
DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
|
16
|
+
|
17
|
+
class DockerPackageManager < Dependabot::Ecosystem::VersionManager
|
18
|
+
extend T::Sig
|
19
|
+
|
20
|
+
NAME = "docker_compose"
|
21
|
+
|
22
|
+
# As docker_compose updater is an in house custom utility, We use a placeholder
|
23
|
+
# version number for docker_compose updater
|
24
|
+
VERSION = "1.0.0"
|
25
|
+
|
26
|
+
SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
|
27
|
+
|
28
|
+
DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
|
29
|
+
|
30
|
+
sig do
|
31
|
+
void
|
32
|
+
end
|
33
|
+
def initialize
|
34
|
+
super(
|
35
|
+
name: NAME,
|
36
|
+
version: Version.new(VERSION),
|
37
|
+
deprecated_versions: DEPRECATED_VERSIONS,
|
38
|
+
supported_versions: SUPPORTED_VERSIONS
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
sig { override.returns(T::Boolean) }
|
43
|
+
def deprecated?
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
sig { override.returns(T::Boolean) }
|
48
|
+
def unsupported?
|
49
|
+
false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
6
|
+
require "dependabot/requirement"
|
7
|
+
require "dependabot/utils"
|
8
|
+
|
9
|
+
module Dependabot
|
10
|
+
module DockerCompose
|
11
|
+
# Lifted from the bundler package manager
|
12
|
+
class Requirement < Dependabot::Requirement
|
13
|
+
extend T::Sig
|
14
|
+
|
15
|
+
# For consistency with other languages, we define a requirements array.
|
16
|
+
# Ruby doesn't have an `OR` separator for requirements, so it always
|
17
|
+
# contains a single element.
|
18
|
+
sig { override.params(requirement_string: T.nilable(String)).returns(T::Array[Requirement]) }
|
19
|
+
def self.requirements_array(requirement_string)
|
20
|
+
[new(T.must(requirement_string))]
|
21
|
+
end
|
22
|
+
|
23
|
+
sig { override.params(version: Version).returns(T::Boolean) }
|
24
|
+
def satisfied_by?(version)
|
25
|
+
super(version.release_part)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Patches Gem::Requirement to make it accept requirement strings like
|
29
|
+
# "~> 4.2.5, >= 4.2.5.1" without first needing to split them.
|
30
|
+
sig { params(requirements: T.any(T.nilable(String), T::Array[T.nilable(String)])).void }
|
31
|
+
def initialize(*requirements)
|
32
|
+
requirements = requirements.flatten.flat_map do |req_string|
|
33
|
+
req_string.to_s.split(",").map(&:strip)
|
34
|
+
end
|
35
|
+
|
36
|
+
super(requirements)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Dependabot::Utils
|
43
|
+
.register_requirement_class("docker_compose", Dependabot::DockerCompose::Requirement)
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# typed: strong
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module DockerCompose
|
8
|
+
class Tag
|
9
|
+
extend T::Sig
|
10
|
+
WORDS_WITH_BUILD = /(?:(?:-[a-z]+)+-[0-9]+)+/
|
11
|
+
VERSION_REGEX = /v?(?<version>[0-9]+(?:[_.][0-9]+)*(?:\.[a-z0-9]+|#{WORDS_WITH_BUILD}|-(?:kb)?[0-9]+)*)/i
|
12
|
+
VERSION_WITH_SFX = /^#{VERSION_REGEX}(?<suffix>-[a-z][a-z0-9.\-]*)?$/i
|
13
|
+
VERSION_WITH_PFX = /^(?<prefix>[a-z][a-z0-9.\-_]*-)?#{VERSION_REGEX}$/i
|
14
|
+
VERSION_WITH_PFX_AND_SFX = /^(?<prefix>[a-z\-_]+-)?#{VERSION_REGEX}(?<suffix>-[a-z\-]+)?$/i
|
15
|
+
NAME_WITH_VERSION =
|
16
|
+
/
|
17
|
+
#{VERSION_WITH_PFX}|
|
18
|
+
#{VERSION_WITH_SFX}|
|
19
|
+
#{VERSION_WITH_PFX_AND_SFX}
|
20
|
+
/x
|
21
|
+
DIGEST = /@(?<digest>[^\s]+)/
|
22
|
+
|
23
|
+
sig { returns(String) }
|
24
|
+
attr_reader :name
|
25
|
+
|
26
|
+
sig { params(name: String).void }
|
27
|
+
def initialize(name)
|
28
|
+
@name = name
|
29
|
+
end
|
30
|
+
|
31
|
+
sig { returns(String) }
|
32
|
+
def to_s
|
33
|
+
name
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { returns(T::Boolean) }
|
37
|
+
def digest?
|
38
|
+
name.match?(DIGEST)
|
39
|
+
end
|
40
|
+
|
41
|
+
sig { returns(T.nilable(T::Boolean)) }
|
42
|
+
def looks_like_prerelease?
|
43
|
+
numeric_version&.match?(/[a-zA-Z]/)
|
44
|
+
end
|
45
|
+
|
46
|
+
sig { params(other: Tag).returns(T::Boolean) }
|
47
|
+
def comparable_to?(other)
|
48
|
+
return false unless comparable?
|
49
|
+
|
50
|
+
other_prefix = other.prefix
|
51
|
+
other_suffix = other.suffix
|
52
|
+
other_format = other.format
|
53
|
+
|
54
|
+
equal_prefix = prefix == other_prefix
|
55
|
+
equal_format = format == other_format
|
56
|
+
return equal_prefix && equal_format if other_format == :sha_suffixed
|
57
|
+
|
58
|
+
equal_suffix = suffix == other_suffix
|
59
|
+
equal_prefix && equal_format && equal_suffix
|
60
|
+
end
|
61
|
+
|
62
|
+
sig { returns(T::Boolean) }
|
63
|
+
def comparable?
|
64
|
+
name.match?(NAME_WITH_VERSION)
|
65
|
+
end
|
66
|
+
|
67
|
+
sig { params(other: Tag).returns(T::Boolean) }
|
68
|
+
def same_precision?(other)
|
69
|
+
other.precision == precision
|
70
|
+
end
|
71
|
+
|
72
|
+
sig { params(other: Tag).returns(T::Boolean) }
|
73
|
+
def same_but_less_precise?(other)
|
74
|
+
other.segments.zip(segments).all? do |segment, other_segment|
|
75
|
+
segment == other_segment || other_segment.nil?
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
sig { returns(T.nilable(T::Boolean)) }
|
80
|
+
def canonical?
|
81
|
+
return false unless numeric_version
|
82
|
+
return true if name == numeric_version
|
83
|
+
|
84
|
+
# .NET tags are suffixed with -sdk
|
85
|
+
return true if numeric_version && name == numeric_version.to_s + "-sdk"
|
86
|
+
|
87
|
+
numeric_version && name == "jdk-" + T.must(numeric_version)
|
88
|
+
end
|
89
|
+
|
90
|
+
sig { returns T.nilable(String) }
|
91
|
+
def prefix
|
92
|
+
name.match(NAME_WITH_VERSION)&.named_captures&.fetch("prefix")
|
93
|
+
end
|
94
|
+
|
95
|
+
sig { returns T.nilable(String) }
|
96
|
+
def suffix
|
97
|
+
name.match(NAME_WITH_VERSION)&.named_captures&.fetch("suffix")
|
98
|
+
end
|
99
|
+
|
100
|
+
sig { returns T.nilable(String) }
|
101
|
+
def version
|
102
|
+
name.match(NAME_WITH_VERSION)&.named_captures&.fetch("version")
|
103
|
+
end
|
104
|
+
|
105
|
+
sig { returns(Symbol) }
|
106
|
+
def format
|
107
|
+
return :sha_suffixed if name.match?(/(^|\-g?)[0-9a-f]{7,}$/)
|
108
|
+
return :year_month if version&.match?(/^[12]\d{3}(?:[.\-]|$)/)
|
109
|
+
return :year_month_day if version&.match?(/^[12](?:\d{5}|\d{7})(?:[.\-]|$)/)
|
110
|
+
return :build_num if version&.match?(/^\d+$/)
|
111
|
+
|
112
|
+
# As an example, "21-ea-32", "22-ea-7", and "22-ea-jdk-nanoserver-1809"
|
113
|
+
# are mapped to "<version>-ea-<build_num>", "<version>-ea-<build_num>",
|
114
|
+
# and "<version>-ea-jdk-nanoserver-<build_num>" respectively.
|
115
|
+
#
|
116
|
+
# That means only "22-ea-7" will be considered as a viable update
|
117
|
+
# candidate for "21-ea-32", since it's the only one that respects that
|
118
|
+
# format.
|
119
|
+
if version&.match?(WORDS_WITH_BUILD)
|
120
|
+
return :"<version>#{T.must(version).match(WORDS_WITH_BUILD).to_s.gsub(/-[0-9]+/, '-<build_num>')}"
|
121
|
+
end
|
122
|
+
|
123
|
+
:normal
|
124
|
+
end
|
125
|
+
|
126
|
+
sig { returns(T.nilable(String)) }
|
127
|
+
def numeric_version
|
128
|
+
return unless comparable?
|
129
|
+
|
130
|
+
version&.gsub(/kb/i, "")&.gsub(/-[a-z]+/, "")&.downcase
|
131
|
+
end
|
132
|
+
|
133
|
+
sig { returns(Integer) }
|
134
|
+
def precision
|
135
|
+
segments.length
|
136
|
+
end
|
137
|
+
|
138
|
+
sig { returns(T::Array[String]) }
|
139
|
+
def segments
|
140
|
+
T.must(numeric_version).split(/[.-]/)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|