dependabot-bundler 0.95.6 → 0.95.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dependabot/bundler/file_fetcher/child_gemfile_finder.rb +68 -0
  3. data/lib/dependabot/bundler/file_fetcher/gemspec_finder.rb +96 -0
  4. data/lib/dependabot/bundler/file_fetcher/path_gemspec_finder.rb +112 -0
  5. data/lib/dependabot/bundler/file_fetcher/require_relative_finder.rb +65 -0
  6. data/lib/dependabot/bundler/file_fetcher.rb +216 -0
  7. data/lib/dependabot/bundler/file_parser/file_preparer.rb +84 -0
  8. data/lib/dependabot/bundler/file_parser/gemfile_checker.rb +46 -0
  9. data/lib/dependabot/bundler/file_parser.rb +297 -0
  10. data/lib/dependabot/bundler/file_updater/gemfile_updater.rb +114 -0
  11. data/lib/dependabot/bundler/file_updater/gemspec_dependency_name_finder.rb +50 -0
  12. data/lib/dependabot/bundler/file_updater/gemspec_sanitizer.rb +298 -0
  13. data/lib/dependabot/bundler/file_updater/gemspec_updater.rb +62 -0
  14. data/lib/dependabot/bundler/file_updater/git_pin_replacer.rb +78 -0
  15. data/lib/dependabot/bundler/file_updater/git_source_remover.rb +100 -0
  16. data/lib/dependabot/bundler/file_updater/lockfile_updater.rb +387 -0
  17. data/lib/dependabot/bundler/file_updater/requirement_replacer.rb +221 -0
  18. data/lib/dependabot/bundler/file_updater.rb +125 -0
  19. data/lib/dependabot/bundler/metadata_finder.rb +204 -0
  20. data/lib/dependabot/bundler/requirement.rb +29 -0
  21. data/lib/dependabot/bundler/update_checker/file_preparer.rb +279 -0
  22. data/lib/dependabot/bundler/update_checker/force_updater.rb +259 -0
  23. data/lib/dependabot/bundler/update_checker/latest_version_finder.rb +165 -0
  24. data/lib/dependabot/bundler/update_checker/requirements_updater.rb +281 -0
  25. data/lib/dependabot/bundler/update_checker/ruby_requirement_setter.rb +113 -0
  26. data/lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb +244 -0
  27. data/lib/dependabot/bundler/update_checker/version_resolver.rb +272 -0
  28. data/lib/dependabot/bundler/update_checker.rb +334 -0
  29. data/lib/dependabot/bundler/version.rb +13 -0
  30. data/lib/dependabot/bundler.rb +27 -0
  31. data/lib/dependabot/monkey_patches/bundler/definition_bundler_version_patch.rb +15 -0
  32. data/lib/dependabot/monkey_patches/bundler/definition_ruby_version_patch.rb +14 -0
  33. data/lib/dependabot/monkey_patches/bundler/git_source_patch.rb +27 -0
  34. metadata +37 -5
