dependabot-common 0.235.0 → 0.237.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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dependabot/clients/azure.rb +3 -3
  3. data/lib/dependabot/config/file.rb +32 -9
  4. data/lib/dependabot/config/file_fetcher.rb +3 -3
  5. data/lib/dependabot/config/ignore_condition.rb +34 -8
  6. data/lib/dependabot/config/update_config.rb +42 -6
  7. data/lib/dependabot/config.rb +1 -1
  8. data/lib/dependabot/dependency_file.rb +89 -14
  9. data/lib/dependabot/dependency_group.rb +29 -5
  10. data/lib/dependabot/errors.rb +101 -13
  11. data/lib/dependabot/file_fetchers/base.rb +250 -93
  12. data/lib/dependabot/file_updaters/artifact_updater.rb +37 -10
  13. data/lib/dependabot/file_updaters/vendor_updater.rb +13 -3
  14. data/lib/dependabot/logger.rb +7 -2
  15. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +13 -6
  16. data/lib/dependabot/pull_request_creator/commit_signer.rb +33 -7
  17. data/lib/dependabot/pull_request_creator/github.rb +13 -10
  18. data/lib/dependabot/pull_request_creator/message.rb +21 -2
  19. data/lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb +37 -16
  20. data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +5 -3
  21. data/lib/dependabot/pull_request_creator/message_builder.rb +5 -18
  22. data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +10 -4
  23. data/lib/dependabot/pull_request_updater/github.rb +2 -2
  24. data/lib/dependabot/shared_helpers.rb +117 -33
  25. data/lib/dependabot/simple_instrumentor.rb +22 -3
  26. data/lib/dependabot/source.rb +65 -17
  27. data/lib/dependabot/update_checkers/version_filters.rb +12 -1
  28. data/lib/dependabot/utils.rb +21 -2
  29. data/lib/dependabot/workspace/base.rb +42 -7
  30. data/lib/dependabot/workspace/change_attempt.rb +31 -3
  31. data/lib/dependabot/workspace/git.rb +34 -4
  32. data/lib/dependabot/workspace.rb +16 -2
  33. data/lib/dependabot.rb +1 -1
  34. metadata +37 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b22cec48025b20921f000f63975cfc9db22dac670fa8ef6710fda754c288f68
4
- data.tar.gz: 901b6246fde924caa2adfdcba0bc19dbd86833133c6cf951967024b656f68918
3
+ metadata.gz: e29557fff3ec856a4ebcb95a2b53dd70f91b5d7f2ea66cd6230e90dbcbbc2dc0
4
+ data.tar.gz: f6b2ce2a845422872e58b37681909fb4357bb1ebcac22c1085db113dc2429426
5
5
  SHA512:
6
- metadata.gz: 819445f789764166001ff2f6ce532e6bd60ecb1a644eb4bb20ec00a15c433c58608af56e3c75bbccba479c2f6b81fd415298083f9d4e74c24ba382881a35280c
7
- data.tar.gz: 3b5f7aa169756240055ded3136f8daae04cc52129a42f0566eddc90232a302427b889ef512534f5e865609d7a7ba526f82deb7cea2b59138c4533e61fa01971a
6
+ metadata.gz: 367d715ab3cb1b0c2c498555419e2212e9986c8e824128ce56695c00cdc190371fa0b7b9115258146ff0573f2e4a8461e1c66651b9d84bb2fdb7b0fe00b901ff
7
+ data.tar.gz: 4e5b3e040476f17cb7cf268ccc0cae90f17178da6a5954b14ca2a2ce280cf0f067b1ce8b88ecc8da5c04ae919cc34b670258b1555f9bfb707fb061cc8439acb3
@@ -271,9 +271,9 @@ module Dependabot
271
271
  )
272
272
  )
273
273
 
274
- raise InternalServerError if response&.status == 500
275
- raise BadGateway if response&.status == 502
276
- raise ServiceNotAvailable if response&.status == 503
274
+ raise InternalServerError if response.status == 500
275
+ raise BadGateway if response.status == 502
276
+ raise ServiceNotAvailable if response.status == 503
277
277
  end
