dependabot-nuget 0.242.0 → 0.243.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/.editorconfig +37 -28
  3. data/helpers/lib/NuGetUpdater/.gitignore +1 -0
  4. data/helpers/lib/NuGetUpdater/NuGetProjects/NuGet.CommandLine/AssemblyMetadataExtractor.cs +2 -1
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Program.cs +2 -2
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +178 -176
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/JsonBuildFile.cs +2 -1
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/PackagesConfigBuildFile.cs +1 -0
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/ProjectBuildFile.cs +5 -4
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/CompatabilityChecker.cs +1 -0
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/FrameworkCompatibilityService.cs +10 -5
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/SupportedFrameworks.cs +16 -12
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +18 -17
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectResolver.cs +7 -7
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/DotNetToolsJsonUpdater.cs +13 -20
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/GlobalJsonUpdater.cs +9 -3
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +32 -16
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +42 -22
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +32 -13
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/WebApplicationTargetsConditionPatcher.cs +47 -0
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/XmlFilePreAndPostProcessor.cs +55 -0
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/JsonHelper.cs +12 -9
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +50 -42
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +16 -3
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProcessExtensions.cs +6 -6
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/XmlExtensions.cs +11 -0
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Files/ProjectBuildFileTests.cs +18 -9
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/FrameworkChecker/CompatibilityCheckerFacts.cs +2 -2
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/FrameworkChecker/FrameworkCompatibilityServiceFacts.cs +7 -7
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/FrameworkChecker/SupportedFrameworkFacts.cs +1 -1
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackagesConfigUpdaterTests.cs +9 -9
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorker.DirsProj.cs +81 -80
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +22 -9
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DotNetTools.cs +140 -104
  35. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs +25 -25
  36. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +8 -9
  37. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +198 -22
  38. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +401 -399
  39. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/JsonHelperTests.cs +17 -15
  40. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +111 -42
  41. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/SdkPackageUpdaterTests.cs +161 -82
  42. data/lib/dependabot/nuget/file_fetcher.rb +3 -23
  43. data/lib/dependabot/nuget/file_parser/project_file_parser.rb +47 -60
  44. data/lib/dependabot/nuget/file_parser.rb +24 -6
  45. data/lib/dependabot/nuget/file_updater.rb +42 -6
  46. data/lib/dependabot/nuget/native_helpers.rb +27 -8
  47. data/lib/dependabot/nuget/nuget_client.rb +130 -24
  48. data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +7 -3
  49. data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +63 -59
  50. data/lib/dependabot/nuget/update_checker/dependency_finder.rb +2 -2
  51. data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +1 -1
  52. data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +22 -17
  53. data/lib/dependabot/nuget/update_checker/repository_finder.rb +292 -270
  54. data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +11 -13
  55. data/lib/dependabot/nuget/update_checker/tfm_finder.rb +80 -82
  56. data/lib/dependabot/nuget/update_checker/version_finder.rb +4 -7
  57. data/lib/dependabot/nuget/version.rb +18 -7
  58. data/lib/dependabot/nuget.rb +0 -2
  59. metadata +7 -5
@@ -31,7 +31,7 @@ public class SdkPackageUpdaterTests
31
31
  // Simple case
32
32
  yield return new object[]
