dependabot-bundler 0.120.5 → 0.123.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/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 +18 -68
- 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 +35 -9
- 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,8 @@
|
|
2
2
|
|
3
3
|
require "dependabot/file_updaters"
|
4
4
|
require "dependabot/file_updaters/base"
|
5
|
+
require "dependabot/bundler/native_helpers"
|
6
|
+
require "dependabot/file_updaters/vendor_updater"
|
5
7
|
|
6
8
|
module Dependabot
|
7
9
|
module Bundler
|
@@ -21,6 +23,7 @@ module Dependabot
|
|
21
23
|
end
|
22
24
|
|
23
25
|
# rubocop:disable Metrics/PerceivedComplexity
|
26
|
+
# rubocop:disable Metrics/AbcSize
|
24
27
|
def updated_dependency_files
|
25
28
|
updated_files = []
|
26
29
|
|
@@ -54,13 +57,16 @@ module Dependabot
|
|
54
57
|
check_updated_files(updated_files)
|
55
58
|
|
56
59
|
base_dir = updated_files.first.directory
|
57
|
-
|
60
|
+
vendor_updater.
|
61
|
+
updated_vendor_cache_files(base_directory: base_dir).
|
62
|
+
each do |file|
|
58
63
|
updated_files << file
|
59
64
|
end
|
60
65
|
|
61
66
|
updated_files
|
62
67
|
end
|
63
68
|
# rubocop:enable Metrics/PerceivedComplexity
|
69
|
+
# rubocop:enable Metrics/AbcSize
|
64
70
|
|
65
71
|
private
|
66
72
|
|
@@ -69,76 +75,20 @@ module Dependabot
|
|
69
75
|
return @vendor_cache_dir if defined?(@vendor_cache_dir)
|
70
76
|
|
71
77
|
@vendor_cache_dir =
|
72
|
-
SharedHelpers.
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
# Returns changed files in the vendor/cache folder
|
80
|
-
#
|
81
|
-
# @param base_directory [String] Update config base directory
|
82
|
-
# @return [Array<Dependabot::DependencyFile>]
|
83
|
-
def updated_vendor_cache_files(base_directory:)
|
84
|
-
return [] unless repo_contents_path && vendor_cache_dir
|
85
|
-
|
86
|
-
Dir.chdir(repo_contents_path) do
|
87
|
-
relative_dir = vendor_cache_dir.sub("#{repo_contents_path}/", "")
|
88
|
-
status = SharedHelpers.run_shell_command(
|
89
|
-
"git status --untracked-files=all --porcelain=v1 #{relative_dir}"
|
78
|
+
SharedHelpers.run_helper_subprocess(
|
79
|
+
command: NativeHelpers.helper_path,
|
80
|
+
function: "vendor_cache_dir",
|
81
|
+
args: {
|
82
|
+
dir: repo_contents_path
|
83
|
+
}
|
90
84
|
)
|
91
|
-
changed_paths = status.split("\n").map { |l| l.split(" ") }
|
92
|
-
changed_paths.map do |type, path|
|
93
|
-
deleted = type == "D"
|
94
|
-
encoding = ""
|
95
|
-
encoded_content = File.read(path) unless deleted
|
96
|
-
if binary_file?(path)
|
97
|
-
encoding = Dependabot::DependencyFile::ContentEncoding::BASE64
|
98
|
-
encoded_content = Base64.encode64(encoded_content) unless deleted
|
99
|
-
end
|
100
|
-
Dependabot::DependencyFile.new(
|
101
|
-
name: path,
|
102
|
-
content: encoded_content,
|
103
|
-
directory: base_directory,
|
104
|
-
deleted: deleted,
|
105
|
-
content_encoding: encoding
|
106
|
-
)
|
107
|
-
end
|
108
|
-
end
|
109
85
|
end
|
110
86
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
".gitignore"
|
117
|
-
].freeze
|
118
|
-
|
119
|
-
TEXT_FILE_EXTS = [
|
120
|
-
# code
|
121
|
-
".rb",
|
122
|
-
".erb",
|
123
|
-
".gemspec",
|
124
|
-
".js",
|
125
|
-
".html",
|
126
|
-
# config
|
127
|
-
".json",
|
128
|
-
".xml",
|
129
|
-
".toml",
|
130
|
-
".yaml",
|
131
|
-
".yml",
|
132
|
-
# docs
|
133
|
-
".md",
|
134
|
-
".txt"
|
135
|
-
].freeze
|
136
|
-
|
137
|
-
def binary_file?(path)
|
138
|
-
return false if TEXT_FILE_NAMES.include?(File.basename(path))
|
139
|
-
return false if TEXT_FILE_EXTS.include?(File.extname(path))
|
140
|
-
|
141
|
-
true
|
87
|
+
def vendor_updater
|
88
|
+
Dependabot::FileUpdaters::VendorUpdater.new(
|
89
|
+
repo_contents_path: repo_contents_path,
|
90
|
+
vendor_dir: vendor_cache_dir
|
91
|
+
)
|
142
92
|
end
|
143
93
|
|
144
94
|
def check_required_files
|
@@ -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
|