@@ -0,0 +1,334 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/update_checkers"
4
+ require "dependabot/update_checkers/base"
5
+ require "dependabot/bundler/file_updater/requirement_replacer"
6
+ require "dependabot/bundler/version"
7
+ require "dependabot/git_commit_checker"
8
+
9
+ module Dependabot
10
+ module Bundler
11
+ class UpdateChecker < Dependabot::UpdateCheckers::Base
12
+ require_relative "update_checker/force_updater"
13
+ require_relative "update_checker/file_preparer"
14
+ require_relative "update_checker/requirements_updater"
15
+ require_relative "update_checker/version_resolver"
16
+ require_relative "update_checker/latest_version_finder"
17
+
18
+ def latest_version
19
+ return latest_version_for_git_dependency if git_dependency?
20
+
21
+ latest_version_details&.fetch(:version)
22
+ end
23
+
24
+ def latest_resolvable_version
25
+ return latest_resolvable_version_for_git_dependency if git_dependency?
26
+
27
+ latest_resolvable_version_details&.fetch(:version)
28
+ end
29
+
30
+ def latest_resolvable_version_with_no_unlock
31
+ current_ver = dependency.version
32
+ return current_ver if git_dependency? && git_commit_checker.pinned?
33
+
34
+ @latest_resolvable_version_detail_with_no_unlock ||=
35
+ version_resolver(
36
+ remove_git_source: false,
37
+ unlock_requirement: false
38
+ ).latest_resolvable_version_details
39
+
40
+ if git_dependency?
41
+ @latest_resolvable_version_detail_with_no_unlock&.fetch(:commit_sha)
42
+ else
43
+ @latest_resolvable_version_detail_with_no_unlock&.fetch(:version)
44
+ end
45
+ end
46
+
47
+ def updated_requirements
48
+ RequirementsUpdater.new(
49
+ requirements: dependency.requirements,
50
+ update_strategy: requirements_update_strategy,
51
+ updated_source: updated_source,
52
+ latest_version: latest_version_details&.fetch(:version)&.to_s,
53
+ latest_resolvable_version:
54
+ latest_resolvable_version_details&.fetch(:version)&.to_s
55
+ ).updated_requirements
56
+ end
57
+
58
+ def requirements_unlocked_or_can_be?
59
+ dependency.requirements.
60
+ reject { |r| r[:requirement].nil? }.
61
+ all? do |req|
62
+ requirement = requirement_class.new(req[:requirement])
63
+ next true if requirement.satisfied_by?(Gem::Version.new("100000"))
64
+
65
+ file = dependency_files.find { |f| f.name == req.fetch(:file) }
66
+ updated = FileUpdater::RequirementReplacer.new(
67
+ dependency: dependency,
68
+ file_type: file.name.end_with?("gemspec") ? :gemspec : :gemfile,
69
+ updated_requirement: "whatever"
70
+ ).rewrite(file.content)
71
+
72
+ updated != file.content
73
+ end
74
+ end
75
+
76
+ def requirements_update_strategy
77
+ # If passed in as an option (in the base class) honour that option
78
+ if @requirements_update_strategy
79
+ return @requirements_update_strategy.to_sym
80
+ end
81
+
82
+ # Otherwise, widen ranges for libraries and bump versions for apps
83
+ dependency.version.nil? ? :bump_versions_if_necessary : :bump_versions
84
+ end
85
+
86
+ private
87
+
88
+ def latest_version_resolvable_with_full_unlock?
89
+ return false unless latest_version
90
+
91
+ updated_dependencies = force_updater.updated_dependencies
92
+
93
+ updated_dependencies.none? do |dep|
94
+ old_version = dep.previous_version
95
+ next unless Gem::Version.correct?(old_version)
96
+ next if Gem::Version.new(old_version).prerelease?
97
+
98
+ Gem::Version.new(dep.version).prerelease?
99
+ end
100
+ rescue Dependabot::DependencyFileNotResolvable
101
+ false
102
+ end
103
+
104
+ def updated_dependencies_after_full_unlock
105
+ force_updater.updated_dependencies
106
+ end
107
+
108
+ def git_dependency?
109
+ git_commit_checker.git_dependency?
110
+ end
111
+
112
+ def latest_version_details(remove_git_source: false)
113
+ @latest_version_details ||= {}
114
+ @latest_version_details[remove_git_source] ||=
115
+ latest_version_finder(remove_git_source: remove_git_source).
116
+ latest_version_details
117
+ end
118
+
119
+ def latest_resolvable_version_details(remove_git_source: false)
120
+ @latest_resolvable_version_details ||= {}
121
+ @latest_resolvable_version_details[remove_git_source] ||=
122
+ version_resolver(remove_git_source: remove_git_source).
123
+ latest_resolvable_version_details
124
+ end
125
+
126
+ def latest_version_for_git_dependency
127
+ latest_release =
128
+ latest_version_details(remove_git_source: true)&.
129
+ fetch(:version)
130
+
131
+ # If there's been a release that includes the current pinned ref or
132
+ # that the current branch is behind, we switch to that release.
133
+ return latest_release if git_branch_or_ref_in_release?(latest_release)
134
+
135
+ # Otherwise, if the gem isn't pinned, the latest version is just the
136
+ # latest commit for the specified branch.
137
+ unless git_commit_checker.pinned?
138
+ return git_commit_checker.head_commit_for_current_branch
139
+ end
140
+
141
+ # If the dependency is pinned to a tag that looks like a version then
142
+ # we want to update that tag. The latest version will then be the SHA
143
+ # of the latest tag that looks like a version.
144
+ if git_commit_checker.pinned_ref_looks_like_version?
145
+ latest_tag = git_commit_checker.local_tag_for_latest_version
146
+ return latest_tag&.fetch(:tag_sha) || dependency.version
147
+ end
148
+
149
+ # If the dependency is pinned to a tag that doesn't look like a
150
+ # version then there's nothing we can do.
151
+ dependency.version
152
+ end
153
+
154
+ def latest_resolvable_version_for_git_dependency
155
+ latest_release = latest_resolvable_version_without_git_source
156
+
157
+ # If there's a resolvable release that includes the current pinned
158
+ # ref or that the current branch is behind, we switch to that release.
159
+ return latest_release if git_branch_or_ref_in_release?(latest_release)
160
+
161
+ # Otherwise, if the gem isn't pinned, the latest version is just the
162
+ # latest commit for the specified branch.
163
+ unless git_commit_checker.pinned?
164
+ return latest_resolvable_commit_with_unchanged_git_source
165
+ end
166
+
167
+ # If the dependency is pinned to a tag that looks like a version then
168
+ # we want to update that tag. The latest version will then be the SHA
169
+ # of the latest tag that looks like a version.
170
+ if git_commit_checker.pinned_ref_looks_like_version? &&
171
+ latest_git_tag_is_resolvable?
172
+ new_tag = git_commit_checker.local_tag_for_latest_version
173
+ return new_tag.fetch(:tag_sha)
174
+ end
175
+
176
+ # If the dependency is pinned to a tag that doesn't look like a
177
+ # version then there's nothing we can do.
178
+ dependency.version
179
+ end
180
+
181
+ def latest_resolvable_version_without_git_source
182
+ return nil unless latest_version.is_a?(Gem::Version)
183
+
184
+ latest_resolvable_version_details(remove_git_source: true)&.
185
+ fetch(:version)
186
+ rescue Dependabot::DependencyFileNotResolvable
187
+ nil
188
+ end
189
+
190
+ def latest_resolvable_commit_with_unchanged_git_source
191
+ details = latest_resolvable_version_details(remove_git_source: false)
192
+
193
+ # If this dependency has a git version in the Gemfile.lock but not in
194
+ # the Gemfile (i.e., because they're out-of-sync) we might not get a
195
+ # commit_sha back from Bundler. In that case, return `nil`.
196
+ return unless details.key?(:commit_sha)
197
+
198
+ details.fetch(:commit_sha)
199
+ rescue Dependabot::DependencyFileNotResolvable
200
+ nil
201
+ end
202
+
203
+ def latest_git_tag_is_resolvable?
204
+ return @git_tag_resolvable if @latest_git_tag_is_resolvable_checked
205
+
206
+ @latest_git_tag_is_resolvable_checked = true
207
+
208
+ return false if git_commit_checker.local_tag_for_latest_version.nil?
209
+
210
+ replacement_tag = git_commit_checker.local_tag_for_latest_version
211
+
212
+ VersionResolver.new(
213
+ dependency: dependency,
214
+ unprepared_dependency_files: dependency_files,
215
+ credentials: credentials,
216
+ ignored_versions: ignored_versions,
217
+ replacement_git_pin: replacement_tag.fetch(:tag)
218
+ ).latest_resolvable_version_details
219
+
220
+ @git_tag_resolvable = true
221
+ rescue Dependabot::DependencyFileNotResolvable
222
+ @git_tag_resolvable = false
223
+ end
224
+
225
+ def git_branch_or_ref_in_release?(release)
226
+ return false unless release
227
+
228
+ git_commit_checker.branch_or_ref_in_release?(release)
229
+ end
230
+
231
+ def updated_source
232
+ # Never need to update source, unless a git_dependency
233
+ return dependency_source_details unless git_dependency?
234
+
235
+ # Source becomes `nil` if switching to default rubygems
236
+ return nil if should_switch_source_from_git_to_rubygems?
237
+
238
+ # Update the git tag if updating a pinned version
239
+ if git_commit_checker.pinned_ref_looks_like_version? &&
240
+ latest_git_tag_is_resolvable?
241
+ new_tag = git_commit_checker.local_tag_for_latest_version
242
+ return dependency_source_details.merge(ref: new_tag.fetch(:tag))
243
+ end
244
+
245
+ # Otherwise return the original source
246
+ dependency_source_details
247
+ end
248
+
249
+ def dependency_source_details
250
+ sources =
251
+ dependency.requirements.map { |r| r.fetch(:source) }.uniq.compact
252
+
253
+ raise "Multiple sources! #{sources.join(', ')}" if sources.count > 1
254
+
255
+ sources.first
256
+ end
257
+
258
+ def should_switch_source_from_git_to_rubygems?
259
+ return false unless git_dependency?
260
+ return false if latest_resolvable_version_for_git_dependency.nil?
261
+
262
+ Gem::Version.correct?(latest_resolvable_version_for_git_dependency)
263
+ end
264
+
265
+ def force_updater
266
+ @force_updater ||=
267
+ ForceUpdater.new(
268
+ dependency: dependency,
269
+ dependency_files: dependency_files,
270
+ credentials: credentials,
271
+ target_version: latest_version,
272
+ requirements_update_strategy: requirements_update_strategy
273
+ )
274
+ end
275
+
276
+ def git_commit_checker
277
+ @git_commit_checker ||=
278
+ GitCommitChecker.new(
279
+ dependency: dependency,
280
+ credentials: credentials
281
+ )
282
+ end
283
+
284
+ def version_resolver(remove_git_source:, unlock_requirement: true)
285
+ @version_resolver ||= {}
286
+ @version_resolver[remove_git_source] ||= {}
287
+ @version_resolver[remove_git_source][unlock_requirement] ||=
288
+ begin
289
+ VersionResolver.new(
290
+ dependency: dependency,
291
+ unprepared_dependency_files: dependency_files,
292
+ credentials: credentials,
293
+ ignored_versions: ignored_versions,
294
+ remove_git_source: remove_git_source,
295
+ unlock_requirement: unlock_requirement,
296
+ latest_allowable_version: latest_version
297
+ )
298
+ end
299
+ end
300
+
301
+ def latest_version_finder(remove_git_source:)
302
+ @latest_version_finder ||= {}
303
+ @latest_version_finder[remove_git_source] ||=
304
+ begin
305
+ prepared_dependency_files = prepared_dependency_files(
306
+ remove_git_source: remove_git_source,
307
+ unlock_requirement: true
308
+ )
309
+
310
+ LatestVersionFinder.new(
311
+ dependency: dependency,
312
+ dependency_files: prepared_dependency_files,
313
+ credentials: credentials,
314
+ ignored_versions: ignored_versions
315
+ )
316
+ end
317
+ end
318
+
319
+ def prepared_dependency_files(remove_git_source:, unlock_requirement:,
320
+ latest_allowable_version: nil)
321
+ FilePreparer.new(
322
+ dependency: dependency,
323
+ dependency_files: dependency_files,
324
+ remove_git_source: remove_git_source,
325
+ unlock_requirement: unlock_requirement,
326
+ latest_allowable_version: latest_allowable_version
327
+ ).prepared_dependency_files
328
+ end
329
+ end
330
+ end
331
+ end
332
+
333
+ Dependabot::UpdateCheckers.
334
+ register("bundler", Dependabot::Bundler::UpdateChecker)
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/utils"
4
+
5
+ module Dependabot
6
+ module Bundler
7
+ class Version < Gem::Version
8
+ end
9
+ end
10
+ end
11
+
12
+ Dependabot::Utils.
13
+ register_version_class("bundler", Dependabot::Bundler::Version)
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # These all need to be required so the various classes can be registered in a
4
+ # lookup table of package manager names to concrete classes.
5
+ require "dependabot/bundler/file_fetcher"
6
+ require "dependabot/bundler/file_parser"
7
+ require "dependabot/bundler/update_checker"
8
+ require "dependabot/bundler/file_updater"
9
+ require "dependabot/bundler/metadata_finder"
10
+ require "dependabot/bundler/requirement"
11
+ require "dependabot/bundler/version"
12
+
13
+ require "dependabot/pull_request_creator/labeler"
14
+ Dependabot::PullRequestCreator::Labeler.
15
+ register_label_details("bundler", name: "ruby", colour: "ce2d2d")
16
+
17
+ require "dependabot/dependency"
18
+ Dependabot::Dependency.register_production_check(
19
+ "bundler",
20
+ lambda do |groups|
21
+ return true if groups.empty?
22
+ return true if groups.include?("runtime")
23
+ return true if groups.include?("default")
24
+
25
+ groups.any? { |g| g.include?("prod") }
26
+ end
27
+ )
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/definition"
4
+
5
+ # Ignore the Bundler version specified in the Gemfile (since the only Bundler
6
+ # version available to us is the one we're using).
7
+ module Bundler
8
+ class Definition
9
+ def expanded_dependencies
10
+ @expanded_dependencies ||=
11
+ expand_dependencies(dependencies + metadata_dependencies, @remote).
12
+ reject { |d| d.name == "bundler" }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BundlerDefinitionRubyVersionPatch
4
+ def index
5
+ @index ||= super.tap do
6
+ if ruby_version
7
+ requested_version = ruby_version.to_gem_version_with_patchlevel
8
+ sources.metadata_source.specs <<
9
+ Gem::Specification.new("ruby\0", requested_version)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ Bundler::Definition.prepend(BundlerDefinitionRubyVersionPatch)
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ class Source
5
+ class Git
6
+ class GitProxy
7
+ private
8
+
9
+ # Bundler allows ssh authentication when talking to GitHub but there's
10
+ # no way for Dependabot to do so (it doesn't have any ssh keys).
11
+ # Instead, we convert all `git@github.com:` URLs to use HTTPS.
12
+ def configured_uri_for(uri)
13
+ uri = uri.gsub(/git@(.*?):/, 'https://\1/')
14
+ if uri.match?(/https?:/)
15
+ remote = URI(uri)
16
+ config_auth =
17
+ Bundler.settings[remote.to_s] || Bundler.settings[remote.host]
18
+ remote.userinfo ||= config_auth
19
+ remote.to_s
20
+ else
21
+ uri
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-bundler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.95.6
4
+ version: 0.95.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-08 00:00:00.000000000 Z
11
+ date: 2019-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.95.6
19
+ version: 0.95.7
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.95.6
26
+ version: 0.95.7
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: byebug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -142,7 +142,39 @@ email: support@dependabot.com
142
142
  executables: []