33
33
  {
34
- new []
34
+ new[]
35
35
  {
36
36
  (Path: "src/Project.csproj", Content: """
37
37
  <Project Sdk="Microsoft.NET.Sdk">
@@ -44,7 +44,7 @@ public class SdkPackageUpdaterTests
44
44
  </Project>
45
45
  """)
46
46
  }, // starting contents
47
- new []
47
+ new[]
48
48
  {
49
49
  (Path: "src/Project.csproj", Content: """
50
50
  <Project Sdk="Microsoft.NET.Sdk">
@@ -61,98 +61,104 @@ public class SdkPackageUpdaterTests
61
61
  };
62
62
 
63
63
  // Dependency package has version constraint
64
- yield return new object[]
65
- {
64
+ yield return
65
+ [
66
66
  new[]
67
67
  {
68
68
  (Path: "src/Project/Project.csproj", Content: """
69
- <Project Sdk="Microsoft.NET.Sdk">
70
- <PropertyGroup>
71
- <TargetFramework>netstandard2.0</TargetFramework>
72
- </PropertyGroup>
73
- <ItemGroup>
74
- <PackageReference Include="AWSSDK.S3" Version="3.3.17.3" />
75
- <PackageReference Include="AWSSDK.Core" Version="3.3.21.19" />
76
- </ItemGroup>
77
- </Project>
78
- """),
69
+ <Project Sdk="Microsoft.NET.Sdk">
70
+ <PropertyGroup>
71
+ <TargetFramework>netstandard2.0</TargetFramework>
72
+ </PropertyGroup>
73
+ <ItemGroup>
74
+ <PackageReference Include="AWSSDK.S3" Version="3.3.17.3" />
75
+ <PackageReference Include="AWSSDK.Core" Version="3.3.21.19" />
76
+ </ItemGroup>
77
+ </Project>
78
+ """),
79
79
  }, // starting contents
80
80
  new[]
81
81
  {
82
82
  // If a dependency has a version constraint outside of our new-version, we don't update anything
83
83
  (Path: "src/Project/Project.csproj", Content: """
84
- <Project Sdk="Microsoft.NET.Sdk">
85
- <PropertyGroup>
86
- <TargetFramework>netstandard2.0</TargetFramework>
87
- </PropertyGroup>
88
- <ItemGroup>
89
- <PackageReference Include="AWSSDK.S3" Version="3.3.17.3" />
90
- <PackageReference Include="AWSSDK.Core" Version="3.3.21.19" />
91
- </ItemGroup>
92
- </Project>
93
- """),
94
- },// expected contents
95
- "AWSSDK.Core", "3.3.21.19", "3.7.300.20", false // isTransitive
96
- };
84
+ <Project Sdk="Microsoft.NET.Sdk">
85
+ <PropertyGroup>
86
+ <TargetFramework>netstandard2.0</TargetFramework>
87
+ </PropertyGroup>
88
+ <ItemGroup>
89
+ <PackageReference Include="AWSSDK.S3" Version="3.3.17.3" />
90
+ <PackageReference Include="AWSSDK.Core" Version="3.3.21.19" />
91
+ </ItemGroup>
92
+ </Project>
93
+ """),
94
+ }, // expected contents
95
+ "AWSSDK.Core",
96
+ "3.3.21.19",
97
+ "3.7.300.20",
98
+ false // isTransitive
99
+ ];
97
100
 
98
101
  // Dependency project has version constraint
99
- yield return new object[]
100
- {
102
+ yield return
103
+ [
101
104
  new[]
102
105
  {
103
106
  (Path: "src/Project2/Project2.csproj", Content: """
104
- <Project Sdk="Microsoft.NET.Sdk">
105
- <PropertyGroup>
106
- <TargetFramework>netstandard2.0</TargetFramework>
107
- </PropertyGroup>
108
- <ItemGroup>
109
- <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
110
- <ProjectReference Include="../Project/Project.csproj" />
111
- </ItemGroup>
112
- </Project>
113
- """),
107
+ <Project Sdk="Microsoft.NET.Sdk">
108
+ <PropertyGroup>
109
+ <TargetFramework>netstandard2.0</TargetFramework>
110
+ </PropertyGroup>
111
+ <ItemGroup>
112
+ <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
113
+ <ProjectReference Include="../Project/Project.csproj" />
114
+ </ItemGroup>
115
+ </Project>
116
+ """),
114
117
  (Path: "src/Project/Project.csproj", Content: """
115
- <Project Sdk="Microsoft.NET.Sdk">
116
- <PropertyGroup>
117
- <TargetFramework>netstandard2.0</TargetFramework>
118
- </PropertyGroup>
119
- <ItemGroup>
120
- <PackageReference Include="Newtonsoft.Json" Version="[12.0.1, 13.0.0)" />
121
- </ItemGroup>
122
- </Project>
123
- """),
118
+ <Project Sdk="Microsoft.NET.Sdk">
119
+ <PropertyGroup>
120
+ <TargetFramework>netstandard2.0</TargetFramework>
121
+ </PropertyGroup>
122
+ <ItemGroup>
123
+ <PackageReference Include="Newtonsoft.Json" Version="[12.0.1, 13.0.0)" />
124
+ </ItemGroup>
125
+ </Project>
126
+ """),
124
127
  }, // starting contents
125
128
  new[]
126
129
  {
127
130
  (Path: "src/Project2/Project2.csproj", Content: """
