dependabot-nuget 0.287.0 → 0.288.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/.gitignore +1 -0
  3. data/helpers/lib/NuGetUpdater/Directory.Build.targets +17 -0
  4. data/helpers/lib/NuGetUpdater/Directory.Packages.props +10 -3
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs +7 -3
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +1 -1
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +72 -51
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +1 -1
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencyDiscovery.props +7 -0
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencyDiscovery.targets +10 -0
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +36 -19
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscovery.cs +6 -2
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscoveryResult.cs +2 -1
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/ProjectDiscoveryResult.cs +5 -0
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +386 -12
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs +1 -1
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +11 -0
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/NuGetUpdater.Core.csproj +7 -2
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +23 -0
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +0 -4
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/TargetFrameworkReporter.targets +13 -0
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +1 -0
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +2 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/CollectionExtensions.cs +17 -0
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +57 -4
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathComparer.cs +31 -0
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +30 -2
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +50 -0
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +74 -38
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs +50 -4
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Proj.cs +5 -5
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +728 -253
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +322 -78
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +2 -6
  35. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +472 -0
  36. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +46 -1
  37. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/NuGetUpdater.Core.Test.csproj +0 -1
  38. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +1 -1
  39. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +33 -0
  40. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryDirectory.cs +3 -2
  41. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +4 -2
  42. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/PathHelperTests.cs +3 -2
  43. data/lib/dependabot/nuget/file_parser.rb +7 -1
  44. data/lib/dependabot/nuget/native_discovery/native_discovery_json_reader.rb +0 -3
  45. data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +7 -10
  46. data/lib/dependabot/nuget/native_helpers.rb +13 -4
  47. metadata +12 -8
  48. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DirectoryPackagesPropsDiscovery.cs +0 -69
  49. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DirectoryPackagesPropsDiscoveryResult.cs +0 -11
  50. data/lib/dependabot/nuget/native_discovery/native_directory_packages_props_discovery.rb +0 -44
