dependabot-common 0.335.0 → 0.337.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca29ec928a5e569aa377708755f29f998ca87ddb68ed2722a5171386427e3f87
4
- data.tar.gz: 206f507ef450d40f3a002187a7890dc5b5abc88c7d8df5e53a87a27a14aa9f71
3
+ metadata.gz: 5b0ffe5707059285fd1f9a5ec262e5bb5ee208edbc66bf448bab3bafb1777e2f
4
+ data.tar.gz: 8822c407c862de5043ac786b628a8640e977a2a806f5abc5b16cd2aebbcba0d1
5
5
  SHA512:
6
- metadata.gz: 3a3baf81472a1b7528fb6f95f9c5ed76f79186fd4aa442e073b2f0bc60e676186f592ab16a18f1f6bb747e652e522d0f1af2a7ac077a3dbce0d89001c001fc93
7
- data.tar.gz: 26a4aaa04570ec094267b7e2739a394fe4d279807ad03453ac6cec8c766d18cb3b13e73665923cf8e58ca64ab6fad7b8b8a20656a0feaa93b80bcdaed6119503
6
+ metadata.gz: 101633a5e8ee69f8b9da421b78ef56d080fa128574038f9ead3e66611e9411e12ae9e12ca71e0511a7be2ece9a586a061733aec9188b723acae48bef0c3dc226
7
+ data.tar.gz: be0d92563c07aa54897bef06002c76e4c8ee262a48e6dde7298afb7aace9b0a14854600e99486d47d39eb3eb0d06b110c57f408cc9e662ae0b68f92a588289c6
@@ -2,7 +2,7 @@
2
2
 
3
3
  Dependency graphers are used to convert a set of parsed dependencies into a data structure we can use to output the dependency graph of a project in a generic data structure based on GitHub's [Dependency submission API](https://docs.github.com/en/rest/dependency-graph/dependency-submission).
4
4
 
5
- We will expect each language Dependabot supports to implement a `Dependabot::DependencyGraphers` class in future, but for now any modules that do not implement a specific class fail over to a 'best effort' generic implementation that works in most cases.
5
+ We will expect each language Dependabot supports to implement a `Dependabot::DependencyGraphers` class in future, but for now any modules that do not implement a specific class fail over to a 'best effort' generic implementation.
6
6
 
7
7
  ## Public API
8
8
 
@@ -39,9 +39,9 @@ An example of a `.resolved_dependencies` hash for a Bundler project:
39
39
  }
