dependabot-common 0.212.0 → 0.213.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/dependabot/clients/bitbucket.rb +8 -1
- data/lib/dependabot/config/file.rb +1 -1
- data/lib/dependabot/dependency.rb +19 -2
- data/lib/dependabot/errors.rb +3 -3
- data/lib/dependabot/experiments.rb +19 -0
- data/lib/dependabot/file_fetchers/base.rb +143 -80
- data/lib/dependabot/file_parsers/base/dependency_set.rb +106 -41
- data/lib/dependabot/git_commit_checker.rb +23 -11
- data/lib/dependabot/git_metadata_fetcher.rb +1 -1
- data/lib/dependabot/pull_request_creator/branch_namer.rb +15 -4
- data/lib/dependabot/pull_request_creator/labeler.rb +6 -6
- data/lib/dependabot/pull_request_creator/message_builder/issue_linker.rb +5 -5
- data/lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb +33 -5
- data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +1 -3
- data/lib/dependabot/pull_request_creator/message_builder.rb +78 -6
- data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +3 -2
- data/lib/dependabot/pull_request_creator.rb +6 -3
- data/lib/dependabot/pull_request_updater/azure.rb +1 -1
- data/lib/dependabot/pull_request_updater/github.rb +15 -12
- data/lib/dependabot/pull_request_updater.rb +2 -1
- data/lib/dependabot/source.rb +9 -9
- data/lib/dependabot/update_checkers/base.rb +1 -1
- data/lib/dependabot/version.rb +1 -1
- metadata +16 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23fa5c7ea872ca0849f22018af9b0811ad9044f03a4e7d59aa023b3dd80bd4e6
|
4
|
+
data.tar.gz: cea778ebef75ccec5afcd3e5932af78d9711c51c4c864ea02d65930fce8ca4dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b14ad55cbabd2a49bd35c7f8012f95972515eead80a71363353a8978286e9d756fd97da5442cb3013acdebfb1a77c7f8f7c450bac553a2d6f52b12687fcf2d43
|
7
|
+
data.tar.gz: 86cbba3afb724d1ee0b6c1fd0bb357a33c288263b3032e0ef029e099b5d7f7d8d5104526a8890d6233fdb8850b56ecd05cb0746bd8e6fe8fd84338db8caa28dd
|
@@ -144,7 +144,14 @@ module Dependabot
|
|
144
144
|
end
|
145
145
|
# rubocop:enable Metrics/ParameterLists
|
146
146
|
|
147
|
+
def current_user
|
148
|
+
base_url = "https://api.bitbucket.org/2.0/user?fields=uuid"
|
149
|
+
response = get(base_url)
|
150
|
+
JSON.parse(response.body).fetch("uuid")
|
151
|
+
end
|
152
|
+
|
147
153
|
def default_reviewers(repo)
|
154
|
+
current_uuid = current_user
|
148
155
|
path = "#{repo}/default-reviewers?pagelen=100&fields=values.uuid,next"
|
149
156
|
reviewers_url = base_url + path
|
150
157
|
|
@@ -153,7 +160,7 @@ module Dependabot
|
|
153
160
|
reviewer_data = []
|
154
161
|
|
155
162
|
default_reviewers.each do |reviewer|
|
156
|
-
reviewer_data.append({ uuid: reviewer.fetch("uuid") })
|
163
|
+
reviewer_data.append({ uuid: reviewer.fetch("uuid") }) unless current_uuid == reviewer.fetch("uuid")
|
157
164
|
end
|
158
165
|
|
159
166
|
reviewer_data
|
@@ -71,7 +71,7 @@ module Dependabot
|
|
71
71
|
commit_message = cfg&.dig(:"commit-message") || {}
|
72
72
|
Dependabot::Config::UpdateConfig::CommitMessageOptions.new(
|
73
73
|
prefix: commit_message[:prefix],
|
74
|
-
prefix_development: commit_message[:"prefix-development"],
|
74
|
+
prefix_development: commit_message[:"prefix-development"] || commit_message[:prefix],
|
75
75
|
include: commit_message[:include]
|
76
76
|
)
|
77
77
|
end
|
@@ -37,11 +37,11 @@ module Dependabot
|
|
37
37
|
|
38
38
|
attr_reader :name, :version, :requirements, :package_manager,
|
39
39
|
:previous_version, :previous_requirements,
|
40
|
-
:subdependency_metadata
|
40
|
+
:subdependency_metadata, :metadata
|
41
41
|
|
42
42
|
def initialize(name:, requirements:, package_manager:, version: nil,
|
43
43
|
previous_version: nil, previous_requirements: nil,
|
44
|
-
subdependency_metadata: [], removed: false)
|
44
|
+
subdependency_metadata: [], removed: false, metadata: {})
|
45
45
|
@name = name
|
46
46
|
@version = version
|
47
47
|
@requirements = requirements.map { |req| symbolize_keys(req) }
|
@@ -54,6 +54,7 @@ module Dependabot
|
|
54
54
|
map { |h| symbolize_keys(h) }
|
55
55
|
end
|
56
56
|
@removed = removed
|
57
|
+
@metadata = symbolize_keys(metadata || {})
|
57
58
|
|
58
59
|
check_values
|
59
60
|
end
|
@@ -105,6 +106,22 @@ module Dependabot
|
|
105
106
|
display_name_builder.call(name)
|
106
107
|
end
|
107
108
|
|
109
|
+
# Returns all detected versions of the dependency. Only ecosystems that
|
110
|
+
# support this feature will return more than the current version.
|
111
|
+
def all_versions
|
112
|
+
all_versions = metadata[:all_versions]
|
113
|
+
return [version].compact unless all_versions
|
114
|
+
|
115
|
+
all_versions.filter_map(&:version)
|
116
|
+
end
|
117
|
+
|
118
|
+
# This dependency is being indirectly updated by an update to another
|
119
|
+
# dependency. We don't need to try and update it ourselves but want to
|
120
|
+
# surface it to the user in the PR.
|
121
|
+
def informational_only?
|
122
|
+
metadata[:information_only]
|
123
|
+
end
|
124
|
+
|
108
125
|
def ==(other)
|
109
126
|
other.instance_of?(self.class) && to_h == other.to_h
|
110
127
|
end
|
data/lib/dependabot/errors.rb
CHANGED
@@ -4,9 +4,9 @@ require "dependabot/utils"
|
|
4
4
|
|
5
5
|
module Dependabot
|
6
6
|
class DependabotError < StandardError
|
7
|
-
BASIC_AUTH_REGEX = %r{://(?<auth>[^:]*:[^@%\s]+(@|%40))}
|
7
|
+
BASIC_AUTH_REGEX = %r{://(?<auth>[^:]*:[^@%\s]+(@|%40))}
|
8
8
|
# Remove any path segment from fury.io sources
|
9
|
-
FURY_IO_PATH_REGEX = %r{fury\.io/(?<path>.+)}
|
9
|
+
FURY_IO_PATH_REGEX = %r{fury\.io/(?<path>.+)}
|
10
10
|
|
11
11
|
def initialize(message = nil)
|
12
12
|
super(sanitize_message(message))
|
@@ -18,7 +18,7 @@ module Dependabot
|
|
18
18
|
return message unless message.is_a?(String)
|
19
19
|
|
20
20
|
path_regex =
|
21
|
-
Regexp.escape(Utils::BUMP_TMP_DIR_PATH) + "
|
21
|
+
Regexp.escape(Utils::BUMP_TMP_DIR_PATH) + "\\/" +
|
22
22
|
Regexp.escape(Utils::BUMP_TMP_FILE_PREFIX) + "[a-zA-Z0-9-]*"
|
23
23
|
|
24
24
|
message = message.gsub(/#{path_regex}/, "dependabot_tmp_dir").strip
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dependabot
|
4
|
+
module Experiments
|
5
|
+
@experiments = {}
|
6
|
+
|
7
|
+
def self.reset!
|
8
|
+
@experiments = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.register(name, value)
|
12
|
+
@experiments[name.to_sym] = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.enabled?(name)
|
16
|
+
!!@experiments[name.to_sym]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "stringio"
|
3
4
|
require "dependabot/config"
|
4
5
|
require "dependabot/dependency_file"
|
5
6
|
require "dependabot/source"
|
@@ -69,6 +70,7 @@ module Dependabot
|
|
69
70
|
end
|
70
71
|
|
71
72
|
def commit
|
73
|
+
return cloned_commit if cloned_commit
|
72
74
|
return source.commit if source.commit
|
73
75
|
|
74
76
|
branch = target_branch || default_branch_for_repo
|
@@ -84,7 +86,11 @@ module Dependabot
|
|
84
86
|
def clone_repo_contents
|
85
87
|
@clone_repo_contents ||=
|
86
88
|
_clone_repo_contents(target_directory: repo_contents_path)
|
87
|
-
rescue Dependabot::SharedHelpers::HelperSubprocessFailed
|
89
|
+
rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
|
90
|
+
if e.message.include?("fatal: Remote branch #{target_branch} not found in upstream origin")
|
91
|
+
raise Dependabot::BranchNotFound, target_branch
|
92
|
+
end
|
93
|
+
|
88
94
|
raise Dependabot::RepoNotFound, source
|
89
95
|
end
|
90
96
|
|
@@ -168,6 +174,97 @@ module Dependabot
|
|
168
174
|
end
|
169
175
|
end
|
170
176
|
|
177
|
+
def cloned_commit
|
178
|
+
return if repo_contents_path.nil? || !File.directory?(File.join(repo_contents_path, ".git"))
|
179
|
+
|
180
|
+
SharedHelpers.with_git_configured(credentials: credentials) do
|
181
|
+
Dir.chdir(repo_contents_path) do
|
182
|
+
return SharedHelpers.run_shell_command("git rev-parse HEAD")&.strip
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def default_branch_for_repo
|
188
|
+
@default_branch_for_repo ||= client_for_provider.
|
189
|
+
fetch_default_branch(repo)
|
190
|
+
rescue *CLIENT_NOT_FOUND_ERRORS
|
191
|
+
raise Dependabot::RepoNotFound, source
|
192
|
+
end
|
193
|
+
|
194
|
+
def update_linked_paths(repo, path, commit, github_response)
|
195
|
+
case github_response.type
|
196
|
+
when "submodule"
|
197
|
+
sub_source = Source.from_url(github_response.submodule_git_url)
|
198
|
+
return unless sub_source
|
199
|
+
|
200
|
+
@linked_paths[path] = {
|
201
|
+
repo: sub_source.repo,
|
202
|
+
provider: sub_source.provider,
|
203
|
+
commit: github_response.sha,
|
204
|
+
path: "/"
|
205
|
+
}
|
206
|
+
when "symlink"
|
207
|
+
updated_path = File.join(File.dirname(path), github_response.target)
|
208
|
+
@linked_paths[path] = {
|
209
|
+
repo: repo,
|
210
|
+
provider: "github",
|
211
|
+
commit: commit,
|
212
|
+
path: Pathname.new(updated_path).cleanpath.to_path
|
213
|
+
}
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def recurse_submodules_when_cloning?
|
218
|
+
false
|
219
|
+
end
|
220
|
+
|
221
|
+
def client_for_provider
|
222
|
+
case source.provider
|
223
|
+
when "github" then github_client
|
224
|
+
when "gitlab" then gitlab_client
|
225
|
+
when "azure" then azure_client
|
226
|
+
when "bitbucket" then bitbucket_client
|
227
|
+
when "codecommit" then codecommit_client
|
228
|
+
else raise "Unsupported provider '#{source.provider}'."
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def github_client
|
233
|
+
@github_client ||=
|
234
|
+
Dependabot::Clients::GithubWithRetries.for_source(
|
235
|
+
source: source,
|
236
|
+
credentials: credentials
|
237
|
+
)
|
238
|
+
end
|
239
|
+
|
240
|
+
def gitlab_client
|
241
|
+
@gitlab_client ||=
|
242
|
+
Dependabot::Clients::GitlabWithRetries.for_source(
|
243
|
+
source: source,
|
244
|
+
credentials: credentials
|
245
|
+
)
|
246
|
+
end
|
247
|
+
|
248
|
+
def azure_client
|
249
|
+
@azure_client ||=
|
250
|
+
Dependabot::Clients::Azure.
|
251
|
+
for_source(source: source, credentials: credentials)
|
252
|
+
end
|
253
|
+
|
254
|
+
def bitbucket_client
|
255
|
+
# TODO: When self-hosted Bitbucket is supported this should use
|
256
|
+
# `Bitbucket.for_source`
|
257
|
+
@bitbucket_client ||=
|
258
|
+
Dependabot::Clients::BitbucketWithRetries.
|
259
|
+
for_bitbucket_dot_org(credentials: credentials)
|
260
|
+
end
|
261
|
+
|
262
|
+
def codecommit_client
|
263
|
+
@codecommit_client ||=
|
264
|
+
Dependabot::Clients::CodeCommit.
|
265
|
+
for_source(source: source, credentials: credentials)
|
266
|
+
end
|
267
|
+
|
171
268
|
#################################################
|
172
269
|
# INTERNAL METHODS (not for use by sub-classes) #
|
173
270
|
#################################################
|
@@ -254,29 +351,6 @@ module Dependabot
|
|
254
351
|
end
|
255
352
|
end
|
256
353
|
|
257
|
-
def update_linked_paths(repo, path, commit, github_response)
|
258
|
-
case github_response.type
|
259
|
-
when "submodule"
|
260
|
-
sub_source = Source.from_url(github_response.submodule_git_url)
|
261
|
-
return unless sub_source
|
262
|
-
|
263
|
-
@linked_paths[path] = {
|
264
|
-
repo: sub_source.repo,
|
265
|
-
provider: sub_source.provider,
|
266
|
-
commit: github_response.sha,
|
267
|
-
path: "/"
|
268
|
-
}
|
269
|
-
when "symlink"
|
270
|
-
updated_path = File.join(File.dirname(path), github_response.target)
|
271
|
-
@linked_paths[path] = {
|
272
|
-
repo: repo,
|
273
|
-
provider: "github",
|
274
|
-
commit: commit,
|
275
|
-
path: Pathname.new(updated_path).cleanpath.to_path
|
276
|
-
}
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
354
|
def _build_github_file_struct(file)
|
281
355
|
OpenStruct.new(
|
282
356
|
name: file.name,
|
@@ -473,13 +547,6 @@ module Dependabot
|
|
473
547
|
end
|
474
548
|
# rubocop:enable Metrics/AbcSize
|
475
549
|
|
476
|
-
def default_branch_for_repo
|
477
|
-
@default_branch_for_repo ||= client_for_provider.
|
478
|
-
fetch_default_branch(repo)
|
479
|
-
rescue *CLIENT_NOT_FOUND_ERRORS
|
480
|
-
raise Dependabot::RepoNotFound, source
|
481
|
-
end
|
482
|
-
|
483
550
|
# Update the @linked_paths hash by exploiting a side-effect of
|
484
551
|
# recursively calling `repo_contents` for each directory up the tree
|
485
552
|
# until a submodule or symlink is found
|
@@ -504,6 +571,10 @@ module Dependabot
|
|
504
571
|
max_by(&:length)
|
505
572
|
end
|
506
573
|
|
574
|
+
# rubocop:disable Metrics/AbcSize
|
575
|
+
# rubocop:disable Metrics/MethodLength
|
576
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
577
|
+
# rubocop:disable Metrics/BlockLength
|
507
578
|
def _clone_repo_contents(target_directory:)
|
508
579
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
509
580
|
path = target_directory || File.join("tmp", source.repo)
|
@@ -512,62 +583,54 @@ module Dependabot
|
|
512
583
|
return path if Dir.exist?(File.join(path, ".git"))
|
513
584
|
|
514
585
|
FileUtils.mkdir_p(path)
|
515
|
-
|
586
|
+
|
587
|
+
clone_options = StringIO.new
|
588
|
+
clone_options << "--no-tags --depth 1"
|
589
|
+
clone_options << if recurse_submodules_when_cloning?
|
590
|
+
" --recurse-submodules --shallow-submodules"
|
591
|
+
else
|
592
|
+
" --no-recurse-submodules"
|
593
|
+
end
|
594
|
+
clone_options << " --branch #{source.branch} --single-branch" if source.branch
|
516
595
|
SharedHelpers.run_shell_command(
|
517
596
|
<<~CMD
|
518
|
-
git clone
|
597
|
+
git clone #{clone_options.string} #{source.url} #{path}
|
519
598
|
CMD
|
520
599
|
)
|
521
|
-
path
|
522
|
-
end
|
523
|
-
end
|
524
600
|
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
end
|
551
|
-
|
552
|
-
def azure_client
|
553
|
-
@azure_client ||=
|
554
|
-
Dependabot::Clients::Azure.
|
555
|
-
for_source(source: source, credentials: credentials)
|
556
|
-
end
|
557
|
-
|
558
|
-
def bitbucket_client
|
559
|
-
# TODO: When self-hosted Bitbucket is supported this should use
|
560
|
-
# `Bitbucket.for_source`
|
561
|
-
@bitbucket_client ||=
|
562
|
-
Dependabot::Clients::BitbucketWithRetries.
|
563
|
-
for_bitbucket_dot_org(credentials: credentials)
|
564
|
-
end
|
601
|
+
if source.commit
|
602
|
+
# This code will only be called for testing. Production will never pass a commit
|
603
|
+
# since Dependabot always wants to use the latest commit on a branch.
|
604
|
+
Dir.chdir(path) do
|
605
|
+
fetch_options = StringIO.new
|
606
|
+
fetch_options << "--depth 1"
|
607
|
+
fetch_options << if recurse_submodules_when_cloning?
|
608
|
+
" --recurse-submodules=on-demand"
|
609
|
+
else
|
610
|
+
" --no-recurse-submodules"
|
611
|
+
end
|
612
|
+
# Need to fetch the commit due to the --depth 1 above.
|
613
|
+
SharedHelpers.run_shell_command("git fetch #{fetch_options.string} origin #{source.commit}")
|
614
|
+
|
615
|
+
reset_options = StringIO.new
|
616
|
+
reset_options << "--hard"
|
617
|
+
reset_options << if recurse_submodules_when_cloning?
|
618
|
+
" --recurse-submodules"
|
619
|
+
else
|
620
|
+
" --no-recurse-submodules"
|
621
|
+
end
|
622
|
+
# Set HEAD to this commit so later calls so git reset HEAD will work.
|
623
|
+
SharedHelpers.run_shell_command("git reset #{reset_options.string} #{source.commit}")
|
624
|
+
end
|
625
|
+
end
|
565
626
|
|
566
|
-
|
567
|
-
|
568
|
-
Dependabot::Clients::CodeCommit.
|
569
|
-
for_source(source: source, credentials: credentials)
|
627
|
+
path
|
628
|
+
end
|
570
629
|
end
|
630
|
+
# rubocop:enable Metrics/AbcSize
|
631
|
+
# rubocop:enable Metrics/MethodLength
|
632
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
633
|
+
# rubocop:enable Metrics/BlockLength
|
571
634
|
end
|
572
635
|
end
|
573
636
|
end
|
@@ -14,34 +14,42 @@ module Dependabot
|
|
14
14
|
raise ArgumentError, "must be an array of Dependency objects"
|
15
15
|
end
|
16
16
|
|
17
|
-
@dependencies = dependencies
|
18
17
|
@case_sensitive = case_sensitive
|
18
|
+
@dependencies = Hash.new { |hsh, key| hsh[key] = DependencySlot.new }
|
19
|
+
dependencies.each { |dep| self << dep }
|
19
20
|
end
|
20
21
|
|
21
|
-
|
22
|
+
def dependencies
|
23
|
+
@dependencies.values.filter_map(&:combined)
|
24
|
+
end
|
22
25
|
|
23
26
|
def <<(dep)
|
24
27
|
raise ArgumentError, "must be a Dependency object" unless dep.is_a?(Dependency)
|
25
28
|
|
26
|
-
|
29
|
+
@dependencies[key_for_dependency(dep)] << dep
|
30
|
+
self
|
31
|
+
end
|
27
32
|
|
28
|
-
|
33
|
+
def +(other)
|
34
|
+
raise ArgumentError, "must be a DependencySet" unless other.is_a?(DependencySet)
|
29
35
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
dependencies << dep
|
36
|
+
other_names = other.dependencies.map(&:name)
|
37
|
+
other_names.each do |name|
|
38
|
+
all_versions = other.all_versions_for_name(name)
|
39
|
+
all_versions.each { |dep| self << dep }
|
35
40
|
end
|
36
41
|
|
37
42
|
self
|
38
43
|
end
|
39
44
|
|
40
|
-
def
|
41
|
-
|
45
|
+
def all_versions_for_name(name)
|
46
|
+
key = key_for_name(name)
|
47
|
+
@dependencies.key?(key) ? @dependencies[key].all_versions : []
|
48
|
+
end
|
42
49
|
|
43
|
-
|
44
|
-
|
50
|
+
def dependency_for_name(name)
|
51
|
+
key = key_for_name(name)
|
52
|
+
@dependencies.key?(key) ? @dependencies[key].combined : nil
|
45
53
|
end
|
46
54
|
|
47
55
|
private
|
@@ -50,41 +58,98 @@ module Dependabot
|
|
50
58
|
@case_sensitive
|
51
59
|
end
|
52
60
|
|
53
|
-
def
|
54
|
-
|
61
|
+
def key_for_name(name)
|
62
|
+
case_sensitive? ? name : name.downcase
|
63
|
+
end
|
55
64
|
|
56
|
-
|
65
|
+
def key_for_dependency(dep)
|
66
|
+
key_for_name(dep.name)
|
57
67
|
end
|
58
68
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
69
|
+
# There can only be one entry per dependency name in a `DependencySet`. Each entry
|
70
|
+
# is assigned a `DependencySlot`.
|
71
|
+
#
|
72
|
+
# In some ecosystems (like `npm_and_yarn`), however, multiple versions of a
|
73
|
+
# dependency may be encountered and added to the set. The `DependencySlot` retains
|
74
|
+
# all added versions and presents a single unified dependency for the entry
|
75
|
+
# that combines the attributes of these versions.
|
76
|
+
#
|
77
|
+
# The combined dependency is accessible via `DependencySet#dependencies` or
|
78
|
+
# `DependencySet#dependency_for_name`. The list of individual versions of the
|
79
|
+
# dependency is accessible via `DependencySet#all_versions_for_name`.
|
80
|
+
class DependencySlot
|
81
|
+
attr_reader :all_versions, :combined
|
82
|
+
|
83
|
+
def initialize
|
84
|
+
@all_versions = []
|
85
|
+
@combined = nil
|
86
|
+
end
|
87
|
+
|
88
|
+
def <<(dep)
|
89
|
+
return self if @all_versions.include?(dep)
|
90
|
+
|
91
|
+
@combined = if @combined
|
92
|
+
combined_dependency(@combined, dep)
|
93
|
+
else
|
94
|
+
Dependency.new(
|
95
|
+
name: dep.name,
|
96
|
+
version: dep.version,
|
97
|
+
requirements: dep.requirements,
|
98
|
+
package_manager: dep.package_manager,
|
99
|
+
subdependency_metadata: dep.subdependency_metadata
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
index_of_same_version =
|
104
|
+
@all_versions.find_index { |other| other.version == dep.version }
|
105
|
+
|
106
|
+
if index_of_same_version.nil?
|
107
|
+
@all_versions << dep
|
71
108
|
else
|
72
|
-
|
109
|
+
same_version = @all_versions[index_of_same_version]
|
110
|
+
@all_versions[index_of_same_version] = combined_dependency(same_version, dep)
|
73
111
|
end
|
74
112
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
# Produces a new dependency by merging the attributes of `old_dep` with those of
|
119
|
+
# `new_dep`. Requirements and subdependency metadata will be combined and deduped.
|
120
|
+
# The version of the combined dependency is determined by the logic below.
|
121
|
+
def combined_dependency(old_dep, new_dep)
|
122
|
+
version = if old_dep.top_level? # Prefer a direct dependency over a transitive one
|
123
|
+
old_dep.version || new_dep.version
|
124
|
+
elsif !version_class.correct?(new_dep.version)
|
125
|
+
old_dep.version
|
126
|
+
elsif !version_class.correct?(old_dep.version)
|
127
|
+
new_dep.version
|
128
|
+
elsif version_class.new(new_dep.version) > version_class.new(old_dep.version)
|
129
|
+
old_dep.version
|
130
|
+
else
|
131
|
+
new_dep.version
|
132
|
+
end
|
133
|
+
requirements = (old_dep.requirements + new_dep.requirements).uniq
|
134
|
+
subdependency_metadata = (
|
135
|
+
(old_dep.subdependency_metadata || []) +
|
136
|
+
(new_dep.subdependency_metadata || [])
|
137
|
+
).uniq
|
138
|
+
|
139
|
+
Dependency.new(
|
140
|
+
name: old_dep.name,
|
141
|
+
version: version,
|
142
|
+
requirements: requirements,
|
143
|
+
package_manager: old_dep.package_manager,
|
144
|
+
subdependency_metadata: subdependency_metadata
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
def version_class
|
149
|
+
@version_class ||= Utils.version_class_for_package_manager(@combined.package_manager)
|
150
|
+
end
|
87
151
|
end
|
152
|
+
private_constant :DependencySlot
|
88
153
|
end
|
89
154
|
end
|
90
155
|
end
|
@@ -19,7 +19,7 @@ module Dependabot
|
|
19
19
|
|
|
20
20
|
[0-9]+\.[0-9]+(?:\.[a-z0-9\-]+)*
|
21
21
|
)$
|
22
|
-
/ix
|
22
|
+
/ix
|
23
23
|
|
24
24
|
def initialize(dependency:, credentials:,
|
25
25
|
ignored_versions: [], raise_on_ignored: false,
|
@@ -49,8 +49,14 @@ module Dependabot
|
|
49
49
|
return true if branch
|
50
50
|
return true if dependency.version&.start_with?(ref)
|
51
51
|
|
52
|
-
#
|
53
|
-
|
52
|
+
# If the specified `ref` is actually a tag, we're pinned
|
53
|
+
return true if local_upload_pack.match?(%r{ refs/tags/#{ref}$})
|
54
|
+
|
55
|
+
# If the specified `ref` is actually a branch, we're NOT pinned
|
56
|
+
return false if local_upload_pack.match?(%r{ refs/heads/#{ref}$})
|
57
|
+
|
58
|
+
# Otherwise, assume we're pinned
|
59
|
+
true
|
54
60
|
end
|
55
61
|
|
56
62
|
def pinned_ref_looks_like_version?
|
@@ -61,6 +67,10 @@ module Dependabot
|
|
61
67
|
|
62
68
|
def pinned_ref_looks_like_commit_sha?
|
63
69
|
ref = dependency_source_details.fetch(:ref)
|
70
|
+
ref_looks_like_commit_sha?(ref)
|
71
|
+
end
|
72
|
+
|
73
|
+
def ref_looks_like_commit_sha?(ref)
|
64
74
|
return false unless ref&.match?(/^[0-9a-f]{6,40}$/)
|
65
75
|
|
66
76
|
return false unless pinned?
|
@@ -365,17 +375,19 @@ module Dependabot
|
|
365
375
|
def listing_tags
|
366
376
|
return [] unless listing_source_url
|
367
377
|
|
368
|
-
|
378
|
+
@listing_tags ||= begin
|
379
|
+
tags = listing_repo_git_metadata_fetcher.tags
|
369
380
|
|
370
|
-
|
371
|
-
|
372
|
-
|
381
|
+
if dependency_source_details&.fetch(:ref, nil)&.start_with?("tags/")
|
382
|
+
tags = tags.map do |tag|
|
383
|
+
tag.dup.tap { |t| t.name = "tags/#{tag.name}" }
|
384
|
+
end
|
373
385
|
end
|
374
|
-
end
|
375
386
|
|
376
|
-
|
377
|
-
|
378
|
-
|
387
|
+
tags
|
388
|
+
rescue GitDependenciesNotReachable
|
389
|
+
[]
|
390
|
+
end
|
379
391
|
end
|
380
392
|
|
381
393
|
def listing_upload_pack
|