dependabot-common 0.334.0 → 0.336.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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dependabot/clients/azure.rb +108 -60
  3. data/lib/dependabot/clients/bitbucket.rb +17 -4
  4. data/lib/dependabot/clients/codecommit.rb +17 -7
  5. data/lib/dependabot/config/file.rb +31 -28
  6. data/lib/dependabot/dependency.rb +18 -7
  7. data/lib/dependabot/dependency_file.rb +17 -6
  8. data/lib/dependabot/dependency_graphers/README.md +61 -0
  9. data/lib/dependabot/dependency_graphers/base.rb +129 -0
  10. data/lib/dependabot/dependency_graphers/generic.rb +76 -0
  11. data/lib/dependabot/dependency_graphers.rb +33 -0
  12. data/lib/dependabot/file_fetchers/base.rb +11 -4
  13. data/lib/dependabot/file_filtering.rb +9 -5
  14. data/lib/dependabot/file_parsers/base.rb +8 -2
  15. data/lib/dependabot/file_updaters/artifact_updater.rb +1 -0
  16. data/lib/dependabot/git_commit_checker.rb +17 -10
  17. data/lib/dependabot/git_metadata_fetcher.rb +4 -2
  18. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +6 -2
  19. data/lib/dependabot/metadata_finders/base/changelog_pruner.rb +4 -2
  20. data/lib/dependabot/notices.rb +7 -3
  21. data/lib/dependabot/package/release_cooldown_options.rb +6 -2
  22. data/lib/dependabot/pull_request_creator/azure.rb +15 -3
  23. data/lib/dependabot/pull_request_creator/bitbucket.rb +13 -3
  24. data/lib/dependabot/pull_request_creator/branch_namer/base.rb +8 -2
  25. data/lib/dependabot/pull_request_creator/branch_namer/dependency_group_strategy.rb +15 -5
  26. data/lib/dependabot/pull_request_creator/branch_namer/multi_ecosystem_strategy.rb +15 -5
  27. data/lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb +11 -7
  28. data/lib/dependabot/pull_request_creator/branch_namer.rb +11 -2
  29. data/lib/dependabot/pull_request_creator/codecommit.rb +20 -7
  30. data/lib/dependabot/pull_request_creator/commit_signer.rb +10 -4
  31. data/lib/dependabot/pull_request_creator/github.rb +18 -5
  32. data/lib/dependabot/pull_request_creator/gitlab.rb +16 -4
  33. data/lib/dependabot/pull_request_creator/labeler.rb +35 -19
  34. data/lib/dependabot/pull_request_creator/message_builder/issue_linker.rb +15 -10
  35. data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +7 -2
  36. data/lib/dependabot/pull_request_creator/message_builder.rb +16 -6
  37. data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +7 -2
  38. data/lib/dependabot/pull_request_creator.rb +31 -12
  39. data/lib/dependabot/pull_request_updater/azure.rb +9 -2
  40. data/lib/dependabot/pull_request_updater/github.rb +10 -3
  41. data/lib/dependabot/pull_request_updater/gitlab.rb +9 -2
  42. data/lib/dependabot/pull_request_updater.rb +11 -4
  43. data/lib/dependabot/security_advisory.rb +12 -6
  44. data/lib/dependabot/shared_helpers.rb +36 -19
  45. data/lib/dependabot/source.rb +14 -4
  46. data/lib/dependabot/update_checkers/base.rb +13 -5
  47. data/lib/dependabot.rb +1 -1
  48. metadata +16 -12
