dependabot-nuget 0.352.0 → 0.353.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +15 -41
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +102 -46
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +0 -3
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyGroup.cs +19 -0
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +23 -2
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +4 -2
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/OutOfDisk.cs +9 -0
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/IApiHandler.cs +11 -1
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +25 -4
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs +2 -2
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/GroupUpdateAllVersionsHandler.cs +4 -4
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandler.cs +3 -3
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshSecurityUpdatePullRequestHandler.cs +2 -2
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshVersionUpdatePullRequestHandler.cs +2 -2
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +20 -23
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +41 -1
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +93 -0
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs +2 -5
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +21 -9
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +23 -104
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +1 -66
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/ApiModel/JobTests.cs +39 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/EndToEndTests.cs +142 -0
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/HttpApiHandlerTests.cs +1 -0
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/JobErrorBaseTests.cs +7 -0
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MessageReportTests.cs +11 -0
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +76 -7
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +8 -0
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackageReferenceUpdaterTests.cs +30 -0
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +25 -0
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/PathHelperTests.cs +250 -0
  33. metadata +5 -4
@@ -30,7 +30,7 @@ internal class RefreshVersionUpdatePullRequestHandler : IUpdateHandler
30
30
  {
31
31
  var repoContentsPath = caseInsensitiveRepoContentsPath ?? originalRepoContentsPath;
32
32
  var jobDependencies = job.Dependencies.ToHashSet(StringComparer.OrdinalIgnoreCase);
33
- foreach (var directory in job.GetAllDirectories())
33
+ foreach (var directory in job.GetAllDirectories(repoContentsPath.FullName))
34
34
  {
35
35
  var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, directory);
36
36
  logger.ReportDiscovery(discoveryResult);
@@ -81,7 +81,7 @@ internal class RefreshVersionUpdatePullRequestHandler : IUpdateHandler
81
81
  var dependencyName = dependencyUpdatesToPerform.Key;
82
82
  var dependencyInfosToUpdate = dependencyUpdatesToPerform.Value
83
83
  .Where(o => !job.IsDependencyIgnoredByNameOnly(o.Dependency.Name))
84
- .Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency, allowCooldown: true)))
84
+ .Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency, groupMatchers: [], allowCooldown: true)))
85
85
  .ToArray();
86
86
 
87
87
  foreach (var (projectPath, dependency, dependencyInfo) in dependencyInfosToUpdate)
@@ -108,7 +108,7 @@ internal static class PackageReferenceUpdater
108
108
  return [.. updateOperations];
109
109
  }
110
110
 
111
- private static async Task<(Dictionary<string, HashSet<string>> PackageParents, Dictionary<string, NuGetVersion> PackageVersions)> GetPackageGraphForDependencies(string repoRoot, string projectPath, string targetFramework, ImmutableArray<Dependency> topLevelDependencies, ILogger logger)
111
+ internal static async Task<(Dictionary<string, HashSet<string>> PackageParents, Dictionary<string, NuGetVersion> PackageVersions)> GetPackageGraphForDependencies(string repoRoot, string projectPath, string targetFramework, ImmutableArray<Dependency> topLevelDependencies, ILogger logger)
112
112
  {
113
113
  var packageParents = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
114
114
  var packageVersions = new Dictionary<string, NuGetVersion>(StringComparer.OrdinalIgnoreCase);
@@ -117,37 +117,34 @@ internal static class PackageReferenceUpdater
117
117
  {
118
118
  // generate project.assets.json
119
119
  var parsedTargetFramework = NuGetFramework.Parse(targetFramework);
120
- var tempProject = await MSBuildHelper.CreateTempProjectAsync(tempDir, repoRoot, projectPath, targetFramework, topLevelDependencies, logger, importDependencyTargets: false);
121
- var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["build", tempProject, "/t:_ReportDependencies"], tempDir.FullName);
120
+ var tempProject = await MSBuildHelper.CreateTempProjectAsync(tempDir, repoRoot, projectPath, targetFramework, topLevelDependencies, logger, importDependencyTargets: true);
121
+ var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["msbuild", tempProject, "/t:Restore,GenerateBuildDependencyFile"], tempDir.FullName);
122
122
  var assetsJsonPath = Path.Join(tempDir.FullName, "obj", "project.assets.json");
