dependabot-bundler 0.122.1 → 0.123.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/dependabot/bundler/file_fetcher.rb +1 -0
- data/lib/dependabot/bundler/file_parser.rb +44 -91
- data/lib/dependabot/bundler/file_parser/gemfile_declaration_finder.rb +5 -3
- data/lib/dependabot/bundler/file_updater.rb +8 -5
- data/lib/dependabot/bundler/file_updater/lockfile_updater.rb +16 -245
- data/lib/dependabot/bundler/native_helpers.rb +18 -0
- data/lib/dependabot/bundler/update_checker/file_preparer.rb +1 -0
- data/lib/dependabot/bundler/update_checker/force_updater.rb +32 -186
- data/lib/dependabot/bundler/update_checker/latest_version_finder.rb +0 -4
- data/lib/dependabot/bundler/update_checker/latest_version_finder/dependency_source.rb +43 -52
- data/lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb +68 -89
- data/lib/dependabot/bundler/update_checker/version_resolver.rb +63 -132
- metadata +4 -6
- 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 -17
- data/lib/dependabot/monkey_patches/bundler/git_source_patch.rb +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8747477c27b4da3a9dac1cbc9f5e4c210718cfc65acd1b12635ba0679e4821b
|
4
|
+
data.tar.gz: e3782b672bc41feb50ee37e28f3fc8bf3f95afe54e93d263bd10d2774be9f738
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20a99c0f98e7eb0e6e0364cc5d6e38089ede24bf5679eab7ec27c50a7bf1b257f45dc977e7567784260c29b98f88ad82c5c666077e0af8418be8a71bf7cf8ca0
|
7
|
+
data.tar.gz: 5dbec91e58373da6bc18af1c662a14a529cfad32c44fa27ff84cb98a1381ea243f19267323e25db1a92e5fae22a1ec712dd0050138f8d7156a136128318bb0ec
|
@@ -192,6 +192,7 @@ module Dependabot
|
|
192
192
|
fetch_child_gemfiles(file: gemfile, previously_fetched_files: [])
|
193
193
|
end
|
194
194
|
|
195
|
+
# TODO: Stop sanitizing the lockfile once we have bundler 2 installed
|
195
196
|
def sanitized_lockfile_content
|
196
197
|
regex = FileUpdater::LockfileUpdater::LOCKFILE_ENDING
|
197
198
|
lockfile.content.gsub(regex, "")
|
@@ -4,6 +4,7 @@ require "dependabot/dependency"
|
|
4
4
|
require "dependabot/file_parsers"
|
5
5
|
require "dependabot/file_parsers/base"
|
6
6
|
require "dependabot/bundler/file_updater/lockfile_updater"
|
7
|
+
require "dependabot/bundler/native_helpers"
|
7
8
|
require "dependabot/bundler/version"
|
8
9
|
require "dependabot/shared_helpers"
|
9
10
|
require "dependabot/errors"
|
@@ -25,19 +26,6 @@ module Dependabot
|
|
25
26
|
|
26
27
|
private
|
27
28
|
|
28
|
-
# Can't be a constant because some of these don't exist in bundler
|
29
|
-
# 1.15, which Heroku uses, which causes an exception on boot.
|
30
|
-
def sources
|
31
|
-
[
|
32
|
-
NilClass,
|
33
|
-
::Bundler::Source::Rubygems,
|
34
|
-
::Bundler::Source::Git,
|
35
|
-
::Bundler::Source::Path,
|
36
|
-
::Bundler::Source::Gemspec,
|
37
|
-
::Bundler::Source::Metadata
|
38
|
-
]
|
39
|
-
end
|
40
|
-
|
41
29
|
def gemfile_dependencies
|
42
30
|
dependencies = DependencySet.new
|
43
31
|
|
@@ -51,12 +39,12 @@ module Dependabot
|
|
51
39
|
|
52
40
|
dependencies <<
|
53
41
|
Dependency.new(
|
54
|
-
name: dep.name,
|
55
|
-
version: dependency_version(dep.name)&.to_s,
|
42
|
+
name: dep.fetch("name"),
|
43
|
+
version: dependency_version(dep.fetch("name"))&.to_s,
|
56
44
|
requirements: [{
|
57
45
|
requirement: gemfile_declaration_finder.enhanced_req_string,
|
58
|
-
groups: dep.groups,
|
59
|
-
source:
|
46
|
+
groups: dep.fetch("groups").map(&:to_sym),
|
47
|
+
source: dep.fetch("source")&.transform_keys(&:to_sym),
|
60
48
|
file: file.name
|
61
49
|
}],
|
62
50
|
package_manager: "bundler"
|
@@ -71,15 +59,19 @@ module Dependabot
|
|
71
59
|
dependencies = DependencySet.new
|
72
60
|
|
73
61
|
gemspecs.each do |gemspec|
|
74
|
-
parsed_gemspec(gemspec).
|
62
|
+
parsed_gemspec(gemspec).each do |dependency|
|
75
63
|
dependencies <<
|
76
64
|
Dependency.new(
|
77
|
-
name: dependency.name,
|
78
|
-
version: dependency_version(dependency.name)&.to_s,
|
65
|
+
name: dependency.fetch("name"),
|
66
|
+
version: dependency_version(dependency.fetch("name"))&.to_s,
|
79
67
|
requirements: [{
|
80
|
-
requirement: dependency.requirement.to_s,
|
81
|
-
groups: dependency.
|
82
|
-
|
68
|
+
requirement: dependency.fetch("requirement").to_s,
|
69
|
+
groups: if dependency.fetch("type") == "runtime"
|
70
|
+
["runtime"]
|
71
|
+
else
|
72
|
+
["development"]
|
73
|
+
end,
|
74
|
+
source: dependency.fetch("source")&.transform_keys(&:to_sym),
|
83
75
|
file: gemspec.name
|
84
76
|
}],
|
85
77
|
package_manager: "bundler"
|
@@ -122,28 +114,25 @@ module Dependabot
|
|
122
114
|
repo_contents_path) do
|
123
115
|
write_temporary_dependency_files
|
124
116
|
|
125
|
-
SharedHelpers.
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
end
|
117
|
+
SharedHelpers.run_helper_subprocess(
|
118
|
+
command: NativeHelpers.helper_path,
|
119
|
+
function: "parsed_gemfile",
|
120
|
+
args: {
|
121
|
+
gemfile_name: gemfile.name,
|
122
|
+
lockfile_name: lockfile&.name,
|
123
|
+
dir: Dir.pwd
|
124
|
+
}
|
125
|
+
)
|
135
126
|
end
|
136
|
-
rescue SharedHelpers::
|
137
|
-
|
127
|
+
rescue SharedHelpers::HelperSubprocessFailed => e
|
128
|
+
handle_eval_error(e) if e.error_class == "JSON::ParserError"
|
138
129
|
|
139
130
|
msg = e.error_class + " with message: " +
|
140
|
-
e.
|
131
|
+
e.message.force_encoding("UTF-8").encode
|
141
132
|
raise Dependabot::DependencyFileNotEvaluatable, msg
|
142
133
|
end
|
143
134
|
|
144
|
-
def
|
145
|
-
raise err unless err.message == "marshal data too short"
|
146
|
-
|
135
|
+
def handle_eval_error(err)
|
147
136
|
msg = "Error evaluating your dependency files: #{err.message}"
|
148
137
|
raise Dependabot::DependencyFileNotEvaluatable, msg
|
149
138
|
end
|
@@ -153,19 +142,20 @@ module Dependabot
|
|
153
142
|
@parsed_gemspecs[file.name] ||=
|
154
143
|
SharedHelpers.in_a_temporary_repo_directory(base_directory,
|
155
144
|
repo_contents_path) do
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
145
|
+
write_temporary_dependency_files
|
146
|
+
|
147
|
+
SharedHelpers.run_helper_subprocess(
|
148
|
+
command: NativeHelpers.helper_path,
|
149
|
+
function: "parsed_gemspec",
|
150
|
+
args: {
|
151
|
+
gemspec_name: file.name,
|
152
|
+
lockfile_name: lockfile&.name,
|
153
|
+
dir: Dir.pwd
|
154
|
+
}
|
155
|
+
)
|
166
156
|
end
|
167
|
-
rescue SharedHelpers::
|
168
|
-
msg = e.error_class + " with message: " + e.
|
157
|
+
rescue SharedHelpers::HelperSubprocessFailed => e
|
158
|
+
msg = e.error_class + " with message: " + e.message
|
169
159
|
raise Dependabot::DependencyFileNotEvaluatable, msg
|
170
160
|
end
|
171
161
|
|
@@ -185,6 +175,8 @@ module Dependabot
|
|
185
175
|
FileUtils.mkdir_p(Pathname.new(path).dirname)
|
186
176
|
File.write(path, file.content)
|
187
177
|
end
|
178
|
+
|
179
|
+
File.write(lockfile.name, sanitized_lockfile_content) if lockfile
|
188
180
|
end
|
189
181
|
|
190
182
|
def check_required_files
|
@@ -199,42 +191,6 @@ module Dependabot
|
|
199
191
|
raise "A gemspec or Gemfile must be provided!"
|
200
192
|
end
|
201
193
|
|
202
|
-
def source_for(dependency)
|
203
|
-
source = dependency.source
|
204
|
-
if lockfile && default_rubygems?(source)
|
205
|
-
# If there's a lockfile and the Gemfile doesn't have anything
|
206
|
-
# interesting to say about the source, check that.
|
207
|
-
source = source_from_lockfile(dependency.name)
|
208
|
-
end
|
209
|
-
raise "Bad source: #{source}" unless sources.include?(source.class)
|
210
|
-
|
211
|
-
return nil if default_rubygems?(source)
|
212
|
-
|
213
|
-
details = { type: source.class.name.split("::").last.downcase }
|
214
|
-
if source.is_a?(::Bundler::Source::Git)
|
215
|
-
details.merge!(git_source_details(source))
|
216
|
-
end
|
217
|
-
if source.is_a?(::Bundler::Source::Rubygems)
|
218
|
-
details[:url] = source.remotes.first.to_s
|
219
|
-
end
|
220
|
-
details
|
221
|
-
end
|
222
|
-
|
223
|
-
def git_source_details(source)
|
224
|
-
{
|
225
|
-
url: source.uri,
|
226
|
-
branch: source.branch || "master",
|
227
|
-
ref: source.ref
|
228
|
-
}
|
229
|
-
end
|
230
|
-
|
231
|
-
def default_rubygems?(source)
|
232
|
-
return true if source.nil?
|
233
|
-
return false unless source.is_a?(::Bundler::Source::Rubygems)
|
234
|
-
|
235
|
-
source.remotes.any? { |r| r.to_s.include?("rubygems.org") }
|
236
|
-
end
|
237
|
-
|
238
194
|
def dependency_version(dependency_name)
|
239
195
|
return unless lockfile
|
240
196
|
|
@@ -255,10 +211,6 @@ module Dependabot
|
|
255
211
|
spec.version
|
256
212
|
end
|
257
213
|
|
258
|
-
def source_from_lockfile(dependency_name)
|
259
|
-
parsed_lockfile.specs.find { |s| s.name == dependency_name }&.source
|
260
|
-
end
|
261
|
-
|
262
214
|
def gemfile
|
263
215
|
@gemfile ||= get_original_file("Gemfile") ||
|
264
216
|
get_original_file("gems.rb")
|
@@ -315,6 +267,7 @@ module Dependabot
|
|
315
267
|
groups.any? { |g| g.include?("prod") }
|
316
268
|
end
|
317
269
|
|
270
|
+
# TODO: Stop sanitizing the lockfile once we have bundler 2 installed
|
318
271
|
def sanitized_lockfile_content
|
319
272
|
regex = FileUpdater::LockfileUpdater::LOCKFILE_ENDING
|
320
273
|
lockfile.content.gsub(regex, "")
|
@@ -20,7 +20,7 @@ module Dependabot
|
|
20
20
|
def enhanced_req_string
|
21
21
|
return unless gemfile_includes_dependency?
|
22
22
|
|
23
|
-
fallback_string = dependency.requirement
|
23
|
+
fallback_string = dependency.fetch("requirement")
|
24
24
|
req_nodes = declaration_node.children[3..-1]
|
25
25
|
req_nodes = req_nodes.reject { |child| child.type == :hash }
|
26
26
|
|
@@ -28,7 +28,9 @@ module Dependabot
|
|
28
28
|
return fallback_string unless req_nodes.all? { |n| n.type == :str }
|
29
29
|
|
30
30
|
original_req_string = req_nodes.map { |n| n.children.last }
|
31
|
-
|
31
|
+
fallback_requirement =
|
32
|
+
Gem::Requirement.new(fallback_string.split(", "))
|
33
|
+
if fallback_requirement == Gem::Requirement.new(original_req_string)
|
32
34
|
original_req_string.join(", ")
|
33
35
|
else
|
34
36
|
fallback_string
|
@@ -65,7 +67,7 @@ module Dependabot
|
|
65
67
|
return false unless node.is_a?(Parser::AST::Node)
|
66
68
|
return false unless node.children[1] == :gem
|
67
69
|
|
68
|
-
node.children[2].children.first == dependency.name
|
70
|
+
node.children[2].children.first == dependency.fetch("name")
|
69
71
|
end
|
70
72
|
end
|
71
73
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "dependabot/file_updaters"
|
4
4
|
require "dependabot/file_updaters/base"
|
5
|
+
require "dependabot/bundler/native_helpers"
|
5
6
|
require "dependabot/file_updaters/vendor_updater"
|
6
7
|
|
7
8
|
module Dependabot
|
@@ -74,11 +75,13 @@ module Dependabot
|
|
74
75
|
return @vendor_cache_dir if defined?(@vendor_cache_dir)
|
75
76
|
|
76
77
|
@vendor_cache_dir =
|
77
|
-
SharedHelpers.
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
SharedHelpers.run_helper_subprocess(
|
79
|
+
command: NativeHelpers.helper_path,
|
80
|
+
function: "vendor_cache_dir",
|
81
|
+
args: {
|
82
|
+
dir: repo_contents_path
|
83
|
+
}
|
84
|
+
)
|
82
85
|
end
|
83
86
|
|
84
87
|
def vendor_updater
|
@@ -2,18 +2,14 @@
|
|
2
2
|
|
3
3
|
require "bundler"
|
4
4
|
|
5
|
-
require "dependabot/monkey_patches/bundler/definition_ruby_version_patch"
|
6
|
-
require "dependabot/monkey_patches/bundler/definition_bundler_version_patch"
|
7
|
-
require "dependabot/monkey_patches/bundler/git_source_patch"
|
8
|
-
|
9
5
|
require "dependabot/shared_helpers"
|
10
6
|
require "dependabot/errors"
|
11
7
|
require "dependabot/bundler/file_updater"
|
12
|
-
require "dependabot/
|
8
|
+
require "dependabot/bundler/native_helpers"
|
9
|
+
|
13
10
|
module Dependabot
|
14
11
|
module Bundler
|
15
12
|
class FileUpdater
|
16
|
-
# rubocop:disable Metrics/ClassLength
|
17
13
|
class LockfileUpdater
|
18
14
|
require_relative "gemfile_updater"
|
19
15
|
require_relative "gemspec_updater"
|
@@ -25,13 +21,6 @@ module Dependabot
|
|
25
21
|
/(?<ending>\s*(?:RUBY VERSION|BUNDLED WITH).*)/m.freeze
|
26
22
|
GIT_DEPENDENCIES_SECTION = /GIT\n.*?\n\n(?!GIT)/m.freeze
|
27
23
|
GIT_DEPENDENCY_DETAILS = /GIT\n.*?\n\n/m.freeze
|
28
|
-
GEM_NOT_FOUND_ERROR_REGEX =
|
29
|
-
/
|
30
|
-
locked\sto\s(?<name>[^\s]+)\s\(|
|
31
|
-
not\sfind\s(?<name>[^\s]+)-\d|
|
32
|
-
has\s(?<name>[^\s]+)\slocked\sat
|
33
|
-
/x.freeze
|
34
|
-
RETRYABLE_ERRORS = [::Bundler::HTTPError].freeze
|
35
24
|
|
36
25
|
# Can't be a constant because some of these don't exist in bundler
|
37
26
|
# 1.15, which Heroku uses, which causes an exception on boot.
|
@@ -77,22 +66,21 @@ module Dependabot
|
|
77
66
|
) do |tmp_dir|
|
78
67
|
write_temporary_dependency_files
|
79
68
|
|
80
|
-
SharedHelpers.
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
end
|
69
|
+
SharedHelpers.run_helper_subprocess(
|
70
|
+
command: NativeHelpers.helper_path,
|
71
|
+
function: "update_lockfile",
|
72
|
+
args: {
|
73
|
+
gemfile_name: gemfile.name,
|
74
|
+
lockfile_name: lockfile.name,
|
75
|
+
using_bundler_2: using_bundler_2?,
|
76
|
+
dir: tmp_dir,
|
77
|
+
credentials: relevant_credentials,
|
78
|
+
dependencies: dependencies.map(&:to_h)
|
79
|
+
}
|
80
|
+
)
|
93
81
|
end
|
94
82
|
post_process_lockfile(lockfile_body)
|
95
|
-
rescue SharedHelpers::
|
83
|
+
rescue SharedHelpers::HelperSubprocessFailed => e
|
96
84
|
raise unless ruby_lock_error?(e)
|
97
85
|
|
98
86
|
@dont_lock_ruby_version = true
|
@@ -129,195 +117,6 @@ module Dependabot
|
|
129
117
|
end
|
130
118
|
end
|
131
119
|
|
132
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
133
|
-
def generate_lockfile
|
134
|
-
dependencies_to_unlock = dependencies.map(&:name)
|
135
|
-
|
136
|
-
begin
|
137
|
-
definition = build_definition(dependencies_to_unlock)
|
138
|
-
|
139
|
-
old_reqs = lock_deps_being_updated_to_exact_versions(definition)
|
140
|
-
|
141
|
-
definition.resolve_remotely!
|
142
|
-
|
143
|
-
old_reqs.each do |dep_name, old_req|
|
144
|
-
d_dep = definition.dependencies.find { |d| d.name == dep_name }
|
145
|
-
if old_req == :none then definition.dependencies.delete(d_dep)
|
146
|
-
else d_dep.instance_variable_set(:@requirement, old_req)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
cache_vendored_gems(definition) if ::Bundler.app_cache.exist?
|
151
|
-
|
152
|
-
definition.to_lock
|
153
|
-
rescue ::Bundler::GemNotFound => e
|
154
|
-
unlock_yanked_gem(dependencies_to_unlock, e) && retry
|
155
|
-
rescue ::Bundler::VersionConflict => e
|
156
|
-
unlock_blocking_subdeps(dependencies_to_unlock, e) && retry
|
157
|
-
rescue *RETRYABLE_ERRORS
|
158
|
-
raise if @retrying
|
159
|
-
|
160
|
-
@retrying = true
|
161
|
-
sleep(rand(1.0..5.0))
|
162
|
-
retry
|
163
|
-
end
|
164
|
-
end
|
165
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
166
|
-
|
167
|
-
def cache_vendored_gems(definition)
|
168
|
-
# Dependencies that have been unlocked for the update (including
|
169
|
-
# sub-dependencies)
|
170
|
-
unlocked_gems = definition.instance_variable_get(:@unlock).
|
171
|
-
fetch(:gems).reject { |gem| __keep_on_prune?(gem) }
|
172
|
-
bundler_opts = {
|
173
|
-
cache_all: true,
|
174
|
-
cache_all_platforms: true,
|
175
|
-
no_prune: true
|
176
|
-
}
|
177
|
-
|
178
|
-
::Bundler.settings.temporary(**bundler_opts) do
|
179
|
-
# Fetch and cache gems on all platforms without pruning
|
180
|
-
::Bundler::Runtime.new(nil, definition).cache
|
181
|
-
|
182
|
-
# Only prune unlocked gems (the original implementation is in
|
183
|
-
# Bundler::Runtime)
|
184
|
-
cache_path = ::Bundler.app_cache
|
185
|
-
resolve = definition.resolve
|
186
|
-
prune_gem_cache(resolve, cache_path, unlocked_gems)
|
187
|
-
prune_git_and_path_cache(resolve, cache_path)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
# This is not officially supported and may be removed without notice.
|
192
|
-
def __keep_on_prune?(spec_name)
|
193
|
-
unless (specs = ::Bundler.settings[:persistent_gems_after_clean])
|
194
|
-
return false
|
195
|
-
end
|
196
|
-
|
197
|
-
specs.include?(spec_name)
|
198
|
-
end
|
199
|
-
|
200
|
-
# Copied from Bundler::Runtime: Modified to only prune gems that have
|
201
|
-
# been unlocked
|
202
|
-
def prune_gem_cache(resolve, cache_path, unlocked_gems)
|
203
|
-
cached_gems = Dir["#{cache_path}/*.gem"]
|
204
|
-
|
205
|
-
outdated_gems = cached_gems.reject do |path|
|
206
|
-
spec = ::Bundler.rubygems.spec_from_gem path
|
207
|
-
|
208
|
-
!unlocked_gems.include?(spec.name) || resolve.any? do |s|
|
209
|
-
s.name == spec.name && s.version == spec.version &&
|
210
|
-
!s.source.is_a?(::Bundler::Source::Git)
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
return unless outdated_gems.any?
|
215
|
-
|
216
|
-
outdated_gems.each do |path|
|
217
|
-
File.delete(path)
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
# Copied from Bundler::Runtime
|
222
|
-
def prune_git_and_path_cache(resolve, cache_path)
|
223
|
-
cached_git_and_path = Dir["#{cache_path}/*/.bundlecache"]
|
224
|
-
|
225
|
-
outdated_git_and_path = cached_git_and_path.reject do |path|
|
226
|
-
name = File.basename(File.dirname(path))
|
227
|
-
|
228
|
-
resolve.any? do |s|
|
229
|
-
s.source.respond_to?(:app_cache_dirname) &&
|
230
|
-
s.source.app_cache_dirname == name
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
return unless outdated_git_and_path.any?
|
235
|
-
|
236
|
-
outdated_git_and_path.each do |path|
|
237
|
-
path = File.dirname(path)
|
238
|
-
FileUtils.rm_rf(path)
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
def unlock_yanked_gem(dependencies_to_unlock, error)
|
243
|
-
raise unless error.message.match?(GEM_NOT_FOUND_ERROR_REGEX)
|
244
|
-
|
245
|
-
gem_name = error.message.match(GEM_NOT_FOUND_ERROR_REGEX).
|
246
|
-
named_captures["name"]
|
247
|
-
raise if dependencies_to_unlock.include?(gem_name)
|
248
|
-
|
249
|
-
dependencies_to_unlock << gem_name
|
250
|
-
end
|
251
|
-
|
252
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
253
|
-
def unlock_blocking_subdeps(dependencies_to_unlock, error)
|
254
|
-
all_deps = ::Bundler::LockfileParser.new(sanitized_lockfile_body).
|
255
|
-
specs.map(&:name).map(&:to_s)
|
256
|
-
top_level = build_definition([]).dependencies.
|
257
|
-
map(&:name).map(&:to_s)
|
258
|
-
allowed_new_unlocks = all_deps - top_level - dependencies_to_unlock
|
259
|
-
|
260
|
-
raise if allowed_new_unlocks.none?
|
261
|
-
|
262
|
-
# Unlock any sub-dependencies that Bundler reports caused the
|
263
|
-
# conflict
|
264
|
-
potentials_deps =
|
265
|
-
error.cause.conflicts.values.
|
266
|
-
flat_map(&:requirement_trees).
|
267
|
-
map do |tree|
|
268
|
-
tree.find { |req| allowed_new_unlocks.include?(req.name) }
|
269
|
-
end.compact.map(&:name)
|
270
|
-
|
271
|
-
# If there are specific dependencies we can unlock, unlock them
|
272
|
-
if potentials_deps.any?
|
273
|
-
return dependencies_to_unlock.append(*potentials_deps)
|
274
|
-
end
|
275
|
-
|
276
|
-
# Fall back to unlocking *all* sub-dependencies. This is required
|
277
|
-
# because Bundler's VersionConflict objects don't include enough
|
278
|
-
# information to chart the full path through all conflicts unwound
|
279
|
-
dependencies_to_unlock.append(*allowed_new_unlocks)
|
280
|
-
end
|
281
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
282
|
-
|
283
|
-
def build_definition(dependencies_to_unlock)
|
284
|
-
defn = ::Bundler::Definition.build(
|
285
|
-
gemfile.name,
|
286
|
-
lockfile.name,
|
287
|
-
gems: dependencies_to_unlock
|
288
|
-
)
|
289
|
-
|
290
|
-
# Bundler unlocks the sub-dependencies of gems it is passed even
|
291
|
-
# if those sub-deps are top-level dependencies. We only want true
|
292
|
-
# subdeps unlocked, like they were in the UpdateChecker, so we
|
293
|
-
# mutate the unlocked gems array.
|
294
|
-
unlocked = defn.instance_variable_get(:@unlock).fetch(:gems)
|
295
|
-
must_not_unlock = defn.dependencies.map(&:name).map(&:to_s) -
|
296
|
-
dependencies_to_unlock
|
297
|
-
unlocked.reject! { |n| must_not_unlock.include?(n) }
|
298
|
-
|
299
|
-
defn
|
300
|
-
end
|
301
|
-
|
302
|
-
def lock_deps_being_updated_to_exact_versions(definition)
|
303
|
-
dependencies.each_with_object({}) do |dep, old_reqs|
|
304
|
-
defn_dep = definition.dependencies.find { |d| d.name == dep.name }
|
305
|
-
|
306
|
-
if defn_dep.nil?
|
307
|
-
definition.dependencies <<
|
308
|
-
::Bundler::Dependency.new(dep.name, dep.version)
|
309
|
-
old_reqs[dep.name] = :none
|
310
|
-
elsif git_dependency?(dep) &&
|
311
|
-
defn_dep.source.is_a?(::Bundler::Source::Git)
|
312
|
-
defn_dep.source.unlock!
|
313
|
-
elsif Gem::Version.correct?(dep.version)
|
314
|
-
new_req = Gem::Requirement.create("= #{dep.version}")
|
315
|
-
old_reqs[dep.name] = defn_dep.requirement
|
316
|
-
defn_dep.instance_variable_set(:@requirement, new_req)
|
317
|
-
end
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
120
|
def write_ruby_version_file
|
322
121
|
return unless ruby_version_file
|
323
122
|
|
@@ -488,6 +287,7 @@ module Dependabot
|
|
488
287
|
dependency_files.find { |f| f.name == "gems.locked" }
|
489
288
|
end
|
490
289
|
|
290
|
+
# TODO: Stop sanitizing the lockfile once we have bundler 2 installed
|
491
291
|
def sanitized_lockfile_body
|
492
292
|
lockfile.content.gsub(LOCKFILE_ENDING, "")
|
493
293
|
end
|
@@ -509,41 +309,12 @@ module Dependabot
|
|
509
309
|
dependency_files.select { |f| f.name.end_with?(".specification") }
|
510
310
|
end
|
511
311
|
|
512
|
-
def set_bundler_flags_and_credentials
|
513
|
-
# Set auth details
|
514
|
-
relevant_credentials.each do |cred|
|
515
|
-
token = cred["token"] ||
|
516
|
-
"#{cred['username']}:#{cred['password']}"
|
517
|
-
|
518
|
-
::Bundler.settings.set_command_option(
|
519
|
-
cred.fetch("host"),
|
520
|
-
token.gsub("@", "%40F").gsub("?", "%3F")
|
521
|
-
)
|
522
|
-
end
|
523
|
-
|
524
|
-
# Use HTTPS for GitHub if lockfile was generated by Bundler 2
|
525
|
-
set_bundler_2_flags if using_bundler_2?
|
526
|
-
end
|
527
|
-
|
528
|
-
def set_bundler_2_flags
|
529
|
-
::Bundler.settings.set_command_option("forget_cli_options", "true")
|
530
|
-
::Bundler.settings.set_command_option("github.https", "true")
|
531
|
-
end
|
532
|
-
|
533
|
-
def git_dependency?(dep)
|
534
|
-
GitCommitChecker.new(
|
535
|
-
dependency: dep,
|
536
|
-
credentials: credentials
|
537
|
-
).git_dependency?
|
538
|
-
end
|
539
|
-
|
540
312
|
def using_bundler_2?
|
541
313
|
return unless lockfile
|
542
314
|
|
543
315
|
lockfile.content.match?(/BUNDLED WITH\s+2/m)
|
544
316
|
end
|
545
317
|
end
|
546
|
-
# rubocop:enable Metrics/ClassLength
|
547
318
|
end
|
548
319
|
end
|
549
320
|
end
|