128
- <Project Sdk="Microsoft.NET.Sdk">
129
- <PropertyGroup>
130
- <TargetFramework>netstandard2.0</TargetFramework>
131
- </PropertyGroup>
132
- <ItemGroup>
133
- <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
134
- <ProjectReference Include="../Project/Project.csproj" />
135
- </ItemGroup>
136
- </Project>
137
- """), // starting contents
131
+ <Project Sdk="Microsoft.NET.Sdk">
132
+ <PropertyGroup>
133
+ <TargetFramework>netstandard2.0</TargetFramework>
134
+ </PropertyGroup>
135
+ <ItemGroup>
136
+ <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
137
+ <ProjectReference Include="../Project/Project.csproj" />
138
+ </ItemGroup>
139
+ </Project>
140
+ """), // starting contents
138
141
  (Path: "src/Project/Project.csproj", Content: """
139
- <Project Sdk="Microsoft.NET.Sdk">
140
- <PropertyGroup>
141
- <TargetFramework>netstandard2.0</TargetFramework>
142
- </PropertyGroup>
143
- <ItemGroup>
144
- <PackageReference Include="Newtonsoft.Json" Version="[12.0.1, 13.0.0)" />
145
- </ItemGroup>
146
- </Project>
147
- """),
148
- },// expected contents
149
- "Newtonsoft.Json", "12.0.1", "13.0.1", false // isTransitive
150
- };
142
+ <Project Sdk="Microsoft.NET.Sdk">
143
+ <PropertyGroup>
144
+ <TargetFramework>netstandard2.0</TargetFramework>
145
+ </PropertyGroup>
146
+ <ItemGroup>
147
+ <PackageReference Include="Newtonsoft.Json" Version="[12.0.1, 13.0.0)" />
148
+ </ItemGroup>
149
+ </Project>
150
+ """),
151
+ }, // expected contents
152
+ "Newtonsoft.Json",
153
+ "12.0.1",
154
+ "13.0.1",
155
+ false // isTransitive
156
+ ];
151
157
 
152
158
  // Multiple references
153
- yield return new object[]
154
- {
155
- new []
159
+ yield return
160
+ [
161
+ new[]
156
162
  {
157
163
  (Path: "src/Project.csproj", Content: """
158
164
  <Project Sdk="Microsoft.NET.Sdk">
@@ -168,7 +174,7 @@ public class SdkPackageUpdaterTests
168
174
  </Project>
169
175
  """)
170
176
  }, // starting contents
171
- new []
177
+ new[]
172
178
  {
173
179
  (Path: "src/Project.csproj", Content: """
174
180
  <Project Sdk="Microsoft.NET.Sdk">
@@ -184,13 +190,83 @@ public class SdkPackageUpdaterTests
184
190
  </Project>
