dependabot-core 0.93.17 → 0.94.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/lib/dependabot/dependency.rb +16 -21
  4. data/lib/dependabot/file_fetchers.rb +1 -5
  5. data/lib/dependabot/file_parsers.rb +1 -5
  6. data/lib/dependabot/file_updaters.rb +1 -5
  7. data/lib/dependabot/metadata_finders.rb +1 -5
  8. data/lib/dependabot/pull_request_creator/labeler.rb +26 -24
  9. data/lib/dependabot/update_checkers.rb +1 -5
  10. data/lib/dependabot/utils.rb +2 -12
  11. data/lib/dependabot/version.rb +1 -1
  12. metadata +1 -28
  13. data/lib/dependabot/file_fetchers/ruby/bundler.rb +0 -215
  14. data/lib/dependabot/file_fetchers/ruby/bundler/child_gemfile_finder.rb +0 -70
  15. data/lib/dependabot/file_fetchers/ruby/bundler/gemspec_finder.rb +0 -98
  16. data/lib/dependabot/file_fetchers/ruby/bundler/path_gemspec_finder.rb +0 -114
  17. data/lib/dependabot/file_fetchers/ruby/bundler/require_relative_finder.rb +0 -67
  18. data/lib/dependabot/file_parsers/ruby/bundler.rb +0 -294
  19. data/lib/dependabot/file_parsers/ruby/bundler/file_preparer.rb +0 -86
  20. data/lib/dependabot/file_parsers/ruby/bundler/gemfile_checker.rb +0 -48
  21. data/lib/dependabot/file_updaters/ruby/bundler.rb +0 -123
  22. data/lib/dependabot/file_updaters/ruby/bundler/gemfile_updater.rb +0 -116
  23. data/lib/dependabot/file_updaters/ruby/bundler/gemspec_dependency_name_finder.rb +0 -52
  24. data/lib/dependabot/file_updaters/ruby/bundler/gemspec_sanitizer.rb +0 -298
  25. data/lib/dependabot/file_updaters/ruby/bundler/gemspec_updater.rb +0 -64
  26. data/lib/dependabot/file_updaters/ruby/bundler/git_pin_replacer.rb +0 -80
  27. data/lib/dependabot/file_updaters/ruby/bundler/git_source_remover.rb +0 -102
  28. data/lib/dependabot/file_updaters/ruby/bundler/lockfile_updater.rb +0 -389
  29. data/lib/dependabot/file_updaters/ruby/bundler/requirement_replacer.rb +0 -223
  30. data/lib/dependabot/metadata_finders/ruby/bundler.rb +0 -202
  31. data/lib/dependabot/update_checkers/ruby/bundler.rb +0 -331
  32. data/lib/dependabot/update_checkers/ruby/bundler/file_preparer.rb +0 -281
  33. data/lib/dependabot/update_checkers/ruby/bundler/force_updater.rb +0 -261
  34. data/lib/dependabot/update_checkers/ruby/bundler/latest_version_finder.rb +0 -169
  35. data/lib/dependabot/update_checkers/ruby/bundler/requirements_updater.rb +0 -283
  36. data/lib/dependabot/update_checkers/ruby/bundler/ruby_requirement_setter.rb +0 -115
  37. data/lib/dependabot/update_checkers/ruby/bundler/shared_bundler_helpers.rb +0 -246
  38. data/lib/dependabot/update_checkers/ruby/bundler/version_resolver.rb +0 -272
  39. data/lib/dependabot/utils/ruby/requirement.rb +0 -26
