dependabot-nuget 0.289.0 → 0.290.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/Directory.Packages.props +1 -1
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +7 -3
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +1 -1
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +26 -1
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +2 -1
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Run.cs +0 -6
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +3 -1
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +24 -9
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +0 -13
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/RequirementConverter.cs +17 -0
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Advisory.cs +13 -0
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/AllowedUpdate.cs +18 -1
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/CommitOptions.cs +8 -0
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Condition.cs +19 -0
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyGroup.cs +8 -0
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/GroupPullRequest.cs +9 -0
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +13 -10
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PullRequest.cs +11 -0
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/RequirementsUpdateStrategy.cs +15 -0
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +24 -4
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/VersionConverter.cs +19 -0
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +2 -1
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +13 -12
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/JsonHelper.cs +2 -0
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProjectHelper.cs +2 -2
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +5 -2
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.DotNetToolsJson.cs +45 -1
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.GlobalJson.cs +35 -1
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +0 -4
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +85 -0
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +7 -31
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +340 -0
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryDirectory.cs +18 -7
  35. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackagesConfigUpdaterTests.cs +24 -0
  36. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +0 -12
  37. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DotNetTools.cs +84 -0
  38. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs +66 -0
  39. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +55 -0
  40. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +0 -6
  41. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +557 -713
  42. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/PathHelperTests.cs +2 -2
  43. data/lib/dependabot/nuget/analysis/analysis_json_reader.rb +1 -1
  44. data/lib/dependabot/nuget/analysis/dependency_analysis.rb +3 -3
  45. data/lib/dependabot/nuget/discovery/dependency_details.rb +10 -3
  46. data/lib/dependabot/nuget/discovery/dependency_file_discovery.rb +8 -12
  47. data/lib/dependabot/nuget/discovery/discovery_json_reader.rb +214 -29
  48. data/lib/dependabot/nuget/discovery/project_discovery.rb +41 -8
  49. data/lib/dependabot/nuget/discovery/workspace_discovery.rb +14 -19
  50. data/lib/dependabot/nuget/file_fetcher.rb +2 -3
  51. data/lib/dependabot/nuget/file_parser.rb +2 -3
  52. data/lib/dependabot/nuget/file_updater.rb +13 -13
  53. data/lib/dependabot/nuget/native_helpers.rb +14 -5
  54. data/lib/dependabot/nuget/update_checker/requirements_updater.rb +23 -27
  55. data/lib/dependabot/nuget/update_checker.rb +116 -190
  56. metadata +18 -29
  57. data/lib/dependabot/nuget/discovery/directory_packages_props_discovery.rb +0 -43
  58. data/lib/dependabot/nuget/http_response_helpers.rb +0 -19
  59. data/lib/dependabot/nuget/native_discovery/native_dependency_details.rb +0 -102
  60. data/lib/dependabot/nuget/native_discovery/native_dependency_file_discovery.rb +0 -122
  61. data/lib/dependabot/nuget/native_discovery/native_discovery_json_reader.rb +0 -277
  62. data/lib/dependabot/nuget/native_discovery/native_evaluation_details.rb +0 -63
  63. data/lib/dependabot/nuget/native_discovery/native_project_discovery.rb +0 -104
  64. data/lib/dependabot/nuget/native_discovery/native_property_details.rb +0 -43
  65. data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +0 -61
  66. data/lib/dependabot/nuget/native_update_checker/native_requirements_updater.rb +0 -105
  67. data/lib/dependabot/nuget/native_update_checker/native_update_checker.rb +0 -214
  68. data/lib/dependabot/nuget/nuget_client.rb +0 -223
  69. data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +0 -116
  70. data/lib/dependabot/nuget/update_checker/dependency_finder.rb +0 -297
  71. data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +0 -221
  72. data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +0 -110
  73. data/lib/dependabot/nuget/update_checker/property_updater.rb +0 -196
  74. data/lib/dependabot/nuget/update_checker/repository_finder.rb +0 -466
  75. data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +0 -34
  76. data/lib/dependabot/nuget/update_checker/tfm_finder.rb +0 -30
  77. data/lib/dependabot/nuget/update_checker/version_finder.rb +0 -449