123
123
  var assetsJsonContent = await File.ReadAllTextAsync(assetsJsonPath);
124
124
 
125
125
  // build reverse dependency graph
126
126
  var assets = JsonDocument.Parse(assetsJsonContent).RootElement;
127
- foreach (var tfmObject in assets.GetProperty("targets").EnumerateObject())
127
+ var tfmObjects = assets.GetProperty("targets").EnumerateObject().ToImmutableArray();
128
+ if (tfmObjects.Length != 1)
128
129
  {
129
- var reportedTargetFramework = NuGetFramework.Parse(tfmObject.Name);
130
- if (reportedTargetFramework != parsedTargetFramework)
131
- {
132
- // not interested in this target framework
133
- continue;
134
- }
130
+ logger.Error($"Expected exactly one target framework group compatible with {targetFramework} but found {tfmObjects.Length}. Values: {tfmObjects.Select(t => t.Name)}");
131
+ return (packageParents, packageVersions);
132
+ }
135
133
 
136
- foreach (var parentObject in tfmObject.Value.EnumerateObject())
137
- {
138
- var parts = parentObject.Name.Split('/');
139
- var parentName = parts[0];
140
- var parentVersion = parts[1];
141
- packageVersions[parentName] = NuGetVersion.Parse(parentVersion);
134
+ foreach (var parentObject in tfmObjects[0].Value.EnumerateObject())
135
+ {
136
+ var parts = parentObject.Name.Split('/');
137
+ var parentName = parts[0];
138
+ var parentVersion = parts[1];
139
+ packageVersions[parentName] = NuGetVersion.Parse(parentVersion);
142
140
 
143
- if (parentObject.Value.TryGetProperty("dependencies", out var dependencies))
141
+ if (parentObject.Value.TryGetProperty("dependencies", out var dependencies))
142
+ {
143
+ foreach (var childObject in dependencies.EnumerateObject())
144
144
  {
145
- foreach (var childObject in dependencies.EnumerateObject())
146
- {
147
- var childName = childObject.Name;
148
- var parentSet = packageParents.GetOrAdd(childName, () => new(StringComparer.OrdinalIgnoreCase));
149
- parentSet.Add(parentName);
150
- }
145
+ var childName = childObject.Name;
146
+ var parentSet = packageParents.GetOrAdd(childName, () => new(StringComparer.OrdinalIgnoreCase));
147
+ parentSet.Add(parentName);
151
148
  }
152
149
  }
153
150
  }
@@ -493,7 +493,7 @@ internal static partial class MSBuildHelper
493
493
  var topLevelPackagesNames = packages.Select(p => p.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
494
494
  var tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages, logger, importDependencyTargets: false);
495
495
 
496
- var experimentsManager = new ExperimentsManager() { UseSingleRestore = false }; // single restore is meaningless here
496
+ var experimentsManager = new ExperimentsManager();
497
497
  var projectDiscovery = await SdkProjectDiscovery.DiscoverAsync(repoRoot, tempDirectory.FullName, tempProjectPath, experimentsManager, logger);
498
498
  var allDependencies = projectDiscovery
499
499
  .Where(p => p.FilePath == Path.GetFileName(tempProjectPath))
@@ -545,6 +545,37 @@ internal static partial class MSBuildHelper
545
545
  return targets;
546
546
  }
547
547
 
548
+ internal static async Task<ImmutableArray<string>> GetProjectTargetFrameworksAsync(string projectPath, ILogger logger)
549
+ {
550
+ var extension = Path.GetExtension(projectPath)?.ToLowerInvariant();
551
+ if (extension == ".sln" || extension == ".slnx")
552
+ {
553
+ // solution files don't specify target frameworks, so we can skip the process invocation
554
+ return [];
555
+ }
556
+
557
+ var projectDirectory = Path.GetDirectoryName(projectPath)!;
558
+ var args = new[]
559
+ {
560
+ "msbuild",
561
+ projectPath,
562
+ "-getProperty:TargetFrameworks"
563
+ };
564
+
565
+ var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(args, projectDirectory);
566
+ if (exitCode != 0)
567
+ {
568
+ logger.Warn($"Unable to determine target frameworks for project [{projectPath}]:\nSTDOUT:\n{stdOut}\nSTDERR:\n{stdErr}\n");
569
+ return [];
570
+ }
571
+
572
+ var tfms = Regex.Replace(stdOut, "@[\r\n\t ]", "")
573
+ .Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
574
+ .OrderBy(t => t)
575
+ .ToImmutableArray();
576
+ return tfms;
577
+ }
578
+
548
579
  internal static string? GetMissingFile(string output)
