dependabot-common 0.381.0 → 0.383.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/dependabot/config/ignore_condition.rb +1 -1
- data/lib/dependabot/credential.rb +14 -1
- data/lib/dependabot/dependency.rb +12 -10
- data/lib/dependabot/dependency_file.rb +1 -1
- data/lib/dependabot/dependency_group.rb +62 -7
- data/lib/dependabot/dependency_requirement.rb +94 -0
- data/lib/dependabot/errors.rb +74 -3
- data/lib/dependabot/file_parsers/base/dependency_set.rb +1 -1
- data/lib/dependabot/file_parsers/base.rb +5 -0
- data/lib/dependabot/file_updaters/artifact_updater.rb +38 -17
- data/lib/dependabot/file_updaters/vendor_updater.rb +40 -16
- data/lib/dependabot/git_commit_checker.rb +12 -11
- data/lib/dependabot/git_cooldown_date_resolver.rb +114 -0
- data/lib/dependabot/git_tag_details.rb +78 -0
- data/lib/dependabot/metadata_finders/base/commits_finder.rb +1 -1
- data/lib/dependabot/notices.rb +2 -2
- data/lib/dependabot/pull_request_creator/branch_namer/base.rb +5 -3
- data/lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb +16 -16
- data/lib/dependabot/pull_request_creator.rb +1 -1
- data/lib/dependabot/pull_request_updater.rb +4 -4
- data/lib/dependabot/requirements_updater/base.rb +3 -1
- data/lib/dependabot/update_checkers/base.rb +15 -1
- data/lib/dependabot.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1fb1a4d6243812d664a20067d226c2eec111080d39e7337217744a58a9d8f0b6
|
|
4
|
+
data.tar.gz: 609737fc8b6040222a744d58ea03f8587fec15136cb835d319c31b798f7ebf32
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5e3042cb52f78e0396e75a3c6707a6706a1e2f4f1e12fc16310079eae0ae08336f688a75a92795cc6a8ba50ba62b9d0b9168b3ca4d5780439c7bccf574ab4179
|
|
7
|
+
data.tar.gz: a15d7f181d2d4afd8b5bf3e72f0450827d435f8e61e98f7863bfa0c254e8e2b983bb831901f1c95d27da8abfe791bf673d6c6e7fcc29b8d5e61c0e3c631ea9e6
|
|
@@ -52,7 +52,7 @@ module Dependabot
|
|
|
52
52
|
update_types.map(&:downcase).filter_map(&:strip)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
sig { params(dependency: Dependency).returns(T::Array[
|
|
55
|
+
sig { params(dependency: Dependency).returns(T::Array[String]) }
|
|
56
56
|
def versions_by_type(dependency)
|
|
57
57
|
version = correct_version_for(dependency)
|
|
58
58
|
return [] unless version
|
|
@@ -11,10 +11,20 @@ module Dependabot
|
|
|
11
11
|
|
|
12
12
|
def_delegators :@credential, :fetch, :keys, :[]=, :delete, :slice, :values, :entries
|
|
13
13
|
|
|
14
|
-
sig { params(credential: T::Hash[String, T.any(T::Boolean, String)]).void }
|
|
14
|
+
sig { params(credential: T::Hash[String, T.any(T::Boolean, String, T::Array[String])]).void }
|
|
15
15
|
def initialize(credential)
|
|
16
16
|
@replaces_base = T.let(credential["replaces-base"] == true, T::Boolean)
|
|
17
17
|
credential.delete("replaces-base")
|
|
18
|
+
|
|
19
|
+
raw_scope = credential.delete("scope")
|
|
20
|
+
@scope = T.let(
|
|
21
|
+
case raw_scope
|
|
22
|
+
when String then [raw_scope]
|
|
23
|
+
when Array then raw_scope
|
|
24
|
+
end,
|
|
25
|
+
T.nilable(T::Array[String])
|
|
26
|
+
)
|
|
27
|
+
|
|
18
28
|
@credential = T.let(T.unsafe(credential), T::Hash[String, String])
|
|
19
29
|
end
|
|
20
30
|
|
|
@@ -23,6 +33,9 @@ module Dependabot
|
|
|
23
33
|
@replaces_base
|
|
24
34
|
end
|
|
25
35
|
|
|
36
|
+
sig { returns(T.nilable(T::Array[String])) }
|
|
37
|
+
attr_reader :scope
|
|
38
|
+
|
|
26
39
|
sig { params(key: String).returns(T.nilable(String)) }
|
|
27
40
|
def [](key)
|
|
28
41
|
@credential[key]
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "sorbet-runtime"
|
|
5
|
+
require "dependabot/dependency_requirement"
|
|
5
6
|
require "dependabot/version"
|
|
6
7
|
|
|
7
8
|
module Dependabot
|
|
@@ -90,7 +91,7 @@ module Dependabot
|
|
|
90
91
|
sig { returns(T.nilable(String)) }
|
|
91
92
|
attr_reader :version
|
|
92
93
|
|
|
93
|
-
sig { returns(T::Array[
|
|
94
|
+
sig { returns(T::Array[Dependabot::DependencyRequirement]) }
|
|
94
95
|
attr_reader :requirements
|
|
95
96
|
|
|
96
97
|
sig { returns(String) }
|
|
@@ -99,7 +100,7 @@ module Dependabot
|
|
|
99
100
|
sig { returns(T.nilable(String)) }
|
|
100
101
|
attr_reader :previous_version
|
|
101
102
|
|
|
102
|
-
sig { returns(T.nilable(T::Array[
|
|
103
|
+
sig { returns(T.nilable(T::Array[Dependabot::DependencyRequirement])) }
|
|
103
104
|
attr_reader :previous_requirements
|
|
104
105
|
|
|
105
106
|
sig { returns(T.nilable(String)) }
|
|
@@ -124,7 +125,6 @@ module Dependabot
|
|
|
124
125
|
sig { returns(T.nilable(Time)) }
|
|
125
126
|
attr_accessor :attribution_timestamp
|
|
126
127
|
|
|
127
|
-
# rubocop:disable Metrics/AbcSize
|
|
128
128
|
# rubocop:disable Metrics/PerceivedComplexity
|
|
129
129
|
sig do
|
|
130
130
|
params(
|
|
@@ -162,12 +162,15 @@ module Dependabot
|
|
|
162
162
|
T.nilable(String)
|
|
163
163
|
)
|
|
164
164
|
@version = nil if @version == ""
|
|
165
|
-
@requirements = T.let(
|
|
165
|
+
@requirements = T.let(
|
|
166
|
+
requirements.map { |req| DependencyRequirement.create(req) },
|
|
167
|
+
T::Array[Dependabot::DependencyRequirement]
|
|
168
|
+
)
|
|
166
169
|
@previous_version = previous_version
|
|
167
170
|
@previous_version = nil if @previous_version == ""
|
|
168
171
|
@previous_requirements = T.let(
|
|
169
|
-
previous_requirements&.map { |req|
|
|
170
|
-
T.nilable(T::Array[
|
|
172
|
+
previous_requirements&.map { |req| DependencyRequirement.create(req) },
|
|
173
|
+
T.nilable(T::Array[Dependabot::DependencyRequirement])
|
|
171
174
|
)
|
|
172
175
|
@package_manager = package_manager
|
|
173
176
|
@directory = directory
|
|
@@ -181,7 +184,6 @@ module Dependabot
|
|
|
181
184
|
@metadata = T.let(symbolize_keys(metadata || {}), T::Hash[Symbol, T.untyped])
|
|
182
185
|
check_values
|
|
183
186
|
end
|
|
184
|
-
# rubocop:enable Metrics/AbcSize
|
|
185
187
|
# rubocop:enable Metrics/PerceivedComplexity
|
|
186
188
|
|
|
187
189
|
sig { returns(T::Boolean) }
|
|
@@ -272,7 +274,7 @@ module Dependabot
|
|
|
272
274
|
end
|
|
273
275
|
end
|
|
274
276
|
|
|
275
|
-
sig { params(requirements: T::Array[
|
|
277
|
+
sig { params(requirements: T::Array[Dependabot::DependencyRequirement]).returns(T.nilable(String)) }
|
|
276
278
|
def docker_digest_from_reqs(requirements)
|
|
277
279
|
requirements
|
|
278
280
|
.filter_map { |r| r.dig(:source, "digest") || r.dig(:source, :digest) }
|
|
@@ -340,9 +342,9 @@ module Dependabot
|
|
|
340
342
|
self == other
|
|
341
343
|
end
|
|
342
344
|
|
|
343
|
-
sig { returns(T::Array[
|
|
345
|
+
sig { returns(T::Array[Dependabot::DependencyRequirement]) }
|
|
344
346
|
def specific_requirements
|
|
345
|
-
requirements.select { |r| requirement_class.new(r
|
|
347
|
+
requirements.select { |r| requirement_class.new(r.requirement).specific? }
|
|
346
348
|
end
|
|
347
349
|
|
|
348
350
|
sig { returns(T.class_of(Dependabot::Requirement)) }
|
|
@@ -123,7 +123,7 @@ module Dependabot
|
|
|
123
123
|
raise "Only symlinked files must specify a target!" if symlink_target
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
-
sig { returns(T::Hash[String, T.
|
|
126
|
+
sig { returns(T::Hash[String, T.nilable(T.any(String, T::Boolean))]) }
|
|
127
127
|
def to_h
|
|
128
128
|
details = {
|
|
129
129
|
"name" => name,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "dependabot/experiments"
|
|
@@ -28,10 +28,23 @@ module Dependabot
|
|
|
28
28
|
sig { returns(T.nilable(String)) }
|
|
29
29
|
attr_reader :group_by
|
|
30
30
|
|
|
31
|
+
# The following readers are parsed once from the raw rules hash so callers
|
|
32
|
+
# get typed access instead of repeatedly casting rules["patterns"] and
|
|
33
|
+
# friends at every use site. A nil value means the rule is absent (which the
|
|
34
|
+
# matching logic treats differently from an empty list).
|
|
35
|
+
sig { returns(T.nilable(T::Array[String])) }
|
|
36
|
+
attr_reader :patterns
|
|
37
|
+
|
|
38
|
+
sig { returns(T.nilable(T::Array[String])) }
|
|
39
|
+
attr_reader :exclude_patterns
|
|
40
|
+
|
|
41
|
+
sig { returns(T.nilable(T::Array[String])) }
|
|
42
|
+
attr_reader :update_types
|
|
43
|
+
|
|
31
44
|
sig do
|
|
32
45
|
params(
|
|
33
46
|
name: String,
|
|
34
|
-
rules: T::Hash[String, T.
|
|
47
|
+
rules: T::Hash[String, T.any(String, T::Array[String])],
|
|
35
48
|
applies_to: T.nilable(String)
|
|
36
49
|
)
|
|
37
50
|
.void
|
|
@@ -41,7 +54,10 @@ module Dependabot
|
|
|
41
54
|
# For backwards compatibility, if no applies_to is provided, default to "version-updates"
|
|
42
55
|
@applies_to = T.let(applies_to || "version-updates", String)
|
|
43
56
|
@rules = rules
|
|
44
|
-
@group_by = T.let(rules
|
|
57
|
+
@group_by = T.let(string_rule(rules, "group-by"), T.nilable(String))
|
|
58
|
+
@patterns = T.let(string_array_rule(rules, "patterns"), T.nilable(T::Array[String]))
|
|
59
|
+
@exclude_patterns = T.let(string_array_rule(rules, "exclude-patterns"), T.nilable(T::Array[String]))
|
|
60
|
+
@update_types = T.let(string_array_rule(rules, "update-types"), T.nilable(T::Array[String]))
|
|
45
61
|
@dependencies = T.let([], T::Array[Dependabot::Dependency])
|
|
46
62
|
end
|
|
47
63
|
|
|
@@ -75,16 +91,18 @@ module Dependabot
|
|
|
75
91
|
|
|
76
92
|
sig { params(dependency_name: String).returns(T::Boolean) }
|
|
77
93
|
def matches_pattern?(dependency_name)
|
|
78
|
-
|
|
94
|
+
patterns = self.patterns
|
|
95
|
+
return true if patterns.nil? # If no patterns are defined, we pass this check by default
|
|
79
96
|
|
|
80
|
-
|
|
97
|
+
patterns.any? { |rule| WildcardMatcher.match?(rule, dependency_name) }
|
|
81
98
|
end
|
|
82
99
|
|
|
83
100
|
sig { params(dependency_name: String).returns(T::Boolean) }
|
|
84
101
|
def matches_excluded_pattern?(dependency_name)
|
|
85
|
-
|
|
102
|
+
exclude_patterns = self.exclude_patterns
|
|
103
|
+
return false if exclude_patterns.nil? # If there are no exclusions, fail by default
|
|
86
104
|
|
|
87
|
-
|
|
105
|
+
exclude_patterns.any? { |rule| WildcardMatcher.match?(rule, dependency_name) }
|
|
88
106
|
end
|
|
89
107
|
|
|
90
108
|
sig { params(dependency: Dependabot::Dependency).returns(T::Boolean) }
|
|
@@ -102,5 +120,42 @@ module Dependabot
|
|
|
102
120
|
def experimental_rules_enabled?
|
|
103
121
|
Dependabot::Experiments.enabled?(:grouped_updates_experimental_rules)
|
|
104
122
|
end
|
|
123
|
+
|
|
124
|
+
# Reads a rule whose value is expected to be a single string (e.g.
|
|
125
|
+
# "group-by"), returning nil when the key is absent or the value is not a
|
|
126
|
+
# string.
|
|
127
|
+
sig do
|
|
128
|
+
params(
|
|
129
|
+
rules: T::Hash[String, T.any(String, T::Array[String])],
|
|
130
|
+
key: String
|
|
131
|
+
)
|
|
132
|
+
.returns(T.nilable(String))
|
|
133
|
+
end
|
|
134
|
+
def string_rule(rules, key)
|
|
135
|
+
value = rules[key]
|
|
136
|
+
value.is_a?(String) ? value : nil
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Reads a rule whose value is expected to be a list of strings (e.g.
|
|
140
|
+
# "patterns", "exclude-patterns", "update-types"). Returns nil when the key
|
|
141
|
+
# is absent so callers can distinguish "rule not set" from "empty list", and
|
|
142
|
+
# coerces a lone string into a single-element list.
|
|
143
|
+
sig do
|
|
144
|
+
params(
|
|
145
|
+
rules: T::Hash[String, T.any(String, T::Array[String])],
|
|
146
|
+
key: String
|
|
147
|
+
)
|
|
148
|
+
.returns(T.nilable(T::Array[String]))
|
|
149
|
+
end
|
|
150
|
+
def string_array_rule(rules, key)
|
|
151
|
+
return nil unless rules.key?(key)
|
|
152
|
+
|
|
153
|
+
value = rules[key]
|
|
154
|
+
case value
|
|
155
|
+
when Array then value.grep(String)
|
|
156
|
+
when String then [value]
|
|
157
|
+
else []
|
|
158
|
+
end
|
|
159
|
+
end
|
|
105
160
|
end
|
|
106
161
|
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "sorbet-runtime"
|
|
5
|
+
|
|
6
|
+
module Dependabot
|
|
7
|
+
# A single requirement entry within Dependency#requirements, e.g.:
|
|
8
|
+
#
|
|
9
|
+
# {
|
|
10
|
+
# requirement: ">= 1.0, < 2.0",
|
|
11
|
+
# file: "Gemfile",
|
|
12
|
+
# groups: [:default],
|
|
13
|
+
# source: { type: "rubygems", url: "https://rubygems.org" },
|
|
14
|
+
# metadata: { property_name: "rails.version" } # optional
|
|
15
|
+
# }
|
|
16
|
+
#
|
|
17
|
+
# Subclasses Hash so it is a drop-in replacement at call sites (and in
|
|
18
|
+
# type annotations) that treat requirement entries as
|
|
19
|
+
# T::Hash[Symbol, T.untyped], while exposing typed readers for the
|
|
20
|
+
# well-known keys. New code should prefer the typed readers; hash-style
|
|
21
|
+
# access remains supported while call sites are migrated gradually.
|
|
22
|
+
#
|
|
23
|
+
# Wire compatibility: instances serialise to JSON exactly like the plain
|
|
24
|
+
# hash they were created from, and compare equal (==/eql?/#hash) to plain
|
|
25
|
+
# hashes with the same content, so existing comparisons, Array/Set
|
|
26
|
+
# operations, and API payloads are unaffected.
|
|
27
|
+
#
|
|
28
|
+
# Note on Hash methods: in Ruby 3+, #merge, #dup and #compact preserve
|
|
29
|
+
# this class, while #select, #reject, #except, #transform_values and
|
|
30
|
+
# #to_h return plain Hash instances. Dependency#initialize re-wraps
|
|
31
|
+
# whatever it is given, so both styles remain safe.
|
|
32
|
+
class DependencyRequirement < Hash
|
|
33
|
+
extend T::Sig
|
|
34
|
+
extend T::Generic
|
|
35
|
+
|
|
36
|
+
# The values of a requirement entry are heterogeneous and
|
|
37
|
+
# ecosystem-specific, so this bridge class is necessarily untyped at
|
|
38
|
+
# the Hash level; the typed readers below are the migration path.
|
|
39
|
+
# rubocop:disable Sorbet/ForbidTUntyped
|
|
40
|
+
K = type_member { { fixed: Symbol } }
|
|
41
|
+
V = type_member { { fixed: T.untyped } }
|
|
42
|
+
Elem = type_member { { fixed: [Symbol, T.untyped] } }
|
|
43
|
+
|
|
44
|
+
# Builds a DependencyRequirement from a requirement hash, symbolising
|
|
45
|
+
# top-level keys. Accepts both plain hashes and existing
|
|
46
|
+
# DependencyRequirement instances and always returns a new instance.
|
|
47
|
+
sig { params(hash: T::Hash[T.any(Symbol, String), T.untyped]).returns(DependencyRequirement) }
|
|
48
|
+
def self.create(hash)
|
|
49
|
+
requirement = new
|
|
50
|
+
requirement.replace(hash.keys.to_h { |k| [k.to_sym, hash[k]] })
|
|
51
|
+
requirement
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# The version constraint string, e.g. ">= 1.0, < 2.0". Nil when the
|
|
55
|
+
# dependency is pinned by a lockfile rather than a manifest constraint.
|
|
56
|
+
sig { returns(T.nilable(String)) }
|
|
57
|
+
def requirement
|
|
58
|
+
self[:requirement]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# The manifest file this requirement was declared in, e.g. "Gemfile".
|
|
62
|
+
sig { returns(T.nilable(String)) }
|
|
63
|
+
def file
|
|
64
|
+
self[:file]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# The dependency groups this requirement belongs to, e.g. ["dev"] or
|
|
68
|
+
# [:default]. Element types vary by ecosystem (strings or symbols).
|
|
69
|
+
# Nilable because some requirement entries are constructed with
|
|
70
|
+
# groups: nil, and the reader must reflect that to stay a drop-in for
|
|
71
|
+
# the underlying hash access under sorbet-runtime.
|
|
72
|
+
sig { returns(T.nilable(T::Array[T.untyped])) }
|
|
73
|
+
def groups
|
|
74
|
+
self[:groups]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# The source details for the dependency, e.g.
|
|
78
|
+
# { type: "git", url: "https://github.com/..." }. Keys may be symbols
|
|
79
|
+
# or strings depending on whether the requirement was built by a file
|
|
80
|
+
# parser or deserialised from a job definition.
|
|
81
|
+
sig { returns(T.nilable(T::Hash[T.any(Symbol, String), T.untyped])) }
|
|
82
|
+
def source
|
|
83
|
+
self[:source]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Optional ecosystem-specific metadata about the requirement, e.g.
|
|
87
|
+
# { property_name: "rails.version" }.
|
|
88
|
+
sig { returns(T.nilable(T::Hash[T.any(Symbol, String), T.untyped])) }
|
|
89
|
+
def metadata
|
|
90
|
+
self[:metadata]
|
|
91
|
+
end
|
|
92
|
+
# rubocop:enable Sorbet/ForbidTUntyped
|
|
93
|
+
end
|
|
94
|
+
end
|
data/lib/dependabot/errors.rb
CHANGED
|
@@ -97,6 +97,11 @@ module Dependabot
|
|
|
97
97
|
"error-type": "path_dependencies_not_reachable",
|
|
98
98
|
"error-detail": { dependencies: error.dependencies }
|
|
99
99
|
}
|
|
100
|
+
when Dependabot::PrivateRegistryConfigNotFound
|
|
101
|
+
{
|
|
102
|
+
"error-type": "private_registry_config_not_found",
|
|
103
|
+
"error-detail": { source: error.source }
|
|
104
|
+
}
|
|
100
105
|
when Dependabot::PrivateSourceAuthenticationFailure
|
|
101
106
|
{
|
|
102
107
|
"error-type": "private_source_authentication_failure",
|
|
@@ -238,6 +243,16 @@ module Dependabot
|
|
|
238
243
|
"error-type": "dependency_file_not_resolvable",
|
|
239
244
|
"error-detail": { message: error.message }
|
|
240
245
|
}
|
|
246
|
+
when Dependabot::BlockedDependencyVersion
|
|
247
|
+
{
|
|
248
|
+
"error-type": "blocked_dependency_version",
|
|
249
|
+
"error-detail": {
|
|
250
|
+
"dependency-name": error.dependency_name,
|
|
251
|
+
"blocked-version": error.blocked_version,
|
|
252
|
+
"version-requirement": error.version_requirement,
|
|
253
|
+
reason: error.reason
|
|
254
|
+
}.compact
|
|
255
|
+
}
|
|
241
256
|
when Dependabot::DependencyFileNotEvaluatable
|
|
242
257
|
{
|
|
243
258
|
"error-type": "dependency_file_not_evaluatable",
|
|
@@ -687,6 +702,22 @@ module Dependabot
|
|
|
687
702
|
# Source level errors #
|
|
688
703
|
#######################
|
|
689
704
|
|
|
705
|
+
class PrivateRegistryConfigNotFound < DependabotError
|
|
706
|
+
extend T::Sig
|
|
707
|
+
|
|
708
|
+
sig { returns(String) }
|
|
709
|
+
attr_reader :source
|
|
710
|
+
|
|
711
|
+
sig { params(source: String).void }
|
|
712
|
+
def initialize(source)
|
|
713
|
+
@source = T.let(sanitize_source(source), String)
|
|
714
|
+
msg = "Private npm registries require either a .npmrc file in your repository, " \
|
|
715
|
+
"or explicit `scope`/`replaces-base` configuration in dependabot.yml. " \
|
|
716
|
+
"Registry: #{@source}"
|
|
717
|
+
super(msg)
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
|
|
690
721
|
class PrivateSourceAuthenticationFailure < DependabotError
|
|
691
722
|
extend T::Sig
|
|
692
723
|
|
|
@@ -709,10 +740,10 @@ module Dependabot
|
|
|
709
740
|
sig { returns(String) }
|
|
710
741
|
attr_reader :source
|
|
711
742
|
|
|
712
|
-
sig { params(source: T.nilable(String)).void }
|
|
713
|
-
def initialize(source)
|
|
743
|
+
sig { params(source: T.nilable(String), error_message: T.nilable(String)).void }
|
|
744
|
+
def initialize(source, error_message = nil)
|
|
714
745
|
@source = T.let(sanitize_source(T.must(source)), String)
|
|
715
|
-
msg = "Bad response error while accessing source: #{@source}"
|
|
746
|
+
msg = error_message ? sanitize_source(error_message) : "Bad response error while accessing source: #{@source}"
|
|
716
747
|
super(msg)
|
|
717
748
|
end
|
|
718
749
|
end
|
|
@@ -901,6 +932,46 @@ module Dependabot
|
|
|
901
932
|
# Raised by UpdateChecker if all candidate updates are ignored
|
|
902
933
|
class AllVersionsIgnored < DependabotError; end
|
|
903
934
|
|
|
935
|
+
# Raised when regenerating a lockfile would introduce or change a transitive
|
|
936
|
+
# (indirect) dependency to a version that matches a configured blocked version.
|
|
937
|
+
# The offending change is rejected so the blocked version is never shipped,
|
|
938
|
+
# while other dependencies are still allowed to update.
|
|
939
|
+
class BlockedDependencyVersion < DependabotError
|
|
940
|
+
extend T::Sig
|
|
941
|
+
|
|
942
|
+
sig { returns(String) }
|
|
943
|
+
attr_reader :dependency_name
|
|
944
|
+
|
|
945
|
+
sig { returns(String) }
|
|
946
|
+
attr_reader :blocked_version
|
|
947
|
+
|
|
948
|
+
sig { returns(String) }
|
|
949
|
+
attr_reader :version_requirement
|
|
950
|
+
|
|
951
|
+
sig { returns(T.nilable(String)) }
|
|
952
|
+
attr_reader :reason
|
|
953
|
+
|
|
954
|
+
sig do
|
|
955
|
+
params(
|
|
956
|
+
dependency_name: String,
|
|
957
|
+
blocked_version: String,
|
|
958
|
+
version_requirement: String,
|
|
959
|
+
reason: T.nilable(String)
|
|
960
|
+
).void
|
|
961
|
+
end
|
|
962
|
+
def initialize(dependency_name:, blocked_version:, version_requirement:, reason: nil)
|
|
963
|
+
@dependency_name = dependency_name
|
|
964
|
+
@blocked_version = blocked_version
|
|
965
|
+
@version_requirement = version_requirement
|
|
966
|
+
@reason = reason
|
|
967
|
+
|
|
968
|
+
msg = "Update blocked: transitive dependency #{dependency_name} #{blocked_version} " \
|
|
969
|
+
"matches blocked version requirement '#{version_requirement}'"
|
|
970
|
+
msg += " (reason: #{reason})" if reason && !reason.empty?
|
|
971
|
+
super(msg)
|
|
972
|
+
end
|
|
973
|
+
end
|
|
974
|
+
|
|
904
975
|
# Raised by FileParser if processing may execute external code in the update context
|
|
905
976
|
class UnexpectedExternalCode < DependabotError; end
|
|
906
977
|
|
|
@@ -33,7 +33,7 @@ module Dependabot
|
|
|
33
33
|
@dependencies.values.filter_map(&:combined)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
sig { params(dep: Dependabot::Dependency).returns(T.
|
|
36
|
+
sig { params(dep: Dependabot::Dependency).returns(T.self_type) }
|
|
37
37
|
def <<(dep)
|
|
38
38
|
T.must(@dependencies[key_for_dependency(dep)]) << dep
|
|
39
39
|
self
|
|
@@ -28,6 +28,11 @@ module Dependabot
|
|
|
28
28
|
sig { returns(T::Hash[Symbol, T.untyped]) }
|
|
29
29
|
attr_reader :options
|
|
30
30
|
|
|
31
|
+
sig { returns(T::Boolean) }
|
|
32
|
+
def reject_external_code?
|
|
33
|
+
@reject_external_code
|
|
34
|
+
end
|
|
35
|
+
|
|
31
36
|
sig do
|
|
32
37
|
params(
|
|
33
38
|
dependency_files: T::Array[Dependabot::DependencyFile],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "sorbet-runtime"
|
|
@@ -120,25 +120,46 @@ module Dependabot
|
|
|
120
120
|
|
|
121
121
|
sig do
|
|
122
122
|
overridable
|
|
123
|
-
.params(
|
|
123
|
+
.params(
|
|
124
|
+
name: String,
|
|
125
|
+
content: T.nilable(String),
|
|
126
|
+
directory: String,
|
|
127
|
+
type: String,
|
|
128
|
+
support_file: T::Boolean,
|
|
129
|
+
vendored_file: T::Boolean,
|
|
130
|
+
symlink_target: T.nilable(String),
|
|
131
|
+
content_encoding: String,
|
|
132
|
+
deleted: T::Boolean,
|
|
133
|
+
operation: String,
|
|
134
|
+
mode: T.nilable(String)
|
|
135
|
+
)
|
|
124
136
|
.returns(Dependabot::DependencyFile)
|
|
125
137
|
end
|
|
126
|
-
def create_dependency_file(
|
|
138
|
+
def create_dependency_file(
|
|
139
|
+
name:,
|
|
140
|
+
content: nil,
|
|
141
|
+
directory: "/",
|
|
142
|
+
type: "file",
|
|
143
|
+
support_file: false,
|
|
144
|
+
vendored_file: false,
|
|
145
|
+
symlink_target: nil,
|
|
146
|
+
content_encoding: Dependabot::DependencyFile::ContentEncoding::UTF_8,
|
|
147
|
+
deleted: false,
|
|
148
|
+
operation: Dependabot::DependencyFile::Operation::UPDATE,
|
|
149
|
+
mode: nil
|
|
150
|
+
)
|
|
127
151
|
Dependabot::DependencyFile.new(
|
|
128
|
-
name:
|
|
129
|
-
content:
|
|
130
|
-
directory:
|
|
131
|
-
type:
|
|
132
|
-
support_file:
|
|
133
|
-
vendored_file:
|
|
134
|
-
symlink_target:
|
|
135
|
-
content_encoding:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
deleted: parameters.fetch(:deleted, false),
|
|
140
|
-
operation: parameters.fetch(:operation, Dependabot::DependencyFile::Operation::UPDATE),
|
|
141
|
-
mode: parameters[:mode]
|
|
152
|
+
name: name,
|
|
153
|
+
content: content,
|
|
154
|
+
directory: directory,
|
|
155
|
+
type: type,
|
|
156
|
+
support_file: support_file,
|
|
157
|
+
vendored_file: vendored_file,
|
|
158
|
+
symlink_target: symlink_target,
|
|
159
|
+
content_encoding: content_encoding,
|
|
160
|
+
deleted: deleted,
|
|
161
|
+
operation: operation,
|
|
162
|
+
mode: mode
|
|
142
163
|
)
|
|
143
164
|
end
|
|
144
165
|
end
|
|
@@ -31,27 +31,51 @@ module Dependabot
|
|
|
31
31
|
|
|
32
32
|
private
|
|
33
33
|
|
|
34
|
+
# VendorUpdater always flags files as vendored, so it accepts but ignores
|
|
35
|
+
# the vendored_file argument. The parameter must stay to keep the override
|
|
36
|
+
# signature compatible with ArtifactUpdater#create_dependency_file.
|
|
34
37
|
sig do
|
|
35
38
|
override
|
|
36
|
-
.params(
|
|
39
|
+
.params(
|
|
40
|
+
name: String,
|
|
41
|
+
content: T.nilable(String),
|
|
42
|
+
directory: String,
|
|
43
|
+
type: String,
|
|
44
|
+
support_file: T::Boolean,
|
|
45
|
+
vendored_file: T::Boolean,
|
|
46
|
+
symlink_target: T.nilable(String),
|
|
47
|
+
content_encoding: String,
|
|
48
|
+
deleted: T::Boolean,
|
|
49
|
+
operation: String,
|
|
50
|
+
mode: T.nilable(String)
|
|
51
|
+
)
|
|
37
52
|
.returns(Dependabot::DependencyFile)
|
|
38
53
|
end
|
|
39
|
-
def create_dependency_file(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
def create_dependency_file(
|
|
55
|
+
name:,
|
|
56
|
+
content: nil,
|
|
57
|
+
directory: "/",
|
|
58
|
+
type: "file",
|
|
59
|
+
support_file: false,
|
|
60
|
+
vendored_file: false, # rubocop:disable Lint/UnusedMethodArgument
|
|
61
|
+
symlink_target: nil,
|
|
62
|
+
content_encoding: Dependabot::DependencyFile::ContentEncoding::UTF_8,
|
|
63
|
+
deleted: false,
|
|
64
|
+
operation: Dependabot::DependencyFile::Operation::UPDATE,
|
|
65
|
+
mode: nil
|
|
66
|
+
)
|
|
67
|
+
super(
|
|
68
|
+
name: name,
|
|
69
|
+
content: content,
|
|
70
|
+
directory: directory,
|
|
71
|
+
type: type,
|
|
72
|
+
support_file: support_file,
|
|
46
73
|
vendored_file: true,
|
|
47
|
-
symlink_target:
|
|
48
|
-
content_encoding:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
deleted: parameters.fetch(:deleted, false),
|
|
53
|
-
operation: parameters.fetch(:operation, Dependabot::DependencyFile::Operation::UPDATE),
|
|
54
|
-
mode: parameters[:mode]
|
|
74
|
+
symlink_target: symlink_target,
|
|
75
|
+
content_encoding: content_encoding,
|
|
76
|
+
deleted: deleted,
|
|
77
|
+
operation: operation,
|
|
78
|
+
mode: mode
|
|
55
79
|
)
|
|
56
80
|
end
|
|
57
81
|
end
|
|
@@ -14,6 +14,7 @@ require "dependabot/source"
|
|
|
14
14
|
require "dependabot/dependency"
|
|
15
15
|
require "dependabot/credential"
|
|
16
16
|
require "dependabot/git_metadata_fetcher"
|
|
17
|
+
require "dependabot/git_tag_details"
|
|
17
18
|
module Dependabot
|
|
18
19
|
# rubocop:disable Metrics/ClassLength
|
|
19
20
|
class GitCommitChecker
|
|
@@ -159,31 +160,31 @@ module Dependabot
|
|
|
159
160
|
local_repo_git_metadata_fetcher.head_commit_for_ref(name)
|
|
160
161
|
end
|
|
161
162
|
|
|
162
|
-
sig { returns(T.nilable(
|
|
163
|
+
sig { returns(T.nilable(Dependabot::GitTagDetails)) }
|
|
163
164
|
def local_ref_for_latest_version_matching_existing_precision
|
|
164
165
|
allowed_refs = local_tag_for_pinned_sha ? allowed_version_tags : allowed_version_refs
|
|
165
166
|
|
|
166
167
|
max_local_tag_for_current_precision(allowed_refs)
|
|
167
168
|
end
|
|
168
169
|
|
|
169
|
-
sig { returns(T.nilable(
|
|
170
|
+
sig { returns(T.nilable(Dependabot::GitTagDetails)) }
|
|
170
171
|
def local_ref_for_latest_version_lower_precision
|
|
171
172
|
allowed_refs = local_tag_for_pinned_sha ? allowed_version_tags : allowed_version_refs
|
|
172
173
|
|
|
173
174
|
max_local_tag_for_lower_precision(allowed_refs)
|
|
174
175
|
end
|
|
175
176
|
|
|
176
|
-
sig { returns(T.nilable(
|
|
177
|
+
sig { returns(T.nilable(Dependabot::GitTagDetails)) }
|
|
177
178
|
def local_tag_for_latest_version
|
|
178
179
|
max_local_tag(allowed_version_tags)
|
|
179
180
|
end
|
|
180
181
|
|
|
181
|
-
sig { returns(T::Array[
|
|
182
|
+
sig { returns(T::Array[Dependabot::GitTagDetails]) }
|
|
182
183
|
def local_tags_for_allowed_versions_matching_existing_precision
|
|
183
184
|
select_matching_existing_precision(allowed_version_tags).filter_map { |t| to_local_tag(t) }
|
|
184
185
|
end
|
|
185
186
|
|
|
186
|
-
sig { returns(T::Array[
|
|
187
|
+
sig { returns(T::Array[Dependabot::GitTagDetails]) }
|
|
187
188
|
def local_tags_for_allowed_versions
|
|
188
189
|
allowed_version_tags.filter_map { |t| to_local_tag(t) }
|
|
189
190
|
end
|
|
@@ -272,7 +273,7 @@ module Dependabot
|
|
|
272
273
|
local_tags_matching_sha(commit_sha).map(&:name)
|
|
273
274
|
end
|
|
274
275
|
|
|
275
|
-
sig { params(tags: T::Array[Dependabot::GitRef]).returns(T.nilable(
|
|
276
|
+
sig { params(tags: T::Array[Dependabot::GitRef]).returns(T.nilable(Dependabot::GitTagDetails)) }
|
|
276
277
|
def max_local_tag(tags)
|
|
277
278
|
max_version_tag = tags.max_by { |t| version_from_tag(t) }
|
|
278
279
|
|
|
@@ -295,12 +296,12 @@ module Dependabot
|
|
|
295
296
|
sig { returns(T::Array[String]) }
|
|
296
297
|
attr_reader :ignored_versions
|
|
297
298
|
|
|
298
|
-
sig { params(tags: T::Array[Dependabot::GitRef]).returns(T.nilable(
|
|
299
|
+
sig { params(tags: T::Array[Dependabot::GitRef]).returns(T.nilable(Dependabot::GitTagDetails)) }
|
|
299
300
|
def max_local_tag_for_current_precision(tags)
|
|
300
301
|
max_local_tag(select_matching_existing_precision(tags))
|
|
301
302
|
end
|
|
302
303
|
|
|
303
|
-
sig { params(tags: T::Array[Dependabot::GitRef]).returns(T.nilable(
|
|
304
|
+
sig { params(tags: T::Array[Dependabot::GitRef]).returns(T.nilable(Dependabot::GitTagDetails)) }
|
|
304
305
|
def max_local_tag_for_lower_precision(tags)
|
|
305
306
|
max_local_tag(select_lower_precision(tags))
|
|
306
307
|
end
|
|
@@ -553,17 +554,17 @@ module Dependabot
|
|
|
553
554
|
prefix.length > 1 ? prefix.gsub(/v$/i, "") : prefix.gsub(/^v$/i, "")
|
|
554
555
|
end
|
|
555
556
|
|
|
556
|
-
sig { params(tag: T.nilable(Dependabot::GitRef)).returns(T.nilable(
|
|
557
|
+
sig { params(tag: T.nilable(Dependabot::GitRef)).returns(T.nilable(Dependabot::GitTagDetails)) }
|
|
557
558
|
def to_local_tag(tag)
|
|
558
559
|
return unless tag
|
|
559
560
|
|
|
560
561
|
version = version_from_tag(tag)
|
|
561
|
-
|
|
562
|
+
GitTagDetails.new(
|
|
562
563
|
tag: tag.name,
|
|
563
564
|
version: version,
|
|
564
565
|
commit_sha: tag.commit_sha,
|
|
565
566
|
tag_sha: tag.ref_sha
|
|
566
|
-
|
|
567
|
+
)
|
|
567
568
|
end
|
|
568
569
|
|
|
569
570
|
sig { returns(T.nilable(String)) }
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "sorbet-runtime"
|
|
5
|
+
require "dependabot/clients/github_with_retries"
|
|
6
|
+
require "dependabot/shared_helpers"
|
|
7
|
+
require "dependabot/source"
|
|
8
|
+
|
|
9
|
+
module Dependabot
|
|
10
|
+
# Shared logic for resolving release dates from git-based sources for cooldown
|
|
11
|
+
# purposes. Used by ecosystems that rely on git tags (pre-commit, GitHub Actions)
|
|
12
|
+
# rather than package registries.
|
|
13
|
+
#
|
|
14
|
+
# Priority: GitHub Release published_at > tag creation date (for-each-ref) > commit date.
|
|
15
|
+
#
|
|
16
|
+
# Including classes must implement:
|
|
17
|
+
# - `cooldown_source_url` — returns the git source URL
|
|
18
|
+
# - `cooldown_credentials` — returns the credentials array
|
|
19
|
+
module GitCooldownDateResolver
|
|
20
|
+
extend T::Sig
|
|
21
|
+
extend T::Helpers
|
|
22
|
+
|
|
23
|
+
abstract!
|
|
24
|
+
|
|
25
|
+
# The git source URL for the dependency (e.g. "https://github.com/owner/repo")
|
|
26
|
+
sig { abstract.returns(T.nilable(String)) }
|
|
27
|
+
def cooldown_source_url; end
|
|
28
|
+
|
|
29
|
+
# Credentials for GitHub API access
|
|
30
|
+
sig { abstract.returns(T::Array[Dependabot::Credential]) }
|
|
31
|
+
def cooldown_credentials; end
|
|
32
|
+
|
|
33
|
+
# Strips the `tags/` prefix that GitCommitChecker may add when the pinned
|
|
34
|
+
# ref starts with `tags/`, preventing construction of invalid refs like
|
|
35
|
+
# `refs/tags/tags/v1.0.0`.
|
|
36
|
+
sig { params(tag_name: String).returns(String) }
|
|
37
|
+
def normalize_tag_name(tag_name)
|
|
38
|
+
tag_name.delete_prefix("tags/")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Resolves the best available date for a candidate tag.
|
|
42
|
+
# Priority: GitHub Release published_at > tag creation date > commit date.
|
|
43
|
+
sig { params(tag_name: String, commit_sha: String).returns(Time) }
|
|
44
|
+
def resolve_candidate_date(tag_name, commit_sha)
|
|
45
|
+
releases = cached_github_releases
|
|
46
|
+
unless releases.empty?
|
|
47
|
+
release = releases.find { |r| r.tag_name == tag_name }
|
|
48
|
+
return release.published_at if release&.published_at
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
tag_creation_date(tag_name, commit_sha)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Looks up the GitHub Release published_at date for a given tag name.
|
|
55
|
+
# Returns nil if no release exists for this tag.
|
|
56
|
+
sig { params(tag_name: String).returns(T.nilable(Time)) }
|
|
57
|
+
def github_release_published_at(tag_name)
|
|
58
|
+
releases = cached_github_releases
|
|
59
|
+
return nil if releases.empty?
|
|
60
|
+
|
|
61
|
+
release = releases.find { |r| r.tag_name == tag_name }
|
|
62
|
+
return nil unless release&.published_at
|
|
63
|
+
|
|
64
|
+
release.published_at
|
|
65
|
+
rescue StandardError => e
|
|
66
|
+
Dependabot.logger.debug("Error fetching GitHub release date for #{tag_name}: #{e.message}")
|
|
67
|
+
nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Returns the tag creation date for cooldown purposes (used inside bare clone).
|
|
71
|
+
# Priority: tag creation date from for-each-ref > commit date fallback.
|
|
72
|
+
sig { params(tag_name: String, commit_sha: String).returns(Time) }
|
|
73
|
+
def tag_creation_date(tag_name, commit_sha)
|
|
74
|
+
tag_date_str = SharedHelpers.run_shell_command(
|
|
75
|
+
"git for-each-ref --format=\"%(creatordate:iso)\" \"refs/tags/#{tag_name}\"",
|
|
76
|
+
fingerprint: "git for-each-ref --format=\"%(creatordate:iso)\" \"refs/tags/<tag_name>\""
|
|
77
|
+
).strip
|
|
78
|
+
|
|
79
|
+
if tag_date_str.empty?
|
|
80
|
+
tag_date_str = SharedHelpers.run_shell_command(
|
|
81
|
+
"git show --no-patch --format=\"%cd\" --date=iso #{commit_sha}",
|
|
82
|
+
fingerprint: "git show --no-patch --format=\"%cd\" --date=iso <commit_sha>"
|
|
83
|
+
).strip
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
Time.parse(tag_date_str)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Fetches and caches GitHub releases for the dependency source.
|
|
90
|
+
# Returns an empty array for non-GitHub sources.
|
|
91
|
+
sig { returns(T::Array[T.untyped]) } # rubocop:disable Sorbet/ForbidTUntyped
|
|
92
|
+
def cached_github_releases
|
|
93
|
+
@cached_github_releases ||= T.let(
|
|
94
|
+
begin
|
|
95
|
+
url = cooldown_source_url
|
|
96
|
+
source = Source.from_url(url)
|
|
97
|
+
if source&.provider == "github"
|
|
98
|
+
client = Dependabot::Clients::GithubWithRetries.for_source(
|
|
99
|
+
source: T.must(source),
|
|
100
|
+
credentials: cooldown_credentials
|
|
101
|
+
)
|
|
102
|
+
client.releases(T.must(source).repo, per_page: 100)
|
|
103
|
+
else
|
|
104
|
+
[]
|
|
105
|
+
end
|
|
106
|
+
rescue StandardError => e
|
|
107
|
+
Dependabot.logger.debug("Error fetching GitHub releases: #{e.message}")
|
|
108
|
+
[]
|
|
109
|
+
end,
|
|
110
|
+
T.nilable(T::Array[T.untyped]) # rubocop:disable Sorbet/ForbidTUntyped
|
|
111
|
+
)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "sorbet-runtime"
|
|
5
|
+
|
|
6
|
+
module Dependabot
|
|
7
|
+
# A git tag (or ref) resolved to a version, as produced by GitCommitChecker's
|
|
8
|
+
# local_tag_for_* / local_ref_for_* methods, e.g.:
|
|
9
|
+
#
|
|
10
|
+
# {
|
|
11
|
+
# tag: "v1.2.0",
|
|
12
|
+
# version: Dependabot::Version.new("1.2.0"),
|
|
13
|
+
# commit_sha: "a1b2c3...",
|
|
14
|
+
# tag_sha: "d4e5f6..." # nil for lightweight tags
|
|
15
|
+
# }
|
|
16
|
+
#
|
|
17
|
+
# Distinct from Dependabot::GitTagWithDetail, which carries a tag name and
|
|
18
|
+
# release date for cooldown handling.
|
|
19
|
+
#
|
|
20
|
+
# Subclasses Hash so it is a drop-in replacement at the many call sites that
|
|
21
|
+
# read entries with [:key] / fetch and treat them as
|
|
22
|
+
# T::Hash[Symbol, T.untyped], while exposing typed readers for the well-known
|
|
23
|
+
# keys. Instances compare equal (Hash#==) to plain hashes with the same
|
|
24
|
+
# content, so existing comparisons and API payloads are unaffected.
|
|
25
|
+
class GitTagDetails < Hash
|
|
26
|
+
extend T::Sig
|
|
27
|
+
extend T::Generic
|
|
28
|
+
|
|
29
|
+
# The values are heterogeneous (strings and a version object), so this
|
|
30
|
+
# bridge class is necessarily untyped at the Hash level; the typed readers
|
|
31
|
+
# below are the migration path.
|
|
32
|
+
# rubocop:disable Sorbet/ForbidTUntyped
|
|
33
|
+
K = type_member { { fixed: Symbol } }
|
|
34
|
+
V = type_member { { fixed: T.untyped } }
|
|
35
|
+
Elem = type_member { { fixed: [Symbol, T.untyped] } }
|
|
36
|
+
# rubocop:enable Sorbet/ForbidTUntyped
|
|
37
|
+
|
|
38
|
+
sig do
|
|
39
|
+
params(
|
|
40
|
+
tag: String,
|
|
41
|
+
version: T.nilable(Gem::Version),
|
|
42
|
+
commit_sha: T.nilable(String),
|
|
43
|
+
tag_sha: T.nilable(String)
|
|
44
|
+
).void
|
|
45
|
+
end
|
|
46
|
+
def initialize(tag:, version: nil, commit_sha: nil, tag_sha: nil)
|
|
47
|
+
super()
|
|
48
|
+
self[:tag] = tag
|
|
49
|
+
self[:version] = version
|
|
50
|
+
self[:commit_sha] = commit_sha
|
|
51
|
+
self[:tag_sha] = tag_sha
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# The tag or ref name, e.g. "v1.2.0".
|
|
55
|
+
sig { returns(String) }
|
|
56
|
+
def tag
|
|
57
|
+
self[:tag]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The version parsed from the tag name.
|
|
61
|
+
sig { returns(T.nilable(Gem::Version)) }
|
|
62
|
+
def version
|
|
63
|
+
self[:version]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# The SHA of the commit the tag points at.
|
|
67
|
+
sig { returns(T.nilable(String)) }
|
|
68
|
+
def commit_sha
|
|
69
|
+
self[:commit_sha]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# The SHA of the tag object itself (nil for lightweight tags).
|
|
73
|
+
sig { returns(T.nilable(String)) }
|
|
74
|
+
def tag_sha
|
|
75
|
+
self[:tag_sha]
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -145,7 +145,7 @@ module Dependabot
|
|
|
145
145
|
end
|
|
146
146
|
|
|
147
147
|
# TODO: Refactor me so that Composer doesn't need to be special cased
|
|
148
|
-
sig { params(requirements: T.nilable(T::Array[
|
|
148
|
+
sig { params(requirements: T.nilable(T::Array[Dependabot::DependencyRequirement])).returns(T::Boolean) }
|
|
149
149
|
def git_source?(requirements)
|
|
150
150
|
# Special case Composer, which uses git as a source but handles tags
|
|
151
151
|
# internally
|
data/lib/dependabot/notices.rb
CHANGED
|
@@ -59,8 +59,8 @@ module Dependabot
|
|
|
59
59
|
|
|
60
60
|
# Converts the Notice object to a hash.
|
|
61
61
|
# @return [Hash] The hash representation of the notice.
|
|
62
|
-
sig { returns(T::Hash[Symbol, T.
|
|
63
|
-
def
|
|
62
|
+
sig { returns(T::Hash[Symbol, T.any(String, T::Boolean)]) }
|
|
63
|
+
def to_h
|
|
64
64
|
{
|
|
65
65
|
mode: @mode,
|
|
66
66
|
type: @type,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
+
require "digest"
|
|
4
5
|
require "sorbet-runtime"
|
|
5
6
|
|
|
6
7
|
module Dependabot
|
|
@@ -70,9 +71,10 @@ module Dependabot
|
|
|
70
71
|
sanitized_name = sanitized_name.gsub("/", separator)
|
|
71
72
|
|
|
72
73
|
# Shorten the ref in case users refs have length limits
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
branch_name_max_length = max_length
|
|
75
|
+
if branch_name_max_length && (sanitized_name.length > branch_name_max_length)
|
|
76
|
+
sha = T.must(Digest::SHA1.hexdigest(sanitized_name)[0, branch_name_max_length])
|
|
77
|
+
sanitized_name[[branch_name_max_length - sha.size, 0].max..] = sha
|
|
76
78
|
end
|
|
77
79
|
|
|
78
80
|
sanitized_name
|
|
@@ -119,21 +119,21 @@ module Dependabot
|
|
|
119
119
|
|
|
120
120
|
sig { params(dependency: Dependabot::Dependency).returns(String) }
|
|
121
121
|
def sanitized_requirement(dependency)
|
|
122
|
-
new_library_requirement(dependency)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
122
|
+
T.must(new_library_requirement(dependency))
|
|
123
|
+
.delete(" ")
|
|
124
|
+
.gsub("!=", "neq-")
|
|
125
|
+
.gsub(">=", "gte-")
|
|
126
|
+
.gsub("<=", "lte-")
|
|
127
|
+
.gsub("~>", "tw-")
|
|
128
|
+
.gsub("^", "tw-")
|
|
129
|
+
.gsub("||", "or-")
|
|
130
|
+
.gsub("~", "approx-")
|
|
131
|
+
.gsub("~=", "tw-")
|
|
132
|
+
.gsub(/==*/, "eq-")
|
|
133
|
+
.gsub(">", "gt-")
|
|
134
|
+
.gsub("<", "lt-")
|
|
135
|
+
.gsub("*", "star")
|
|
136
|
+
.gsub(",", "-and-")
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
sig { params(dependency: Dependabot::Dependency).returns(T.nilable(String)) }
|
|
@@ -176,7 +176,7 @@ module Dependabot
|
|
|
176
176
|
previous_ref(dependency) != new_ref(dependency)
|
|
177
177
|
end
|
|
178
178
|
|
|
179
|
-
sig { params(dependency: Dependabot::Dependency).returns(T.
|
|
179
|
+
sig { params(dependency: Dependabot::Dependency).returns(T.nilable(String)) }
|
|
180
180
|
def new_library_requirement(dependency)
|
|
181
181
|
updated_reqs =
|
|
182
182
|
dependency.requirements - T.must(dependency.previous_requirements)
|
|
@@ -197,7 +197,7 @@ module Dependabot
|
|
|
197
197
|
milestone: nil,
|
|
198
198
|
branch_name_separator: "/",
|
|
199
199
|
branch_name_prefix: "dependabot",
|
|
200
|
-
branch_name_max_length:
|
|
200
|
+
branch_name_max_length: 100,
|
|
201
201
|
label_language: false,
|
|
202
202
|
automerge_candidate: false,
|
|
203
203
|
github_redirection_service: DEFAULT_GITHUB_REDIRECTION_SERVICE,
|
|
@@ -40,7 +40,7 @@ module Dependabot
|
|
|
40
40
|
sig { returns(T.nilable(String)) }
|
|
41
41
|
attr_reader :commit_message
|
|
42
42
|
|
|
43
|
-
sig { returns(T::Hash[Symbol,
|
|
43
|
+
sig { returns(T::Hash[Symbol, Integer]) }
|
|
44
44
|
attr_reader :provider_metadata
|
|
45
45
|
|
|
46
46
|
sig do
|
|
@@ -54,7 +54,7 @@ module Dependabot
|
|
|
54
54
|
author_details: T.nilable(T::Hash[Symbol, String]),
|
|
55
55
|
signature_key: T.nilable(String),
|
|
56
56
|
commit_message: T.nilable(String),
|
|
57
|
-
provider_metadata: T::Hash[Symbol,
|
|
57
|
+
provider_metadata: T::Hash[Symbol, Integer]
|
|
58
58
|
)
|
|
59
59
|
.void
|
|
60
60
|
end
|
|
@@ -84,7 +84,7 @@ module Dependabot
|
|
|
84
84
|
|
|
85
85
|
# TODO: Each implementation returns a client-specific type.
|
|
86
86
|
# We should standardise this to return a `Dependabot::Branch` type instead.
|
|
87
|
-
sig { returns(T.untyped) }
|
|
87
|
+
sig { returns(T.untyped) } # rubocop:disable Sorbet/ForbidTUntyped
|
|
88
88
|
def update
|
|
89
89
|
case source.provider
|
|
90
90
|
when "github" then github_updater.update
|
|
@@ -120,7 +120,7 @@ module Dependabot
|
|
|
120
120
|
files: files,
|
|
121
121
|
credentials: credentials,
|
|
122
122
|
pull_request_number: pull_request_number,
|
|
123
|
-
target_project_id:
|
|
123
|
+
target_project_id: provider_metadata[:target_project_id]
|
|
124
124
|
)
|
|
125
125
|
end
|
|
126
126
|
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
require "sorbet-runtime"
|
|
5
5
|
|
|
6
|
+
require "dependabot/dependency_requirement"
|
|
7
|
+
|
|
6
8
|
module Dependabot
|
|
7
9
|
module RequirementsUpdater
|
|
8
10
|
module Base
|
|
@@ -15,7 +17,7 @@ module Dependabot
|
|
|
15
17
|
|
|
16
18
|
interface!
|
|
17
19
|
|
|
18
|
-
sig { abstract.returns(T::Array[
|
|
20
|
+
sig { abstract.returns(T::Array[Dependabot::DependencyRequirement]) }
|
|
19
21
|
def updated_requirements; end
|
|
20
22
|
|
|
21
23
|
private
|
|
@@ -182,7 +182,7 @@ module Dependabot
|
|
|
182
182
|
dependency.version
|
|
183
183
|
end
|
|
184
184
|
|
|
185
|
-
sig { overridable.returns(T::Array[
|
|
185
|
+
sig { overridable.returns(T::Array[Dependabot::DependencyRequirement]) }
|
|
186
186
|
def updated_requirements
|
|
187
187
|
raise NotImplementedError
|
|
188
188
|
end
|
|
@@ -226,6 +226,20 @@ module Dependabot
|
|
|
226
226
|
|
|
227
227
|
private
|
|
228
228
|
|
|
229
|
+
# Wraps an array of raw requirement hashes (e.g. the output of an
|
|
230
|
+
# ecosystem RequirementsUpdater) into typed DependencyRequirement
|
|
231
|
+
# objects, so updated_requirements overrides can satisfy the typed
|
|
232
|
+
# return contract. Entries that are already DependencyRequirement
|
|
233
|
+
# instances are returned as-is; plain hashes are wrapped. Re-wrapping
|
|
234
|
+
# would produce a value-equal copy, so skipping it avoids needless
|
|
235
|
+
# allocations.
|
|
236
|
+
sig { params(requirements: T::Array[T::Hash[Symbol, T.untyped]]).returns(T::Array[Dependabot::DependencyRequirement]) }
|
|
237
|
+
def wrap_requirements(requirements)
|
|
238
|
+
requirements.map do |requirement|
|
|
239
|
+
requirement.is_a?(Dependabot::DependencyRequirement) ? requirement : Dependabot::DependencyRequirement.create(requirement)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
229
243
|
sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
|
|
230
244
|
def active_advisories
|
|
231
245
|
security_advisories.select { |a| a.vulnerable?(T.must(current_version)) }
|
data/lib/dependabot.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-common
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.383.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -534,6 +534,7 @@ files:
|
|
|
534
534
|
- lib/dependabot/dependency_graphers/base.rb
|
|
535
535
|
- lib/dependabot/dependency_graphers/generic.rb
|
|
536
536
|
- lib/dependabot/dependency_group.rb
|
|
537
|
+
- lib/dependabot/dependency_requirement.rb
|
|
537
538
|
- lib/dependabot/ecosystem.rb
|
|
538
539
|
- lib/dependabot/errors.rb
|
|
539
540
|
- lib/dependabot/experiments.rb
|
|
@@ -551,8 +552,10 @@ files:
|
|
|
551
552
|
- lib/dependabot/file_updaters/base.rb
|
|
552
553
|
- lib/dependabot/file_updaters/vendor_updater.rb
|
|
553
554
|
- lib/dependabot/git_commit_checker.rb
|
|
555
|
+
- lib/dependabot/git_cooldown_date_resolver.rb
|
|
554
556
|
- lib/dependabot/git_metadata_fetcher.rb
|
|
555
557
|
- lib/dependabot/git_ref.rb
|
|
558
|
+
- lib/dependabot/git_tag_details.rb
|
|
556
559
|
- lib/dependabot/git_tag_with_detail.rb
|
|
557
560
|
- lib/dependabot/logger.rb
|
|
558
561
|
- lib/dependabot/metadata_finders.rb
|
|
@@ -617,7 +620,7 @@ licenses:
|
|
|
617
620
|
- MIT
|
|
618
621
|
metadata:
|
|
619
622
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
620
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
623
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.383.0
|
|
621
624
|
rdoc_options: []
|
|
622
625
|
require_paths:
|
|
623
626
|
- lib
|