dependabot-bundler 0.94.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/helpers/Makefile +9 -0
  3. data/helpers/build +26 -0
  4. data/lib/dependabot/bundler.rb +27 -0
  5. data/lib/dependabot/bundler/file_fetcher.rb +216 -0
  6. data/lib/dependabot/bundler/file_fetcher/child_gemfile_finder.rb +68 -0
  7. data/lib/dependabot/bundler/file_fetcher/gemspec_finder.rb +96 -0
  8. data/lib/dependabot/bundler/file_fetcher/path_gemspec_finder.rb +112 -0
  9. data/lib/dependabot/bundler/file_fetcher/require_relative_finder.rb +65 -0
  10. data/lib/dependabot/bundler/file_parser.rb +297 -0
  11. data/lib/dependabot/bundler/file_parser/file_preparer.rb +84 -0
  12. data/lib/dependabot/bundler/file_parser/gemfile_checker.rb +46 -0
  13. data/lib/dependabot/bundler/file_updater.rb +125 -0
  14. data/lib/dependabot/bundler/file_updater/gemfile_updater.rb +114 -0
  15. data/lib/dependabot/bundler/file_updater/gemspec_dependency_name_finder.rb +50 -0
  16. data/lib/dependabot/bundler/file_updater/gemspec_sanitizer.rb +296 -0
  17. data/lib/dependabot/bundler/file_updater/gemspec_updater.rb +62 -0
  18. data/lib/dependabot/bundler/file_updater/git_pin_replacer.rb +78 -0
  19. data/lib/dependabot/bundler/file_updater/git_source_remover.rb +100 -0
  20. data/lib/dependabot/bundler/file_updater/lockfile_updater.rb +387 -0
  21. data/lib/dependabot/bundler/file_updater/requirement_replacer.rb +221 -0
  22. data/lib/dependabot/bundler/metadata_finder.rb +204 -0
  23. data/lib/dependabot/bundler/requirement.rb +29 -0
  24. data/lib/dependabot/bundler/update_checker.rb +334 -0
  25. data/lib/dependabot/bundler/update_checker/file_preparer.rb +279 -0
  26. data/lib/dependabot/bundler/update_checker/force_updater.rb +259 -0
  27. data/lib/dependabot/bundler/update_checker/latest_version_finder.rb +165 -0
  28. data/lib/dependabot/bundler/update_checker/requirements_updater.rb +281 -0
  29. data/lib/dependabot/bundler/update_checker/ruby_requirement_setter.rb +113 -0
  30. data/lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb +244 -0
  31. data/lib/dependabot/bundler/update_checker/version_resolver.rb +272 -0
  32. data/lib/dependabot/bundler/version.rb +13 -0
  33. metadata +200 -0
