dependabot-common 0.235.0 → 0.237.0

Sign up to get free protection for your applications and to get access to all the features.
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