278
278
 
279
279
  raise Unauthorized if response&.status == 401
@@ -1,19 +1,37 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/config/update_config"
5
+ require "sorbet-runtime"
5
6
 
6
7
  module Dependabot
7
8
  module Config
8
9
  # Configuration for the repository, a parsed dependabot.yaml.
9
10
  class File
10
- attr_reader :updates, :registries
11
+ extend T::Sig
11
12
 
13
+ sig { returns(T::Array[T::Hash[Symbol, String]]) }
14
+ attr_reader :updates
15
+
16
+ sig { returns T::Array[T.untyped] }
17
+ attr_reader :registries
18
+
19
+ sig do
20
+ params(
21
+ updates: T.nilable(T::Array[T::Hash[Symbol, String]]),
22
+ registries: T.nilable(T::Array[T.untyped])
23
+ )
24
+ .void
25
+ end
12
26
  def initialize(updates:, registries: nil)
13
- @updates = updates || []
14
- @registries = registries || []
27
+ @updates = T.let(updates || [], T::Array[T::Hash[Symbol, String]])
28
+ @registries = T.let(registries || [], T::Array[T.untyped])
15
29
  end
16
30
 
31
+ sig do
32
+ params(package_manager: String, directory: T.nilable(String), target_branch: T.nilable(String))
33
+ .returns(UpdateConfig)
34
+ end
17
35
  def update_config(package_manager, directory: nil, target_branch: nil)
18
36
  dir = directory || "/"
19
37
  package_ecosystem = PACKAGE_MANAGER_LOOKUP.invert.fetch(package_manager)
@@ -21,13 +39,14 @@ module Dependabot
21
39
  u[:"package-ecosystem"] == package_ecosystem && u[:directory] == dir &&
22
40
  (target_branch.nil? || u[:"target-branch"] == target_branch)
23
41
  end
