dependabot-gradle 0.84.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nokogiri"
4
+ require "dependabot/shared_helpers"
5
+ require "dependabot/gradle/file_parser/repositories_finder"
6
+ require "dependabot/gradle/update_checker"
7
+ require "dependabot/gradle/version"
8
+ require "dependabot/gradle/requirement"
9
+
10
+ module Dependabot
11
+ module Gradle
12
+ class UpdateChecker
13
+ class VersionFinder
14
+ GOOGLE_MAVEN_REPO = "https://maven.google.com"
15
+ TYPE_SUFFICES = %w(jre android java).freeze
16
+
17
+ def initialize(dependency:, dependency_files:, ignored_versions:)
18
+ @dependency = dependency
19
+ @dependency_files = dependency_files
20
+ @ignored_versions = ignored_versions
21
+ end
22
+
23
+ def latest_version_details
24
+ possible_versions = versions
25
+
26
+ unless wants_prerelease?
27
+ possible_versions =
28
+ possible_versions.
29
+ reject { |v| v.fetch(:version).prerelease? }
30
+ end
31
+
32
+ unless wants_date_based_version?
33
+ possible_versions =
34
+ possible_versions.
35
+ reject { |v| v.fetch(:version) > version_class.new(1900) }
36
+ end
37
+
38
+ possible_versions =
39
+ possible_versions.
40
+ select { |v| matches_dependency_version_type?(v.fetch(:version)) }
41
+
42
+ ignored_versions.each do |req|
43
+ ignore_req = Gradle::Requirement.new(req.split(","))
44
+ possible_versions =
45
+ possible_versions.
46
+ reject { |v| ignore_req.satisfied_by?(v.fetch(:version)) }
47
+ end
48
+
49
+ possible_versions.last
50
+ end
51
+
52
+ def versions
53
+ version_details =
54
+ repository_urls.map do |url|
55
+ next google_version_details if url == GOOGLE_MAVEN_REPO
56
+
57
+ dependency_metadata(url).css("versions > version").
58
+ select { |node| version_class.correct?(node.content) }.
59
+ map { |node| version_class.new(node.content) }.
60
+ map { |version| { version: version, source_url: url } }
61
+ end.flatten.compact
62
+
63
+ version_details.sort_by { |details| details.fetch(:version) }
64
+ end
65
+
66
+ private
67
+
68
+ attr_reader :dependency, :dependency_files, :ignored_versions
69
+
70
+ def wants_prerelease?
71
+ return false unless dependency.version
72
+ return false unless version_class.correct?(dependency.version)
73
+
74
+ version_class.new(dependency.version).prerelease?
75
+ end
76
+
77
+ def wants_date_based_version?
78
+ return false unless dependency.version
79
+ return false unless version_class.correct?(dependency.version)
80
+
81
+ version_class.new(dependency.version) >= version_class.new(100)
82
+ end
83
+
84
+ def google_version_details
85
+ url = GOOGLE_MAVEN_REPO
86
+ group_id, artifact_id = dependency.name.split(":")
87
+
88
+ dependency_metadata_url = "#{GOOGLE_MAVEN_REPO}/"\
89
+ "#{group_id.tr('.', '/')}/"\
90
+ "group-index.xml"
91
+
92
+ @google_version_details ||=
93
+ begin
94
+ response = Excon.get(
95
+ dependency_metadata_url,
96
+ idempotent: true,
97
+ **SharedHelpers.excon_defaults
98
+ )
99
+ Nokogiri::XML(response.body)
100
+ end
101
+
102
+ xpath = "/#{group_id}/#{artifact_id}"
103
+ return unless @google_version_details.at_xpath(xpath)
104
+
105
+ @google_version_details.at_xpath(xpath).
106
+ attributes.fetch("versions").
107
+ value.split(",").
108
+ select { |v| version_class.correct?(v) }.
109
+ map { |v| version_class.new(v) }.
110
+ map { |version| { version: version, source_url: url } }
111
+ end
112
+
113
+ def dependency_metadata(repository_url)
114
+ @dependency_metadata ||= {}
115
+ @dependency_metadata[repository_url] ||=
116
+ begin
117
+ response = Excon.get(
118
+ dependency_metadata_url(repository_url),
119
+ idempotent: true,
120
+ **SharedHelpers.excon_defaults
121
+ )
122
+ Nokogiri::XML(response.body)
123
+ rescue Excon::Error::Socket, Excon::Error::Timeout
124
+ namespace = Gradle::FileParser::RepositoriesFinder
125
+ central = namespace::CENTRAL_REPO_URL
126
+ raise if repository_url == central
127
+
128
+ Nokogiri::XML("")
129
+ end
130
+ end
131
+
132
+ def repository_urls
133
+ requirement_files =
134
+ dependency.requirements.
135
+ map { |r| r.fetch(:file) }.
136
+ map { |nm| dependency_files.find { |f| f.name == nm } }
137
+
138
+ @repository_urls ||=
139
+ requirement_files.flat_map do |target_file|
140
+ Gradle::FileParser::RepositoriesFinder.new(
141
+ dependency_files: dependency_files,
142
+ target_dependency_file: target_file
143
+ ).repository_urls
144
+ end.uniq
145
+ end
146
+
147
+ def matches_dependency_version_type?(comparison_version)
148
+ return true unless dependency.version
149
+
150
+ current_type =
151
+ TYPE_SUFFICES.
152
+ find { |t| dependency.version.split(/[.\-]/).include?(t) }
153
+
154
+ version_type =
155
+ TYPE_SUFFICES.
156
+ find { |t| comparison_version.to_s.split(/[.\-]/).include?(t) }
157
+
158
+ current_type == version_type
159
+ end
160
+
161
+ def pom
162
+ filename = dependency.requirements.first.fetch(:file)
163
+ dependency_files.find { |f| f.name == filename }
164
+ end
165
+
166
+ def dependency_metadata_url(repository_url)
167
+ group_id, artifact_id = dependency.name.split(":")
168
+
169
+ "#{repository_url}/"\
170
+ "#{group_id.tr('.', '/')}/"\
171
+ "#{artifact_id}/"\
172
+ "maven-metadata.xml"
173
+ end
174
+
175
+ def version_class
176
+ Gradle::Version
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/utils"
4
+
5
+ # Java versions use dots and dashes when tokenising their versions.
6
+ # Gem::Version converts a "-" to ".pre.", so we override the `to_s` method.
7
+ #
8
+ # See https://maven.apache.org/pom.html#Version_Order_Specification for details.
9
+
10
+ module Dependabot
11
+ module Gradle
12
+ class Version < Gem::Version
13
+ NULL_VALUES = %w(0 final ga).freeze
14
+ PREFIXED_TOKEN_HIERARCHY = {
15
+ "." => { qualifier: 1, number: 4 },
16
+ "-" => { qualifier: 2, number: 3 }
17
+ }.freeze
18
+ NAMED_QUALIFIERS_HIERARCHY = {
19
+ "a" => 1, "alpha" => 1,
20
+ "b" => 2, "beta" => 2,
21
+ "m" => 3, "milestone" => 3,
22
+ "rc" => 4, "cr" => 4,
23
+ "snapshot" => 5,
24
+ "ga" => 6, "" => 6, "final" => 6,
25
+ "sp" => 7
26
+ }.freeze
27
+ VERSION_PATTERN =
28
+ '[0-9a-zA-Z]+(?>\.[0-9a-zA-Z]*)*(-[0-9A-Za-z-]*(\.[0-9A-Za-z-]*)*)?'
29
+ ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/.freeze
30
+
31
+ def self.correct?(version)
32
+ return false if version.nil?
33
+
34
+ version.to_s.match?(ANCHORED_VERSION_PATTERN)
35
+ end
36
+
37
+ def initialize(version)
38
+ @version_string = version.to_s
39
+ super(version.to_s.tr("_", "-"))
40
+ end
41
+
42
+ def to_s
43
+ @version_string
44
+ end
45
+
46
+ def prerelease?
47
+ tokens.any? do |token|
48
+ next false unless NAMED_QUALIFIERS_HIERARCHY[token]
49
+
50
+ NAMED_QUALIFIERS_HIERARCHY[token] < 6
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def tokens
57
+ @tokens ||=
58
+ begin
59
+ version = @version_string.to_s.downcase
60
+ version = fill_tokens(version)
61
+ version = trim_version(version)
62
+ split_into_prefixed_tokens(version).map { |t| t[1..-1] }
63
+ end
64
+ end
65
+
66
+ def <=>(other)
67
+ version = stringify_version(@version_string)
68
+ version = fill_tokens(version)
69
+ version = trim_version(version)
70
+
71
+ other_version = stringify_version(other)
72
+ other_version = fill_tokens(other_version)
73
+ other_version = trim_version(other_version)
74
+
75
+ version, other_version = convert_dates(version, other_version)
76
+
77
+ prefixed_tokens = split_into_prefixed_tokens(version)
78
+ other_prefixed_tokens = split_into_prefixed_tokens(other_version)
79
+
80
+ prefixed_tokens, other_prefixed_tokens =
81
+ pad_for_comparison(prefixed_tokens, other_prefixed_tokens)
82
+
83
+ prefixed_tokens.count.times.each do |index|
84
+ comp = compare_prefixed_token(
85
+ prefix: prefixed_tokens[index][0],
86
+ token: prefixed_tokens[index][1..-1] || "",
87
+ other_prefix: other_prefixed_tokens[index][0],
88
+ other_token: other_prefixed_tokens[index][1..-1] || ""
89
+ )
90
+ return comp unless comp.zero?
91
+ end
92
+
93
+ 0
94
+ end
95
+
96
+ def stringify_version(version)
97
+ version = version.to_s.downcase
98
+
99
+ # Not technically correct, but pragmatic
100
+ version.gsub(/^v(?=\d)/, "")
101
+ end
102
+
103
+ def fill_tokens(version)
104
+ # Add separators when transitioning from digits to characters
105
+ version = version.gsub(/(\d)([A-Za-z])/, '\1-\2')
106
+ version = version.gsub(/([A-Za-z])(\d)/, '\1-\2')
107
+
108
+ # Replace empty tokens with 0
109
+ version = version.gsub(/([\.\-])([\.\-])/, '\10\2')
110
+ version = version.gsub(/^([\.\-])/, '0\1')
111
+ version.gsub(/([\.\-])$/, '\10')
112
+ end
113
+
114
+ def trim_version(version)
115
+ version.split("-").map do |v|
116
+ parts = v.split(".")
117
+ parts = parts[0..-2] while NULL_VALUES.include?(parts&.last)
118
+ parts&.join(".")
119
+ end.compact.reject(&:empty?).join("-")
120
+ end
121
+
122
+ def convert_dates(version, other_version)
123
+ default = [version, other_version]
124
+ return default unless version.match?(/^\d{4}-?\d{2}-?\d{2}$/)
125
+ return default unless other_version.match?(/^\d{4}-?\d{2}-?\d{2}$/)
126
+
127
+ [version.delete("-"), other_version.delete("-")]
128
+ end
129
+
130
+ def split_into_prefixed_tokens(version)
131
+ ".#{version}".split(/(?=[\-\.])/)
132
+ end
133
+
134
+ def pad_for_comparison(prefixed_tokens, other_prefixed_tokens)
135
+ prefixed_tokens = prefixed_tokens.dup
136
+ other_prefixed_tokens = other_prefixed_tokens.dup
137
+
138
+ longest = [prefixed_tokens, other_prefixed_tokens].max_by(&:count)
139
+ shortest = [prefixed_tokens, other_prefixed_tokens].min_by(&:count)
140
+
141
+ longest.count.times do |index|
142
+ next unless shortest[index].nil?
143
+
144
+ shortest[index] = longest[index].start_with?(".") ? ".0" : "-"
145
+ end
146
+
147
+ [prefixed_tokens, other_prefixed_tokens]
148
+ end
149
+
150
+ def compare_prefixed_token(prefix:, token:, other_prefix:, other_token:)
151
+ token_type = token.match?(/^\d+$/) ? :number : :qualifier
152
+ other_token_type = other_token.match?(/^\d+$/) ? :number : :qualifier
153
+
154
+ hierarchy = PREFIXED_TOKEN_HIERARCHY.fetch(prefix).fetch(token_type)
155
+ other_hierarchy =
156
+ PREFIXED_TOKEN_HIERARCHY.fetch(other_prefix).fetch(other_token_type)
157
+
158
+ hierarchy_comparison = hierarchy <=> other_hierarchy
159
+ return hierarchy_comparison unless hierarchy_comparison.zero?
160
+
161
+ compare_token(token: token, other_token: other_token)
162
+ end
163
+
164
+ def compare_token(token:, other_token:)
165
+ if (token_hierarchy = NAMED_QUALIFIERS_HIERARCHY[token])
166
+ return -1 unless NAMED_QUALIFIERS_HIERARCHY[other_token]
167
+
168
+ return token_hierarchy <=> NAMED_QUALIFIERS_HIERARCHY[other_token]
169
+ end
170
+
171
+ return 1 if NAMED_QUALIFIERS_HIERARCHY[other_token]
172
+
173
+ token = token.to_i if token.match?(/^\d+$/)
174
+ other_token = other_token.to_i if other_token.match?(/^\d+$/)
175
+ token <=> other_token
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ Dependabot::Utils.register_version_class("gradle", Dependabot::Gradle::Version)
metadata ADDED
@@ -0,0 +1,186 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dependabot-gradle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.84.0
5
+ platform: ruby
6
+ authors:
7
+ - Dependabot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-12-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dependabot-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.84.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.84.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '12'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '12'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.8'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-its
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec_junit_formatter
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.4'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.61'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.61'
111
+ - !ruby/object:Gem::Dependency
112
+ name: vcr
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '4.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '4.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: webmock
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.4'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.4'
139
+ description: Automated dependency management for Ruby, JavaScript, Python, PHP, Elixir,
140
+ Rust, Java, .NET, Elm and Go
141
+ email: support@dependabot.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - lib/dependabot/gradle.rb
147
+ - lib/dependabot/gradle/file_fetcher.rb
148
+ - lib/dependabot/gradle/file_fetcher/settings_file_parser.rb
149
+ - lib/dependabot/gradle/file_parser.rb
150
+ - lib/dependabot/gradle/file_parser/property_value_finder.rb
151
+ - lib/dependabot/gradle/file_parser/repositories_finder.rb
152
+ - lib/dependabot/gradle/file_updater.rb
153
+ - lib/dependabot/gradle/file_updater/dependency_set_updater.rb
154
+ - lib/dependabot/gradle/file_updater/property_value_updater.rb
155
+ - lib/dependabot/gradle/metadata_finder.rb
156
+ - lib/dependabot/gradle/requirement.rb
157
+ - lib/dependabot/gradle/update_checker.rb
158
+ - lib/dependabot/gradle/update_checker/multi_dependency_updater.rb
159
+ - lib/dependabot/gradle/update_checker/requirements_updater.rb
160
+ - lib/dependabot/gradle/update_checker/version_finder.rb
161
+ - lib/dependabot/gradle/version.rb
162
+ homepage: https://github.com/dependabot/dependabot-core
163
+ licenses:
164
+ - Nonstandard
165
+ metadata: {}
166
+ post_install_message:
167
+ rdoc_options: []
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: 2.5.0
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: 2.5.0
180
+ requirements: []
181
+ rubyforge_project:
182
+ rubygems_version: 2.7.6
183
+ signing_key:
184
+ specification_version: 4
185
+ summary: Gradle support for dependabot-core
186
+ test_files: []