549
580
  {
550
581
  var missingFilePatterns = new[]
@@ -571,6 +602,7 @@ internal static partial class MSBuildHelper
571
602
  ThrowOnTimeout(output);
572
603
  ThrowOnBadResponse(output);
573
604
  ThrowOnUnparseableFile(output);
605
+ ThrowOnMultipleProjectsForPackagesConfig(output);
574
606
  }
575
607
 
576
608
  private static void ThrowOnUnauthenticatedFeed(string stdout)
@@ -704,6 +736,14 @@ internal static partial class MSBuildHelper
704
736
  }
705
737
  }
706
738
 
739
+ private static void ThrowOnMultipleProjectsForPackagesConfig(string output)
740
+ {
741
+ if (output.Contains("Found multiple project files for "))
742
+ {
743
+ throw new Exception("Multiple project files found for single packages.config");
744
+ }
745
+ }
746
+
707
747
  internal static bool TryGetGlobalJsonPath(string repoRootPath, string workspacePath, [NotNullWhen(returnValue: true)] out string? globalJsonPath)
708
748
  {
709
749
  globalJsonPath = PathHelper.GetFileInDirectoryOrParent(workspacePath, repoRootPath, "global.json", caseSensitive: false);
@@ -1,4 +1,6 @@
1
+ using System.Collections.Immutable;
1
2
  using System.Runtime.InteropServices;
3
+ using System.Text;
2
4
  using System.Text.RegularExpressions;
3
5
 
4
6
  namespace NuGetUpdater.Core;
@@ -248,4 +250,95 @@ internal static class PathHelper
248
250
 
249
251
  return candidateFilePath.StartsWith(directoryPath);
250
252
  }
253
+
254
+ public static ImmutableArray<string> GetMatchingDirectoriesUnder(string rootDirectory, string searchPattern, bool caseSensitive)
255
+ {
256
+ // translate pattern to regex
257
+ searchPattern = searchPattern.Replace("\\", "/"); // unix-style paths make things easier
258
+ searchPattern = searchPattern.TrimStart('/'); // pattern shouldn't be rooted
259
+ if (searchPattern == string.Empty)
260
+ {
261
+ searchPattern = "/"; // special case repo root
262
+ }
263
+
264
+ var pb = new StringBuilder();
265
+ pb.Append('^');
266
+ var appendAnchor = true;
267
+ for (int i = 0; i < searchPattern.Length; i++)
268
+ {
269
+ // special case recursive wildcard
270
+ if (searchPattern[i..] == "/**/*")
271
+ {
272
+ pb.Append("($|/.*$)"); // capture just this directory and every subdirectory
273
+ appendAnchor = false;
274
+ break;
275
+ }
276
+
277
+ var c = searchPattern[i];
278
+ switch (c)
279
+ {
280
+ case '*':
281
+ // could be single level or multi-level
282
+ var isRecursiveMatch = i < searchPattern.Length - 2
283
+ && searchPattern[i + 1] == '*'
284
+ && searchPattern[i + 2] == '/';
285
+ if (isRecursiveMatch)
286
+ {
287
+ // match anything
288
+ pb.Append(".*");
289
+ i += 2; // consume the extra characters
290
+ }
291
+ else
292
+ {
293
+ // only match up to a directory separator
294
+ pb.Append("[^/]*");
295
+ }
296
+ break;
297
+ case '?':
298
+ pb.Append(".");
299
+ break;
300
+ case '/':
301
+ pb.Append("/");
302
+ break;
303
+ default:
304
+ if ("+()^$.{}[]|\\".Contains(c))
305
+ {
306
+ pb.Append('\\');
307
+ }
308
+ pb.Append(c);
309
+ break;
310
+ }
311
+ }
312
+
313
+ if (appendAnchor)
314
+ {
315
+ pb.Append('$');
316
+ }
317
+
318
+ var pattern = new Regex(pb.ToString(), caseSensitive ? RegexOptions.IgnoreCase : RegexOptions.None);
319
+
320
+ // find all directories
321
+ var allDirectories = Directory.EnumerateDirectories(rootDirectory, "*", SearchOption.AllDirectories)
322
+ .Select(d => Path.GetRelativePath(rootDirectory, d).NormalizePathToUnix())
323
+ .ToImmutableArray();
324
+
325
+ // filter
326
+ var matchingDirectories = allDirectories.Where(pattern.IsMatch)
327
+ .OrderBy(d => d, caseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase)
328
+ .Select(d => d.EnsurePrefix("/")) // paths must appear rooted from here on out
329
+ .ToImmutableArray();
330
+
331
+ // special case some well-known directories that are hard to generate patterns for
332
+ switch (searchPattern)
333
+ {
334
+ case "/":
335
+ case ".":
336
+ case "/.":
337
+ case "**/*":
338
+ matchingDirectories = [.. matchingDirectories.Prepend("/")];
339
+ break;
340
+ }
341
+
342
+ return matchingDirectories;
343
+ }
251
344
  }