24
- Dependabot::Config::UpdateConfig.new(
42
+ UpdateConfig.new(
25
43
  ignore_conditions: ignore_conditions(cfg),
26
44
  commit_message_options: commit_message_options(cfg)
27
45
  )
28
46
  end
29
47
 
30
48
  # Parse the YAML config file
49
+ sig { params(config: String).returns(File) }
31
50
  def self.parse(config)
32
51
  parsed = YAML.safe_load(config, symbolize_names: true)
33
52
  version = parsed[:version]
@@ -38,7 +57,7 @@ module Dependabot
38
57
 
39
58
  private
40
59
 
41
- PACKAGE_MANAGER_LOOKUP = {
60
+ PACKAGE_MANAGER_LOOKUP = T.let({
42
61
  "bundler" => "bundler",
43
62
  "cargo" => "cargo",
44
63
  "composer" => "composer",
@@ -56,12 +75,13 @@ module Dependabot
56
75
  "pub" => "pub",
57
76
  "swift" => "swift",
58
77
  "terraform" => "terraform"
59
- }.freeze
78
+ }.freeze, T::Hash[String, String])
60
79
 
80
+ sig { params(cfg: T.nilable(T::Hash[Symbol, T.untyped])).returns(T::Array[IgnoreCondition]) }
61
81
  def ignore_conditions(cfg)
62
82
  ignores = cfg&.dig(:ignore) || []
63
83
  ignores.map do |ic|
64
- Dependabot::Config::IgnoreCondition.new(
84
+ IgnoreCondition.new(
65
85
  dependency_name: ic[:"dependency-name"],
66
86
  versions: ic[:versions],
67
87
  update_types: ic[:"update-types"]
@@ -69,9 +89,12 @@ module Dependabot
69
89
  end
70
90
  end
71
91
 
92
+ sig do
93
+ params(cfg: T.nilable(T::Hash[Symbol, T.untyped])).returns(UpdateConfig::CommitMessageOptions)
94
+ end
72
95
  def commit_message_options(cfg)
73
96
  commit_message = cfg&.dig(:"commit-message") || {}
74
- Dependabot::Config::UpdateConfig::CommitMessageOptions.new(
97
+ UpdateConfig::CommitMessageOptions.new(
75
98
  prefix: commit_message[:prefix],
76
99
  prefix_development: commit_message[:"prefix-development"] || commit_message[:prefix],
77
100
  include: commit_message[:include]
@@ -6,7 +6,7 @@ require "dependabot/config/file"
6
6
 
7
7
  module Dependabot
8
8
  module Config
9
- class FileFetcher < Dependabot::FileFetchers::Base
9
+ class FileFetcher < FileFetchers::Base
10
10
  CONFIG_FILE_PATHS = %w(.github/dependabot.yml .github/dependabot.yaml).freeze
11
11
 
12
12
  def self.required_files_in?(filenames)
@@ -35,13 +35,13 @@ module Dependabot
35
35
  fetched_files << config_file
36
36
  break
37
37
  end
38
- rescue Dependabot::DependencyFileNotFound
38
+ rescue DependencyFileNotFound
39
39
  next
40
40
  end
41
41
  end
42
42
 
43
43
  unless self.class.required_files_in?(fetched_files.map(&:name))
44
- raise Dependabot::DependencyFileNotFound.new(nil, self.class.required_files_message)
44
+ raise DependencyFileNotFound.new(nil, self.class.required_files_message)
45
45
  end
46
46
 
47
47
  fetched_files
@@ -1,24 +1,43 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
5
+
4
6
  module Dependabot
5
7
  module Config
6
8
  # Filters versions that should not be considered for dependency updates
7
9
  class IgnoreCondition
10
+ extend T::Sig
11
+
8
12
  PATCH_VERSION_TYPE = "version-update:semver-patch"
9
13
  MINOR_VERSION_TYPE = "version-update:semver-minor"
10
14
  MAJOR_VERSION_TYPE = "version-update:semver-major"
11
15
 
12
16
  ALL_VERSIONS = ">= 0"
13
17
 
14
- attr_reader :dependency_name, :versions, :update_types
18
+ sig { returns(String) }
19
+ attr_reader :dependency_name
20
+
21
+ sig { returns(T::Array[String]) }
22
+ attr_reader :versions
15
23
 
24
+ sig { returns(T::Array[String]) }
25
+ attr_reader :update_types
26
+
27
+ sig do
28
+ params(
29
+ dependency_name: String,
30
+ versions: T.any(NilClass, T::Array[String]),
31
+ update_types: T.any(NilClass, T::Array[String])
32
+ ).void
33
+ end
16
34
  def initialize(dependency_name:, versions: nil, update_types: nil)
17
- @dependency_name = dependency_name
18
- @versions = versions || []
19
- @update_types = update_types || []
35
+ @dependency_name = T.let(dependency_name, String)
36
+ @versions = T.let(versions || [], T::Array[String])
37
+ @update_types = T.let(update_types || [], T::Array[String])
20
38
  end
21
39
 
40
+ sig { params(dependency: Dependency, security_updates_only: T::Boolean).returns(T::Array[String]) }
22
41
  def ignored_versions(dependency, security_updates_only)
23
42
  return versions if security_updates_only
24
43
  return [ALL_VERSIONS] if versions.empty? && transformed_update_types.empty?
@@ -28,10 +47,12 @@ module Dependabot
28
47
 
29
48
  private
30
49
 
50
+ sig { returns(T::Array[String]) }
31
51
  def transformed_update_types
32
52
  update_types.map(&:downcase).filter_map(&:strip)
33
53
  end
34
54
 
55
+ sig { params(dependency: Dependency).returns(T::Array[T.untyped]) }
35
56
  def versions_by_type(dependency)
36
57
  version = correct_version_for(dependency)
37
58
  return [] unless version
@@ -52,9 +73,10 @@ module Dependabot
52
73
  end.compact
53
74
  end
54
75
 
76
+ sig { params(version: String).returns(T::Array[String]) }
55
77
  def ignore_patch(version)
56
78
  parts = version.split(".")
57
- version_parts = parts.fill(0, parts.length...2)
79
+ version_parts = parts.fill("0", parts.length...2)
58
80
  upper_parts = version_parts.first(1) + [version_parts[1].to_i + 1]
59
81
  lower_bound = "> #{version}"
60
82
  upper_bound = "< #{upper_parts.join('.')}"
@@ -62,9 +84,10 @@ module Dependabot
62
84
  ["#{lower_bound}, #{upper_bound}"]
63
85
  end
64
86
 
87
+ sig { params(version: String).returns(T::Array[String]) }
65
88
  def ignore_minor(version)
66
89
  parts = version.split(".")
67
- version_parts = parts.fill(0, parts.length...2)
90
+ version_parts = parts.fill("0", parts.length...2)
68
91
  lower_parts = version_parts.first(1) + [version_parts[1].to_i + 1] + ["a"]
69
92
  upper_parts = version_parts.first(0) + [version_parts[0].to_i + 1]
70
93
  lower_bound = ">= #{lower_parts.join('.')}"
@@ -73,6 +96,7 @@ module Dependabot
73
96
  ["#{lower_bound}, #{upper_bound}"]
74
97
  end
75
98
 
99
+ sig { params(version: String).returns(T::Array[String]) }
76
100
  def ignore_major(version)
77
101
  version_parts = version.split(".")
78
102
  lower_parts = [version_parts[0].to_i + 1] + ["a"]
@@ -81,6 +105,7 @@ module Dependabot
81
105
  [lower_bound]
82
106
  end
83
107
 
108
+ sig { params(dependency: Dependency).returns(T.nilable(Version)) }
84
109
  def correct_version_for(dependency)
85
110
  version = dependency.version
86
111
  return if version.nil? || version.empty?
@@ -91,10 +116,11 @@ module Dependabot
91
116
  version_class.new(version)
92
117
  end
93
118
 
119
+ sig { params(package_manager: String).returns(T.class_of(Version)) }
94
120
  def version_class_for(package_manager)
95
121
  Utils.version_class_for_package_manager(package_manager)
96
122
  rescue StandardError
97
- Dependabot::Version
123
+ Version
98
124
  end
99
125
  end
100
126
  end
@@ -1,30 +1,46 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/config/ignore_condition"
5
+ require "sorbet-runtime"
5
6
 
6
7
  module Dependabot
7
8
  module Config
8
9
  # Configuration for a single ecosystem
9
10
  class UpdateConfig
10
- attr_reader :commit_message_options, :ignore_conditions
11
+ extend T::Sig
12
+
13
+ sig { returns(T.nilable(CommitMessageOptions)) }
14
+ attr_reader :commit_message_options
15
+
16
+ sig { returns(T::Array[IgnoreCondition]) }
17
+ attr_reader :ignore_conditions
18
+
19
+ sig do
20
+ params(
21
+ ignore_conditions: T.nilable(T::Array[IgnoreCondition]),
22
+ commit_message_options: T.nilable(CommitMessageOptions)
23
+ ).void
24
+ end
11
25
  def initialize(ignore_conditions: nil, commit_message_options: nil)
12
- @ignore_conditions = ignore_conditions || []
26
+ @ignore_conditions = T.let(ignore_conditions || [], T::Array[IgnoreCondition])
13
27
  @commit_message_options = commit_message_options
14
28
  end
15
29
 
30
+ sig { params(dependency: Dependency, security_updates_only: T::Boolean).returns(T::Array[String]) }
16
31
  def ignored_versions_for(dependency, security_updates_only: false)
17
32
  normalizer = name_normaliser_for(dependency)
18
- dep_name = normalizer.call(dependency.name)
33
+ dep_name = T.must(normalizer).call(dependency.name)
19
34
 
20
35
  @ignore_conditions
21
- .select { |ic| self.class.wildcard_match?(normalizer.call(ic.dependency_name), dep_name) }
36
+ .select { |ic| self.class.wildcard_match?(T.must(normalizer).call(ic.dependency_name), dep_name) }
22
37
  .map { |ic| ic.ignored_versions(dependency, security_updates_only) }
23
38
  .flatten
24
39
  .compact
25
40
  .uniq
26
41
  end
27
42
 
43
+ sig { params(wildcard_string: T.nilable(String), candidate_string: T.nilable(String)).returns(T::Boolean) }
28
44
  def self.wildcard_match?(wildcard_string, candidate_string)
29
45
  return false unless wildcard_string && candidate_string
30
46
 
@@ -37,24 +53,44 @@ module Dependabot
37
53
 
38
54
  private
39
55
 
56
+ sig { params(dep: Dependency).returns(T.nilable(T.proc.params(arg0: String).returns(String))) }
40
57
  def name_normaliser_for(dep)
41
58
  name_normaliser ||= {}
42
59
  name_normaliser[dep] ||= Dependency.name_normaliser_for_package_manager(dep.package_manager)
43
60
  end
44
61
 
45
62
  class CommitMessageOptions
46
- attr_reader :prefix, :prefix_development, :include
63
+ extend T::Sig
47
64
 
65
+ sig { returns(T.nilable(String)) }
66
+ attr_reader :prefix
67
+
68
+ sig { returns(T.nilable(String)) }
69
+ attr_reader :prefix_development
70
+
71
+ sig { returns(T.nilable(String)) }
72
+ attr_reader :include
73
+
74
+ sig do
75
+ params(
76
+ prefix: T.nilable(String),
77
+ prefix_development: T.nilable(String),
78
+ include: T.nilable(String)
79
+ )
80
+ .void
81
+ end
48
82
  def initialize(prefix:, prefix_development:, include:)
49
83
  @prefix = prefix
50
84
  @prefix_development = prefix_development
51
85
  @include = include
52
86
  end
53
87
 
88
+ sig { returns(T::Boolean) }
54
89
  def include_scope?
55
90
  @include == "scope"
56
91
  end
57
92
 
93
+ sig { returns(T::Hash[Symbol, String]) }
58
94
  def to_h
59
95
  {
60
96
  prefix: @prefix,
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Dependabot
@@ -1,13 +1,47 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "pathname"
5
+ require "sorbet-runtime"
5
6
 
6
7
  module Dependabot
7
8
  class DependencyFile
8
- attr_accessor :name, :content, :directory, :type, :support_file,
9
- :vendored_file, :symlink_target, :content_encoding,
10
- :operation, :mode
9
+ extend T::Sig
10
+
11
+ sig { returns(String) }
12
+ attr_accessor :name
13
+
14
+ sig { returns(T.nilable(String)) }
15
+ attr_accessor :content
16
+
17
+ sig { returns(String) }
18
+ attr_accessor :directory
19
+
20
+ sig { returns(String) }
21
+ attr_accessor :type
22
+
23
+ sig { returns(T::Boolean) }
24
+ attr_accessor :support_file
25
+
26
+ sig { returns(T::Boolean) }
27
+ attr_accessor :vendored_file
28
+
29
+ sig { returns(T.nilable(String)) }
30
+ attr_accessor :symlink_target
31
+
32
+ sig { returns(String) }
33
+ attr_accessor :content_encoding
34
+
35
+ sig { returns(String) }
36
+ attr_accessor :operation
37
+
38
+ sig { returns(T.nilable(String)) }
39
+ attr_accessor :mode
40
+
41
+ # The directory that this file was fetched for. This is useful for multi-directory
42
+ # updates, where a set of files that are related to each other are updated together.
43
+ sig { returns(T.nilable(String)) }
44
+ attr_accessor :job_directory
11
45
 
12
46
  class ContentEncoding
13
47
  UTF_8 = "utf-8"
@@ -20,18 +54,41 @@ module Dependabot
20
54
  DELETE = "delete"
21
55
  end
22
56
 
57
+ class Mode
58
+ FILE = "100644"
59
+ SUBMODULE = "160000"
60
+ end
61
+
62
+ sig do
63
+ params(
64
+ name: String,
65
+ content: T.nilable(String),
66
+ directory: String,
67
+ type: String,
68
+ support_file: T::Boolean,
69
+ vendored_file: T::Boolean,
70
+ symlink_target: T.nilable(String),
71
+ content_encoding: String,
72
+ deleted: T::Boolean,
73
+ operation: String,
74
+ mode: T.nilable(String),
75
+ job_directory: T.nilable(String)
76
+ )
77
+ .void
78
+ end
23
79
  def initialize(name:, content:, directory: "/", type: "file",
24
80
  support_file: false, vendored_file: false, symlink_target: nil,
25
81
  content_encoding: ContentEncoding::UTF_8, deleted: false,
26
- operation: Operation::UPDATE, mode: nil)
82
+ operation: Operation::UPDATE, mode: nil, job_directory: nil)
27
83
  @name = name
28
84
  @content = content
29
- @directory = clean_directory(directory)
85
+ @directory = T.let(clean_directory(directory), String)
30
86
  @symlink_target = symlink_target
31
87
  @support_file = support_file
32
88
  @vendored_file = vendored_file
33
89
  @content_encoding = content_encoding
34
90
  @operation = operation
91
+ @job_directory = job_directory
35
92
 
36
93
  # Make deleted override the operation. Deleted is kept when operation
37
94
  # was introduced to keep compatibility with downstream dependants.
@@ -45,7 +102,7 @@ module Dependabot
45
102
  @type = type
46
103
 
47
104
  begin
48
- @mode = File.stat(realpath).mode.to_s(8)
105
+ @mode = T.let(File.stat(realpath).mode.to_s(8), T.nilable(String))
49
106
  rescue StandardError
50
107
  @mode = mode
51
108
  end
@@ -56,6 +113,7 @@ module Dependabot
56
113
  raise "Only symlinked files must specify a target!" if symlink_target
57
114
  end
58
115
 
116
+ sig { returns(T::Hash[String, T.untyped]) }
59
117
  def to_h
60
118
  details = {
61
119
  "name" => name,
@@ -69,66 +127,83 @@ module Dependabot
69
127
  "mode" => mode
70
128
  }
71
129
 
130
+ details["job_directory"] = job_directory if job_directory
72
131
  details["symlink_target"] = symlink_target if symlink_target
73
132
  details
74
133
  end
75
134
 
135
+ sig { returns(String) }
76
136
  def path
77
137
  Pathname.new(File.join(directory, name)).cleanpath.to_path
78
138
  end
79
139
 
140
+ sig { returns(String) }
80
141
  def realpath
81
142
  (symlink_target || path).sub(%r{^/}, "")
82
143
  end
83
144
 
145
+ sig { params(other: BasicObject).returns(T::Boolean) }
84
146
  def ==(other)
85
- return false unless other.instance_of?(self.class)
86
-
87
- my_hash = to_h.reject { |k| k == "support_file" }
88
- their_hash = other.to_h.reject { |k| k == "support_file" }
89
- my_hash == their_hash
147
+ case other
148
+ when DependencyFile
149
+ my_hash = to_h.reject { |k| k == "support_file" }
150
+ their_hash = other.to_h.reject { |k| k == "support_file" }
151
+ my_hash == their_hash
152
+ else
153
+ false
154
+ end
90
155
  end
91
156
 
157
+ sig { returns(Integer) }
92
158
  def hash
93
159
  to_h.hash
94
160
  end
95
161
 
162
+ sig { params(other: BasicObject).returns(T::Boolean) }
96
163
  def eql?(other)
97
164
  self == other
98
165
  end
99
166
 
167
+ sig { returns(T::Boolean) }
100
168
  def support_file?
101
169
  @support_file
102
170
  end
103
171
 
172
+ sig { returns(T::Boolean) }
104
173
  def vendored_file?
105
174
  @vendored_file
106
175
  end
107
176
 
177
+ sig { returns(T::Boolean) }
108
178
  def deleted
109
179
  @operation == Operation::DELETE
110
180
  end
111
181
 
182
+ sig { params(deleted: T::Boolean).void }
112
183
  def deleted=(deleted)
113
184
  @operation = deleted ? Operation::DELETE : Operation::UPDATE
114
185
  end
115
186
 
187
+ sig { returns(T::Boolean) }
116
188
  def deleted?
117
189
  deleted
118
190
  end
119
191
 
192
+ sig { returns(T::Boolean) }
120
193
  def binary?
121
194
  content_encoding == ContentEncoding::BASE64
122
195
  end
123
196
 
197
+ sig { returns(String) }
124
198
  def decoded_content
125
- return Base64.decode64(content) if binary?
199
+ return Base64.decode64(T.must(content)) if binary?
126
200
 
127
- content
201
+ T.must(content)
128
202
  end
129
203
 
130
204
  private
131
205
 
206
+ sig { params(directory: String).returns(String) }
132
207
  def clean_directory(directory)
133
208
  # Directory should always start with a `/`
134
209
  directory.sub(%r{^/*}, "/")
@@ -1,23 +1,41 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/experiments"
5
5
  require "dependabot/config/ignore_condition"
6
6
  require "dependabot/logger"
7
7
 
8
+ require "sorbet-runtime"
8
9
  require "wildcard_matcher"
9
10
  require "yaml"
10
11
 
11
12
  module Dependabot
12
13
  class DependencyGroup
13
- attr_reader :name, :rules, :dependencies
14
+ extend T::Sig
14
15
 
16
+ sig { returns(String) }
17
+ attr_reader :name
18
+
19
+ sig { returns(T::Hash[String, T.any(String, T::Array[String])]) }
20
+ attr_reader :rules
21
+
22
+ sig { returns(T::Array[Dependabot::Dependency]) }
23
+ attr_reader :dependencies
24
+
25
+ sig do
26
+ params(
27
+ name: String,
28
+ rules: T::Hash[String, T.untyped]
29
+ )
30
+ .void
31
+ end
15
32
  def initialize(name:, rules:)
16
33
  @name = name
17
34
  @rules = rules
18
- @dependencies = []
35
+ @dependencies = T.let([], T::Array[Dependabot::Dependency])
19
36
  end
20
37
 
38
+ sig { params(dependency: Dependabot::Dependency).returns(T::Boolean) }
21
39
  def contains?(dependency)
22
40
  return true if @dependencies.include?(dependency)
23
41
  return false if matches_excluded_pattern?(dependency.name)
@@ -25,11 +43,13 @@ module Dependabot
25
43
  matches_pattern?(dependency.name) && matches_dependency_type?(dependency)
26
44
  end
27
45
 
46
+ sig { returns(T::Hash[String, String]) }
28
47
  def to_h
29
48
  { "name" => name }
30
49
  end
31
50
 
32
51
  # Provides a debug utility to view the group as it appears in the config file.
52
+ sig { returns(String) }
33
53
  def to_config_yaml
34
54
  {
35
55
  "groups" => { name => rules }
@@ -38,18 +58,21 @@ module Dependabot
38
58
 
39
59
  private
40
60
 
61
+ sig { params(dependency_name: String).returns(T::Boolean) }
41
62
  def matches_pattern?(dependency_name)
42
63
  return true unless rules.key?("patterns") # If no patterns are defined, we pass this check by default
43
64
 
44
- rules["patterns"].any? { |rule| WildcardMatcher.match?(rule, dependency_name) }
65
+ T.unsafe(rules["patterns"]).any? { |rule| WildcardMatcher.match?(rule, dependency_name) }
45
66
  end
46
67
 
68
+ sig { params(dependency_name: String).returns(T::Boolean) }
47
69
  def matches_excluded_pattern?(dependency_name)
48
70
  return false unless rules.key?("exclude-patterns") # If there are no exclusions, fail by default
49
71
 
50
- rules["exclude-patterns"].any? { |rule| WildcardMatcher.match?(rule, dependency_name) }
72
+ T.unsafe(rules["exclude-patterns"]).any? { |rule| WildcardMatcher.match?(rule, dependency_name) }
51
73
  end
52
74
 
75
+ sig { params(dependency: Dependabot::Dependency).returns(T::Boolean) }
53
76
  def matches_dependency_type?(dependency)
54
77
  return true unless rules.key?("dependency-type") # If no dependency-type is set, match by default
55
78
 
@@ -60,6 +83,7 @@ module Dependabot
60
83
  end
61
84
  end
62
85
 
86
+ sig { returns(T::Boolean) }
63
87
  def experimental_rules_enabled?
64
88
  Dependabot::Experiments.enabled?(:grouped_updates_experimental_rules)
65
89
  end