@@ -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,279 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/dependency_file"
4
+ require "dependabot/bundler/update_checker"
5
+ require "dependabot/bundler/file_updater/gemspec_sanitizer"
6
+ require "dependabot/bundler/file_updater/git_pin_replacer"
7
+ require "dependabot/bundler/file_updater/git_source_remover"
8
+ require "dependabot/bundler/file_updater/requirement_replacer"
9
+ require "dependabot/bundler/file_updater/gemspec_dependency_name_finder"
10
+ require "dependabot/bundler/file_updater/lockfile_updater"
11
+ require "dependabot/bundler/update_checker/ruby_requirement_setter"
12
+
13
+ module Dependabot
14
+ module Bundler
15
+ class UpdateChecker
16
+ # This class takes a set of dependency files and sanitizes them for use
17
+ # in UpdateCheckers::Ruby::Bundler. In particular, it:
18
+ # - Removes any version requirement on the dependency being updated
19
+ # (in the Gemfile)
20
+ # - Sanitizes any provided gemspecs to remove file imports etc. (since
21
+ # Dependabot doesn't pull down the entire repo). This process is
22
+ # imperfect - an alternative would be to clone the repo
23
+ # - Sets the ruby version in the Gemfile to be the lowest possible
24
+ # version allowed by the gemspec, if the gemspec has a required ruby
25
+ # version range
26
+ class FilePreparer
27
+ VERSION_REGEX = /[0-9]+(?:\.[A-Za-z0-9\-_]+)*/.freeze
28
+
29
+ # Can't be a constant because some of these don't exist in bundler
30
+ # 1.15, which Heroku uses, which causes an exception on boot.
31
+ def gemspec_sources
32
+ [
33
+ ::Bundler::Source::Path,
34
+ ::Bundler::Source::Gemspec
35
+ ]
36
+ end
37
+
38
+ def initialize(dependency_files:, dependency:,
39
+ remove_git_source: false,
40
+ unlock_requirement: true,
41
+ replacement_git_pin: nil,
42
+ latest_allowable_version: nil,
43
+ lock_ruby_version: true)
44
+ @dependency_files = dependency_files
45
+ @dependency = dependency
46
+ @remove_git_source = remove_git_source
47
+ @unlock_requirement = unlock_requirement
48
+ @replacement_git_pin = replacement_git_pin
49
+ @latest_allowable_version = latest_allowable_version
50
+ @lock_ruby_version = lock_ruby_version
51
+ end
52
+
53
+ # rubocop:disable Metrics/AbcSize
54
+ # rubocop:disable Metrics/MethodLength
55
+ def prepared_dependency_files
56
+ files = []
57
+
58
+ if gemfile
59
+ files << DependencyFile.new(
60
+ name: gemfile.name,
61
+ content: gemfile_content_for_update_check(gemfile),
62
+ directory: gemfile.directory
63
+ )
64
+ end
65
+
66
+ top_level_gemspecs.each do |gemspec|
67
+ files << DependencyFile.new(
68
+ name: gemspec.name,
69
+ content: gemspec_content_for_update_check(gemspec),
70
+ directory: gemspec.directory
71
+ )
72
+ end
73
+
74
+ path_gemspecs.each do |file|
75
+ files << DependencyFile.new(
76
+ name: file.name,
77
+ content: sanitize_gemspec_content(file.content),
78
+ directory: file.directory,
79
+ support_file: file.support_file?
80
+ )
81
+ end
82
+
83
+ evaled_gemfiles.each do |file|
84
+ files << DependencyFile.new(
85
+ name: file.name,
86
+ content: gemfile_content_for_update_check(file),
87
+ directory: file.directory
88
+ )
89
+ end
90
+
91
+ # No editing required for lockfile or Ruby version file
92
+ files += [lockfile, ruby_version_file, *imported_ruby_files].compact
93
+ end
94
+ # rubocop:enable Metrics/AbcSize
95
+ # rubocop:enable Metrics/MethodLength
96
+
97
+ private
98
+
99
+ attr_reader :dependency_files, :dependency, :replacement_git_pin,
100
+ :latest_allowable_version
101
+
102
+ def remove_git_source?
103
+ @remove_git_source
104
+ end
105
+
106
+ def unlock_requirement?
107
+ @unlock_requirement
108
+ end
109
+
110
+ def replace_git_pin?
111
+ !replacement_git_pin.nil?
112
+ end
113
+
114
+ def gemfile
115
+ dependency_files.find { |f| f.name == "Gemfile" } ||
116
+ dependency_files.find { |f| f.name == "gems.rb" }
117
+ end
118
+
119
+ def evaled_gemfiles
120
+ dependency_files.
121
+ reject { |f| f.name.end_with?(".gemspec") }.
122
+ reject { |f| f.name.end_with?(".lock") }.
123
+ reject { |f| f.name.end_with?(".ruby-version") }.
124
+ reject { |f| f.name == "Gemfile" }.
125
+ reject { |f| f.name == "gems.rb" }.
126
+ reject { |f| f.name == "gems.locked" }
127
+ end
128
+
129
+ def lockfile
130
+ dependency_files.find { |f| f.name == "Gemfile.lock" } ||
131
+ dependency_files.find { |f| f.name == "gems.locked" }
132
+ end
133
+
134
+ def top_level_gemspecs
135
+ dependency_files.
136
+ select { |f| f.name.end_with?(".gemspec") }.
137
+ reject(&:support_file?)
138
+ end
139
+
140
+ def ruby_version_file
141
+ dependency_files.find { |f| f.name == ".ruby-version" }
142
+ end
143
+
144
+ def path_gemspecs
145
+ all = dependency_files.select { |f| f.name.end_with?(".gemspec") }
146
+ all - top_level_gemspecs
147
+ end
148
+
149
+ def imported_ruby_files
150
+ dependency_files.
151
+ select { |f| f.name.end_with?(".rb") }.
152
+ reject { |f| f.name == "gems.rb" }
153
+ end
154
+
155
+ def gemfile_content_for_update_check(file)
156
+ content = file.content
157
+ content = replace_gemfile_constraint(content, file.name)
158
+ content = remove_git_source(content) if remove_git_source?
159
+ content = replace_git_pin(content) if replace_git_pin?
160
+ content = lock_ruby_version(content) if lock_ruby_version?(file)
161
+ content
162
+ end
163
+
164
+ def gemspec_content_for_update_check(gemspec)
165
+ content = gemspec.content
166
+ content = replace_gemspec_constraint(content, gemspec.name)
167
+ sanitize_gemspec_content(content)
168
+ end
169
+
170
+ def replace_gemfile_constraint(content, filename)
171
+ FileUpdater::RequirementReplacer.new(
172
+ dependency: dependency,
173
+ file_type: :gemfile,
174
+ updated_requirement: updated_version_requirement_string(filename),
175
+ insert_if_bare: true
176
+ ).rewrite(content)
177
+ end
178
+
179
+ def replace_gemspec_constraint(content, filename)
180
+ FileUpdater::RequirementReplacer.new(
181
+ dependency: dependency,
182
+ file_type: :gemspec,
183
+ updated_requirement: updated_version_requirement_string(filename),
184
+ insert_if_bare: true
185
+ ).rewrite(content)
186
+ end
187
+
188
+ def sanitize_gemspec_content(gemspec_content)
189
+ new_version = replacement_version_for_gemspec(gemspec_content)
190
+
191
+ FileUpdater::GemspecSanitizer.
192
+ new(replacement_version: new_version).
193
+ rewrite(gemspec_content)
194
+ end
195
+
196
+ def updated_version_requirement_string(filename)
197
+ lower_bound_req = updated_version_req_lower_bound(filename)
198
+
199
+ return lower_bound_req if latest_allowable_version.nil?
200
+ unless Gem::Version.correct?(latest_allowable_version)
201
+ return lower_bound_req
202
+ end
203
+
204
+ lower_bound_req + ", <= #{latest_allowable_version}"
205
+ end
206
+
207
+ def updated_version_req_lower_bound(filename)
208
+ original_req = dependency.requirements.
209
+ find { |r| r.fetch(:file) == filename }&.
210
+ fetch(:requirement)
211
+
212
+ if original_req && !unlock_requirement? then original_req
213
+ elsif dependency.version&.match?(/^[0-9a-f]{40}$/) then ">= 0"
214
+ elsif dependency.version then ">= #{dependency.version}"
215
+ else
216
+ version_for_requirement =
217
+ dependency.requirements.map { |r| r[:requirement] }.
218
+ reject { |req_string| req_string.start_with?("<") }.
219
+ select { |req_string| req_string.match?(VERSION_REGEX) }.
220
+ map { |req_string| req_string.match(VERSION_REGEX) }.
221
+ select { |version| Gem::Version.correct?(version) }.
222
+ max_by { |version| Gem::Version.new(version) }
223
+
224
+ ">= #{version_for_requirement || 0}"
225
+ end
226
+ end
227
+
228
+ def remove_git_source(content)
229
+ FileUpdater::GitSourceRemover.new(
230
+ dependency: dependency
231
+ ).rewrite(content)
232
+ end
233
+
234
+ def replace_git_pin(content)
235
+ FileUpdater::GitPinReplacer.new(
236
+ dependency: dependency,
237
+ new_pin: replacement_git_pin
238
+ ).rewrite(content)
239
+ end
240
+
241
+ def lock_ruby_version(gemfile_content)
242
+ top_level_gemspecs.each do |gs|
243
+ gemfile_content =
244
+ RubyRequirementSetter.new(gemspec: gs).rewrite(gemfile_content)
245
+ end
246
+
247
+ gemfile_content
248
+ end
249
+
250
+ def lock_ruby_version?(file)
251
+ @lock_ruby_version && file == gemfile
252
+ end
253
+
254
+ def replacement_version_for_gemspec(gemspec_content)
255
+ return "0.0.1" unless lockfile
256
+
257
+ gemspec_specs =
258
+ ::Bundler::LockfileParser.new(sanitized_lockfile_content).specs.
259
+ select { |s| gemspec_sources.include?(s.source.class) }
260
+
261
+ gem_name =
262
+ FileUpdater::GemspecDependencyNameFinder.
263
+ new(gemspec_content: gemspec_content).
264
+ dependency_name
265
+
266
+ return gemspec_specs.first&.version || "0.0.1" unless gem_name
267
+
268
+ spec = gemspec_specs.find { |s| s.name == gem_name }
269
+ spec&.version || gemspec_specs.first&.version || "0.0.1"
270
+ end
271
+
272
+ def sanitized_lockfile_content
273
+ re = FileUpdater::LockfileUpdater::LOCKFILE_ENDING
274
+ lockfile.content.gsub(re, "")
275
+ end
276
+ end
277
+ end
278
+ end
279
+ end