@@ -0,0 +1,472 @@
1
+ using System.Collections.Immutable;
2
+
3
+ using NuGetUpdater.Core.Discover;
4
+ using NuGetUpdater.Core.Test.Update;
5
+
6
+ using Xunit;
7
+
8
+ using TestFile = (string Path, string Content);
9
+
10
+ namespace NuGetUpdater.Core.Test.Discover;
11
+
12
+ public class SdkProjectDiscoveryTests : DiscoveryWorkerTestBase
13
+ {
14
+ [Fact]
15
+ public async Task DiscoveryInSingleProject_TopLevelAndTransitive()
16
+ {
17
+ await TestDiscoverAsync(
18
+ packages:
19
+ [
20
+ MockNuGetPackage.CreateSimplePackage("Top.Level.Package", "1.2.3", "net8.0", [("net8.0", [("Transitive.Dependency", "4.5.6")])]),
21
+ MockNuGetPackage.CreateSimplePackage("Transitive.Dependency", "4.5.6", "net8.0"),
22
+ ],
23
+ startingDirectory: "src",
24
+ projectPath: "src/library.csproj",
25
+ files:
26
+ [
27
+ ("src/library.csproj", """
28
+ <Project Sdk="Microsoft.NET.Sdk">
29
+ <PropertyGroup>
30
+ <TargetFramework>net8.0</TargetFramework>
31
+ </PropertyGroup>
32
+ <ItemGroup>
33
+ <PackageReference Include="Top.Level.Package" Version="1.2.3" />
34
+ </ItemGroup>
35
+ </Project>
36
+ """)
37
+ ],
38
+ expectedProjects:
39
+ [
40
+ new()
41
+ {
42
+ FilePath = "library.csproj",
43
+ Dependencies =
44
+ [
45
+ new("Top.Level.Package", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net8.0"], IsDirect: true),
46
+ new("Transitive.Dependency", "4.5.6", DependencyType.Unknown, TargetFrameworks: ["net8.0"], IsTransitive: true)
47
+ ],
48
+ ImportedFiles = [],
49
+ Properties =
50
+ [
51
+ new("TargetFramework", "net8.0", "src/library.csproj"),
52
+ ],
53
+ TargetFrameworks = ["net8.0"]
54
+ }
55
+ ]
56
+ );
57
+ }
58
+
59
+ [Fact]
60
+ public async Task DiscoveryInSingleProject_PackageAddedInTargetsFile()
61
+ {
62
+ await TestDiscoverAsync(
63
+ packages:
64
+ [
65
+ MockNuGetPackage.CreateSimplePackage("Top.Level.Package", "1.2.3", "net8.0", [("net8.0", [("Transitive.Dependency", "4.5.6")])]),
66
+ MockNuGetPackage.CreateSimplePackage("Transitive.Dependency", "4.5.6", "net8.0"),
67
+ ],
68
+ startingDirectory: "src",
69
+ projectPath: "src/library.csproj",
70
+ files:
71
+ [
72
+ ("src/library.csproj", """
73
+ <Project Sdk="Microsoft.NET.Sdk">
74
+ <PropertyGroup>
75
+ <TargetFramework>net8.0</TargetFramework>
76
+ </PropertyGroup>
77
+ </Project>
78
+ """),
79
+ ("Directory.Build.targets", """
80
+ <Project>
81
+ <ItemGroup>
82
+ <PackageReference Include="Top.Level.Package" Version="1.2.3" />
83
+ </ItemGroup>
84
+ </Project>
85
+ """)
86
+ ],
87
+ expectedProjects:
88
+ [
89
+ new()
90
+ {
91
+ FilePath = "library.csproj",
92
+ Dependencies =
93
+ [
94
+ // dependencies come from `Directory.Build.targets`, but it's through the evaluation of `src/library.csproj` that it's found
95
+ new("Top.Level.Package", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net8.0"], IsDirect: true),
96
+ new("Transitive.Dependency", "4.5.6", DependencyType.Unknown, TargetFrameworks: ["net8.0"], IsTransitive: true)
97
+ ],
98
+ Properties =
99
+ [
100
+ new("TargetFramework", "net8.0", "src/library.csproj"),
101
+ ],
102
+ TargetFrameworks = ["net8.0"]
103
+ }
104
+ ]
105
+ );
106
+ }
107
+
108
+ [Fact]
109
+ public async Task DiscoveryThroughProjectReference()
110
+ {
111
+ await TestDiscoverAsync(
112
+ packages:
113
+ [
114
+ MockNuGetPackage.CreateSimplePackage("Top.Level.Package", "1.2.3", "net8.0"),
115
+ MockNuGetPackage.CreateSimplePackage("Dependency.From.Other.Project", "4.5.6", "net8.0"),
116
+ ],
117
+ startingDirectory: "src/library1",
118
+ projectPath: "src/library1/library1.csproj",
119
+ files:
120
+ [
121
+ ("src/library1/library1.csproj", """
122
+ <Project Sdk="Microsoft.NET.Sdk">
123
+ <PropertyGroup>
124
+ <TargetFramework>net8.0</TargetFramework>
125
+ </PropertyGroup>
126
+ <ItemGroup>
127
+ <ProjectReference Include="../library2/library2.csproj" />
128
+ </ItemGroup>
129
+ <ItemGroup>
130
+ <PackageReference Include="Top.Level.Package" Version="1.2.3" />
131
+ </ItemGroup>
132
+ </Project>
133
+ """),
134
+ ("src/library2/library2.csproj", """
135
+ <Project Sdk="Microsoft.NET.Sdk">
136
+ <PropertyGroup>
137
+ <TargetFramework>net8.0</TargetFramework>
138
+ </PropertyGroup>
139
+ <ItemGroup>
140
+ <PackageReference Include="Dependency.From.Other.Project" Version="4.5.6" />
141
+ </ItemGroup>
142
+ </Project>
143
+ """),
144
+ ],
145
+ expectedProjects:
146
+ [
147
+ new()
148
+ {
149
+ FilePath = "library1.csproj",
150
+ Dependencies =
151
+ [
152
+ new("Top.Level.Package", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net8.0"], IsDirect: true),
153
+ new("Dependency.From.Other.Project", "4.5.6", DependencyType.Unknown, TargetFrameworks: ["net8.0"], IsTransitive: true)
154
+ ],
155
+ ImportedFiles = [],
156
+ ReferencedProjectPaths = [
157
+ "../library2/library2.csproj"
158
+ ],
159
+ Properties =
160
+ [
161
+ new("TargetFramework", "net8.0", "src/library1/library1.csproj"),
162
+ ],
163
+ TargetFrameworks = ["net8.0"]
164
+ },
165
+ new()
166
+ {
167
+ FilePath = "../library2/library2.csproj",
168
+ Dependencies =
169
+ [
170
+ new("Dependency.From.Other.Project", "4.5.6", DependencyType.PackageReference, TargetFrameworks: ["net8.0"], IsDirect: true)
171
+ ],
172
+ Properties =
173
+ [
174
+ new("TargetFramework", "net8.0", "src/library2/library2.csproj"),
175
+ ],
176
+ TargetFrameworks = ["net8.0"]
177
+ }
178
+ ]
179
+ );
180
+ }
181
+
182
+ [Fact]
183
+ public async Task DiscoveryThroughProjectReferenceThroughTransitiveDependency()
184
+ {
185
+ await TestDiscoverAsync(
186
+ packages:
187
+ [
188
+ MockNuGetPackage.CreateSimplePackage("Top.Level.Package", "1.2.3", "net8.0", [("net8.0", [("Transitive.Dependency", "4.5.6")])]),
189
+ MockNuGetPackage.CreateSimplePackage("Transitive.Dependency", "4.5.6", "net8.0"),
190
+ ],
191
+ startingDirectory: "src/library1",
192
+ projectPath: "src/library1/library1.csproj",
193
+ files:
194
+ [
195
+ ("src/library1/library1.csproj", """
196
+ <Project Sdk="Microsoft.NET.Sdk">
197
+ <PropertyGroup>
198
+ <TargetFramework>net8.0</TargetFramework>
199
+ </PropertyGroup>
200
+ <ItemGroup>
201
+ <ProjectReference Include="../library2/library2.csproj" />
202
+ </ItemGroup>
203
+ </Project>
204
+ """),
205
+ ("src/library2/library2.csproj", """
206
+ <Project Sdk="Microsoft.NET.Sdk">
207
+ <PropertyGroup>
208
+ <TargetFramework>net8.0</TargetFramework>
209
+ </PropertyGroup>
210
+ <ItemGroup>
211
+ <PackageReference Include="Top.Level.Package" Version="1.2.3" />
212
+ </ItemGroup>
213
+ </Project>
214
+ """),
215
+ ],
216
+ expectedProjects:
217
+ [
218
+ new()
219
+ {
220
+ FilePath = "library1.csproj",
221
+ Dependencies =
222
+ [
223
+ // these are all transitive through the ProjectReference
224
+ new("Top.Level.Package", "1.2.3", DependencyType.Unknown, TargetFrameworks: ["net8.0"], IsTransitive: true),
225
+ new("Transitive.Dependency", "4.5.6", DependencyType.Unknown, TargetFrameworks: ["net8.0"], IsTransitive: true)
226
+ ],
227
+ ImportedFiles = [],
228
+ ReferencedProjectPaths = [
229
+ "../library2/library2.csproj",
230
+ ],
231
+ Properties =
232
+ [
233
+ new("TargetFramework", "net8.0", "src/library1/library1.csproj"),
234
+ ],
235
+ TargetFrameworks = ["net8.0"]
236
+ },
237
+ new()
238
+ {
239
+ FilePath = "../library2/library2.csproj",
240
+ Dependencies =
241
+ [
242
+ new("Top.Level.Package", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net8.0"], IsDirect: true),
243
+ new("Transitive.Dependency", "4.5.6", DependencyType.Unknown, TargetFrameworks: ["net8.0"], IsTransitive: true)
244
+ ],
245
+ ImportedFiles = [],
246
+ Properties =
247
+ [
248
+ new("TargetFramework", "net8.0", "src/library2/library2.csproj"),
249
+ ],
250
+ TargetFrameworks = ["net8.0"]
251
+ }
252
+ ]
253
+ );
254
+ }
255
+
256
+ [Fact]
257
+ public async Task DiscoverWithMultipleTargetFrameworks()
258
+ {
259
+ await TestDiscoverAsync(
260
+ packages:
261
+ [
262
+ MockNuGetPackage.CreateSimplePackage("Some.Dependency", "1.2.3", "net7.0"),
263
+ ],
264
+ startingDirectory: "src",
265
+ projectPath: "src/library.csproj",
266
+ files:
267
+ [
268
+ ("src/library.csproj", """
269
+ <Project Sdk="Microsoft.NET.Sdk">
270
+ <PropertyGroup>
271
+ <TargetFrameworks>net7.0;net8.0</TargetFrameworks>
272
+ </PropertyGroup>
273
+ <ItemGroup>
274
+ <PackageReference Include="Some.Dependency" Version="1.2.3" />
275
+ </ItemGroup>
276
+ </Project>
277
+ """),
278
+ ],
279
+ expectedProjects:
280
+ [
281
+ new()
282
+ {
283
+ FilePath = "library.csproj",
284
+ Dependencies =
285
+ [
286
+ new("Some.Dependency", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net7.0"], IsDirect: true),
287
+ new("Some.Dependency", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net8.0"], IsDirect: true),
288
+ ],
289
+ ImportedFiles = [],
290
+ Properties =
291
+ [
292
+ new("TargetFrameworks", "net7.0;net8.0", "src/library.csproj"),
293
+ ],
294
+ TargetFrameworks = ["net7.0", "net8.0"]
295
+ },
296
+ ]
297
+ );
298
+ }
299
+
300
+ [Fact]
301
+ public async Task DiscoveryIgnoresNetStandardLibrary()
302
+ {
303
+ await TestDiscoverAsync(
304
+ packages:
305
+ [
306
+ MockNuGetPackage.CreateSimplePackage("Some.Dependency", "1.2.3", "netstandard2.0"),
307
+ ],
308
+ startingDirectory: "src",
309
+ projectPath: "src/library.csproj",
310
+ files:
311
+ [
312
+ ("src/library.csproj", """
313
+ <Project Sdk="Microsoft.NET.Sdk">
314
+ <PropertyGroup>
315
+ <TargetFramework>netstandard2.0</TargetFramework>
316
+ </PropertyGroup>
317
+ <ItemGroup>
318
+ <PackageReference Include="Some.Dependency" Version="1.2.3" />
319
+ </ItemGroup>
320
+ </Project>
321
+ """),
322
+ ],
323
+ expectedProjects:
324
+ [
325
+ new()
326
+ {
327
+ FilePath = "library.csproj",
328
+ Dependencies =
329
+ [
330
+ new("Some.Dependency", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["netstandard2.0"], IsDirect: true),
331
+ ],
332
+ ImportedFiles = [],
333
+ Properties =
334
+ [
335
+ new("TargetFramework", "netstandard2.0", "src/library.csproj"),
336
+ ],
337
+ TargetFrameworks = ["netstandard2.0"]
338
+ },
339
+ ]
340
+ );
341
+ }
342
+
343
+ [Fact]
344
+ public async Task GlobalPackages()
345
+ {
346
+ await TestDiscoverAsync(
347
+ packages:
348
+ [
349
+ MockNuGetPackage.CreateSimplePackage("Some.Dependency", "1.2.3", "netstandard2.0"),
350
+ ],
351
+ startingDirectory: "src",
352
+ projectPath: "src/library.csproj",
353
+ files:
354
+ [
355
+ ("src/library.csproj", """
356
+ <Project Sdk="Microsoft.NET.Sdk">
357
+ <PropertyGroup>
358
+ <TargetFramework>net8.0</TargetFramework>
359
+ <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
360
+ </PropertyGroup>
361
+ </Project>
362
+ """),
363
+ ("src/Directory.Build.props", """
364
+ <Project>
365
+ <ItemGroup>
366
+ <GlobalPackageReference Include="Some.Dependency" Version="1.2.3" />
367
+ </ItemGroup>
368
+ </Project>
369
+ """)
370
+ ],
371
+ expectedProjects:
372
+ [
373
+ new()
374
+ {
375
+ FilePath = "library.csproj",
376
+ Dependencies =
377
+ [
378
+ new("Some.Dependency", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net8.0"], IsDirect: true),
379
+ ],
380
+ ImportedFiles =
381
+ [
382
+ "Directory.Build.props",
383
+ ],
384
+ Properties =
385
+ [
386
+ new("ManagePackageVersionsCentrally", "true", "src/library.csproj"),
387
+ new("TargetFramework", "net8.0", "src/library.csproj"),
388
+ ],
389
+ TargetFrameworks = ["net8.0"]
390
+ },
391
+ ]
392
+ );
393
+ }
394
+
395
+ [Fact]
396
+ public async Task CentralPackageManagementAlternatePackagesPropsLocation()
397
+ {
398
+ // when using central package management, the well-known file `Directory.Packages.props` can be overridden with
399
+ // the `$(DirectoryPackagesPropsPath)` property
400
+ await TestDiscoverAsync(
401
+ packages:
402
+ [
403
+ MockNuGetPackage.CreateSimplePackage("Some.Dependency", "1.2.3", "netstandard2.0"),
404
+ ],
405
+ startingDirectory: "src",
406
+ projectPath: "src/library.csproj",
407
+ files:
408
+ [
409
+ ("src/library.csproj", """
410
+ <Project Sdk="Microsoft.NET.Sdk">
411
+ <PropertyGroup>
412
+ <TargetFramework>net8.0</TargetFramework>
413
+ <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
414
+ </PropertyGroup>
415
+ <ItemGroup>
416
+ <PackageReference Include="Some.Dependency" />
417
+ </ItemGroup>
418
+ </Project>
419
+ """),
420
+ ("src/Directory.Build.props", """
421
+ <Project>
422
+ <PropertyGroup>
423
+ <DirectoryPackagesPropsPath>$(MSBuildThisFileDirectory)..\NonStandardPackages.props</DirectoryPackagesPropsPath>
424
+ </PropertyGroup>
425
+ </Project>
426
+ """),
427
+ ("NonStandardPackages.props", """
428
+ <Project>
429
+ <ItemGroup>
430
+ <PackageVersion Include="Some.Dependency" Version="1.2.3" />
431
+ </ItemGroup>
432
+ </Project>
433
+ """)
434
+ ],
435
+ expectedProjects:
436
+ [
437
+ new()
438
+ {
439
+ FilePath = "library.csproj",
440
+ Dependencies =
441
+ [
442
+ new("Some.Dependency", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net8.0"], IsDirect: true),
443
+ ],
444
+ ImportedFiles =
445
+ [
446
+ "../NonStandardPackages.props",
447
+ "Directory.Build.props",
448
+ ],
449
+ Properties =
450
+ [
451
+ new("ManagePackageVersionsCentrally", "true", "src/library.csproj"),
452
+ new("TargetFramework", "net8.0", "src/library.csproj"),
453
+ ],
454
+ TargetFrameworks = ["net8.0"]
455
+ },
456
+ ]
457
+ );
458
+ }
459
+
460
+ private static async Task TestDiscoverAsync(string startingDirectory, string projectPath, TestFile[] files, ImmutableArray<ExpectedSdkProjectDiscoveryResult> expectedProjects, MockNuGetPackage[]? packages = null)
461
+ {
462
+ using var testDirectory = await TemporaryDirectory.CreateWithContentsAsync(files);
463
+
464
+ await UpdateWorkerTestBase.MockNuGetPackagesInDirectory(packages, testDirectory.DirectoryPath);
465
+
466
+ var logger = new TestLogger();
467
+ var fullProjectPath = Path.Combine(testDirectory.DirectoryPath, projectPath);
468
+ var experimentsManager = new ExperimentsManager() { UseDirectDiscovery = true }; // the following method is direct discovery; this just makes the call to Validate... happy
469
+ var projectDiscovery = await SdkProjectDiscovery.DiscoverWithBinLogAsync(testDirectory.DirectoryPath, Path.GetDirectoryName(fullProjectPath)!, fullProjectPath, logger);
470
+ ValidateProjectResults(expectedProjects, projectDiscovery, experimentsManager);
471
+ }
472
+ }
@@ -291,9 +291,12 @@ namespace NuGetUpdater.Core.Test
291
291
  <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
292
292
  <!-- this is a simplified version of this package used for testing -->
293
293
  <PropertyGroup>
294
- <CentralPackagesFile Condition=" '$(CentralPackagesFile)' == '' ">$([MSBuild]::GetPathOfFileAbove('Packages.props', $(MSBuildProjectDirectory)))</CentralPackagesFile>
294
+ <CentralPackagesFile Condition=" '$(CentralPackagesFile)' == '' ">$([MSBuild]::GetPathOfFileAbove('Packages.props', $(MSBuildProjectDirectory)))</CentralPackagesFile>
295
295
  </PropertyGroup>
296
296
  <Import Project="$(CentralPackagesFile)" Condition="Exists('$(CentralPackagesFile)')" />
297
+ <ItemGroup Condition=" '$(EnableGlobalPackageReferences)' != 'false' ">
298
+ <PackageReference Include="@(GlobalPackageReference)" Condition=" '$(EnableGlobalPackageReferences)' != 'false' " />
299
+ </ItemGroup>
297
300
  </Project>
298
301
  """
299
302
  );
@@ -384,6 +387,47 @@ namespace NuGetUpdater.Core.Test
384
387
  return WellKnownPackages[key];
385
388
  }
386
389
 
390
+ public static MockNuGetPackage WellKnownHostPackage(string packageName, string targetFramework, (string Path, byte[] Content)[]? files = null)
391
+ {
392
+ string key = $"{packageName}/{targetFramework}";
393
+ if (!WellKnownPackages.ContainsKey(key))
394
+ {
395
+ // for the current SDK, the file `Microsoft.NETCoreSdk.BundledVersions.props` contains the version of the
396
+ // `Microsoft.WindowsDesktop.App.Ref` package that will be needed to build, so we find it by TFM
397
+ XDocument propsDocument = XDocument.Load(BundledVersionsPropsPath.Value);
398
+ XElement? ridElement = propsDocument.XPathSelectElement("/Project/PropertyGroup/NETCoreSdkRuntimeIdentifier");
399
+ if (ridElement is null)
400
+ {
401
+ throw new Exception($"Unable to find RID property.");
402
+ }
403
+
404
+ string expectedRid = ridElement.Value.Trim();
405
+
406
+ XElement? matchingAppHostPack = propsDocument.XPathSelectElement(
407
+ $"""
408
+ /Project/ItemGroup/KnownAppHostPack
409
+ [
410
+ @Include='{packageName}' and
411
+ @AppHostPackNamePattern='{packageName}.Host.**RID**' and
412
+ @TargetFramework='{targetFramework}'
413
+ ]
414
+ """);
415
+ if (matchingAppHostPack is null)
416
+ {
417
+ throw new Exception($"Unable to find {packageName}.Host.**RID** version for target framework '{targetFramework}'");
418
+ }
419
+
420
+ string expectedVersion = matchingAppHostPack.Attribute("AppHostPackVersion")!.Value;
421
+ return new(
422
+ $"{packageName}.Host.{expectedRid}",
423
+ expectedVersion,
424
+ Files: files
425
+ );
426
+ }
427
+
428
+ return WellKnownPackages[key];
429
+ }
430
+
387
431
  public static MockNuGetPackage[] CommonPackages { get; } =
388
432
  [
389
433
  CreateSimplePackage("NETStandard.Library", "2.0.3", "netstandard2.0"),
@@ -424,6 +468,7 @@ namespace NuGetUpdater.Core.Test
424
468
  WellKnownReferencePackage("Microsoft.WindowsDesktop.App", "net7.0"),
425
469
  WellKnownReferencePackage("Microsoft.WindowsDesktop.App", "net8.0"),
426
470
  WellKnownReferencePackage("Microsoft.WindowsDesktop.App", "net9.0"),
471
+ WellKnownHostPackage("Microsoft.NETCore.App", "net8.0"),
427
472
  ];
428
473
  }
429
474
  }
@@ -11,7 +11,6 @@
11
11
  </ItemGroup>
12
12
 
13
13
  <ItemGroup>
14
- <PackageReference Include="DiffPlex" />
15
14
  <PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
16
15
  <PackageReference Include="Microsoft.NET.Test.Sdk" />
17
16
  <PackageReference Include="xunit" />
@@ -1429,7 +1429,7 @@ public class RunWorkerTests
1429
1429
  experimentsManager ??= new ExperimentsManager();
1430
1430
  var testApiHandler = new TestApiHandler();
1431
1431
  var logger = new TestLogger();
1432
- discoveryWorker ??= new DiscoveryWorker(logger);
1432
+ discoveryWorker ??= new DiscoveryWorker(experimentsManager, logger);
1433
1433
  analyzeWorker ??= new AnalyzeWorker(logger);
1434
1434
  updaterWorker ??= new UpdaterWorker(experimentsManager, logger);
1435
1435
 
@@ -59,6 +59,34 @@ public class SerializationTests
59
59
  Assert.Equal("specific-sdk", jobWrapper.Job.Source.Directory);
60
60
  }
61
61
 
62
+ [Fact]
63
+ public void DeserializeJob_DebugIsNull()
64
+ {
65
+ // the `debug` field is defined as a `bool`, but can appear as `null` in the wild
66
+ var jobContent = """
67
+ {
68
+ "job": {
69
+ "package-manager": "nuget",
70
+ "allowed-updates": [
71
+ {
72
+ "update-type": "all"
73
+ }
74
+ ],
75
+ "source": {
76
+ "provider": "github",
77
+ "repo": "some-org/some-repo",
78
+ "directory": "specific-sdk",
79
+ "hostname": null,
80
+ "api-endpoint": null
81
+ },
82
+ "debug": null
83
+ }
84
+ }
85
+ """;
86
+ var jobWrapper = RunWorker.Deserialize(jobContent);
87
+ Assert.False(jobWrapper.Job.Debug);
88
+ }
89
+
62
90
  [Fact]
63
91
  public void DeserializeJob_FieldsNotYetSupported()
64
92
  {
@@ -125,6 +153,7 @@ public class SerializationTests
125
153
  },
126
154
  "experiments": {
127
155
  "nuget_legacy_dependency_solver": true,
156
+ "nuget_use_direct_discovery": true,
128
157
  "unexpected_bool": true,
129
158
  "unexpected_number": 42,
130
159
  "unexpected_null": null,
@@ -140,6 +169,7 @@ public class SerializationTests
140
169
  """);
141
170
  var experimentsManager = ExperimentsManager.GetExperimentsManager(jobWrapper.Job.Experiments);
142
171
  Assert.True(experimentsManager.UseLegacyDependencySolver);
172
+ Assert.True(experimentsManager.UseDirectDiscovery);
143
173
  }
144
174
 
145
175
  [Fact]
@@ -166,6 +196,7 @@ public class SerializationTests
166
196
  """);
167
197
  var experimentsManager = ExperimentsManager.GetExperimentsManager(jobWrapper.Job.Experiments);
168
198
  Assert.False(experimentsManager.UseLegacyDependencySolver);
199
+ Assert.False(experimentsManager.UseDirectDiscovery);
169
200
  }
170
201
 
171
202
  [Fact]
@@ -190,6 +221,7 @@ public class SerializationTests
190
221
  """);
191
222
  var experimentsManager = ExperimentsManager.GetExperimentsManager(jobWrapper.Job.Experiments);
192
223
  Assert.False(experimentsManager.UseLegacyDependencySolver);
224
+ Assert.False(experimentsManager.UseDirectDiscovery);
193
225
  }
194
226
 
195
227
  [Fact]
@@ -212,6 +244,7 @@ public class SerializationTests
212
244
 
213
245
  // assert
214
246
  Assert.False(experimentsManager.UseLegacyDependencySolver);
247
+ Assert.False(experimentsManager.UseDirectDiscovery);
215
248
  Assert.Single(capturingTestLogger.Messages.Where(m => m.Contains("Error deserializing job file")));
216
249
  }
217
250
 
@@ -50,14 +50,15 @@ public sealed class TemporaryDirectory : IDisposable
50
50
  var parentDirectory = Path.GetDirectoryName(temporaryDirectory.DirectoryPath)!;
51
51
 
52
52
  // prevent directory crawling
53
- await File.WriteAllTextAsync(Path.Combine(parentDirectory, "Directory.Build.props"), """
53
+ await File.WriteAllTextAsync(Path.Combine(parentDirectory, "Directory.Build.props"), "<Project />");
54
+ await File.WriteAllTextAsync(Path.Combine(parentDirectory, "Directory.Build.targets"), "<Project />");
55
+ await File.WriteAllTextAsync(Path.Combine(parentDirectory, "Directory.Packages.props"), """
54
56
  <Project>
55
57
  <PropertyGroup>
56
58
  <ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
57
59
  </PropertyGroup>
58
60
  </Project>
59
61
  """);
60
- await File.WriteAllTextAsync(Path.Combine(parentDirectory, "Directory.Build.targets"), "<Project />");
61
62
 
62
63
  foreach (var (path, contents) in fileContents)
63
64
  {
@@ -263,8 +263,9 @@ public abstract class UpdateWorkerTestBase : TestBase
263
263
  AssertContainsFiles(expectedResult, actualResult);
264
264
  }
265
265
 
266
- public static async Task MockJobFileInDirectory(string temporaryDirectory)
266
+ public static async Task MockJobFileInDirectory(string temporaryDirectory, ExperimentsManager? experimentsManager = null)
267
267
  {
268
+ experimentsManager ??= new ExperimentsManager();
268
269
  var jobFile = new JobFile()
269
270
  {
270
271
  Job = new()
@@ -278,7 +279,8 @@ public abstract class UpdateWorkerTestBase : TestBase
278
279
  Provider = "github",
279
280
  Repo = "test/repo",
280
281
  Directory = "/",
281
- }
282
+ },
283
+ Experiments = experimentsManager.ToDictionary(),
282
284
  }
283
285
  };
284
286
  await File.WriteAllTextAsync(Path.Join(temporaryDirectory, "job.json"), JsonSerializer.Serialize(jobFile, RunWorker.SerializerOptions));