@@ -0,0 +1,129 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Dependabot
7
+ module DependencyGraphers
8
+ class Base
9
+ extend T::Sig
10
+ extend T::Helpers
11
+
12
+ PURL_TEMPLATE = "pkg:%<type>s/%<name>s%<version>s"
13
+
14
+ abstract!
15
+
16
+ sig { returns(T::Boolean) }
17
+ attr_reader :prepared
18
+
19
+ sig do
20
+ params(file_parser: Dependabot::FileParsers::Base).void
21
+ end
22
+ def initialize(file_parser:)
23
+ @file_parser = file_parser
24
+ @dependencies = T.let([], T::Array[Dependabot::Dependency])
25
+ @prepared = T.let(false, T::Boolean)
26
+ end
27
+
28
+ # Each grapher must implement a heuristic to determine which dependency file should be used as the owner
29
+ # of the resolved_dependencies.
30
+ #
31
+ # Conventionally, this is the lockfile for the file set but some parses may only include the manifest
32
+ # so this method should take into account the correct priority based on which files were parsed.
33
+ sig { abstract.returns(Dependabot::DependencyFile) }
34
+ def relevant_dependency_file; end
35
+
36
+ # A grapher may override this method if it needs to perform extra steps around the normal file parser for
37
+ # the ecosystem.
38
+ sig { void }
39
+ def prepare!
40
+ @dependencies = @file_parser.parse
41
+ @prepared = true
42
+ end
43
+
44
+ sig { returns(T::Hash[String, T.untyped]) }
45
+ def resolved_dependencies
46
+ prepare! unless prepared
47
+
48
+ @dependencies.each_with_object({}) do |dep, resolved|
49
+ resolved[dep.name] = {
50
+ package_url: build_purl(dep),
51
+ relationship: relationship_for(dep),
52
+ scope: scope_for(dep),
53
+ dependencies: fetch_subdependencies(dep),
54
+ metadata: {}
55
+ }
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ sig { returns(Dependabot::FileParsers::Base) }
62
+ attr_reader :file_parser
63
+
64
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
65
+ def dependency_files
66
+ file_parser.dependency_files
67
+ end
68
+
69
+ # Each grapher is expected to implement a method to look up the parents of a given dependency.
70
+ #
71
+ # The strategy that should be used is highly dependent on the ecosystem, in some cases the parser
72
+ # may be able to set this information in the dependency.metadata collection, in others the grapher
73
+ # will need to run additional native commands.
74
+ sig { abstract.params(dependency: Dependabot::Dependency).returns(T::Array[String]) }
75
+ def fetch_subdependencies(dependency); end
76
+
77
+ # Each grapher is expected to implement a method to map the various package managers it supports to
78
+ # the correct Package-URL type, see:
79
+ # https://github.com/package-url/purl-spec/blob/main/PURL-TYPES.rst
80
+ sig { abstract.params(dependency: Dependabot::Dependency).returns(String) }
81
+ def purl_pkg_for(dependency); end
82
+
83
+ # Our basic strategy is just to use the dependency name, but specific graphers may need to override this
84
+ # to meet formal specifics
85
+ sig { params(dependency: Dependabot::Dependency).returns(String) }
86
+ def purl_name_for(dependency)
87
+ dependency.name
88
+ end
89
+
90
+ # We should ensure we don't include an `@` if there isn't a resolved version, but some ecosystems
91
+ # specifically include the `v` or allow certain prefixes
92
+ sig { params(dependency: Dependabot::Dependency).returns(String) }
93
+ def purl_version_for(dependency)
94
+ return "" unless dependency.version
95
+
96
+ "@#{dependency.version}"
97
+ end
98
+
99
+ # Generate a purl for the provided Dependency object
100
+ sig { params(dependency: Dependabot::Dependency).returns(String) }
101
+ def build_purl(dependency)
102
+ format(
103
+ PURL_TEMPLATE,
104
+ type: purl_pkg_for(dependency),
105
+ name: purl_name_for(dependency),
106
+ version: purl_version_for(dependency)
107
+ )
108
+ end
109
+
110
+ sig { params(dep: Dependabot::Dependency).returns(String) }
111
+ def relationship_for(dep)
112
+ if dep.top_level?
113
+ "direct"
114
+ else
115
+ "indirect"
116
+ end
117
+ end
118
+
119
+ sig { params(dependency: Dependabot::Dependency).returns(String) }
120
+ def scope_for(dependency)
121
+ if dependency.production?
122
+ "runtime"
123
+ else
124
+ "development"
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,76 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ require "dependabot/dependency_graphers/base"
7
+
8
+ module Dependabot
9
+ module DependencyGraphers
10
+ class Generic < Base
11
+ extend T::Sig
12
+ extend T::Helpers
13
+
14
+ # Our generic strategy is to use the right-most file in the dependency file list on the
15
+ # assumption that this is normally the lockfile.
16
+ #
17
+ # This isn't a durable strategy but it's good enough to allow most ecosystems to 'just work'
18
+ # as we roll out ecosystem-specific graphers.
19
+ sig { override.returns(Dependabot::DependencyFile) }
20
+ def relevant_dependency_file
21
+ T.must(filtered_dependency_files.last)
22
+ end
23
+
24
+ private
25
+
26
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
27
+ def filtered_dependency_files
28
+ dependency_files.reject { |f| f.support_file? || f.vendored_file? }
29
+ end
30
+
31
+ # Our generic strategy is to check if the parser has attached a `depends_on` key to the Dependency's
32
+ # metadata, but in most cases this will be empty.
33
+ sig { override.params(dependency: Dependabot::Dependency).returns(T::Array[String]) }
34
+ def fetch_subdependencies(dependency)
35
+ dependency.metadata.fetch(:depends_on, [])
36
+ end
37
+
38
+ # TODO: Delegate this to ecosystem-specific base classes
39
+ sig { override.params(dependency: Dependabot::Dependency).returns(String) }
40
+ def purl_pkg_for(dependency)
41
+ case dependency.package_manager
42
+ when "bundler"
43
+ "gem"
44
+ when "npm_and_yarn", "bun"
45
+ "npm"
46
+ when "maven", "gradle"
47
+ "maven"
48
+ when "pip", "uv"
49
+ "pypi"
50
+ when "cargo"
51
+ "cargo"
52
+ when "hex"
53
+ "hex"
54
+ when "composer"
55
+ "composer"
56
+ when "nuget"
57
+ "nuget"
58
+ when "go_modules"
59
+ "golang"
60
+ when "docker"
61
+ "docker"
62
+ when "github_actions"
63
+ "github"
64
+ when "terraform"
65
+ "terraform"
66
+ when "pub"
67
+ "pub"
68
+ when "elm"
69
+ "elm"
70
+ else
71
+ "generic"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,33 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ require "dependabot/dependency_graphers/base"
7
+ require "dependabot/dependency_graphers/generic"
8
+
9
+ module Dependabot
10
+ module DependencyGraphers
11
+ extend T::Sig
12
+
13
+ @graphers = T.let({}, T::Hash[String, T.class_of(Base)])
14
+
15
+ sig { params(package_manager: String).returns(T.class_of(Base)) }
16
+ def self.for_package_manager(package_manager)
17
+ grapher = @graphers[package_manager]
18
+ return grapher if grapher
19
+
20
+ # If an ecosystem has not defined its own graphing strategy, then we use
21
+ # a best-effort generic while we are rolling out graphing capabilities.
22
+ #
23
+ # This approach allows us to assess the quality of data from the ecosystem's
24
+ # parser and triage the scope of work to implement the non-generic class.
25
+ Generic
26
+ end
27
+
28
+ sig { params(package_manager: String, grapher: T.class_of(Base)).void }
29
+ def self.register(package_manager, grapher)
30
+ @graphers[package_manager] = grapher
31
+ end
32
+ end
33
+ end
@@ -307,8 +307,12 @@ module Dependabot
307
307
  )
