dependabot-bundler 0.95.5 → 0.95.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- metadata +4 -38
- data/helpers/Makefile +0 -9
- data/helpers/build +0 -26
- data/lib/dependabot/bundler.rb +0 -27
- data/lib/dependabot/bundler/file_fetcher.rb +0 -216
- data/lib/dependabot/bundler/file_fetcher/child_gemfile_finder.rb +0 -68
- data/lib/dependabot/bundler/file_fetcher/gemspec_finder.rb +0 -96
- data/lib/dependabot/bundler/file_fetcher/path_gemspec_finder.rb +0 -112
- data/lib/dependabot/bundler/file_fetcher/require_relative_finder.rb +0 -65
- data/lib/dependabot/bundler/file_parser.rb +0 -297
- data/lib/dependabot/bundler/file_parser/file_preparer.rb +0 -84
- data/lib/dependabot/bundler/file_parser/gemfile_checker.rb +0 -46
- data/lib/dependabot/bundler/file_updater.rb +0 -125
- data/lib/dependabot/bundler/file_updater/gemfile_updater.rb +0 -114
- data/lib/dependabot/bundler/file_updater/gemspec_dependency_name_finder.rb +0 -50
- data/lib/dependabot/bundler/file_updater/gemspec_sanitizer.rb +0 -298
- data/lib/dependabot/bundler/file_updater/gemspec_updater.rb +0 -62
- data/lib/dependabot/bundler/file_updater/git_pin_replacer.rb +0 -78
- data/lib/dependabot/bundler/file_updater/git_source_remover.rb +0 -100
- data/lib/dependabot/bundler/file_updater/lockfile_updater.rb +0 -387
- data/lib/dependabot/bundler/file_updater/requirement_replacer.rb +0 -221
- data/lib/dependabot/bundler/metadata_finder.rb +0 -204
- data/lib/dependabot/bundler/requirement.rb +0 -29
- data/lib/dependabot/bundler/update_checker.rb +0 -334
- data/lib/dependabot/bundler/update_checker/file_preparer.rb +0 -279
- data/lib/dependabot/bundler/update_checker/force_updater.rb +0 -259
- data/lib/dependabot/bundler/update_checker/latest_version_finder.rb +0 -165
- data/lib/dependabot/bundler/update_checker/requirements_updater.rb +0 -281
- data/lib/dependabot/bundler/update_checker/ruby_requirement_setter.rb +0 -113
- data/lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb +0 -244
- data/lib/dependabot/bundler/update_checker/version_resolver.rb +0 -272
- data/lib/dependabot/bundler/version.rb +0 -13
- data/lib/dependabot/monkey_patches/bundler/definition_bundler_version_patch.rb +0 -15
- data/lib/dependabot/monkey_patches/bundler/definition_ruby_version_patch.rb +0 -14
- data/lib/dependabot/monkey_patches/bundler/git_source_patch.rb +0 -27
@@ -1,221 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "parser/current"
|
4
|
-
require "dependabot/bundler/file_updater"
|
5
|
-
|
6
|
-
module Dependabot
|
7
|
-
module Bundler
|
8
|
-
class FileUpdater
|
9
|
-
class RequirementReplacer
|
10
|
-
attr_reader :dependency, :file_type, :updated_requirement,
|
11
|
-
:previous_requirement
|
12
|
-
|
13
|
-
def initialize(dependency:, file_type:, updated_requirement:,
|
14
|
-
previous_requirement: nil, insert_if_bare: false)
|
15
|
-
@dependency = dependency
|
16
|
-
@file_type = file_type
|
17
|
-
@updated_requirement = updated_requirement
|
18
|
-
@previous_requirement = previous_requirement
|
19
|
-
@insert_if_bare = insert_if_bare
|
20
|
-
end
|
21
|
-
|
22
|
-
def rewrite(content)
|
23
|
-
buffer = Parser::Source::Buffer.new("(gemfile_content)")
|
24
|
-
buffer.source = content
|
25
|
-
ast = Parser::CurrentRuby.new.parse(buffer)
|
26
|
-
|
27
|
-
updated_content = Rewriter.new(
|
28
|
-
dependency: dependency,
|
29
|
-
file_type: file_type,
|
30
|
-
updated_requirement: updated_requirement,
|
31
|
-
insert_if_bare: insert_if_bare?
|
32
|
-
).rewrite(buffer, ast)
|
33
|
-
|
34
|
-
update_comment_spacing_if_required(content, updated_content)
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def insert_if_bare?
|
40
|
-
@insert_if_bare
|
41
|
-
end
|
42
|
-
|
43
|
-
def update_comment_spacing_if_required(content, updated_content)
|
44
|
-
return updated_content unless previous_requirement
|
45
|
-
|
46
|
-
return updated_content if updated_content == content
|
47
|
-
return updated_content if length_change.zero?
|
48
|
-
|
49
|
-
updated_lines = updated_content.lines
|
50
|
-
updated_line_index =
|
51
|
-
updated_lines.length.
|
52
|
-
times.find { |i| content.lines[i] != updated_content.lines[i] }
|
53
|
-
updated_line = updated_lines[updated_line_index]
|
54
|
-
|
55
|
-
updated_line =
|
56
|
-
if length_change.positive?
|
57
|
-
updated_line.sub(/(?<=\s)\s{#{length_change}}#/, "#")
|
58
|
-
elsif length_change.negative?
|
59
|
-
updated_line.sub(/(?<=\s{2})#/, " " * length_change.abs + "#")
|
60
|
-
end
|
61
|
-
|
62
|
-
updated_lines[updated_line_index] = updated_line
|
63
|
-
updated_lines.join
|
64
|
-
end
|
65
|
-
|
66
|
-
def length_change
|
67
|
-
unless previous_requirement.start_with?("=")
|
68
|
-
return updated_requirement.length - previous_requirement.length
|
69
|
-
end
|
70
|
-
|
71
|
-
updated_requirement.length -
|
72
|
-
previous_requirement.gsub(/^=/, "").strip.length
|
73
|
-
end
|
74
|
-
|
75
|
-
class Rewriter < Parser::TreeRewriter
|
76
|
-
# TODO: Ideally we wouldn't have to ignore all of these, but
|
77
|
-
# implementing each one will be tricky.
|
78
|
-
SKIPPED_TYPES = %i(send lvar dstr begin if splat const).freeze
|
79
|
-
|
80
|
-
def initialize(dependency:, file_type:, updated_requirement:,
|
81
|
-
insert_if_bare:)
|
82
|
-
@dependency = dependency
|
83
|
-
@file_type = file_type
|
84
|
-
@updated_requirement = updated_requirement
|
85
|
-
@insert_if_bare = insert_if_bare
|
86
|
-
|
87
|
-
return if %i(gemfile gemspec).include?(file_type)
|
88
|
-
|
89
|
-
raise "File type must be :gemfile or :gemspec. Got #{file_type}."
|
90
|
-
end
|
91
|
-
|
92
|
-
def on_send(node)
|
93
|
-
return unless declares_targeted_gem?(node)
|
94
|
-
|
95
|
-
req_nodes = node.children[3..-1]
|
96
|
-
req_nodes = req_nodes.reject { |child| child.type == :hash }
|
97
|
-
|
98
|
-
return if req_nodes.none? && !insert_if_bare?
|
99
|
-
return if req_nodes.any? { |n| SKIPPED_TYPES.include?(n.type) }
|
100
|
-
|
101
|
-
quote_characters = extract_quote_characters_from(req_nodes)
|
102
|
-
space_after_specifier = space_after_specifier?(req_nodes)
|
103
|
-
use_equality_operator = use_equality_operator?(req_nodes)
|
104
|
-
|
105
|
-
new_req = new_requirement_string(
|
106
|
-
quote_characters: quote_characters,
|
107
|
-
space_after_specifier: space_after_specifier,
|
108
|
-
use_equality_operator: use_equality_operator
|
109
|
-
)
|
110
|
-
if req_nodes.any?
|
111
|
-
replace(range_for(req_nodes), new_req)
|
112
|
-
else
|
113
|
-
insert_after(range_for(node.children[2..2]), ", #{new_req}")
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
private
|
118
|
-
|
119
|
-
attr_reader :dependency, :file_type, :updated_requirement
|
120
|
-
|
121
|
-
def insert_if_bare?
|
122
|
-
@insert_if_bare
|
123
|
-
end
|
124
|
-
|
125
|
-
def declaration_methods
|
126
|
-
return %i(gem) if file_type == :gemfile
|
127
|
-
|
128
|
-
%i(add_dependency add_runtime_dependency
|
129
|
-
add_development_dependency)
|
130
|
-
end
|
131
|
-
|
132
|
-
def declares_targeted_gem?(node)
|
133
|
-
return false unless declaration_methods.include?(node.children[1])
|
134
|
-
|
135
|
-
node.children[2].children.first == dependency.name
|
136
|
-
end
|
137
|
-
|
138
|
-
def extract_quote_characters_from(requirement_nodes)
|
139
|
-
return ['"', '"'] if requirement_nodes.none?
|
140
|
-
|
141
|
-
case requirement_nodes.first.type
|
142
|
-
when :str, :dstr
|
143
|
-
[
|
144
|
-
requirement_nodes.first.loc.begin.source,
|
145
|
-
requirement_nodes.first.loc.end.source
|
146
|
-
]
|
147
|
-
else
|
148
|
-
[
|
149
|
-
requirement_nodes.first.children.first.loc.begin.source,
|
150
|
-
requirement_nodes.first.children.first.loc.end.source
|
151
|
-
]
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def space_after_specifier?(requirement_nodes)
|
156
|
-
return true if requirement_nodes.none?
|
157
|
-
|
158
|
-
req_string =
|
159
|
-
case requirement_nodes.first.type
|
160
|
-
when :str, :dstr
|
161
|
-
requirement_nodes.first.loc.expression.source
|
162
|
-
else
|
163
|
-
requirement_nodes.first.children.first.loc.expression.source
|
164
|
-
end
|
165
|
-
|
166
|
-
ops = Gem::Requirement::OPS.keys
|
167
|
-
return true if ops.none? { |op| req_string.include?(op) }
|
168
|
-
|
169
|
-
req_string.include?(" ")
|
170
|
-
end
|
171
|
-
|
172
|
-
def use_equality_operator?(requirement_nodes)
|
173
|
-
return true if requirement_nodes.none?
|
174
|
-
|
175
|
-
req_string =
|
176
|
-
case requirement_nodes.first.type
|
177
|
-
when :str, :dstr
|
178
|
-
requirement_nodes.first.loc.expression.source
|
179
|
-
else
|
180
|
-
requirement_nodes.first.children.first.loc.expression.source
|
181
|
-
end
|
182
|
-
|
183
|
-
req_string.match?(/(?<![<>])=/)
|
184
|
-
end
|
185
|
-
|
186
|
-
def new_requirement_string(quote_characters:,
|
187
|
-
space_after_specifier:,
|
188
|
-
use_equality_operator:)
|
189
|
-
open_quote, close_quote = quote_characters
|
190
|
-
new_requirement_string =
|
191
|
-
updated_requirement.split(",").
|
192
|
-
map do |r|
|
193
|
-
req_string = serialized_req(r, use_equality_operator)
|
194
|
-
%(#{open_quote}#{req_string}#{close_quote})
|
195
|
-
end.join(", ")
|
196
|
-
|
197
|
-
new_requirement_string.delete!(" ") unless space_after_specifier
|
198
|
-
new_requirement_string
|
199
|
-
end
|
200
|
-
|
201
|
-
def serialized_req(req, use_equality_operator)
|
202
|
-
tmp_req = req
|
203
|
-
|
204
|
-
# Gem::Requirement serializes exact matches as a string starting
|
205
|
-
# with `=`. We may need to remove that equality operator if it
|
206
|
-
# wasn't used originally.
|
207
|
-
unless use_equality_operator
|
208
|
-
tmp_req = tmp_req.gsub(/(?<![<>])=/, "")
|
209
|
-
end
|
210
|
-
|
211
|
-
tmp_req.strip
|
212
|
-
end
|
213
|
-
|
214
|
-
def range_for(nodes)
|
215
|
-
nodes.first.loc.begin.begin.join(nodes.last.loc.expression)
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
@@ -1,204 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "excon"
|
4
|
-
require "dependabot/metadata_finders"
|
5
|
-
require "dependabot/metadata_finders/base"
|
6
|
-
|
7
|
-
module Dependabot
|
8
|
-
module Bundler
|
9
|
-
class MetadataFinder < 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
|
-
|
203
|
-
Dependabot::MetadataFinders.
|
204
|
-
register("bundler", Dependabot::Bundler::MetadataFinder)
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "dependabot/utils"
|
4
|
-
|
5
|
-
module Dependabot
|
6
|
-
module Bundler
|
7
|
-
class Requirement < Gem::Requirement
|
8
|
-
# For consistency with other langauges, we define a requirements array.
|
9
|
-
# Ruby doesn't have an `OR` separator for requirements, so it always
|
10
|
-
# contains a single element.
|
11
|
-
def self.requirements_array(requirement_string)
|
12
|
-
[new(requirement_string)]
|
13
|
-
end
|
14
|
-
|
15
|
-
# Patches Gem::Requirement to make it accept requirement strings like
|
16
|
-
# "~> 4.2.5, >= 4.2.5.1" without first needing to split them.
|
17
|
-
def initialize(*requirements)
|
18
|
-
requirements = requirements.flatten.flat_map do |req_string|
|
19
|
-
req_string.split(",")
|
20
|
-
end
|
21
|
-
|
22
|
-
super(requirements)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
Dependabot::Utils.
|
29
|
-
register_requirement_class("bundler", Dependabot::Bundler::Requirement)
|