40
40
  ```
41
41
 
42
- ## Writing a file fetcher for a new language
42
+ ## Writing a dependency grapher for a new language
43
43
 
44
- All new file fetchers should inherit from `Dependabot::DependencyGraphers::Base` and
44
+ All new dependency graphers should inherit from `Dependabot::DependencyGraphers::Base` and
45
45
  implement the following methods:
46
46
 
47
47
  | Method | Description |
@@ -52,3 +52,10 @@ implement the following methods:
52
52
 
53
53
  > [!WARNING]
54
54
  > While PURLs are preferred in all languages for `.fetch_subdependencies`, for languages where multiple versions of a single dependency are permitted they _must_ be provided to be precise.
55
+
56
+ ## Overriding file parser behaviour
57
+
58
+ In most cases, an ecosystem's file parser should provide us the dependency data we need to build the graph, but in some cases we may need to tweak this behaviour or experiment with alternative parsing strategies.
59
+
60
+ The `Dependabot::DependencyGraphers::Base` class provides the `prepare!` method as the hook that is called to generate the dependency list - if required this method can be redefined for a specific ecosystem to make
61
+ additional or alternative calls.
@@ -5,6 +5,21 @@ require "sorbet-runtime"
5
5
 
6
6
  module Dependabot
7
7
  module DependencyGraphers
8
+ # This is a small value class that specifies the information we expect to be returned for each
9
+ # dependency strictly.
10
+ class ResolvedDependency < T::ImmutableStruct
11
+ # A valid purl for the dependency, e.g. pkg:/npm/tunnel@0.0.6
12
+ const :package_url, String
13
+ # Is this a direct dependency?
14
+ const :direct, T::Boolean
15
+ # Is this a runtime dependency?
16
+ const :runtime, T::Boolean
17
+ # A list of packages this dependency itself depends on if direct is false. Note that:
18
+ # - a valid purl for the parent dependency is preferable
19
+ # - the package name is acceptable **unless the ecosystem allows multiple versions of a package to be used**
20
+ const :dependencies, T::Array[String]
21
+ end
22
+
8
23
  class Base
9
24
  extend T::Sig
10
25
  extend T::Helpers
@@ -13,23 +28,16 @@ module Dependabot
13
28
 
14
29
  abstract!
15
30
 
16
- # TODO(brrygrdn): Inject the Dependency parser instead of pre-parsed `dependencies`
17
- #
18
- # Semantically it makes sense for the grapher to wrap the parser as a higher order function, but we already know
19
- # that some package managers will require extra native commands before, after or during the parse - in extreme
20
- # cases it may make sense to use an alternative parser that is more optimal.
21
- #
22
- # By injecting the parser, this allows the ecosystem to encapsulate the package manager specifics without the
23
- # executor needing to manage parser modes / feature flags.
31
+ sig { returns(T::Boolean) }
32
+ attr_reader :prepared
33
+
24
34
  sig do
25
- params(
26
- dependency_files: T::Array[Dependabot::DependencyFile],
27
- dependencies: T::Array[Dependabot::Dependency]
28
- ).void
35
+ params(file_parser: Dependabot::FileParsers::Base).void
29
36
  end
30
- def initialize(dependency_files:, dependencies:)
31
- @dependency_files = dependency_files
32
- @dependencies = dependencies
37
+ def initialize(file_parser:)
38
+ @file_parser = file_parser
39
+ @dependencies = T.let([], T::Array[Dependabot::Dependency])
40
+ @prepared = T.let(false, T::Boolean)
33
41
  end
34
42
 
35
43
  # Each grapher must implement a heuristic to determine which dependency file should be used as the owner
@@ -40,21 +48,38 @@ module Dependabot
40
48
  sig { abstract.returns(Dependabot::DependencyFile) }
41
49
  def relevant_dependency_file; end
42
50
 
43
- sig { returns(T::Hash[Symbol, T.untyped]) }
51
+ # A grapher may override this method if it needs to perform extra steps around the normal file parser for
52
+ # the ecosystem.
53
+ sig { void }
54
+ def prepare!
55
+ @dependencies = @file_parser.parse
56
+ @prepared = true
57
+ end
58
+
59
+ sig { returns(T::Hash[String, ResolvedDependency]) }
44
60
  def resolved_dependencies
61
+ prepare! unless prepared
62
+
45
63
  @dependencies.each_with_object({}) do |dep, resolved|
46
- resolved[dep.name] = {
64
+ resolved[dep.name] = ResolvedDependency.new(
47
65
  package_url: build_purl(dep),
48
- relationship: relationship_for(dep),
49
- scope: scope_for(dep),
50
- dependencies: fetch_subdependencies(dep),
51
- metadata: {}
52
- }
66
+ direct: dep.top_level?,
67
+ runtime: dep.production?,
68
+ dependencies: fetch_subdependencies(dep)
69
+ )
53
70
  end
54
71
  end
55
72
 
56
73
  private
57
74
 
75
+ sig { returns(Dependabot::FileParsers::Base) }
76
+ attr_reader :file_parser
77
+
78
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
79
+ def dependency_files
80
+ file_parser.dependency_files
81
+ end
82
+
58
83
  # Each grapher is expected to implement a method to look up the parents of a given dependency.
59
84
  #
60
85
  # The strategy that should be used is highly dependent on the ecosystem, in some cases the parser
@@ -95,24 +120,6 @@ module Dependabot
95
120
  version: purl_version_for(dependency)
96
121
  )
97
122
  end
98
-
99
- sig { params(dep: Dependabot::Dependency).returns(String) }
100
- def relationship_for(dep)
101
- if dep.top_level?
102
- "direct"
103
- else
104
- "indirect"
105
- end
106
- end
107
-
108
- sig { params(dependency: Dependabot::Dependency).returns(String) }
109
- def scope_for(dependency)
110
- if dependency.production?
111
- "runtime"
112
- else
113
- "development"
114
- end
115
- end
116
123
  end
117
124
  end
118
125
  end
@@ -25,7 +25,7 @@ module Dependabot
25
25
 
26
26
  sig { returns(T::Array[Dependabot::DependencyFile]) }
27
27
  def filtered_dependency_files
28
- @dependency_files.reject { |f| f.support_file? || f.vendored_file? }
28
+ dependency_files.reject { |f| f.support_file? || f.vendored_file? }
29
29
  end
30
30
 
31
31
  # Our generic strategy is to check if the parser has attached a `depends_on` key to the Dependency's
data/lib/dependabot.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Dependabot
5
- VERSION = "0.335.0"
5
+ VERSION = "0.337.0"
6
6
  end
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.335.0
4
+ version: 0.337.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -630,7 +630,7 @@ licenses:
630
630
  - MIT
631
631
  metadata:
632
632
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
633
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.335.0
633
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.337.0
634
634
  rdoc_options: []
635
635
  require_paths:
636
636
  - lib