185
191
  """)
186
192
  }, // expected contents
187
- "Newtonsoft.Json", "12.0.1", "13.0.1", false // isTransitive
188
- };
193
+ "Newtonsoft.Json",
194
+ "12.0.1",
195
+ "13.0.1",
196
+ false // isTransitive
197
+ ];
198
+
199
+ // Make sure we don't update if there are incoherent versions
200
+ yield return
201
+ [
202
+ new[]
203
+ {
204
+ (Path: "src/Project.csproj", Content: """
205
+ <Project Sdk="Microsoft.NET.Sdk">
206
+ <PropertyGroup>
207
+ <TargetFramework>netcoreapp2.1</TargetFramework>
208
+ </PropertyGroup>
209
+ <ItemGroup>
210
+ <PackageReference Include="Microsoft.Extensions.Primitives" Version="2.2.0" />
211
+ <PackageReference Include="Microsoft.Extensions.Options" Version="2.2.0" />
212
+ <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.2.0" />
213
+ <PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
214
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.0" />
215
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
216
+ <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.2.0" />
217
+ <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.2.0" />
218
+ <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
219
+ <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.2.0" />
220
+ <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="2.2.0" />
221
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.2.0" />
222
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="2.2.0" />
223
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="2.2.0" />
224
+ <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.0" />
225
+ <PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
226
+ <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.0" />
227
+ </ItemGroup>
228
+ </Project>
229
+ """)
230
+ }, // starting contents
231
+ new[]
232
+ {
233
+ (Path: "src/Project.csproj", Content: """
234
+ <Project Sdk="Microsoft.NET.Sdk">
235
+ <PropertyGroup>
236
+ <TargetFramework>netcoreapp2.1</TargetFramework>
237
+ </PropertyGroup>
238
+ <ItemGroup>
239
+ <PackageReference Include="Microsoft.Extensions.Primitives" Version="2.2.0" />
240
+ <PackageReference Include="Microsoft.Extensions.Options" Version="2.2.0" />
241
+ <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.2.0" />
242
+ <PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
243
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.0" />
244
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
245
+ <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.2.0" />
246
+ <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.2.0" />
247
+ <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
248
+ <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.2.0" />
249
+ <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="2.2.0" />
250
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.2.0" />
251
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="2.2.0" />
252
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="2.2.0" />
253
+ <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.0" />
254
+ <PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
255
+ <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.0" />
256
+ </ItemGroup>
257
+ </Project>
258
+ """)
259
+ }, // expected contents
260
+ "Microsoft.EntityFrameworkCore.SqlServer",
261
+ "2.1.0",
262
+ "2.2.0",
263
+ false // isTransitive
264
+ ];
189
265
 
190
266
  // PackageReference with Version as child element
191
- yield return new object[]
192
- {
193
- new []
267
+ yield return
268
+ [
269
+ new[]
194
270
  {
195
271
  (Path: "src/Project.csproj", Content: """
196
272
  <Project Sdk="Microsoft.NET.Sdk">
@@ -205,7 +281,7 @@ public class SdkPackageUpdaterTests
205
281
  </Project>
206
282
  """)
207
283
  }, // starting contents
208
- new []
284
+ new[]
209
285
  {
210
286
  (Path: "src/Project.csproj", Content: """
211
287
  <Project Sdk="Microsoft.NET.Sdk">
@@ -220,8 +296,11 @@ public class SdkPackageUpdaterTests
220
296
  </Project>
