dependabot-core 0.93.17 → 0.94.0
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 +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/dependabot/dependency.rb +16 -21
- data/lib/dependabot/file_fetchers.rb +1 -5
- data/lib/dependabot/file_parsers.rb +1 -5
- data/lib/dependabot/file_updaters.rb +1 -5
- data/lib/dependabot/metadata_finders.rb +1 -5
- data/lib/dependabot/pull_request_creator/labeler.rb +26 -24
- data/lib/dependabot/update_checkers.rb +1 -5
- data/lib/dependabot/utils.rb +2 -12
- data/lib/dependabot/version.rb +1 -1
- metadata +1 -28
- data/lib/dependabot/file_fetchers/ruby/bundler.rb +0 -215
- data/lib/dependabot/file_fetchers/ruby/bundler/child_gemfile_finder.rb +0 -70
- data/lib/dependabot/file_fetchers/ruby/bundler/gemspec_finder.rb +0 -98
- data/lib/dependabot/file_fetchers/ruby/bundler/path_gemspec_finder.rb +0 -114
- data/lib/dependabot/file_fetchers/ruby/bundler/require_relative_finder.rb +0 -67
- data/lib/dependabot/file_parsers/ruby/bundler.rb +0 -294
- data/lib/dependabot/file_parsers/ruby/bundler/file_preparer.rb +0 -86
- data/lib/dependabot/file_parsers/ruby/bundler/gemfile_checker.rb +0 -48
- data/lib/dependabot/file_updaters/ruby/bundler.rb +0 -123
- data/lib/dependabot/file_updaters/ruby/bundler/gemfile_updater.rb +0 -116
- data/lib/dependabot/file_updaters/ruby/bundler/gemspec_dependency_name_finder.rb +0 -52
- data/lib/dependabot/file_updaters/ruby/bundler/gemspec_sanitizer.rb +0 -298
- data/lib/dependabot/file_updaters/ruby/bundler/gemspec_updater.rb +0 -64
- data/lib/dependabot/file_updaters/ruby/bundler/git_pin_replacer.rb +0 -80
- data/lib/dependabot/file_updaters/ruby/bundler/git_source_remover.rb +0 -102
- data/lib/dependabot/file_updaters/ruby/bundler/lockfile_updater.rb +0 -389
- data/lib/dependabot/file_updaters/ruby/bundler/requirement_replacer.rb +0 -223
- data/lib/dependabot/metadata_finders/ruby/bundler.rb +0 -202
- data/lib/dependabot/update_checkers/ruby/bundler.rb +0 -331
- data/lib/dependabot/update_checkers/ruby/bundler/file_preparer.rb +0 -281
- data/lib/dependabot/update_checkers/ruby/bundler/force_updater.rb +0 -261
- data/lib/dependabot/update_checkers/ruby/bundler/latest_version_finder.rb +0 -169
- data/lib/dependabot/update_checkers/ruby/bundler/requirements_updater.rb +0 -283
- data/lib/dependabot/update_checkers/ruby/bundler/ruby_requirement_setter.rb +0 -115
- data/lib/dependabot/update_checkers/ruby/bundler/shared_bundler_helpers.rb +0 -246
- data/lib/dependabot/update_checkers/ruby/bundler/version_resolver.rb +0 -272
- data/lib/dependabot/utils/ruby/requirement.rb +0 -26
@@ -1,223 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "parser/current"
|
4
|
-
require "dependabot/file_updaters/ruby/bundler"
|
5
|
-
|
6
|
-
module Dependabot
|
7
|
-
module FileUpdaters
|
8
|
-
module Ruby
|
9
|
-
class Bundler
|
10
|
-
class RequirementReplacer
|
11
|
-
attr_reader :dependency, :file_type, :updated_requirement,
|
12
|
-
:previous_requirement
|
13
|
-
|
14
|
-
def initialize(dependency:, file_type:, updated_requirement:,
|
15
|
-
previous_requirement: nil, insert_if_bare: false)
|
16
|
-
@dependency = dependency
|
17
|
-
@file_type = file_type
|
18
|
-
@updated_requirement = updated_requirement
|
19
|
-
@previous_requirement = previous_requirement
|
20
|
-
@insert_if_bare = insert_if_bare
|
21
|
-
end
|
22
|
-
|
23
|
-
def rewrite(content)
|
24
|
-
buffer = Parser::Source::Buffer.new("(gemfile_content)")
|
25
|
-
buffer.source = content
|
26
|
-
ast = Parser::CurrentRuby.new.parse(buffer)
|
27
|
-
|
28
|
-
updated_content = Rewriter.new(
|
29
|
-
dependency: dependency,
|
30
|
-
file_type: file_type,
|
31
|
-
updated_requirement: updated_requirement,
|
32
|
-
insert_if_bare: insert_if_bare?
|
33
|
-
).rewrite(buffer, ast)
|
34
|
-
|
35
|
-
update_comment_spacing_if_required(content, updated_content)
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def insert_if_bare?
|
41
|
-
@insert_if_bare
|
42
|
-
end
|
43
|
-
|
44
|
-
def update_comment_spacing_if_required(content, updated_content)
|
45
|
-
return updated_content unless previous_requirement
|
46
|
-
|
47
|
-
return updated_content if updated_content == content
|
48
|
-
return updated_content if length_change.zero?
|
49
|
-
|
50
|
-
updated_lines = updated_content.lines
|
51
|
-
updated_line_index =
|
52
|
-
updated_lines.length.
|
53
|
-
times.find { |i| content.lines[i] != updated_content.lines[i] }
|
54
|
-
updated_line = updated_lines[updated_line_index]
|
55
|
-
|
56
|
-
updated_line =
|
57
|
-
if length_change.positive?
|
58
|
-
updated_line.sub(/(?<=\s)\s{#{length_change}}#/, "#")
|
59
|
-
elsif length_change.negative?
|
60
|
-
updated_line.sub(/(?<=\s{2})#/, " " * length_change.abs + "#")
|
61
|
-
end
|
62
|
-
|
63
|
-
updated_lines[updated_line_index] = updated_line
|
64
|
-
updated_lines.join
|
65
|
-
end
|
66
|
-
|
67
|
-
def length_change
|
68
|
-
unless previous_requirement.start_with?("=")
|
69
|
-
return updated_requirement.length - previous_requirement.length
|
70
|
-
end
|
71
|
-
|
72
|
-
updated_requirement.length -
|
73
|
-
previous_requirement.gsub(/^=/, "").strip.length
|
74
|
-
end
|
75
|
-
|
76
|
-
class Rewriter < Parser::TreeRewriter
|
77
|
-
# TODO: Ideally we wouldn't have to ignore all of these, but
|
78
|
-
# implementing each one will be tricky.
|
79
|
-
SKIPPED_TYPES = %i(send lvar dstr begin if splat const).freeze
|
80
|
-
|
81
|
-
def initialize(dependency:, file_type:, updated_requirement:,
|
82
|
-
insert_if_bare:)
|
83
|
-
@dependency = dependency
|
84
|
-
@file_type = file_type
|
85
|
-
@updated_requirement = updated_requirement
|
86
|
-
@insert_if_bare = insert_if_bare
|
87
|
-
|
88
|
-
return if %i(gemfile gemspec).include?(file_type)
|
89
|
-
|
90
|
-
raise "File type must be :gemfile or :gemspec. Got #{file_type}."
|
91
|
-
end
|
92
|
-
|
93
|
-
def on_send(node)
|
94
|
-
return unless declares_targeted_gem?(node)
|
95
|
-
|
96
|
-
req_nodes = node.children[3..-1]
|
97
|
-
req_nodes = req_nodes.reject { |child| child.type == :hash }
|
98
|
-
|
99
|
-
return if req_nodes.none? && !insert_if_bare?
|
100
|
-
return if req_nodes.any? { |n| SKIPPED_TYPES.include?(n.type) }
|
101
|
-
|
102
|
-
quote_characters = extract_quote_characters_from(req_nodes)
|
103
|
-
space_after_specifier = space_after_specifier?(req_nodes)
|
104
|
-
use_equality_operator = use_equality_operator?(req_nodes)
|
105
|
-
|
106
|
-
new_req = new_requirement_string(
|
107
|
-
quote_characters: quote_characters,
|
108
|
-
space_after_specifier: space_after_specifier,
|
109
|
-
use_equality_operator: use_equality_operator
|
110
|
-
)
|
111
|
-
if req_nodes.any?
|
112
|
-
replace(range_for(req_nodes), new_req)
|
113
|
-
else
|
114
|
-
insert_after(range_for(node.children[2..2]), ", #{new_req}")
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
private
|
119
|
-
|
120
|
-
attr_reader :dependency, :file_type, :updated_requirement
|
121
|
-
|
122
|
-
def insert_if_bare?
|
123
|
-
@insert_if_bare
|
124
|
-
end
|
125
|
-
|
126
|
-
def declaration_methods
|
127
|
-
return %i(gem) if file_type == :gemfile
|
128
|
-
|
129
|
-
%i(add_dependency add_runtime_dependency
|
130
|
-
add_development_dependency)
|
131
|
-
end
|
132
|
-
|
133
|
-
def declares_targeted_gem?(node)
|
134
|
-
return false unless declaration_methods.include?(node.children[1])
|
135
|
-
|
136
|
-
node.children[2].children.first == dependency.name
|
137
|
-
end
|
138
|
-
|
139
|
-
def extract_quote_characters_from(requirement_nodes)
|
140
|
-
return ['"', '"'] if requirement_nodes.none?
|
141
|
-
|
142
|
-
case requirement_nodes.first.type
|
143
|
-
when :str, :dstr
|
144
|
-
[
|
145
|
-
requirement_nodes.first.loc.begin.source,
|
146
|
-
requirement_nodes.first.loc.end.source
|
147
|
-
]
|
148
|
-
else
|
149
|
-
[
|
150
|
-
requirement_nodes.first.children.first.loc.begin.source,
|
151
|
-
requirement_nodes.first.children.first.loc.end.source
|
152
|
-
]
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def space_after_specifier?(requirement_nodes)
|
157
|
-
return true if requirement_nodes.none?
|
158
|
-
|
159
|
-
req_string =
|
160
|
-
case requirement_nodes.first.type
|
161
|
-
when :str, :dstr
|
162
|
-
requirement_nodes.first.loc.expression.source
|
163
|
-
else
|
164
|
-
requirement_nodes.first.children.first.loc.expression.source
|
165
|
-
end
|
166
|
-
|
167
|
-
ops = Gem::Requirement::OPS.keys
|
168
|
-
return true if ops.none? { |op| req_string.include?(op) }
|
169
|
-
|
170
|
-
req_string.include?(" ")
|
171
|
-
end
|
172
|
-
|
173
|
-
def use_equality_operator?(requirement_nodes)
|
174
|
-
return true if requirement_nodes.none?
|
175
|
-
|
176
|
-
req_string =
|
177
|
-
case requirement_nodes.first.type
|
178
|
-
when :str, :dstr
|
179
|
-
requirement_nodes.first.loc.expression.source
|
180
|
-
else
|
181
|
-
requirement_nodes.first.children.first.loc.expression.source
|
182
|
-
end
|
183
|
-
|
184
|
-
req_string.match?(/(?<![<>])=/)
|
185
|
-
end
|
186
|
-
|
187
|
-
def new_requirement_string(quote_characters:,
|
188
|
-
space_after_specifier:,
|
189
|
-
use_equality_operator:)
|
190
|
-
open_quote, close_quote = quote_characters
|
191
|
-
new_requirement_string =
|
192
|
-
updated_requirement.split(",").
|
193
|
-
map do |r|
|
194
|
-
req_string = serialized_req(r, use_equality_operator)
|
195
|
-
%(#{open_quote}#{req_string}#{close_quote})
|
196
|
-
end.join(", ")
|
197
|
-
|
198
|
-
new_requirement_string.delete!(" ") unless space_after_specifier
|
199
|
-
new_requirement_string
|
200
|
-
end
|
201
|
-
|
202
|
-
def serialized_req(req, use_equality_operator)
|
203
|
-
tmp_req = req
|
204
|
-
|
205
|
-
# Gem::Requirement serializes exact matches as a string starting
|
206
|
-
# with `=`. We may need to remove that equality operator if it
|
207
|
-
# wasn't used originally.
|
208
|
-
unless use_equality_operator
|
209
|
-
tmp_req = tmp_req.gsub(/(?<![<>])=/, "")
|
210
|
-
end
|
211
|
-
|
212
|
-
tmp_req.strip
|
213
|
-
end
|
214
|
-
|
215
|
-
def range_for(nodes)
|
216
|
-
nodes.first.loc.begin.begin.join(nodes.last.loc.expression)
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
@@ -1,202 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "excon"
|
4
|
-
require "dependabot/metadata_finders/base"
|
5
|
-
|
6
|
-
module Dependabot
|
7
|
-
module MetadataFinders
|
8
|
-
module Ruby
|
9
|
-
class Bundler < Dependabot::MetadataFinders::Base
|
10
|
-
SOURCE_KEYS = %w(
|
11
|
-
source_code_uri
|
12
|
-
homepage_uri
|
13
|
-
wiki_uri
|
14
|
-
bug_tracker_uri
|
15
|
-
documentation_uri
|
16
|
-
changelog_uri
|
17
|
-
mailing_list_uri
|
18
|
-
download_uri
|
19
|
-
).freeze
|
20
|
-
|
21
|
-
def homepage_url
|
22
|
-
return super unless %w(default rubygems).include?(new_source_type)
|
23
|
-
return super unless rubygems_api_response["homepage_uri"]
|
24
|
-
|
25
|
-
rubygems_api_response["homepage_uri"]
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def look_up_source
|
31
|
-
case new_source_type
|
32
|
-
when "git" then find_source_from_git_url
|
33
|
-
when "default", "rubygems" then find_source_from_rubygems
|
34
|
-
else raise "Unexpected source type: #{new_source_type}"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def new_source_type
|
39
|
-
sources =
|
40
|
-
dependency.requirements.map { |r| r.fetch(:source) }.uniq.compact
|
41
|
-
|
42
|
-
return "default" if sources.empty?
|
43
|
-
raise "Multiple sources! #{sources.join(', ')}" if sources.count > 1
|
44
|
-
|
45
|
-
sources.first[:type] || sources.first.fetch("type")
|
46
|
-
end
|
47
|
-
|
48
|
-
def find_source_from_rubygems
|
49
|
-
api_source = find_source_from_rubygems_api_response
|
50
|
-
return api_source if api_source || new_source_type == "default"
|
51
|
-
|
52
|
-
find_source_from_gemspec_download
|
53
|
-
end
|
54
|
-
|
55
|
-
def find_source_from_rubygems_api_response
|
56
|
-
source_url = rubygems_api_response.
|
57
|
-
values_at(*SOURCE_KEYS).
|
58
|
-
compact.
|
59
|
-
find { |url| Source.from_url(url) }
|
60
|
-
|
61
|
-
Source.from_url(source_url)
|
62
|
-
end
|
63
|
-
|
64
|
-
def find_source_from_git_url
|
65
|
-
info = dependency.requirements.map { |r| r[:source] }.compact.first
|
66
|
-
|
67
|
-
url = info[:url] || info.fetch("url")
|
68
|
-
Source.from_url(url)
|
69
|
-
end
|
70
|
-
|
71
|
-
def find_source_from_gemspec_download
|
72
|
-
github_urls = []
|
73
|
-
return unless rubygems_marshalled_gemspec_response
|
74
|
-
|
75
|
-
rubygems_marshalled_gemspec_response.scan(Source::SOURCE_REGEX) do
|
76
|
-
github_urls << Regexp.last_match.to_s
|
77
|
-
end
|
78
|
-
|
79
|
-
source_url = github_urls.find do |url|
|
80
|
-
repo = Source.from_url(url).repo
|
81
|
-
repo.downcase.end_with?(dependency.name)
|
82
|
-
end
|
83
|
-
return unless source_url
|
84
|
-
|
85
|
-
Source.from_url(source_url)
|
86
|
-
end
|
87
|
-
|
88
|
-
# Note: This response MUST NOT be unmarshalled
|
89
|
-
# (as calling Marshal.load is unsafe)
|
90
|
-
def rubygems_marshalled_gemspec_response
|
91
|
-
if defined?(@rubygems_marshalled_gemspec_response)
|
92
|
-
return @rubygems_marshalled_gemspec_response
|
93
|
-
end
|
94
|
-
|
95
|
-
gemspec_uri =
|
96
|
-
"#{registry_url}quick/Marshal.4.8/"\
|
97
|
-
"#{dependency.name}-#{dependency.version}.gemspec.rz"
|
98
|
-
|
99
|
-
response =
|
100
|
-
Excon.get(
|
101
|
-
gemspec_uri,
|
102
|
-
headers: registry_auth_headers,
|
103
|
-
idempotent: true,
|
104
|
-
**SharedHelpers.excon_defaults
|
105
|
-
)
|
106
|
-
|
107
|
-
if response.status >= 400
|
108
|
-
return @rubygems_marshalled_gemspec_response = nil
|
109
|
-
end
|
110
|
-
|
111
|
-
@rubygems_marshalled_gemspec_response =
|
112
|
-
Zlib::Inflate.inflate(response.body)
|
113
|
-
rescue Zlib::DataError
|
114
|
-
@rubygems_marshalled_gemspec_response = nil
|
115
|
-
end
|
116
|
-
|
117
|
-
def rubygems_api_response
|
118
|
-
return @rubygems_api_response if defined?(@rubygems_api_response)
|
119
|
-
|
120
|
-
response =
|
121
|
-
Excon.get(
|
122
|
-
"#{registry_url}api/v1/gems/#{dependency.name}.json",
|
123
|
-
headers: registry_auth_headers,
|
124
|
-
idempotent: true,
|
125
|
-
**SharedHelpers.excon_defaults
|
126
|
-
)
|
127
|
-
return @rubygems_api_response = {} if response.status >= 400
|
128
|
-
|
129
|
-
response_body = response.body
|
130
|
-
response_body = augment_private_response_if_appropriate(response_body)
|
131
|
-
|
132
|
-
@rubygems_api_response = JSON.parse(response_body)
|
133
|
-
append_slash_to_source_code_uri(@rubygems_api_response)
|
134
|
-
rescue JSON::ParserError, Excon::Error::Timeout
|
135
|
-
@rubygems_api_response = {}
|
136
|
-
end
|
137
|
-
|
138
|
-
def append_slash_to_source_code_uri(listing)
|
139
|
-
# We have to do this so that `Source.from_url(...)` doesn't prune the
|
140
|
-
# last line off of the directory.
|
141
|
-
return listing unless listing&.fetch("source_code_uri", nil)
|
142
|
-
return listing if listing.fetch("source_code_uri").end_with?("/")
|
143
|
-
|
144
|
-
listing["source_code_uri"] = listing["source_code_uri"] + "/"
|
145
|
-
listing
|
146
|
-
end
|
147
|
-
|
148
|
-
def augment_private_response_if_appropriate(response_body)
|
149
|
-
return response_body if new_source_type == "default"
|
150
|
-
|
151
|
-
parsed_body = JSON.parse(response_body)
|
152
|
-
return response_body if (SOURCE_KEYS - parsed_body.keys).none?
|
153
|
-
|
154
|
-
digest = parsed_body.values_at("version", "authors", "info").hash
|
155
|
-
|
156
|
-
source_url = parsed_body.
|
157
|
-
values_at(*SOURCE_KEYS).
|
158
|
-
compact.
|
159
|
-
find { |url| Source.from_url(url) }
|
160
|
-
return response_body if source_url
|
161
|
-
|
162
|
-
rubygems_response =
|
163
|
-
Excon.get(
|
164
|
-
"https://rubygems.org/api/v1/gems/#{dependency.name}.json",
|
165
|
-
idempotent: true,
|
166
|
-
**SharedHelpers.excon_defaults
|
167
|
-
)
|
168
|
-
parsed_rubygems_body = JSON.parse(rubygems_response.body)
|
169
|
-
rubygems_digest =
|
170
|
-
parsed_rubygems_body.values_at("version", "authors", "info").hash
|
171
|
-
|
172
|
-
digest == rubygems_digest ? rubygems_response.body : response_body
|
173
|
-
rescue JSON::ParserError, Excon::Error::Socket, Excon::Error::Timeout
|
174
|
-
response_body
|
175
|
-
end
|
176
|
-
|
177
|
-
def registry_url
|
178
|
-
return "https://rubygems.org/" if new_source_type == "default"
|
179
|
-
|
180
|
-
info = dependency.requirements.map { |r| r[:source] }.compact.first
|
181
|
-
info[:url] || info.fetch("url")
|
182
|
-
end
|
183
|
-
|
184
|
-
def registry_auth_headers
|
185
|
-
return {} unless new_source_type == "rubygems"
|
186
|
-
|
187
|
-
token =
|
188
|
-
credentials.
|
189
|
-
select { |cred| cred["type"] == "rubygems_server" }.
|
190
|
-
find { |cred| registry_url.include?(cred["host"]) }&.
|
191
|
-
fetch("token")
|
192
|
-
|
193
|
-
return {} unless token
|
194
|
-
|
195
|
-
token += ":" unless token.include?(":")
|
196
|
-
encoded_token = Base64.encode64(token).delete("\n")
|
197
|
-
{ "Authorization" => "Basic #{encoded_token}" }
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
@@ -1,331 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "dependabot/update_checkers/base"
|
4
|
-
require "dependabot/file_updaters/ruby/bundler/requirement_replacer"
|
5
|
-
require "dependabot/git_commit_checker"
|
6
|
-
|
7
|
-
module Dependabot
|
8
|
-
module UpdateCheckers
|
9
|
-
module Ruby
|
10
|
-
class Bundler < Dependabot::UpdateCheckers::Base
|
11
|
-
require_relative "bundler/force_updater"
|
12
|
-
require_relative "bundler/file_preparer"
|
13
|
-
require_relative "bundler/requirements_updater"
|
14
|
-
require_relative "bundler/version_resolver"
|
15
|
-
require_relative "bundler/latest_version_finder"
|
16
|
-
|
17
|
-
def latest_version
|
18
|
-
return latest_version_for_git_dependency if git_dependency?
|
19
|
-
|
20
|
-
latest_version_details&.fetch(:version)
|
21
|
-
end
|
22
|
-
|
23
|
-
def latest_resolvable_version
|
24
|
-
return latest_resolvable_version_for_git_dependency if git_dependency?
|
25
|
-
|
26
|
-
latest_resolvable_version_details&.fetch(:version)
|
27
|
-
end
|
28
|
-
|
29
|
-
def latest_resolvable_version_with_no_unlock
|
30
|
-
current_ver = dependency.version
|
31
|
-
return current_ver if git_dependency? && git_commit_checker.pinned?
|
32
|
-
|
33
|
-
@latest_resolvable_version_detail_with_no_unlock ||=
|
34
|
-
version_resolver(
|
35
|
-
remove_git_source: false,
|
36
|
-
unlock_requirement: false
|
37
|
-
).latest_resolvable_version_details
|
38
|
-
|
39
|
-
if git_dependency?
|
40
|
-
@latest_resolvable_version_detail_with_no_unlock&.fetch(:commit_sha)
|
41
|
-
else
|
42
|
-
@latest_resolvable_version_detail_with_no_unlock&.fetch(:version)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def updated_requirements
|
47
|
-
RequirementsUpdater.new(
|
48
|
-
requirements: dependency.requirements,
|
49
|
-
update_strategy: requirements_update_strategy,
|
50
|
-
updated_source: updated_source,
|
51
|
-
latest_version: latest_version_details&.fetch(:version)&.to_s,
|
52
|
-
latest_resolvable_version:
|
53
|
-
latest_resolvable_version_details&.fetch(:version)&.to_s
|
54
|
-
).updated_requirements
|
55
|
-
end
|
56
|
-
|
57
|
-
def requirements_unlocked_or_can_be?
|
58
|
-
dependency.requirements.
|
59
|
-
reject { |r| r[:requirement].nil? }.
|
60
|
-
all? do |req|
|
61
|
-
requirement = requirement_class.new(req[:requirement])
|
62
|
-
next true if requirement.satisfied_by?(Gem::Version.new("100000"))
|
63
|
-
|
64
|
-
file = dependency_files.find { |f| f.name == req.fetch(:file) }
|
65
|
-
updated = FileUpdaters::Ruby::Bundler::RequirementReplacer.new(
|
66
|
-
dependency: dependency,
|
67
|
-
file_type: file.name.end_with?("gemspec") ? :gemspec : :gemfile,
|
68
|
-
updated_requirement: "whatever"
|
69
|
-
).rewrite(file.content)
|
70
|
-
|
71
|
-
updated != file.content
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def requirements_update_strategy
|
76
|
-
# If passed in as an option (in the base class) honour that option
|
77
|
-
if @requirements_update_strategy
|
78
|
-
return @requirements_update_strategy.to_sym
|
79
|
-
end
|
80
|
-
|
81
|
-
# Otherwise, widen ranges for libraries and bump versions for apps
|
82
|
-
dependency.version.nil? ? :bump_versions_if_necessary : :bump_versions
|
83
|
-
end
|
84
|
-
|
85
|
-
private
|
86
|
-
|
87
|
-
def latest_version_resolvable_with_full_unlock?
|
88
|
-
return false unless latest_version
|
89
|
-
|
90
|
-
updated_dependencies = force_updater.updated_dependencies
|
91
|
-
|
92
|
-
updated_dependencies.none? do |dep|
|
93
|
-
old_version = dep.previous_version
|
94
|
-
next unless Gem::Version.correct?(old_version)
|
95
|
-
next if Gem::Version.new(old_version).prerelease?
|
96
|
-
|
97
|
-
Gem::Version.new(dep.version).prerelease?
|
98
|
-
end
|
99
|
-
rescue Dependabot::DependencyFileNotResolvable
|
100
|
-
false
|
101
|
-
end
|
102
|
-
|
103
|
-
def updated_dependencies_after_full_unlock
|
104
|
-
force_updater.updated_dependencies
|
105
|
-
end
|
106
|
-
|
107
|
-
def git_dependency?
|
108
|
-
git_commit_checker.git_dependency?
|
109
|
-
end
|
110
|
-
|
111
|
-
def latest_version_details(remove_git_source: false)
|
112
|
-
@latest_version_details ||= {}
|
113
|
-
@latest_version_details[remove_git_source] ||=
|
114
|
-
latest_version_finder(remove_git_source: remove_git_source).
|
115
|
-
latest_version_details
|
116
|
-
end
|
117
|
-
|
118
|
-
def latest_resolvable_version_details(remove_git_source: false)
|
119
|
-
@latest_resolvable_version_details ||= {}
|
120
|
-
@latest_resolvable_version_details[remove_git_source] ||=
|
121
|
-
version_resolver(remove_git_source: remove_git_source).
|
122
|
-
latest_resolvable_version_details
|
123
|
-
end
|
124
|
-
|
125
|
-
def latest_version_for_git_dependency
|
126
|
-
latest_release =
|
127
|
-
latest_version_details(remove_git_source: true)&.
|
128
|
-
fetch(:version)
|
129
|
-
|
130
|
-
# If there's been a release that includes the current pinned ref or
|
131
|
-
# that the current branch is behind, we switch to that release.
|
132
|
-
return latest_release if git_branch_or_ref_in_release?(latest_release)
|
133
|
-
|
134
|
-
# Otherwise, if the gem isn't pinned, the latest version is just the
|
135
|
-
# latest commit for the specified branch.
|
136
|
-
unless git_commit_checker.pinned?
|
137
|
-
return git_commit_checker.head_commit_for_current_branch
|
138
|
-
end
|
139
|
-
|
140
|
-
# If the dependency is pinned to a tag that looks like a version then
|
141
|
-
# we want to update that tag. The latest version will then be the SHA
|
142
|
-
# of the latest tag that looks like a version.
|
143
|
-
if git_commit_checker.pinned_ref_looks_like_version?
|
144
|
-
latest_tag = git_commit_checker.local_tag_for_latest_version
|
145
|
-
return latest_tag&.fetch(:tag_sha) || dependency.version
|
146
|
-
end
|
147
|
-
|
148
|
-
# If the dependency is pinned to a tag that doesn't look like a
|
149
|
-
# version then there's nothing we can do.
|
150
|
-
dependency.version
|
151
|
-
end
|
152
|
-
|
153
|
-
def latest_resolvable_version_for_git_dependency
|
154
|
-
latest_release = latest_resolvable_version_without_git_source
|
155
|
-
|
156
|
-
# If there's a resolvable release that includes the current pinned
|
157
|
-
# ref or that the current branch is behind, we switch to that release.
|
158
|
-
return latest_release if git_branch_or_ref_in_release?(latest_release)
|
159
|
-
|
160
|
-
# Otherwise, if the gem isn't pinned, the latest version is just the
|
161
|
-
# latest commit for the specified branch.
|
162
|
-
unless git_commit_checker.pinned?
|
163
|
-
return latest_resolvable_commit_with_unchanged_git_source
|
164
|
-
end
|
165
|
-
|
166
|
-
# If the dependency is pinned to a tag that looks like a version then
|
167
|
-
# we want to update that tag. The latest version will then be the SHA
|
168
|
-
# of the latest tag that looks like a version.
|
169
|
-
if git_commit_checker.pinned_ref_looks_like_version? &&
|
170
|
-
latest_git_tag_is_resolvable?
|
171
|
-
new_tag = git_commit_checker.local_tag_for_latest_version
|
172
|
-
return new_tag.fetch(:tag_sha)
|
173
|
-
end
|
174
|
-
|
175
|
-
# If the dependency is pinned to a tag that doesn't look like a
|
176
|
-
# version then there's nothing we can do.
|
177
|
-
dependency.version
|
178
|
-
end
|
179
|
-
|
180
|
-
def latest_resolvable_version_without_git_source
|
181
|
-
return nil unless latest_version.is_a?(Gem::Version)
|
182
|
-
|
183
|
-
latest_resolvable_version_details(remove_git_source: true)&.
|
184
|
-
fetch(:version)
|
185
|
-
rescue Dependabot::DependencyFileNotResolvable
|
186
|
-
nil
|
187
|
-
end
|
188
|
-
|
189
|
-
def latest_resolvable_commit_with_unchanged_git_source
|
190
|
-
details = latest_resolvable_version_details(remove_git_source: false)
|
191
|
-
|
192
|
-
# If this dependency has a git version in the Gemfile.lock but not in
|
193
|
-
# the Gemfile (i.e., because they're out-of-sync) we might not get a
|
194
|
-
# commit_sha back from Bundler. In that case, return `nil`.
|
195
|
-
return unless details.key?(:commit_sha)
|
196
|
-
|
197
|
-
details.fetch(:commit_sha)
|
198
|
-
rescue Dependabot::DependencyFileNotResolvable
|
199
|
-
nil
|
200
|
-
end
|
201
|
-
|
202
|
-
def latest_git_tag_is_resolvable?
|
203
|
-
return @git_tag_resolvable if @latest_git_tag_is_resolvable_checked
|
204
|
-
|
205
|
-
@latest_git_tag_is_resolvable_checked = true
|
206
|
-
|
207
|
-
return false if git_commit_checker.local_tag_for_latest_version.nil?
|
208
|
-
|
209
|
-
replacement_tag = git_commit_checker.local_tag_for_latest_version
|
210
|
-
|
211
|
-
VersionResolver.new(
|
212
|
-
dependency: dependency,
|
213
|
-
unprepared_dependency_files: dependency_files,
|
214
|
-
credentials: credentials,
|
215
|
-
ignored_versions: ignored_versions,
|
216
|
-
replacement_git_pin: replacement_tag.fetch(:tag)
|
217
|
-
).latest_resolvable_version_details
|
218
|
-
|
219
|
-
@git_tag_resolvable = true
|
220
|
-
rescue Dependabot::DependencyFileNotResolvable
|
221
|
-
@git_tag_resolvable = false
|
222
|
-
end
|
223
|
-
|
224
|
-
def git_branch_or_ref_in_release?(release)
|
225
|
-
return false unless release
|
226
|
-
|
227
|
-
git_commit_checker.branch_or_ref_in_release?(release)
|
228
|
-
end
|
229
|
-
|
230
|
-
def updated_source
|
231
|
-
# Never need to update source, unless a git_dependency
|
232
|
-
return dependency_source_details unless git_dependency?
|
233
|
-
|
234
|
-
# Source becomes `nil` if switching to default rubygems
|
235
|
-
return nil if should_switch_source_from_git_to_rubygems?
|
236
|
-
|
237
|
-
# Update the git tag if updating a pinned version
|
238
|
-
if git_commit_checker.pinned_ref_looks_like_version? &&
|
239
|
-
latest_git_tag_is_resolvable?
|
240
|
-
new_tag = git_commit_checker.local_tag_for_latest_version
|
241
|
-
return dependency_source_details.merge(ref: new_tag.fetch(:tag))
|
242
|
-
end
|
243
|
-
|
244
|
-
# Otherwise return the original source
|
245
|
-
dependency_source_details
|
246
|
-
end
|
247
|
-
|
248
|
-
def dependency_source_details
|
249
|
-
sources =
|
250
|
-
dependency.requirements.map { |r| r.fetch(:source) }.uniq.compact
|
251
|
-
|
252
|
-
raise "Multiple sources! #{sources.join(', ')}" if sources.count > 1
|
253
|
-
|
254
|
-
sources.first
|
255
|
-
end
|
256
|
-
|
257
|
-
def should_switch_source_from_git_to_rubygems?
|
258
|
-
return false unless git_dependency?
|
259
|
-
return false if latest_resolvable_version_for_git_dependency.nil?
|
260
|
-
|
261
|
-
Gem::Version.correct?(latest_resolvable_version_for_git_dependency)
|
262
|
-
end
|
263
|
-
|
264
|
-
def force_updater
|
265
|
-
@force_updater ||=
|
266
|
-
ForceUpdater.new(
|
267
|
-
dependency: dependency,
|
268
|
-
dependency_files: dependency_files,
|
269
|
-
credentials: credentials,
|
270
|
-
target_version: latest_version,
|
271
|
-
requirements_update_strategy: requirements_update_strategy
|
272
|
-
)
|
273
|
-
end
|
274
|
-
|
275
|
-
def git_commit_checker
|
276
|
-
@git_commit_checker ||=
|
277
|
-
GitCommitChecker.new(
|
278
|
-
dependency: dependency,
|
279
|
-
credentials: credentials
|
280
|
-
)
|
281
|
-
end
|
282
|
-
|
283
|
-
def version_resolver(remove_git_source:, unlock_requirement: true)
|
284
|
-
@version_resolver ||= {}
|
285
|
-
@version_resolver[remove_git_source] ||= {}
|
286
|
-
@version_resolver[remove_git_source][unlock_requirement] ||=
|
287
|
-
begin
|
288
|
-
VersionResolver.new(
|
289
|
-
dependency: dependency,
|
290
|
-
unprepared_dependency_files: dependency_files,
|
291
|
-
credentials: credentials,
|
292
|
-
ignored_versions: ignored_versions,
|
293
|
-
remove_git_source: remove_git_source,
|
294
|
-
unlock_requirement: unlock_requirement,
|
295
|
-
latest_allowable_version: latest_version
|
296
|
-
)
|
297
|
-
end
|
298
|
-
end
|
299
|
-
|
300
|
-
def latest_version_finder(remove_git_source:)
|
301
|
-
@latest_version_finder ||= {}
|
302
|
-
@latest_version_finder[remove_git_source] ||=
|
303
|
-
begin
|
304
|
-
prepared_dependency_files = prepared_dependency_files(
|
305
|
-
remove_git_source: remove_git_source,
|
306
|
-
unlock_requirement: true
|
307
|
-
)
|
308
|
-
|
309
|
-
LatestVersionFinder.new(
|
310
|
-
dependency: dependency,
|
311
|
-
dependency_files: prepared_dependency_files,
|
312
|
-
credentials: credentials,
|
313
|
-
ignored_versions: ignored_versions
|
314
|
-
)
|
315
|
-
end
|
316
|
-
end
|
317
|
-
|
318
|
-
def prepared_dependency_files(remove_git_source:, unlock_requirement:,
|
319
|
-
latest_allowable_version: nil)
|
320
|
-
FilePreparer.new(
|
321
|
-
dependency: dependency,
|
322
|
-
dependency_files: dependency_files,
|
323
|
-
remove_git_source: remove_git_source,
|
324
|
-
unlock_requirement: unlock_requirement,
|
325
|
-
latest_allowable_version: latest_allowable_version
|
326
|
-
).prepared_dependency_files
|
327
|
-
end
|
328
|
-
end
|
329
|
-
end
|
330
|
-
end
|
331
|
-
end
|