@@ -61,13 +61,10 @@ public partial class DiscoveryWorkerTests
61
61
  );
62
62
  }
63
63
 
64
- [Theory]
65
- [InlineData(true)]
66
- [InlineData(false)]
67
- public async Task DiscoveryIsMergedWithPackageReferences(bool useSingleRestore)
64
+ [Fact]
65
+ public async Task DiscoveryIsMergedWithPackageReferences()
68
66
  {
69
67
  await TestDiscoveryAsync(
70
- experimentsManager: new ExperimentsManager() { UseSingleRestore = useSingleRestore },
71
68
  packages:
72
69
  [
73
70
  MockNuGetPackage.CreateSimplePackage("Package.A", "1.0.0", "net46"),
@@ -626,7 +626,7 @@ public partial class DiscoveryWorkerTests
626
626
  ("src/project.csproj", """
627
627
  <Project Sdk="Microsoft.NET.Sdk">
628
628
  <PropertyGroup>
629
- <TargetFrameworks>net8.0-ios;net8.0-android;net8.0-macos;net8.0-maccatalyst;net8.0-windows</TargetFrameworks>
629
+ <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst;net8.0-macos;net8.0-windows</TargetFrameworks>
630
630
  </PropertyGroup>
631
631
  <ItemGroup>
632
632
  <PackageReference Include="Some.Package" Version="1.2.3" />
@@ -645,7 +645,7 @@ public partial class DiscoveryWorkerTests
645
645
  new("Some.Package", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net8.0-android", "net8.0-ios", "net8.0-maccatalyst", "net8.0-macos", "net8.0-windows"], IsDirect: true),
646
646
  ],
647
647
  Properties = [
648
- new("TargetFrameworks", "net8.0-ios;net8.0-android;net8.0-macos;net8.0-maccatalyst;net8.0-windows", @"src/project.csproj"),
648
+ new("TargetFrameworks", "net8.0-android;net8.0-ios;net8.0-maccatalyst;net8.0-macos;net8.0-windows", @"src/project.csproj"),
649
649
  ],
650
650
  TargetFrameworks = ["net8.0-android", "net8.0-ios", "net8.0-maccatalyst", "net8.0-macos", "net8.0-windows"],
651
651
  ReferencedProjectPaths = [],
@@ -737,7 +737,7 @@ public partial class DiscoveryWorkerTests
737
737
 
738
738
  // The SDK package handling is detected in a very specific circumstance; an assembly being removed from the
739
739
  // `@(References)` item group in the `_HandlePackageFileConflicts` target. Since we don't want to involve
740
- // the real SDK, we fake some required targets.
740
+ // the real SDK, we fake some required targets in the same shape as the real SDK.
741
741
  await TestDiscoveryAsync(
742
742
  packages: [],
743
743
  workspacePath: "",
@@ -764,6 +764,14 @@ public partial class DiscoveryWorkerTests
764
764
  <Reference Include="@(RuntimeCopyLocalItems)" />
765
765
  </ItemGroup>
766
766
 
767
+ <Target Name="ResolveProjectReferences">
768
+ <!-- this target needs to exist for discovery to work -->
769
+ </Target>
770
+
771
+ <Target Name="Restore">
772
+ <!-- this target needs to exist for discovery to work -->
773
+ </Target>
774
+
767
775
  <Target Name="_HandlePackageFileConflicts">
768
776
  <!-- this target needs to exist for discovery to work -->
769
777
  <ItemGroup>
@@ -775,21 +783,25 @@ public partial class DiscoveryWorkerTests
775
783
  </ItemGroup>
776
784
  </Target>
777
785
 
778
- <Target Name="ResolveAssemblyReferences" DependsOnTargets="_HandlePackageFileConflicts">
786
+ <Target Name="ResolvePackageAssets">
779
787
  <!-- this target needs to exist for discovery to work -->
780
788
  </Target>
781
789
 
782
- <Target Name="GenerateBuildDependencyFile">
790
+ <Target Name="ResolveFrameworkReferences" DependsOnTargets="ResolvePackageAssets">
791
+ <!-- this target needs to exist for discovery to work -->
792
+ </Target>
793
+
794
+ <Target Name="ResolveRuntimePackAssets" DependsOnTargets="ResolveFrameworkReferences">
795
+ <!-- this target needs to exist for discovery to work -->
796
+ </Target>
797
+
798
+ <Target Name="GenerateBuildDependencyFile" DependsOnTargets="_HandlePackageFileConflicts;ResolveRuntimePackAssets">
783
799
  <!-- this target needs to exist for discovery to work -->
784
800
  <ItemGroup>
785
801
  <!-- this removal is what removes the regular package reference from the project -->
786
802
  <RuntimeCopyLocalItems Remove="TestOnlyAssembly.dll" />
787
803
  </ItemGroup>
788
804
  </Target>
789
-
790
- <Target Name="ResolvePackageAssets">
791
- <!-- this target needs to exist for discovery to work -->
792
- </Target>
793
805
  </Project>
794
806
  """)
795
807
  ],
@@ -1,6 +1,8 @@
1
1
  using System.Collections.Immutable;
2
2
  using System.Text.Json;
3
3
 
4
+ using Microsoft.Build.Evaluation;
5
+
4
6
  using NuGetUpdater.Core.Discover;
5
7
  using NuGetUpdater.Core.Run.ApiModel;
6
8
  using NuGetUpdater.Core.Test.Utilities;
@@ -164,13 +166,10 @@ public partial class DiscoveryWorkerTests : DiscoveryWorkerTestBase
164
166
  );
165
167
  }