221
297
  """)
222
298
  }, // expected contents
223
- "Newtonsoft.Json", "12.0.1", "13.0.1", false // isTransitive
224
- };
299
+ "Newtonsoft.Json",
300
+ "12.0.1",
301
+ "13.0.1",
302
+ false // isTransitive
303
+ ];
225
304
  }
226
305
 
227
306
  private static void AssertContentsEqual((string Path, string Contents)[] expectedContents, TemporaryDirectory directory)
@@ -72,7 +72,9 @@ module Dependabot
72
72
  project_files += fsproj_file
73
73
  project_files += sln_project_files
74
74
  project_files += proj_files
75
- project_files += project_files.filter_map { |f| directory_packages_props_file_from_project_file(f) }
75
+ project_files += project_files.filter_map do |f|
76
+ named_file_up_tree_from_project_file(f, "Directory.Packages.props")
77
+ end
76
78
  project_files
77
79
  end
78
80
  rescue Octokit::NotFound, Gitlab::Error::NotFound
@@ -191,28 +193,6 @@ module Dependabot
191
193
  @proj_files ||= find_and_fetch_with_suffix(".proj")
192
194
  end
193
195
 
194
- def directory_packages_props_file_from_project_file(project_file)
195
- # walk up the tree from each project file stopping at the first `Directory.Packages.props` file found
196
- # https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management#central-package-management-rules
197
-
198
- found_directory_packages_props_file = nil
199
- directory_path = Pathname.new(directory)
200
- full_project_dir = Pathname.new(project_file.directory).join(project_file.name).dirname
201
- full_project_dir.ascend.each do |base|
202
- break if found_directory_packages_props_file
203
-
204
- candidate_file_path = Pathname.new(base).join("Directory.Packages.props").cleanpath.to_path
205
- candidate_directory = Pathname.new(File.dirname(candidate_file_path))
206
- relative_candidate_directory = candidate_directory.relative_path_from(directory_path)
207
- candidate_file = repo_contents(dir: relative_candidate_directory).find do |f|
208
- f.name.casecmp?("Directory.Packages.props")
209
- end
210
- found_directory_packages_props_file = fetch_file_from_host(candidate_file.name) if candidate_file
211
- end
212
-
213
- found_directory_packages_props_file
214
- end
215
-
216
196
  def find_and_fetch_with_suffix(suffix)
217
197
  repo_contents.select { |f| f.name.end_with?(suffix) }.map { |f| fetch_file_from_host(f.name) }
218
198
  end
@@ -27,6 +27,8 @@ module Dependabot
27
27
 
28
28
  PROJECT_REFERENCE_SELECTOR = "ItemGroup > ProjectReference"
29
29
 
30
+ PROJECT_FILE_SELECTOR = "ItemGroup > ProjectFile"
31
+
30
32
  PACKAGE_REFERENCE_SELECTOR = "ItemGroup > PackageReference, " \
31
33
  "ItemGroup > GlobalPackageReference"
32
34
 
@@ -56,6 +58,24 @@ module Dependabot
56
58
  cache[key] ||= parse_dependencies(project_file)
57
59
  end
58
60
 
61
+ def downstream_file_references(project_file:)
62
+ file_set = Set.new
63
+
64
+ doc = Nokogiri::XML(project_file.content)
65
+ doc.remove_namespaces!
66
+ proj_refs = doc.css(PROJECT_REFERENCE_SELECTOR)
67
+ proj_files = doc.css(PROJECT_FILE_SELECTOR)
68
+ ref_nodes = proj_refs + proj_files
69
+ ref_nodes.each do |project_reference_node|
70
+ dep_file = get_attribute_value(project_reference_node, "Include")
71
+ full_project_path = full_path(project_file, dep_file)
72
+ full_project_path = full_project_path[1..-1] if full_project_path.start_with?("/")
73
+ file_set << full_project_path if full_project_path
74
+ end
75
+
76
+ file_set
77
+ end
78
+
59
79
  def target_frameworks(project_file:)
60
80
  target_framework = details_for_property("TargetFramework", project_file)
61
81
  return [target_framework&.fetch(:value)] if target_framework
@@ -80,6 +100,21 @@ module Dependabot
80
100
 
81
101
  attr_reader :dependency_files, :credentials
82
102
 
103
+ def full_path(project_file, ref_path)
104
+ project_file_directory = File.dirname(project_file.name)
105
+ is_rooted = project_file_directory.start_with?("/")
106
+ # Root the directory path to avoid expand_path prepending the working directory
107
+ project_file_directory = "/" + project_file_directory unless is_rooted
108
+
109
+ # normalize path separators
110
+ relative_path = ref_path.tr("\\", "/")
111
+ # path is relative to the project file directory
112
+ relative_path = File.join(project_file_directory, relative_path)
113
+ result = File.expand_path(relative_path)
114
+ result = result[1..-1] unless is_rooted
115
+ result
116
+ end
117
+
83
118
  def parse_dependencies(project_file)
84
119
  dependency_set = Dependabot::FileParsers::Base::DependencySet.new
85
120
 
@@ -131,27 +166,20 @@ module Dependabot
131
166
  end
132
167
 
133
168
  def add_transitive_dependencies_from_project_references(project_file, doc, dependency_set)
134
- project_file_directory = File.dirname(project_file.name)
135
- is_rooted = project_file_directory.start_with?("/")
136
- # Root the directory path to avoid expand_path prepending the working directory
137
- project_file_directory = "/" + project_file_directory unless is_rooted
138
-
139
169
  # Look for regular project references
140
- doc.css(PROJECT_REFERENCE_SELECTOR).each do |reference_node|
170
+ project_refs = doc.css(PROJECT_REFERENCE_SELECTOR)
171
+ # Look for ProjectFile references (dirs.proj)
172
+ project_files = doc.css(PROJECT_FILE_SELECTOR)
173
+ ref_nodes = project_refs + project_files
174
+
175
+ ref_nodes.each do |reference_node|
141
176
  relative_path = dependency_name(reference_node, project_file)
142
177
  # This could result from a <ProjectReference Remove="..." /> item.
143
178
  next unless relative_path
144
179
 
145
- # normalize path separators
146
- relative_path = relative_path.tr("\\", "/")
147
- # path is relative to the project file directory
148
- relative_path = File.join(project_file_directory, relative_path)
149
-
150
- # get absolute path
151
- full_path = File.expand_path(relative_path)
152
- full_path = full_path[1..-1] unless is_rooted
180
+ full_project_path = full_path(project_file, relative_path)
153
181
 
154
- referenced_file = dependency_files.find { |f| f.name == full_path }
182
+ referenced_file = dependency_files.find { |f| f.name == full_project_path }
155
183
  next unless referenced_file
156
184
 
157
185
  dependency_set(project_file: referenced_file).dependencies.each do |dep|
@@ -279,61 +307,20 @@ module Dependabot
279
307
  end
280
308
 
281
309
  def dependency_has_search_results?(dependency)
282
- dependency_urls = UpdateChecker::RepositoryFinder.new(
310
+ dependency_urls = RepositoryFinder.new(
283
311
  dependency: dependency,
284
312
  credentials: credentials,
285
313
  config_files: nuget_configs
286
314
  ).dependency_urls
287
- if dependency_urls.empty?
288
- dependency_urls = [UpdateChecker::RepositoryFinder.get_default_repository_details(dependency.name)]
289
- end
315
+ dependency_urls = [RepositoryFinder.get_default_repository_details(dependency.name)] if dependency_urls.empty?
290
316
  dependency_urls.any? do |dependency_url|
291
317
  dependency_url_has_matching_result?(dependency.name, dependency_url)
292
318
  end
293
319
  end
294
320
 
295
321
  def dependency_url_has_matching_result?(dependency_name, dependency_url)
296
- repository_type = dependency_url.fetch(:repository_type)
297
- if repository_type == "v3"
298
- dependency_url_has_matching_result_v3?(dependency_name, dependency_url)
299
- elsif repository_type == "v2"
300
- dependency_url_has_matching_result_v2?(dependency_name, dependency_url)
301
- else
302
- raise "Unknown repository type: #{repository_type}"
303
- end
304
- end
305
-
306
- def dependency_url_has_matching_result_v3?(dependency_name, dependency_url)
307
- versions = NugetClient.get_package_versions_v3(dependency_name, dependency_url)
308
-
309
- versions != nil
310
- end
311
-
312
- def dependency_url_has_matching_result_v2?(dependency_name, dependency_url)
313
- url = dependency_url.fetch(:versions_url)
314
- auth_header = dependency_url.fetch(:auth_header)
315
- response = execute_search_for_dependency_url(url, auth_header)
316
- return false unless response.status == 200
317
-
318
- doc = Nokogiri::XML(response.body)
319
- doc.remove_namespaces!
320
- id_nodes = doc.xpath("/feed/entry/properties/Id")
321
- found_matching_result = id_nodes.any? do |id_node|
322
- return false unless id_node.text
323
-
324
- id_node.text.casecmp?(dependency_name)
325
- end
326
- found_matching_result
327
- end
328
-
329
- def execute_search_for_dependency_url(url, auth_header)
330
- cache = ProjectFileParser.dependency_url_search_cache
331
- cache[url] ||= Dependabot::RegistryClient.get(
332
- url: url,
333
- headers: auth_header
334
- )
335
-
336
- cache[url]
322
+ versions = NugetClient.get_package_versions(dependency_name, dependency_url)
323
+ versions&.any?
337
324
  end
338
325
 
339
326
  def dependency_name(dependency_node, project_file)
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "nokogiri"
@@ -6,12 +6,15 @@ require "nokogiri"
6
6
  require "dependabot/dependency"
7
7
  require "dependabot/file_parsers"
8
8
  require "dependabot/file_parsers/base"
9
+ require "sorbet-runtime"
9
10
 
10
11
  # For details on how dotnet handles version constraints, see:
11
12
  # https://docs.microsoft.com/en-us/nuget/reference/package-versioning
12
13
  module Dependabot
13
14
  module Nuget
14
15
  class FileParser < Dependabot::FileParsers::Base
16
+ extend T::Sig
17
+
15
18
  require "dependabot/file_parsers/base/dependency_set"
16
19
  require_relative "file_parser/project_file_parser"
17
20
  require_relative "file_parser/packages_config_parser"
@@ -20,6 +23,7 @@ module Dependabot
20
23
 
21
24
  PACKAGE_CONF_DEPENDENCY_SELECTOR = "packages > packages"
22
25
 
26
+ sig { override.returns(T::Array[Dependabot::Dependency]) }
23
27
  def parse
24
28
  dependency_set = DependencySet.new
25
29
  dependency_set += project_file_dependencies
@@ -31,6 +35,7 @@ module Dependabot
31
35
 
32
36
  private
33
37
 
38
+ sig { returns(Dependabot::FileParsers::Base::DependencySet) }
34
39
  def project_file_dependencies
35
40
  dependency_set = DependencySet.new
36
41
 
@@ -42,6 +47,7 @@ module Dependabot
42
47
  dependency_set
43
48
  end
44
49
 
50
+ sig { returns(Dependabot::FileParsers::Base::DependencySet) }
45
51
  def packages_config_dependencies
46
52
  dependency_set = DependencySet.new
47
53
 
@@ -53,26 +59,32 @@ module Dependabot
53
59
  dependency_set
54
60
  end
55
61
 
62
+ sig { returns(Dependabot::FileParsers::Base::DependencySet) }
56
63
  def global_json_dependencies
57
64
  return DependencySet.new unless global_json
58
65
 
59
66
  GlobalJsonParser.new(global_json: global_json).dependency_set
60
67
  end
61
68
 
69
+ sig { returns(Dependabot::FileParsers::Base::DependencySet) }
62
70
  def dotnet_tools_json_dependencies
63
71
  return DependencySet.new unless dotnet_tools_json
64
72
 
65
73
  DotNetToolsJsonParser.new(dotnet_tools_json: dotnet_tools_json).dependency_set
66
74
  end
67
75
 
76
+ sig { returns(Dependabot::Nuget::FileParser::ProjectFileParser) }
68
77
  def project_file_parser
69
- @project_file_parser ||=
78
+ @project_file_parser ||= T.let(
70
79
  ProjectFileParser.new(
71
80
  dependency_files: dependency_files,
72
81
  credentials: credentials
73
- )
82
+ ),
83
+ T.nilable(Dependabot::Nuget::FileParser::ProjectFileParser)
84
+ )
74
85
  end
75
86
 
87
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
76
88
  def project_files
77
89
  projfile = /\.([a-z]{2})?proj$/
78
90
  packageprops = /[Dd]irectory.[Pp]ackages.props/
@@ -83,12 +95,14 @@ module Dependabot
83
95
  end
84
96
  end
85
97
 
98
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
86
99
  def packages_config_files
87
100
  dependency_files.select do |f|
88
- f.name.split("/").last.casecmp("packages.config").zero?
101
+ f.name.split("/").last&.casecmp("packages.config")&.zero?
89
102
  end
90
103
  end
91
104
 
105
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
92
106
  def project_import_files
93
107
  dependency_files -
94
108
  project_files -
@@ -98,18 +112,22 @@ module Dependabot
98
112
  [dotnet_tools_json]
99
113
  end
100
114
 
115
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
101
116
  def nuget_configs
102
117
  dependency_files.select { |f| f.name.match?(/nuget\.config$/i) }
103
118
  end
104
119
 
120
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
105
121
  def global_json
106
- dependency_files.find { |f| f.name.casecmp("global.json").zero? }
122
+ dependency_files.find { |f| f.name.casecmp("global.json")&.zero? }
107
123
  end
108
124
 
125
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
109
126
  def dotnet_tools_json
110
- dependency_files.find { |f| f.name.casecmp(".config/dotnet-tools.json").zero? }
127
+ dependency_files.find { |f| f.name.casecmp(".config/dotnet-tools.json")&.zero? }
111
128
  end
112
129
 
130
+ sig { override.void }
113
131
  def check_required_files
114
132
  return if project_files.any? || packages_config_files.any?
115
133