308
308
  .returns(T::Array[T.untyped])
309
309
  end
310
- def repo_contents(dir: ".", ignore_base_directory: false,
311
- raise_errors: true, fetch_submodules: false)
310
+ def repo_contents(
311
+ dir: ".",
312
+ ignore_base_directory: false,
313
+ raise_errors: true,
314
+ fetch_submodules: false
315
+ )
312
316
  dir = File.join(directory, dir) unless ignore_base_directory
313
317
  path = Pathname.new(dir).cleanpath.to_path.gsub(%r{^/*}, "")
314
318
 
@@ -316,8 +320,11 @@ module Dependabot
316
320
  @repo_contents[dir.to_s] ||= if repo_contents_path
317
321
  _cloned_repo_contents(path)
318
322
  else
319
- _fetch_repo_contents(path, raise_errors: raise_errors,
320
- fetch_submodules: fetch_submodules)
323
+ _fetch_repo_contents(
324
+ path,
325
+ raise_errors: raise_errors,
326
+ fetch_submodules: fetch_submodules
327
+ )
321
328
  end
322
329
  end
323
330
 
@@ -29,8 +29,10 @@ module Dependabot
29
29
  return true if normalized_path == pattern || normalized_path == normalized_pattern
30
30
 
31
31
  # Directory prefix match: check if path is inside an excluded directory
32
- normalized_path.start_with?("#{pattern}#{File::SEPARATOR}",
33
- "#{normalized_pattern}#{File::SEPARATOR}")
32
+ normalized_path.start_with?(
33
+ "#{pattern}#{File::SEPARATOR}",
34
+ "#{normalized_pattern}#{File::SEPARATOR}"
35
+ )
34
36
  end
35
37
 
36
38
  # Check for recursive pattern matches (patterns ending with /**)
@@ -81,9 +83,11 @@ module Dependabot
81
83
 
82
84
  # Helper method to check if a file path should be excluded
83
85
  sig do
84
- params(path: String,
85
- context: String,
86
- exclude_paths: T.nilable(T::Array[String])).returns(T::Boolean)
86
+ params(
87
+ path: String,
88
+ context: String,
89
+ exclude_paths: T.nilable(T::Array[String])
90
+ ).returns(T::Boolean)
87
91
  end
88
92
  def self.should_exclude_path?(path, context, exclude_paths)
89
93
  return false unless Dependabot::Experiments.enabled?(:enable_exclude_paths_subdirectory_manifest_files)
@@ -39,8 +39,14 @@ module Dependabot
39
39
  )
40
40
  .void
41
41
  end
42
- def initialize(dependency_files:, source:, repo_contents_path: nil,
43
- credentials: [], reject_external_code: false, options: {})
42
+ def initialize(
43
+ dependency_files:,
44
+ source:,
45
+ repo_contents_path: nil,
46
+ credentials: [],
47
+ reject_external_code: false,
48
+ options: {}
49
+ )
44
50
  @dependency_files = dependency_files
45
51
  @repo_contents_path = repo_contents_path
46
52
  @credentials = credentials
@@ -82,6 +82,7 @@ module Dependabot
82
82
 
83
83
  sig { returns(T.nilable(String)) }
84
84
  attr_reader :repo_contents_path
85
+
85
86
  sig { returns(T.nilable(String)) }
86
87
  attr_reader :target_directory
87
88
 
@@ -38,9 +38,14 @@ module Dependabot
38
38
  )
39
39
  .void
40
40
  end
41
- def initialize(dependency:, credentials:,
42
- ignored_versions: [], raise_on_ignored: false,
43
- consider_version_branches_pinned: false, dependency_source_details: nil)
41
+ def initialize(
42
+ dependency:,
43
+ credentials:,
44
+ ignored_versions: [],
45
+ raise_on_ignored: false,
46
+ consider_version_branches_pinned: false,
47
+ dependency_source_details: nil
48
+ )
44
49
  @dependency = dependency
45
50
  @credentials = credentials
46
51
  @ignored_versions = ignored_versions
@@ -102,13 +107,15 @@ module Dependabot
102
107
 
103
108
  sig { returns(Excon::Response) }
104
109
  def ref_details_for_pinned_ref
105
- T.must(T.let(
106
- GitMetadataFetcher.new(
107
- url: dependency.source_details&.fetch(:url, nil),
108
- credentials: credentials
109
- ).ref_details_for_pinned_ref(ref_pinned),
110
- T.nilable(Excon::Response)
111
- ))
110
+ T.must(
111
+ T.let(
112
+ GitMetadataFetcher.new(
113
+ url: dependency.source_details&.fetch(:url, nil),
114
+ credentials: credentials
115
+ ).ref_details_for_pinned_ref(ref_pinned),
116
+ T.nilable(Excon::Response)
117
+ )
118
+ )
112
119
  end
113
120
 
114
121
  sig { params(ref: String).returns(T::Boolean) }
@@ -97,8 +97,10 @@ module Dependabot
97
97
 
98
98
  sig { returns(T::Array[GitTagWithDetail]) }
99
99
  def refs_for_tag_with_detail
100
- @refs_for_tag_with_detail ||= T.let(parse_refs_for_tag_with_detail,
101
- T.nilable(T::Array[GitTagWithDetail]))
100
+ @refs_for_tag_with_detail ||= T.let(
101
+ parse_refs_for_tag_with_detail,
102
+ T.nilable(T::Array[GitTagWithDetail])
103
+ )
102
104
  end
103
105
 
104
106
  sig { returns(T::Array[GitTagWithDetail]) }
@@ -48,8 +48,12 @@ module Dependabot
48
48
  )
49
49
  .void
50
50
  end
51
- def initialize(source:, dependency:, credentials:,
52
- suggested_changelog_url: nil)
51
+ def initialize(
52
+ source:,
53
+ dependency:,
54
+ credentials:,
55
+ suggested_changelog_url: nil
56
+ )
53
57
  @source = source
54
58
  @dependency = dependency
55
59
  @credentials = credentials
@@ -47,8 +47,10 @@ module Dependabot
47
47
  if T.must(old_version_changelog_line) < T.must(new_version_changelog_line)
48
48
  Range.new(old_version_changelog_line, -1)
49
49
  else
50
- Range.new(new_version_changelog_line,
51
- T.must(old_version_changelog_line) - 1)
50
+ Range.new(
51
+ new_version_changelog_line,
52
+ T.must(old_version_changelog_line) - 1
53
+ )
52
54
  end
53
55
  elsif old_version_changelog_line
54
56
  return if T.must(old_version_changelog_line).zero?
@@ -40,9 +40,13 @@ module Dependabot
40
40
  ).void
41
41
  end
42
42
  def initialize(
43
- mode:, type:, package_manager_name:,
44
- title: "", description: "",
45
- show_in_pr: false, show_alert: false
43
+ mode:,
44
+ type:,
45
+ package_manager_name:,
46
+ title: "",
47
+ description: "",
48
+ show_in_pr: false,
49
+ show_alert: false
46
50
  )
47
51
  @mode = mode
48
52
  @type = type
@@ -19,8 +19,12 @@ module Dependabot
19
19
  ).void
20
20
  end
21
21
  def initialize(
22
- default_days: 0, semver_major_days: 0, semver_minor_days: 0, semver_patch_days: 0,
23
- include: [], exclude: []
22
+ default_days: 0,
23
+ semver_major_days: 0,
24
+ semver_minor_days: 0,
25
+ semver_patch_days: 0,
26
+ include: [],
27
+ exclude: []
24
28
  )
25
29
  default_days ||= 0
26
30
  semver_major_days ||= 0
@@ -74,9 +74,21 @@ module Dependabot
74
74
  )
75
75
  .void
76
76
  end
77
- def initialize(source:, branch_name:, base_commit:, credentials:,
78
- files:, commit_message:, pr_description:, pr_name:,
79
- author_details:, labeler:, reviewers: nil, assignees: nil, work_item: nil)
77
+ def initialize(
78
+ source:,
79
+ branch_name:,
80
+ base_commit:,
81
+ credentials:,
82
+ files:,
83
+ commit_message:,
84
+ pr_description:,
85
+ pr_name:,
86
+ author_details:,
87
+ labeler:,
88
+ reviewers: nil,
89
+ assignees: nil,
90
+ work_item: nil
91
+ )
80
92
  @source = source
81
93
  @branch_name = branch_name
82
94
  @base_commit = base_commit
@@ -65,9 +65,19 @@ module Dependabot
65
65
  )
66
66
  .void
67
67
  end
68
- def initialize(source:, branch_name:, base_commit:, credentials:,
69
- files:, commit_message:, pr_description:, pr_name:,
70
- author_details:, labeler: nil, work_item: nil)
68
+ def initialize(
69
+ source:,
70
+ branch_name:,
71
+ base_commit:,
72
+ credentials:,
73
+ files:,
74
+ commit_message:,
75
+ pr_description:,
76
+ pr_name:,
77
+ author_details:,
78
+ labeler: nil,
79
+ work_item: nil
80
+ )
71
81
  @source = source
72
82
  @branch_name = branch_name
73
83
  @base_commit = base_commit
@@ -38,8 +38,14 @@ module Dependabot
38
38
  )
39
39
  .void
40
40
  end
41
- def initialize(dependencies:, files:, target_branch:, separator: "/",
42
- prefix: "dependabot", max_length: nil)
41
+ def initialize(
42
+ dependencies:,
43
+ files:,
44
+ target_branch:,
45
+ separator: "/",
46
+ prefix: "dependabot",
47
+ max_length: nil
48
+ )
43
49
  @dependencies = dependencies
44
50
  @files = files
45
51
  @target_branch = target_branch
@@ -23,8 +23,16 @@ module Dependabot
23
23
  )
24
24
  .void
25
25
  end
26
- def initialize(dependencies:, files:, target_branch:, dependency_group:, includes_security_fixes:,
27
- separator: "/", prefix: "dependabot", max_length: nil)
26
+ def initialize(
27
+ dependencies:,
28
+ files:,
29
+ target_branch:,
30
+ dependency_group:,
31
+ includes_security_fixes:,
32
+ separator: "/",
33
+ prefix: "dependabot",
34
+ max_length: nil
35
+ )
28
36
  super(
29
37
  dependencies: dependencies,
30
38
  files: files,
@@ -76,9 +84,11 @@ module Dependabot
76
84
  sig { returns(T.nilable(String)) }
77
85
  def dependency_digest
78
86
  @dependency_digest ||= T.let(
79
- Digest::MD5.hexdigest(dependencies.map do |dependency|
80
- "#{dependency.name}-#{dependency.removed? ? 'removed' : dependency.version}"
81
- end.sort.join(",")).slice(0, 10),
87
+ Digest::MD5.hexdigest(
88
+ dependencies.map do |dependency|
89
+ "#{dependency.name}-#{dependency.removed? ? 'removed' : dependency.version}"
90
+ end.sort.join(",")
91
+ ).slice(0, 10),
82
92
  T.nilable(String)
83
93
  )
84
94
  end
@@ -23,8 +23,16 @@ module Dependabot
23
23
  )
24
24
  .void
25
25
  end
26
- def initialize(dependencies:, files:, target_branch:, includes_security_fixes:, multi_ecosystem_name:,
27
- separator: "/", prefix: "dependabot", max_length: nil)
26
+ def initialize(
27
+ dependencies:,
28
+ files:,
29
+ target_branch:,
30
+ includes_security_fixes:,
31
+ multi_ecosystem_name:,
32
+ separator: "/",
33
+ prefix: "dependabot",
34
+ max_length: nil
35
+ )
28
36
  super(
29
37
  dependencies: dependencies,
30
38
  files: files,
@@ -68,9 +76,11 @@ module Dependabot
68
76
  sig { returns(T.nilable(String)) }
69
77
  def dependency_digest
70
78
  @dependency_digest ||= T.let(
71
- Digest::MD5.hexdigest(dependencies.map do |dependency|
72
- "#{dependency.name}-#{dependency.removed? ? 'removed' : dependency.version}"
73
- end.sort.join(",")).slice(0, 10),
79
+ Digest::MD5.hexdigest(
80
+ dependencies.map do |dependency|
81
+ "#{dependency.name}-#{dependency.removed? ? 'removed' : dependency.version}"
82
+ end.sort.join(",")
83
+ ).slice(0, 10),
74
84
  T.nilable(String)
75
85
  )
76
86
  end
@@ -75,10 +75,12 @@ module Dependabot
75
75
  sig { returns(String) }
76
76
  def property_name
77
77
  @property_name ||=
78
- T.let(T.must(dependencies.first).requirements
79
- .find { |r| r.dig(:metadata, :property_name) }
80
- &.dig(:metadata, :property_name),
81
- T.nilable(String))
78
+ T.let(
79
+ T.must(dependencies.first).requirements
80
+ .find { |r| r.dig(:metadata, :property_name) }
81
+ &.dig(:metadata, :property_name),
82
+ T.nilable(String)
83
+ )
82
84
 
83
85
  raise "No property name!" unless @property_name
84
86
 
@@ -215,9 +217,11 @@ module Dependabot
215
217
  sig { returns(T.nilable(String)) }
216
218
  def dependency_digest
217
219
  T.let(
218
- Digest::MD5.hexdigest(dependencies.map do |dependency|
219
- "#{dependency.name}-#{dependency.removed? ? 'removed' : dependency.version}"
220
- end.sort.join(",")).slice(0, 10),
220
+ Digest::MD5.hexdigest(
221
+ dependencies.map do |dependency|
222
+ "#{dependency.name}-#{dependency.removed? ? 'removed' : dependency.version}"
223
+ end.sort.join(",")
224
+ ).slice(0, 10),
221
225
  T.nilable(String)
222
226
  )
223
227
  end
@@ -56,8 +56,17 @@ module Dependabot
56
56
  )
57
57
  .void
58
58
  end
59
- def initialize(dependencies:, files:, target_branch:, dependency_group: nil, separator: "/",
60
- prefix: "dependabot", max_length: nil, includes_security_fixes: false, multi_ecosystem_name: nil)
59
+ def initialize(
60
+ dependencies:,
61
+ files:,
62
+ target_branch:,
63
+ dependency_group: nil,
64
+ separator: "/",
65
+ prefix: "dependabot",
66
+ max_length: nil,
67
+ includes_security_fixes: false,
68
+ multi_ecosystem_name: nil
69
+ )
61
70
  @dependencies = dependencies
62
71
  @files = files
63
72
  @target_branch = target_branch