@@ -4,9 +4,9 @@
4
4
  require "dependabot/dependency_file"
5
5
  require "dependabot/file_updaters"
6
6
  require "dependabot/file_updaters/base"
7
- require "dependabot/nuget/native_discovery/native_dependency_details"
8
- require "dependabot/nuget/native_discovery/native_discovery_json_reader"
9
- require "dependabot/nuget/native_discovery/native_workspace_discovery"
7
+ require "dependabot/nuget/discovery/dependency_details"
8
+ require "dependabot/nuget/discovery/discovery_json_reader"
9
+ require "dependabot/nuget/discovery/workspace_discovery"
10
10
  require "dependabot/nuget/native_helpers"
11
11
  require "dependabot/shared_helpers"
12
12
  require "sorbet-runtime"
@@ -57,7 +57,7 @@ module Dependabot
57
57
  try_update_projects(dependency) || try_update_json(dependency)
58
58
  end
59
59
  updated_files = dependency_files.filter_map do |f|
60
- dependency_file_path = NativeDiscoveryJsonReader.dependency_file_path(
60
+ dependency_file_path = DiscoveryJsonReader.dependency_file_path(
61
61
  repo_contents_path: T.must(repo_contents_path),
62
62
  dependency_file: f
63
63
  )
@@ -97,7 +97,7 @@ module Dependabot
97
97
  # run update for each project file
98
98
  project_files.each do |project_file|
99
99
  project_dependencies = project_dependencies(project_file)
100
- dependency_file_path = NativeDiscoveryJsonReader.dependency_file_path(
100
+ dependency_file_path = DiscoveryJsonReader.dependency_file_path(
101
101
  repo_contents_path: T.must(repo_contents_path),
102
102
  dependency_file: project_file
103
103
  )
@@ -128,7 +128,7 @@ module Dependabot
128
128
 
129
129
  # We just need to feed the updater a project file, grab the first
130
130
  project_file = T.must(project_files.first)
131
- dependency_file_path = NativeDiscoveryJsonReader.dependency_file_path(
131
+ dependency_file_path = DiscoveryJsonReader.dependency_file_path(
132
132
  repo_contents_path: T.must(repo_contents_path),
133
133
  dependency_file: project_file
134
134
  )
@@ -168,13 +168,13 @@ module Dependabot
168
168
  @update_tooling_calls
169
169
  end
170
170
 
171
- sig { returns(T.nilable(NativeWorkspaceDiscovery)) }
171
+ sig { returns(T.nilable(WorkspaceDiscovery)) }
172
172
  def workspace
173
173
  dependency_file_paths = dependency_files.map do |f|
174
- NativeDiscoveryJsonReader.dependency_file_path(repo_contents_path: T.must(repo_contents_path),
175
- dependency_file: f)
174
+ DiscoveryJsonReader.dependency_file_path(repo_contents_path: T.must(repo_contents_path),
175
+ dependency_file: f)
176
176
  end
177
- NativeDiscoveryJsonReader.load_discovery_for_dependency_file_paths(dependency_file_paths).workspace_discovery
177
+ DiscoveryJsonReader.load_discovery_for_dependency_file_paths(dependency_file_paths).workspace_discovery
178
178
  end
179
179
 
180
180
  sig { params(project_file: Dependabot::DependencyFile).returns(T::Array[String]) }
@@ -182,7 +182,7 @@ module Dependabot
182
182
  workspace&.projects&.find { |p| p.file_path == project_file.name }&.referenced_project_paths || []
183
183
  end
184
184
 
185
- sig { params(project_file: Dependabot::DependencyFile).returns(T::Array[NativeDependencyDetails]) }
185
+ sig { params(project_file: Dependabot::DependencyFile).returns(T::Array[DependencyDetails]) }
186
186
  def project_dependencies(project_file)
187
187
  workspace&.projects&.find do |p|
188
188
  full_project_file_path = File.join(project_file.directory, project_file.name)
@@ -190,12 +190,12 @@ module Dependabot
190
190
  end&.dependencies || []
191
191
  end
192
192
 
193
- sig { returns(T::Array[NativeDependencyDetails]) }
193
+ sig { returns(T::Array[DependencyDetails]) }
194
194
  def global_json_dependencies
195
195
  workspace&.global_json&.dependencies || []
196
196
  end
197
197
 
198
- sig { returns(T::Array[NativeDependencyDetails]) }
198
+ sig { returns(T::Array[DependencyDetails]) }
199
199
  def dotnet_tools_json_dependencies
200
200
  workspace&.dotnet_tools_json&.dependencies || []
201
201
  end
@@ -81,6 +81,8 @@ module Dependabot
81
81
  fingerprint = [
82
82
  exe_path,
83
83
  "discover",
84
+ "--job-path",
85
+ "<job-path>",
84
86
  "--repo-root",
85
87
  "<repo-root>",
86
88
  "--workspace",
@@ -116,15 +118,17 @@ module Dependabot
116
118
  end
117
119
 
118
120
  sig do
119
- params(repo_root: String, discovery_file_path: String, dependency_file_path: String,
121
+ params(job_path: String, repo_root: String, discovery_file_path: String, dependency_file_path: String,
120
122
  analysis_folder_path: String).returns([String, String])
121
123
  end
122
- def self.get_nuget_analyze_tool_command(repo_root:, discovery_file_path:, dependency_file_path:,
124
+ def self.get_nuget_analyze_tool_command(job_path:, repo_root:, discovery_file_path:, dependency_file_path:,
123
125
  analysis_folder_path:)
124
126
  exe_path = File.join(native_helpers_root, "NuGetUpdater", "NuGetUpdater.Cli")
125
127
  command_parts = [
126
128
  exe_path,
127
129
  "analyze",
130
+ "--job-path",
131
+ job_path,
128
132
  "--repo-root",
129
133
  repo_root,
130
134
  "--discovery-file-path",
@@ -140,6 +144,8 @@ module Dependabot
140
144
  fingerprint = [
141
145
  exe_path,
142
146
  "analyze",
147
+ "--job-path",
148
+ "<job-path>",
143
149
  "--discovery-file-path",
144
150
  "<discovery-file-path>",
145
151
  "--dependency-file-path",
@@ -153,13 +159,14 @@ module Dependabot
153
159
 
154
160
  sig do
155
161
  params(
156
- repo_root: String, discovery_file_path: String, dependency_file_path: String,
162
+ job_path: String, repo_root: String, discovery_file_path: String, dependency_file_path: String,
157
163
  analysis_folder_path: String, credentials: T::Array[Dependabot::Credential]
158
164
  ).void
159
165
  end
160
- def self.run_nuget_analyze_tool(repo_root:, discovery_file_path:, dependency_file_path:,
166
+ def self.run_nuget_analyze_tool(job_path:, repo_root:, discovery_file_path:, dependency_file_path:,
161
167
  analysis_folder_path:, credentials:)
162
- (command, fingerprint) = get_nuget_analyze_tool_command(repo_root: repo_root,
168
+ (command, fingerprint) = get_nuget_analyze_tool_command(job_path: job_path,
169
+ repo_root: repo_root,
163
170
  discovery_file_path: discovery_file_path,
164
171
  dependency_file_path: dependency_file_path,
165
172
  analysis_folder_path: analysis_folder_path)
@@ -205,6 +212,8 @@ module Dependabot
205
212
  fingerprint = [
206
213
  exe_path,
207
214
  "update",
215
+ "--job-path",
216
+ "<job-path>",
208
217
  "--repo-root",
209
218
  "<repo-root>",
210
219
  "--solution-or-project",
@@ -9,6 +9,7 @@
9
9
  require "sorbet-runtime"
10
10
 
11
11
  require "dependabot/update_checkers/base"
12
+ require "dependabot/nuget/discovery/dependency_details"
12
13
  require "dependabot/nuget/version"
13
14
 
14
15
  module Dependabot
@@ -20,22 +21,18 @@ module Dependabot
20
21
  sig do
21
22
  params(
22
23
  requirements: T::Array[T::Hash[Symbol, T.untyped]],
23
- latest_version: T.nilable(T.any(String, Dependabot::Nuget::Version)),
24
- source_details: T.nilable(T::Hash[Symbol, T.untyped])
24
+ dependency_details: T.nilable(Dependabot::Nuget::DependencyDetails)
25
25
  )
26
26
  .void
27
27
  end
28
- def initialize(requirements:, latest_version:, source_details:)
28
+ def initialize(requirements:, dependency_details:)
29
29
  @requirements = requirements
30
- @source_details = source_details
31
- return unless latest_version
32
-
33
- @latest_version = T.let(version_class.new(latest_version), Dependabot::Nuget::Version)
30
+ @dependency_details = dependency_details
34
31
  end
35
32
 
36
33
  sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
37
34
  def updated_requirements
38
- return requirements unless latest_version
35
+ return requirements unless clean_version
39
36
 
40
37
  # NOTE: Order is important here. The FileUpdater needs the updated
41
38
  # requirement at index `i` to correspond to the previous requirement
@@ -53,13 +50,21 @@ module Dependabot
53
50
  # version
54
51
  req[:requirement].sub(
55
52
  /#{Nuget::Version::VERSION_PATTERN}/o,
56
- latest_version.to_s
53
+ clean_version.to_s
57
54
  )
58
55
  end
59
56
 
60
57
  next req if new_req == req.fetch(:requirement)
61
58
 
62
- req.merge(requirement: new_req, source: updated_source)
59
+ new_source = req[:source]&.dup
60
+ unless @dependency_details.nil?
61
+ new_source = {
62
+ type: "nuget_repo",
63
+ source_url: @dependency_details.info_url
64
+ }
65
+ end
66
+
67
+ req.merge({ requirement: new_req, source: new_source })
63
68
  end
64
69
  end
65
70
 
@@ -68,17 +73,18 @@ module Dependabot
68
73
  sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
69
74
  attr_reader :requirements
70
75
 
71
- sig { returns(T.nilable(Dependabot::Nuget::Version)) }
72
- attr_reader :latest_version
73
-
74
- sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
75
- attr_reader :source_details
76
-
77
76
  sig { returns(T.class_of(Dependabot::Nuget::Version)) }
78
77
  def version_class
79
78
  Dependabot::Nuget::Version
80
79
  end
81
80
 
81
+ sig { returns(T.nilable(Dependabot::Nuget::Version)) }
82
+ def clean_version
83
+ return unless @dependency_details&.version
84
+
85
+ version_class.new(@dependency_details.version)
86
+ end
87
+
82
88
  sig { params(req_string: String).returns(String) }
83
89
  def update_wildcard_requirement(req_string)
84
90
  return req_string if req_string == "*-*"
@@ -88,21 +94,11 @@ module Dependabot
88
94
  precision = T.must(req_string.split("*").first).split(/\.|\-/).count
89
95
  wildcard_section = req_string.partition(/(?=[.\-]\*)/).last
90
96
 
91
- version_parts = T.must(latest_version).segments.first(precision)
97
+ version_parts = T.must(clean_version).segments.first(precision)
92
98
  version = version_parts.join(".")
93
99
 
94
100
  version + wildcard_section
95
101
  end
96
-
97
- sig { returns(T::Hash[Symbol, T.untyped]) }
98
- def updated_source
99
- {
100
- type: "nuget_repo",
101
- url: source_details&.fetch(:repo_url),
102
- nuspec_url: source_details&.fetch(:nuspec_url),
103
- source_url: source_details&.fetch(:source_url)
104
- }
105
- end
106
102
  end
107
103
  end
108
104
  end
@@ -1,7 +1,8 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
- require "dependabot/nuget/file_parser"
4
+ require "dependabot/nuget/analysis/analysis_json_reader"
5
+ require "dependabot/nuget/discovery/discovery_json_reader"
5
6
  require "dependabot/update_checkers"
6
7
  require "dependabot/update_checkers/base"
7
8
  require "sorbet-runtime"
@@ -11,38 +12,22 @@ module Dependabot
11
12
  class UpdateChecker < Dependabot::UpdateCheckers::Base
12
13
  extend T::Sig
13
14
 
14
- require_relative "update_checker/version_finder"
15
- require_relative "update_checker/property_updater"
16
15
  require_relative "update_checker/requirements_updater"
17
- require_relative "update_checker/dependency_finder"
18
-
19
- require_relative "native_update_checker/native_update_checker"
20
-
21
- PROPERTY_REGEX = /\$\((?<property>.*?)\)/
22
-
23
- sig { returns(T::Boolean) }
24
- def self.native_analysis_enabled?
25
- Dependabot::Experiments.enabled?(:nuget_native_analysis)
26
- end
27
16
 
28
17
  sig { override.returns(T.nilable(String)) }
29
18
  def latest_version
30
- return native_update_checker.latest_version if UpdateChecker.native_analysis_enabled?
31
-
32
19
  # No need to find latest version for transitive dependencies unless they have a vulnerability.
33
20
  return dependency.version if !dependency.top_level? && !vulnerable?
34
21
 
35
22
  # if no update sources have the requisite package, then we can only assume that the current version is correct
36
23
  @latest_version = T.let(
37
- latest_version_details&.fetch(:version)&.to_s || dependency.version,
24
+ update_analysis.dependency_analysis.updated_version,
38
25
  T.nilable(String)
39
26
  )
40
27
  end
41
28
 
42
29
  sig { override.returns(T.nilable(T.any(String, Gem::Version))) }
43
30
  def latest_resolvable_version
44
- return native_update_checker.latest_resolvable_version if UpdateChecker.native_analysis_enabled?
45
-
46
31
  # We always want a full unlock since any package update could update peer dependencies as well.
47
32
  # To force a full unlock instead of an own unlock, we return nil.
48
33
  nil
@@ -50,232 +35,173 @@ module Dependabot
50
35
 
51
36
  sig { override.returns(Dependabot::Nuget::Version) }
52
37
  def lowest_security_fix_version
53
- return native_update_checker.lowest_security_fix_version if UpdateChecker.native_analysis_enabled?
54
-
55
- lowest_security_fix_version_details&.fetch(:version)
38
+ update_analysis.dependency_analysis.numeric_updated_version
56
39
  end
57
40
 
58
41
  sig { override.returns(T.nilable(Dependabot::Nuget::Version)) }
59
42
  def lowest_resolvable_security_fix_version
60
43
  return nil if version_comes_from_multi_dependency_property?
61
44
 
62
- lowest_security_fix_version
45
+ update_analysis.dependency_analysis.numeric_updated_version
63
46
  end
64
47
 
65
48
  sig { override.returns(NilClass) }
66
49
  def latest_resolvable_version_with_no_unlock
67
- return native_update_checker.latest_resolvable_version_with_no_unlock if UpdateChecker.native_analysis_enabled?
68
-
69
50
  # Irrelevant, since Nuget has a single dependency file
70
51
  nil
71
52
  end
72
53
 
73
54
  sig { override.returns(T::Array[T::Hash[Symbol, T.untyped]]) }
74
55
  def updated_requirements
75
- return native_update_checker.updated_requirements if UpdateChecker.native_analysis_enabled?
76
-
56
+ dep_details = updated_dependency_details.find { |d| d.name.casecmp?(dependency.name) }
77
57
  RequirementsUpdater.new(
78
58
  requirements: dependency.requirements,
79
- latest_version: preferred_resolvable_version_details&.fetch(:version, nil)&.to_s,
80
- source_details: preferred_resolvable_version_details&.slice(:nuspec_url, :repo_url, :source_url)
59
+ dependency_details: dep_details
81
60
  ).updated_requirements
82
61
  end
83
62
 
84
63
  sig { returns(T::Boolean) }
85
64
  def up_to_date?
86
- return native_update_checker.up_to_date? if UpdateChecker.native_analysis_enabled?
87
-
88
- # No need to update transitive dependencies unless they have a vulnerability.
89
- return true if !dependency.top_level? && !vulnerable?
90
-
91
- # If any requirements have an uninterpolated property in them then
92
- # that property couldn't be found, and we assume that the dependency
93
- # is up-to-date
94
- return true unless requirements_unlocked_or_can_be?
95
-
96
- super
65
+ !update_analysis.dependency_analysis.can_update
97
66
  end
98
67
 
99
68
  sig { returns(T::Boolean) }
100
69
  def requirements_unlocked_or_can_be?
101
- # If any requirements have an uninterpolated property in them then
102
- # that property couldn't be found, and the requirement therefore
103
- # cannot be unlocked (since we can't update that property)
104
- dependency.requirements.none? do |req|
105
- req.fetch(:requirement)&.match?(PROPERTY_REGEX)
106
- end
70
+ update_analysis.dependency_analysis.can_update
107
71
  end
108
72
 
109
73
  private
110
74
 
111
- sig { returns(Dependabot::Nuget::NativeUpdateChecker) }
112
- def native_update_checker
113
- @native_update_checker ||=
114
- T.let(
115
- Dependabot::Nuget::NativeUpdateChecker.new(
116
- dependency: dependency,
117
- dependency_files: dependency_files,
118
- credentials: credentials,
119
- repo_contents_path: repo_contents_path,
120
- ignored_versions: ignored_versions,
121
- raise_on_ignored: raise_on_ignored,
122
- security_advisories: security_advisories,
123
- requirements_update_strategy: requirements_update_strategy,
124
- dependency_group: dependency_group,
125
- options: options
126
- ),
127
- T.nilable(Dependabot::Nuget::NativeUpdateChecker)
128
- )
75
+ sig { returns(String) }
76
+ def job_file_path
77
+ ENV.fetch("DEPENDABOT_JOB_PATH")
129
78
  end
130
79
 
131
- sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
132
- def preferred_resolvable_version_details
133
- # If this dependency is vulnerable, prefer trying to update to the
134
- # lowest_resolvable_security_fix_version. Otherwise update all the way
135
- # to the latest_resolvable_version.
136
- return lowest_security_fix_version_details if vulnerable?
137
-
138
- latest_version_details
80
+ sig { returns(AnalysisJsonReader) }
81
+ def update_analysis
82
+ @update_analysis ||= T.let(request_analysis, T.nilable(AnalysisJsonReader))
139
83
  end
140
84
 
141
- sig { override.returns(T::Boolean) }
142
- def latest_version_resolvable_with_full_unlock?
143
- if UpdateChecker.native_analysis_enabled?
144
- return native_update_checker.public_latest_version_resolvable_with_full_unlock?
145
- end
146
-
147
- # We always want a full unlock since any package update could update peer dependencies as well.
148
- return true unless version_comes_from_multi_dependency_property?
149
-
150
- property_updater.update_possible?
85
+ sig { returns(String) }
86
+ def dependency_file_path
87
+ d = File.join(Dir.tmpdir, "dependency")
88
+ FileUtils.mkdir_p(d)
89
+ File.join(d, "#{dependency.name}.json")
151
90
  end
152
91
 
153
- sig { override.returns(T::Array[Dependabot::Dependency]) }
154
- def updated_dependencies_after_full_unlock
155
- if UpdateChecker.native_analysis_enabled?
156
- return native_update_checker.public_updated_dependencies_after_full_unlock
92
+ sig { returns(T::Array[String]) }
93
+ def dependency_file_paths
94
+ dependency_files.map do |file|
95
+ DiscoveryJsonReader.dependency_file_path(
96
+ repo_contents_path: T.must(repo_contents_path),
97
+ dependency_file: file
98
+ )
157
99
  end
100
+ end
158
101
 
159
- return property_updater.updated_dependencies if version_comes_from_multi_dependency_property?
160
-
161
- puts "Finding updated dependencies for #{dependency.name}."
162
-
163
- updated_dependency = Dependency.new(
164
- name: dependency.name,
165
- version: latest_version,
166
- requirements: updated_requirements,
167
- previous_version: dependency.version,
168
- previous_requirements: dependency.requirements,
169
- package_manager: dependency.package_manager
102
+ sig { returns(AnalysisJsonReader) }
103
+ def request_analysis
104
+ discovery_file_path = DiscoveryJsonReader.get_discovery_json_path_for_dependency_file_paths(
105
+ dependency_file_paths
170
106
  )
171
- updated_dependencies = [updated_dependency]
172
- updated_dependencies += DependencyFinder.new(
173
- dependency: updated_dependency,
174
- dependency_files: dependency_files,
175
- ignored_versions: ignored_versions,
176
- credentials: credentials,
177
- repo_contents_path: @repo_contents_path
178
- ).updated_peer_dependencies
179
- updated_dependencies
180
- end
107
+ analysis_folder_path = AnalysisJsonReader.temp_directory
108
+
109
+ write_dependency_info
110
+
111
+ NativeHelpers.run_nuget_analyze_tool(job_path: job_file_path,
112
+ repo_root: T.must(repo_contents_path),
113
+ discovery_file_path: discovery_file_path,
114
+ dependency_file_path: dependency_file_path,
115
+ analysis_folder_path: analysis_folder_path,
116
+ credentials: credentials)
117
+
118
+ analysis_json = AnalysisJsonReader.analysis_json(dependency_name: dependency.name)
119
+
120
+ AnalysisJsonReader.new(analysis_json: T.must(analysis_json))
121
+ end
122
+
123
+ sig { void }
124
+ def write_dependency_info
125
+ dependency_info = {
126
+ Name: dependency.name,
127
+ Version: dependency.version.to_s,
128
+ IsVulnerable: vulnerable?,
129
+ IgnoredVersions: ignored_versions,
130
+ Vulnerabilities: security_advisories.map do |vulnerability|
131
+ {
132
+ DependencyName: vulnerability.dependency_name,
133
+ PackageManager: vulnerability.package_manager,
134
+ VulnerableVersions: vulnerability.vulnerable_versions.map(&:to_s),
135
+ SafeVersions: vulnerability.safe_versions.map(&:to_s)
136
+ }
137
+ end
138
+ }.to_json
139
+ dependency_directory = File.dirname(dependency_file_path)
181
140
 
182
- sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
183
- def preferred_version_details
184
- return lowest_security_fix_version_details if vulnerable?
141
+ begin
142
+ Dir.mkdir(dependency_directory)
143
+ rescue StandardError
144
+ nil?
145
+ end
185
146
 
186
- latest_version_details
147
+ Dependabot.logger.info("Writing dependency info: #{dependency_info}")
148
+ File.write(dependency_file_path, dependency_info)
187
149
  end
188
150
 
189
- sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
190
- def latest_version_details
191
- @latest_version_details ||=
192
- T.let(
193
- version_finder.latest_version_details,
194
- T.nilable(T::Hash[Symbol, T.untyped])
195
- )
151
+ sig { returns(Dependabot::FileParsers::Base::DependencySet) }
152
+ def discovered_dependencies
153
+ DiscoveryJsonReader.load_discovery_for_dependency_file_paths(dependency_file_paths).dependency_set
196
154
  end
197
155
 
198
- sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
199
- def lowest_security_fix_version_details
200
- @lowest_security_fix_version_details ||=
201
- T.let(
202
- version_finder.lowest_security_fix_version_details,
203
- T.nilable(T::Hash[Symbol, T.untyped])
204
- )
156
+ sig { override.returns(T::Boolean) }
157
+ def latest_version_resolvable_with_full_unlock?
158
+ # We always want a full unlock since any package update could update peer dependencies as well.
159
+ true
205
160
  end
206
161
 
207
- sig { returns(Dependabot::Nuget::UpdateChecker::VersionFinder) }
208
- def version_finder
209
- @version_finder ||=
210
- T.let(
211
- VersionFinder.new(
212
- dependency: dependency,
213
- dependency_files: dependency_files,
214
- credentials: credentials,
215
- ignored_versions: ignored_versions,
216
- raise_on_ignored: @raise_on_ignored,
217
- security_advisories: security_advisories,
218
- repo_contents_path: @repo_contents_path
219
- ),
220
- T.nilable(Dependabot::Nuget::UpdateChecker::VersionFinder)
221
- )
222
- end
162
+ sig { override.returns(T::Array[Dependabot::Dependency]) }
163
+ def updated_dependencies_after_full_unlock
164
+ dependencies = discovered_dependencies.dependencies
165
+ updated_dependency_details.filter_map do |dependency_details|
166
+ dep = dependencies.find { |d| d.name.casecmp(dependency_details.name)&.zero? }
167
+ next unless dep
168
+
169
+ metadata = {}
170
+ # For peer dependencies, instruct updater to not directly update this dependency
171
+ metadata = { information_only: true } unless dependency.name.casecmp(dependency_details.name)&.zero?
172
+
173
+ # rebuild the new requirements with the updated dependency details
174
+ updated_reqs = dep.requirements.map do |r|
175
+ r = r.clone
176
+ r[:requirement] = dependency_details.version
177
+ r[:source] = {
178
+ type: "nuget_repo",
179
+ source_url: dependency_details.info_url
180
+ }
181
+ r
182
+ end
223
183
 
224
- sig { returns(Dependabot::Nuget::UpdateChecker::PropertyUpdater) }
225
- def property_updater
226
- @property_updater ||=
227
- T.let(
228
- PropertyUpdater.new(
229
- dependency: dependency,
230
- dependency_files: dependency_files,
231
- target_version_details: latest_version_details,
232
- credentials: credentials,
233
- ignored_versions: ignored_versions,
234
- raise_on_ignored: @raise_on_ignored,
235
- repo_contents_path: @repo_contents_path
236
- ),
237
- T.nilable(Dependabot::Nuget::UpdateChecker::PropertyUpdater)
184
+ Dependency.new(
185
+ name: dep.name,
186
+ version: dependency_details.version,
187
+ requirements: updated_reqs,
188
+ previous_version: dep.version,
189
+ previous_requirements: dep.requirements,
190
+ package_manager: dep.package_manager,
191
+ metadata: metadata
238
192
  )
239
- end
240
-
241
- sig { returns(T::Boolean) }
242
- def version_comes_from_multi_dependency_property?
243
- declarations_using_a_property.any? do |requirement|
244
- property_name = requirement.fetch(:metadata).fetch(:property_name)
245
-
246
- all_property_based_dependencies.any? do |dep|
247
- next false if dep.name == dependency.name
248
-
249
- dep.requirements.any? do |req|
250
- req.dig(:metadata, :property_name) == property_name
251
- end
252
- end
253
193
  end
254
194
  end
255
195
 
256
- sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
257
- def declarations_using_a_property
258
- @declarations_using_a_property ||=
259
- T.let(
260
- dependency.requirements
261
- .select { |req| req.dig(:metadata, :property_name) },
262
- T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
263
- )
196
+ sig { returns(T::Array[Dependabot::Nuget::DependencyDetails]) }
197
+ def updated_dependency_details
198
+ @updated_dependency_details ||= T.let(update_analysis.dependency_analysis.updated_dependencies,
199
+ T.nilable(T::Array[Dependabot::Nuget::DependencyDetails]))
264
200
  end
265
201
 
266
- sig { returns(T::Array[Dependabot::Dependency]) }
267
- def all_property_based_dependencies
268
- @all_property_based_dependencies ||=
269
- T.let(
270
- Nuget::FileParser.new(
271
- dependency_files: dependency_files,
272
- repo_contents_path: repo_contents_path,
273
- source: nil
274
- ).parse.select do |dep|
275
- dep.requirements.any? { |req| req.dig(:metadata, :property_name) }
276
- end,
277
- T.nilable(T::Array[Dependabot::Dependency])
278
- )
202
+ sig { returns(T::Boolean) }
203
+ def version_comes_from_multi_dependency_property?
204
+ update_analysis.dependency_analysis.version_comes_from_multi_dependency_property
279
205
  end
280
206
  end
281
207
  end