143
143
  extensions: []
144
144
  extra_rdoc_files: []
145
- files: []
145
+ files:
146
+ - lib/dependabot/bundler.rb
147
+ - lib/dependabot/bundler/file_fetcher.rb
148
+ - lib/dependabot/bundler/file_fetcher/child_gemfile_finder.rb
149
+ - lib/dependabot/bundler/file_fetcher/gemspec_finder.rb
150
+ - lib/dependabot/bundler/file_fetcher/path_gemspec_finder.rb
151
+ - lib/dependabot/bundler/file_fetcher/require_relative_finder.rb
152
+ - lib/dependabot/bundler/file_parser.rb
153
+ - lib/dependabot/bundler/file_parser/file_preparer.rb
154
+ - lib/dependabot/bundler/file_parser/gemfile_checker.rb
155
+ - lib/dependabot/bundler/file_updater.rb
156
+ - lib/dependabot/bundler/file_updater/gemfile_updater.rb
157
+ - lib/dependabot/bundler/file_updater/gemspec_dependency_name_finder.rb
158
+ - lib/dependabot/bundler/file_updater/gemspec_sanitizer.rb
159
+ - lib/dependabot/bundler/file_updater/gemspec_updater.rb
160
+ - lib/dependabot/bundler/file_updater/git_pin_replacer.rb
161
+ - lib/dependabot/bundler/file_updater/git_source_remover.rb
162
+ - lib/dependabot/bundler/file_updater/lockfile_updater.rb
163
+ - lib/dependabot/bundler/file_updater/requirement_replacer.rb
164
+ - lib/dependabot/bundler/metadata_finder.rb
165
+ - lib/dependabot/bundler/requirement.rb
166
+ - lib/dependabot/bundler/update_checker.rb
167
+ - lib/dependabot/bundler/update_checker/file_preparer.rb
168
+ - lib/dependabot/bundler/update_checker/force_updater.rb
169
+ - lib/dependabot/bundler/update_checker/latest_version_finder.rb
170
+ - lib/dependabot/bundler/update_checker/requirements_updater.rb
171
+ - lib/dependabot/bundler/update_checker/ruby_requirement_setter.rb
172
+ - lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb
173
+ - lib/dependabot/bundler/update_checker/version_resolver.rb
174
+ - lib/dependabot/bundler/version.rb
175
+ - lib/dependabot/monkey_patches/bundler/definition_bundler_version_patch.rb
176
+ - lib/dependabot/monkey_patches/bundler/definition_ruby_version_patch.rb
177
+ - lib/dependabot/monkey_patches/bundler/git_source_patch.rb
146
178
  homepage: https://github.com/dependabot/dependabot-core
147
179
  licenses:
148
180
  - Nonstandard