166
168
 
167
- [Theory]
168
- [InlineData(true)]
169
- [InlineData(false)]
170
- public async Task TestDependenciesSeparatedBySemicolon(bool useSingleRestore)
169
+ [Fact]
170
+ public async Task TestDependenciesSeparatedBySemicolon()
171
171
  {
172
172
  await TestDiscoveryAsync(
173
- experimentsManager: new ExperimentsManager() { UseSingleRestore = useSingleRestore },
174
173
  packages:
175
174
  [
176
175
  MockNuGetPackage.CreateSimplePackage("Some.Package", "9.0.1", "net8.0"),
@@ -369,13 +368,10 @@ public partial class DiscoveryWorkerTests : DiscoveryWorkerTestBase
369
368
  );
370
369
  }
371
370
 
372
- [Theory]
373
- [InlineData(true)]
374
- [InlineData(false)]
375
- public async Task TestPackageConfig(bool useSingleRestore)
371
+ [Fact]
372
+ public async Task TestPackageConfig()
376
373
  {
377
374
  await TestDiscoveryAsync(
378
- experimentsManager: new ExperimentsManager() { UseSingleRestore = useSingleRestore },
379
375
  packages:
380
376
  [
381
377
  MockNuGetPackage.CreateSimplePackage("Some.Package", "7.0.1", "net45"),
@@ -492,14 +488,11 @@ public partial class DiscoveryWorkerTests : DiscoveryWorkerTestBase
492
488
  );
493
489
  }
494
490
 
495
- [Theory]
496
- [InlineData(true)]
497
- [InlineData(false)]
498
- public async Task TestRepo(bool useSingleRestore)
491
+ [Fact]
492
+ public async Task TestRepo()
499
493
  {
500
494
  var solutionPath = "solution.sln";
501
495
  await TestDiscoveryAsync(
502
- experimentsManager: new ExperimentsManager() { UseSingleRestore = useSingleRestore },
503
496
  packages:
504
497
  [
505
498
  MockNuGetPackage.CreateSimplePackage("Some.Package", "9.0.1", "net7.0"),
@@ -625,13 +618,10 @@ public partial class DiscoveryWorkerTests : DiscoveryWorkerTestBase
625
618
  );
626
619
  }
627
620
 
628
- [Theory]
629
- [InlineData(true)]
630
- [InlineData(false)]
631
- public async Task TestRepo_Sln(bool useSingleRestore)
621
+ [Fact]
622
+ public async Task TestRepo_Sln()
632
623
  {
633
624
  await TestDiscoveryAsync(
634
- experimentsManager: new ExperimentsManager() { UseSingleRestore = useSingleRestore },
635
625
  packages: [
636
626
  MockNuGetPackage.CreateSimplePackage("Package.A", "1.2.3", "net8.0"),
637
627
  MockNuGetPackage.CreateSimplePackage("Package.B", "4.5.6", "net8.0"),
@@ -721,14 +711,11 @@ public partial class DiscoveryWorkerTests : DiscoveryWorkerTestBase
721
711
  );
722
712
  }
723
713
 
724
- [Theory]
725
- [InlineData(true)]
726
- [InlineData(false)]
727
- public async Task TestRepo_Slnx(bool useSingleRestore)
714
+ [Fact]
715
+ public async Task TestRepo_Slnx()
728
716
  {
729
717
  var solutionPath = "solution.slnx";
730
718
  await TestDiscoveryAsync(
731
- experimentsManager: new ExperimentsManager() { UseSingleRestore = useSingleRestore },
732
719
  packages:
733
720
  [
734
721
  MockNuGetPackage.CreateSimplePackage("Some.Package", "9.0.1", "net7.0"),
@@ -864,77 +851,6 @@ public partial class DiscoveryWorkerTests : DiscoveryWorkerTestBase
864
851
  );
865
852
  }
866
853
 
867
- [Fact]
868
- public async Task TestDirsProj_CasingMismatchIsResolved()
869
- {
870
- var dirsProjPath = "dirs.proj";
871
- await TestDiscoveryAsync(
872
- packages:
873
- [
874
- MockNuGetPackage.CreateSimplePackage("Some.Package", "9.0.1", "net7.0"),
875
- ],
876
- workspacePath: "",
877
- files: new[]
878
- {
879
- ("src/project.csproj", """
880
- <Project Sdk="Microsoft.NET.Sdk">
881
- <PropertyGroup>
882
- <TargetFrameworks>net7.0;net8.0</TargetFrameworks>
883
- </PropertyGroup>
884
-
885
- <ItemGroup>
886
- <PackageReference Include="Some.Package" />
887
- </ItemGroup>
888
- </Project>
889
- """),
890
- ("Directory.Build.props", "<Project />"),
891
- ("Directory.Packages.props", """
892
- <Project>
893
- <PropertyGroup>
894
- <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
895
- <SomePackageVersion>9.0.1</SomePackageVersion>
896
- </PropertyGroup>
897
-
898
- <ItemGroup>
899
- <PackageVersion Include="Some.Package" Version="$(SomePackageVersion)" />
900
- </ItemGroup>
901
- </Project>
902
- """),
903
- // Introduce a casing difference in the project reference
904
- (dirsProjPath, """
905
- <Project>
906
- <ItemGroup>
907
- <ProjectReference Include="SRC/PROJECT.CSPROJ" />
908
- </ItemGroup>
909
- </Project>
910
- """)
911
- },
912
- expectedResult: new()
913
- {
914
- Path = "",
915
- Projects = [
916
- new()
917
- {
918
- FilePath = "src/project.csproj",
919
- TargetFrameworks = ["net7.0", "net8.0"],
920
- Dependencies = [
921
- new("Some.Package", "9.0.1", DependencyType.PackageReference, TargetFrameworks: ["net7.0", "net8.0"], IsDirect: true)
922
- ],
923
- Properties = [
924
- new("TargetFrameworks", "net7.0;net8.0", "src/project.csproj"),
925
- ],
926
- ReferencedProjectPaths = [],
927
- ImportedFiles = [
928
- "../Directory.Build.props",
929
- "../Directory.Packages.props",
930
- ],
931
- AdditionalFiles = [],
932
- }
933
- ],
934
- }
935
- );
936
- }
937
-
938
854
  [Fact]
939
855
  public async Task NonSupportedProjectExtensionsAreSkipped()
940
856
  {
@@ -1619,20 +1535,23 @@ public partial class DiscoveryWorkerTests : DiscoveryWorkerTestBase
1619
1535
  );
1620
1536
  }
1621
1537
 
1622
- [Theory]
1623
- [InlineData(@"..\project2\project2.csproj")] // relative
1624
- [InlineData(@"$(MSBuildThisFileDirectory)..\project2\project2.csproj")] // absolute
1625
- public async Task ExpandEntryPoints(string projectReferencePath)
1538
+ [Fact]
1539
+ public async Task ExpandEntryPoints()
1626
1540
  {
1627
1541
  using var tempDir = await TemporaryDirectory.CreateWithContentsAsync(
1542
+ ("src/dirs.proj", """
1543
+ <Project>
1544
+ <ItemGroup>
1545
+ <ProjectFile Include="project1\project1.csproj" /><!-- relative -->
1546
+ <ProjectFile Include="$(MSBuildThisFileDirectory)project2\project2.csproj" /><!-- absolute -->
1547
+ </ItemGroup>
1548
+ </Project>
1549
+ """),
1628
1550
  ("src/project1/project1.csproj", $"""
1629
1551
  <Project Sdk="Microsoft.NET.Sdk">
1630
1552
  <PropertyGroup>
1631
1553
  <TargetFramework>net9.0</TargetFramework>
1632
1554
  </PropertyGroup>
1633
- <ItemGroup>
1634
- <ProjectReference Include="{projectReferencePath}" />
1635
- </ItemGroup>
1636
1555
  </Project>
1637
1556
  """),
1638
1557
  ("src/project2/project2.csproj", """
@@ -1643,7 +1562,7 @@ public partial class DiscoveryWorkerTests : DiscoveryWorkerTestBase
1643
1562
  </Project>
1644
1563
  """)
1645
1564
  );
1646
- var actualEntryPoints = (await DiscoveryWorker.ExpandEntryPointsIntoProjectsAsync([Path.Combine(tempDir.DirectoryPath, "src/project1/project1.csproj")], new ExperimentsManager()))
1565
+ var actualEntryPoints = (await DiscoveryWorker.ExpandEntryPointsIntoProjectsAsync([Path.Combine(tempDir.DirectoryPath, "src/dirs.proj")], new ExperimentsManager()))
1647
1566
  .Select(p => p.NormalizePathToUnix())
1648
1567
  .ToArray();
1649
1568
  var expectedEntryPoints = new[]
@@ -580,63 +580,12 @@ public class SdkProjectDiscoveryTests : DiscoveryWorkerTestBase
580
580
  );
581
581
  }
582
582
 
583
- [Fact]
584
- public async Task ExistingPackageIncompatibilityShouldNotPreventRestore()
585
- {
586
- // Package.A tries to pull in a transitive dependency of Transitive.Package/2.0.0 but that package is explicitly pinned at 1.0.0
587
- // Normally this would cause a restore failure which means discovery would also fail
588
- // This test ensures we can still run discovery
589
- await TestDiscoverAsync(
590
- useSingleRestore: false,
591
- packages: [
592
- MockNuGetPackage.CreateSimplePackage("Package.A", "1.0.0", "net8.0", [(null, [("Transitive.Package", "2.0.0")])]),
593
- MockNuGetPackage.CreateSimplePackage("Transitive.Package", "1.0.0", "net8.0"),
594
- MockNuGetPackage.CreateSimplePackage("Transitive.Package", "2.0.0", "net8.0"),
595
- ],
596
- startingDirectory: "src",
597
- projectPath: "src/library.csproj",
598
- files: [
599
- ("src/library.csproj", """
600
- <Project Sdk="Microsoft.NET.Sdk">
601
- <PropertyGroup>
602
- <TargetFramework>net8.0</TargetFramework>
603
- </PropertyGroup>
604
- <ItemGroup>
605
- <PackageReference Include="Package.A" Version="1.0.0" />
606
- <PackageReference Include="Transitive.Package" Version="1.0.0" />
607
- </ItemGroup>
608
- </Project>
609
- """)
610
- ],
611
- expectedProjects: [
612
- new()
613
- {
614
- FilePath = "library.csproj",
615
- Dependencies =
616
- [
617
- new("Package.A", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"], IsDirect: true),
618
- new("Transitive.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"], IsDirect: true)
619
- ],
620
- ImportedFiles = [],
621
- Properties =
622
- [
623
- new("TargetFramework", "net8.0", "src/library.csproj"),
624
- ],
625
- TargetFrameworks = ["net8.0"],
626
- ReferencedProjectPaths = [],
627
- AdditionalFiles = [],
628
- }
629
- ]
630
- );
631
- }
632
-
633
583
  [Fact]
634
584
  public async Task DependenciesCanBeDiscoveredWithoutCompiling_FromProjectWithSingleTfm()
635
585
  {
636
586
  using var tempDir = new TemporaryDirectory();
637
587
  var errorSentinelPath = Path.Combine(tempDir.DirectoryPath, "error-sentinel.txt");
638
588
  await TestDiscoverAsync(
639
- useSingleRestore: true,
640
589
  startingDirectory: "src",
641
590
  packages: [
642
591
  MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0"),
@@ -691,7 +640,6 @@ public class SdkProjectDiscoveryTests : DiscoveryWorkerTestBase
691
640
  using var tempDir = new TemporaryDirectory();
692
641
  var errorSentinelPath = Path.Combine(tempDir.DirectoryPath, "error-sentinel.txt");
693
642
  await TestDiscoverAsync(
694
- useSingleRestore: true,
695
643
  startingDirectory: "src",
696
644
  packages: [
697
645
  MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0"),
@@ -747,19 +695,6 @@ public class SdkProjectDiscoveryTests : DiscoveryWorkerTestBase
747
695
  ImmutableArray<ExpectedSdkProjectDiscoveryResult> expectedProjects,
748
696
  MockNuGetPackage[]? packages = null
749
697
  )
750
- {
751
- await TestDiscoverAsync(useSingleRestore: true, startingDirectory, projectPath, files, expectedProjects, packages);
752
- await TestDiscoverAsync(useSingleRestore: false, startingDirectory, projectPath, files, expectedProjects, packages);
753
- }
754
-
755
- private static async Task TestDiscoverAsync(
756
- bool useSingleRestore,
757
- string startingDirectory,
758
- string projectPath,
759
- TestFile[] files,
760
- ImmutableArray<ExpectedSdkProjectDiscoveryResult> expectedProjects,
761
- MockNuGetPackage[]? packages = null
762
- )
763
698
  {
764
699
  using var testDirectory = await TemporaryDirectory.CreateWithContentsAsync(files);
765
700
 
@@ -767,7 +702,7 @@ public class SdkProjectDiscoveryTests : DiscoveryWorkerTestBase
767
702
 
768
703
  var logger = new TestLogger();
769
704
  var fullProjectPath = Path.Combine(testDirectory.DirectoryPath, projectPath);
770
- var experimentsManager = new ExperimentsManager() { UseSingleRestore = useSingleRestore };
705
+ var experimentsManager = new ExperimentsManager();
771
706
  var projectDiscovery = await SdkProjectDiscovery.DiscoverAsync(testDirectory.DirectoryPath, Path.GetDirectoryName(fullProjectPath)!, fullProjectPath, experimentsManager, logger);
772
707
  ValidateProjectResults(expectedProjects, projectDiscovery);
773
708
  }