@@ -1,223 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "parser/current"
4
- require "dependabot/file_updaters/ruby/bundler"
5
-
6
- module Dependabot
7
- module FileUpdaters
8
- module Ruby
9
- class Bundler
10
- class RequirementReplacer
11
- attr_reader :dependency, :file_type, :updated_requirement,
12
- :previous_requirement
13
-
14
- def initialize(dependency:, file_type:, updated_requirement:,
15
- previous_requirement: nil, insert_if_bare: false)
16
- @dependency = dependency
17
- @file_type = file_type
18
- @updated_requirement = updated_requirement
19
- @previous_requirement = previous_requirement
20
- @insert_if_bare = insert_if_bare
21
- end
22
-
23
- def rewrite(content)
24
- buffer = Parser::Source::Buffer.new("(gemfile_content)")
25
- buffer.source = content
26
- ast = Parser::CurrentRuby.new.parse(buffer)
27
-
28
- updated_content = Rewriter.new(
29
- dependency: dependency,
30
- file_type: file_type,
31
- updated_requirement: updated_requirement,
32
- insert_if_bare: insert_if_bare?
33
- ).rewrite(buffer, ast)
34
-
35
- update_comment_spacing_if_required(content, updated_content)
36
- end
37
-
38
- private
39
-
40
- def insert_if_bare?
41
- @insert_if_bare
42
- end
43
-
44
- def update_comment_spacing_if_required(content, updated_content)
45
- return updated_content unless previous_requirement
46
-
47
- return updated_content if updated_content == content
48
- return updated_content if length_change.zero?
49
-
50
- updated_lines = updated_content.lines
51
- updated_line_index =
52
- updated_lines.length.
53
- times.find { |i| content.lines[i] != updated_content.lines[i] }
54
- updated_line = updated_lines[updated_line_index]
55
-
56
- updated_line =
57
- if length_change.positive?
58
- updated_line.sub(/(?<=\s)\s{#{length_change}}#/, "#")
59
- elsif length_change.negative?
60
- updated_line.sub(/(?<=\s{2})#/, " " * length_change.abs + "#")
61
- end
62
-
63
- updated_lines[updated_line_index] = updated_line
64
- updated_lines.join
65
- end
66
-
67
- def length_change
68
- unless previous_requirement.start_with?("=")
69
- return updated_requirement.length - previous_requirement.length
70
- end
71
-
72
- updated_requirement.length -
73
- previous_requirement.gsub(/^=/, "").strip.length
74
- end
75
-
76
- class Rewriter < Parser::TreeRewriter
77
- # TODO: Ideally we wouldn't have to ignore all of these, but
78
- # implementing each one will be tricky.
79
- SKIPPED_TYPES = %i(send lvar dstr begin if splat const).freeze
80
-
81
- def initialize(dependency:, file_type:, updated_requirement:,
82
- insert_if_bare:)
83
- @dependency = dependency
84
- @file_type = file_type
85
- @updated_requirement = updated_requirement
86
- @insert_if_bare = insert_if_bare
87
-
88
- return if %i(gemfile gemspec).include?(file_type)
89
-
90
- raise "File type must be :gemfile or :gemspec. Got #{file_type}."
91
- end
92
-
93
- def on_send(node)
94
- return unless declares_targeted_gem?(node)
95
-
96
- req_nodes = node.children[3..-1]
97
- req_nodes = req_nodes.reject { |child| child.type == :hash }
98
-
99
- return if req_nodes.none? && !insert_if_bare?
100
- return if req_nodes.any? { |n| SKIPPED_TYPES.include?(n.type) }
101
-
102
- quote_characters = extract_quote_characters_from(req_nodes)
103
- space_after_specifier = space_after_specifier?(req_nodes)
104
- use_equality_operator = use_equality_operator?(req_nodes)
105
-
106
- new_req = new_requirement_string(
107
- quote_characters: quote_characters,
108
- space_after_specifier: space_after_specifier,
109
- use_equality_operator: use_equality_operator
110
- )
111
- if req_nodes.any?
112
- replace(range_for(req_nodes), new_req)
113
- else
114
- insert_after(range_for(node.children[2..2]), ", #{new_req}")
115
- end
116
- end
117
-
118
- private
119
-
120
- attr_reader :dependency, :file_type, :updated_requirement
121
-
122
- def insert_if_bare?
123
- @insert_if_bare
124
- end
125
-
126
- def declaration_methods
127
- return %i(gem) if file_type == :gemfile
128
-
129
- %i(add_dependency add_runtime_dependency
130
- add_development_dependency)
131
- end
132
-
133
- def declares_targeted_gem?(node)
134
- return false unless declaration_methods.include?(node.children[1])
135
-
136
- node.children[2].children.first == dependency.name
137
- end
138
-
139
- def extract_quote_characters_from(requirement_nodes)
140
- return ['"', '"'] if requirement_nodes.none?
141
-
142
- case requirement_nodes.first.type
143
- when :str, :dstr
144
- [
145
- requirement_nodes.first.loc.begin.source,
146
- requirement_nodes.first.loc.end.source
147
- ]
148
- else
149
- [
150
- requirement_nodes.first.children.first.loc.begin.source,
151
- requirement_nodes.first.children.first.loc.end.source
152
- ]
153
- end
154
- end
155
-
156
- def space_after_specifier?(requirement_nodes)
157
- return true if requirement_nodes.none?
158
-
159
- req_string =
160
- case requirement_nodes.first.type
161
- when :str, :dstr
162
- requirement_nodes.first.loc.expression.source
163
- else
164
- requirement_nodes.first.children.first.loc.expression.source
165
- end
166
-
167
- ops = Gem::Requirement::OPS.keys
168
- return true if ops.none? { |op| req_string.include?(op) }
169
-
170
- req_string.include?(" ")
171
- end
172
-
173
- def use_equality_operator?(requirement_nodes)
174
- return true if requirement_nodes.none?
175
-
176
- req_string =
177
- case requirement_nodes.first.type
178
- when :str, :dstr
179
- requirement_nodes.first.loc.expression.source
180
- else
181
- requirement_nodes.first.children.first.loc.expression.source
182
- end
183
-
184
- req_string.match?(/(?<![<>])=/)
185
- end
186
-
187
- def new_requirement_string(quote_characters:,
188
- space_after_specifier:,
189
- use_equality_operator:)
190
- open_quote, close_quote = quote_characters
191
- new_requirement_string =
192
- updated_requirement.split(",").
193
- map do |r|
194
- req_string = serialized_req(r, use_equality_operator)
195
- %(#{open_quote}#{req_string}#{close_quote})
196
- end.join(", ")
197
-
198
- new_requirement_string.delete!(" ") unless space_after_specifier
199
- new_requirement_string
200
- end
201
-
202
- def serialized_req(req, use_equality_operator)
203
- tmp_req = req
204
-
205
- # Gem::Requirement serializes exact matches as a string starting
206
- # with `=`. We may need to remove that equality operator if it
207
- # wasn't used originally.
208
- unless use_equality_operator
209
- tmp_req = tmp_req.gsub(/(?<![<>])=/, "")
210
- end
211
-
212
- tmp_req.strip
213
- end
214
-
215
- def range_for(nodes)
216
- nodes.first.loc.begin.begin.join(nodes.last.loc.expression)
217
- end
218
- end
219
- end
220
- end
221
- end
222
- end
223
- end
@@ -1,202 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "excon"
4
- require "dependabot/metadata_finders/base"
5
-
6
- module Dependabot
7
- module MetadataFinders
8
- module Ruby
9
- class Bundler < 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
- end
@@ -1,331 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/update_checkers/base"
4
- require "dependabot/file_updaters/ruby/bundler/requirement_replacer"
5
- require "dependabot/git_commit_checker"
6
-
7
- module Dependabot
8
- module UpdateCheckers
9
- module Ruby
10
- class Bundler < Dependabot::UpdateCheckers::Base
11
- require_relative "bundler/force_updater"
12
- require_relative "bundler/file_preparer"
13
- require_relative "bundler/requirements_updater"
14
- require_relative "bundler/version_resolver"
15
- require_relative "bundler/latest_version_finder"
16
-
17
- def latest_version
18
- return latest_version_for_git_dependency if git_dependency?
19
-
20
- latest_version_details&.fetch(:version)
21
- end
22
-
23
- def latest_resolvable_version
24
- return latest_resolvable_version_for_git_dependency if git_dependency?
25
-
26
- latest_resolvable_version_details&.fetch(:version)
27
- end
28
-
29
- def latest_resolvable_version_with_no_unlock
30
- current_ver = dependency.version
31
- return current_ver if git_dependency? && git_commit_checker.pinned?
32
-
33
- @latest_resolvable_version_detail_with_no_unlock ||=
34
- version_resolver(
35
- remove_git_source: false,
36
- unlock_requirement: false
37
- ).latest_resolvable_version_details
38
-
39
- if git_dependency?
40
- @latest_resolvable_version_detail_with_no_unlock&.fetch(:commit_sha)
41
- else
42
- @latest_resolvable_version_detail_with_no_unlock&.fetch(:version)
43
- end
44
- end
45
-
46
- def updated_requirements
47
- RequirementsUpdater.new(
48
- requirements: dependency.requirements,
49
- update_strategy: requirements_update_strategy,
50
- updated_source: updated_source,
51
- latest_version: latest_version_details&.fetch(:version)&.to_s,
52
- latest_resolvable_version:
53
- latest_resolvable_version_details&.fetch(:version)&.to_s
54
- ).updated_requirements
55
- end
56
-
57
- def requirements_unlocked_or_can_be?
58
- dependency.requirements.
59
- reject { |r| r[:requirement].nil? }.
60
- all? do |req|
61
- requirement = requirement_class.new(req[:requirement])
62
- next true if requirement.satisfied_by?(Gem::Version.new("100000"))
63
-
64
- file = dependency_files.find { |f| f.name == req.fetch(:file) }
65
- updated = FileUpdaters::Ruby::Bundler::RequirementReplacer.new(
66
- dependency: dependency,
67
- file_type: file.name.end_with?("gemspec") ? :gemspec : :gemfile,
68
- updated_requirement: "whatever"
69
- ).rewrite(file.content)
70
-
71
- updated != file.content
72
- end
73
- end
74
-
75
- def requirements_update_strategy
76
- # If passed in as an option (in the base class) honour that option
77
- if @requirements_update_strategy
78
- return @requirements_update_strategy.to_sym
79
- end
80
-
81
- # Otherwise, widen ranges for libraries and bump versions for apps
82
- dependency.version.nil? ? :bump_versions_if_necessary : :bump_versions
83
- end
84
-
85
- private
86
-
87
- def latest_version_resolvable_with_full_unlock?
88
- return false unless latest_version
89
-
90
- updated_dependencies = force_updater.updated_dependencies
91
-
92
- updated_dependencies.none? do |dep|
93
- old_version = dep.previous_version
94
- next unless Gem::Version.correct?(old_version)
95
- next if Gem::Version.new(old_version).prerelease?
96
-
97
- Gem::Version.new(dep.version).prerelease?
98
- end
99
- rescue Dependabot::DependencyFileNotResolvable
100
- false
101
- end
102
-
103
- def updated_dependencies_after_full_unlock
104
- force_updater.updated_dependencies
105
- end
106
-
107
- def git_dependency?
108
- git_commit_checker.git_dependency?
109
- end
110
-
111
- def latest_version_details(remove_git_source: false)
112
- @latest_version_details ||= {}
113
- @latest_version_details[remove_git_source] ||=
114
- latest_version_finder(remove_git_source: remove_git_source).
115
- latest_version_details
116
- end
117
-
118
- def latest_resolvable_version_details(remove_git_source: false)
119
- @latest_resolvable_version_details ||= {}
120
- @latest_resolvable_version_details[remove_git_source] ||=
121
- version_resolver(remove_git_source: remove_git_source).
122
- latest_resolvable_version_details
123
- end
124
-
125
- def latest_version_for_git_dependency
126
- latest_release =
127
- latest_version_details(remove_git_source: true)&.
128
- fetch(:version)
129
-
130
- # If there's been a release that includes the current pinned ref or
131
- # that the current branch is behind, we switch to that release.
132
- return latest_release if git_branch_or_ref_in_release?(latest_release)
133
-
134
- # Otherwise, if the gem isn't pinned, the latest version is just the
135
- # latest commit for the specified branch.
136
- unless git_commit_checker.pinned?
137
- return git_commit_checker.head_commit_for_current_branch
138
- end
139
-
140
- # If the dependency is pinned to a tag that looks like a version then
141
- # we want to update that tag. The latest version will then be the SHA
142
- # of the latest tag that looks like a version.
143
- if git_commit_checker.pinned_ref_looks_like_version?
144
- latest_tag = git_commit_checker.local_tag_for_latest_version
145
- return latest_tag&.fetch(:tag_sha) || dependency.version
146
- end
147
-
148
- # If the dependency is pinned to a tag that doesn't look like a
149
- # version then there's nothing we can do.
150
- dependency.version
151
- end
152
-
153
- def latest_resolvable_version_for_git_dependency
154
- latest_release = latest_resolvable_version_without_git_source
155
-
156
- # If there's a resolvable release that includes the current pinned
157
- # ref or that the current branch is behind, we switch to that release.
158
- return latest_release if git_branch_or_ref_in_release?(latest_release)
159
-
160
- # Otherwise, if the gem isn't pinned, the latest version is just the
161
- # latest commit for the specified branch.
162
- unless git_commit_checker.pinned?
163
- return latest_resolvable_commit_with_unchanged_git_source
164
- end
165
-
166
- # If the dependency is pinned to a tag that looks like a version then
167
- # we want to update that tag. The latest version will then be the SHA
168
- # of the latest tag that looks like a version.
169
- if git_commit_checker.pinned_ref_looks_like_version? &&
170
- latest_git_tag_is_resolvable?
171
- new_tag = git_commit_checker.local_tag_for_latest_version
172
- return new_tag.fetch(:tag_sha)
173
- end
174
-
175
- # If the dependency is pinned to a tag that doesn't look like a
176
- # version then there's nothing we can do.
177
- dependency.version
178
- end
179
-
180
- def latest_resolvable_version_without_git_source
181
- return nil unless latest_version.is_a?(Gem::Version)
182
-
183
- latest_resolvable_version_details(remove_git_source: true)&.
184
- fetch(:version)
185
- rescue Dependabot::DependencyFileNotResolvable
186
- nil
187
- end
188
-
189
- def latest_resolvable_commit_with_unchanged_git_source
190
- details = latest_resolvable_version_details(remove_git_source: false)
191
-
192
- # If this dependency has a git version in the Gemfile.lock but not in
193
- # the Gemfile (i.e., because they're out-of-sync) we might not get a
194
- # commit_sha back from Bundler. In that case, return `nil`.
195
- return unless details.key?(:commit_sha)
196
-
197
- details.fetch(:commit_sha)
198
- rescue Dependabot::DependencyFileNotResolvable
199
- nil
200
- end
201
-
202
- def latest_git_tag_is_resolvable?
203
- return @git_tag_resolvable if @latest_git_tag_is_resolvable_checked
204
-
205
- @latest_git_tag_is_resolvable_checked = true
206
-
207
- return false if git_commit_checker.local_tag_for_latest_version.nil?
208
-
209
- replacement_tag = git_commit_checker.local_tag_for_latest_version
210
-
211
- VersionResolver.new(
212
- dependency: dependency,
213
- unprepared_dependency_files: dependency_files,
214
- credentials: credentials,
215
- ignored_versions: ignored_versions,
216
- replacement_git_pin: replacement_tag.fetch(:tag)
217
- ).latest_resolvable_version_details
218
-
219
- @git_tag_resolvable = true
220
- rescue Dependabot::DependencyFileNotResolvable
221
- @git_tag_resolvable = false
222
- end
223
-
224
- def git_branch_or_ref_in_release?(release)
225
- return false unless release
226
-
227
- git_commit_checker.branch_or_ref_in_release?(release)
228
- end
229
-
230
- def updated_source
231
- # Never need to update source, unless a git_dependency
232
- return dependency_source_details unless git_dependency?
233
-
234
- # Source becomes `nil` if switching to default rubygems
235
- return nil if should_switch_source_from_git_to_rubygems?
236
-
237
- # Update the git tag if updating a pinned version
238
- if git_commit_checker.pinned_ref_looks_like_version? &&
239
- latest_git_tag_is_resolvable?
240
- new_tag = git_commit_checker.local_tag_for_latest_version
241
- return dependency_source_details.merge(ref: new_tag.fetch(:tag))
242
- end
243
-
244
- # Otherwise return the original source
245
- dependency_source_details
246
- end
247
-
248
- def dependency_source_details
249
- sources =
250
- dependency.requirements.map { |r| r.fetch(:source) }.uniq.compact
251
-
252
- raise "Multiple sources! #{sources.join(', ')}" if sources.count > 1
253
-
254
- sources.first
255
- end
256
-
257
- def should_switch_source_from_git_to_rubygems?
258
- return false unless git_dependency?
259
- return false if latest_resolvable_version_for_git_dependency.nil?
260
-
261
- Gem::Version.correct?(latest_resolvable_version_for_git_dependency)
262
- end
263
-
264
- def force_updater
265
- @force_updater ||=
266
- ForceUpdater.new(
267
- dependency: dependency,
268
- dependency_files: dependency_files,
269
- credentials: credentials,
270
- target_version: latest_version,
271
- requirements_update_strategy: requirements_update_strategy
272
- )
273
- end
274
-
275
- def git_commit_checker
276
- @git_commit_checker ||=
277
- GitCommitChecker.new(
278
- dependency: dependency,
279
- credentials: credentials
280
- )
281
- end
282
-
283
- def version_resolver(remove_git_source:, unlock_requirement: true)
284
- @version_resolver ||= {}
285
- @version_resolver[remove_git_source] ||= {}
286
- @version_resolver[remove_git_source][unlock_requirement] ||=
287
- begin
288
- VersionResolver.new(
289
- dependency: dependency,
290
- unprepared_dependency_files: dependency_files,
291
- credentials: credentials,
292
- ignored_versions: ignored_versions,
293
- remove_git_source: remove_git_source,
294
- unlock_requirement: unlock_requirement,
295
- latest_allowable_version: latest_version
296
- )
297
- end
298
- end
299
-
300
- def latest_version_finder(remove_git_source:)
301
- @latest_version_finder ||= {}
302
- @latest_version_finder[remove_git_source] ||=
303
- begin
304
- prepared_dependency_files = prepared_dependency_files(
305
- remove_git_source: remove_git_source,
306
- unlock_requirement: true
307
- )
308
-
309
- LatestVersionFinder.new(
310
- dependency: dependency,
311
- dependency_files: prepared_dependency_files,
312
- credentials: credentials,
313
- ignored_versions: ignored_versions
314
- )
315
- end
316
- end
317
-
318
- def prepared_dependency_files(remove_git_source:, unlock_requirement:,
319
- latest_allowable_version: nil)
320
- FilePreparer.new(
321
- dependency: dependency,
322
- dependency_files: dependency_files,
323
- remove_git_source: remove_git_source,
324
- unlock_requirement: unlock_requirement,
325
- latest_allowable_version: latest_allowable_version
326
- ).prepared_dependency_files
327
- end
328
- end
329
- end
330
- end
331
- end