dependabot-nuget 0.281.0 → 0.282.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3afe0ac22f324c8dacf2c16437998a6b22ad23ae21092f3889d3973eb4a59ddb
4
- data.tar.gz: e3aca7ae87df62bb56d264c5eb88e6f14fc9077e3c3c853cd769e34488d95cfa
3
+ metadata.gz: 40a4e33161303780b957de20221c3daf909d922bdff17bd22dead842f80a585e
4
+ data.tar.gz: f3faa68e7a0d0ef1e3a431acb17569b88309802cffb7be3315d080d0a2ec5f33
5
5
  SHA512:
6
- metadata.gz: f25c4209f6aab5ae958a092b34c9ab9a5d1473e1322646dcd7f1a7d0e753e681b975516fe5b416ca62c7ba7be219590f17c4541f4635bbe3355b9213e3ff587d
7
- data.tar.gz: e058837c6034711c21fd672774b3c37940f0f286af89fbd1e4cdefa9af415647f926bd626f13356bae3304f1e18b98cfcc67390f492ce0d8b06fa4bbf301356b
6
+ metadata.gz: 2d6e0c85681853fcd2d8a539ac2c4b116b8837442073954cd0fc4b717a45ce17cffa8d16f9f3e5d6e9db1f0beffdedb9577e56a05652285e706efabeedef1338
7
+ data.tar.gz: 1ba69c4b218959952b6d86553b24871bbbf43d0a443f35f9de886bdfa78029ae7ea9885c9b8247cb98e5ab39e6e8ea8c923ce4cec60404251791482da7ee923c
@@ -12,6 +12,6 @@
12
12
  <CommonTargetFramework>net9.0</CommonTargetFramework>
13
13
  <ImplicitUsings>enable</ImplicitUsings>
14
14
  <UseArtifactsOutput>true</UseArtifactsOutput>
15
- <ArtifactsPath>$(MSBuildThisFileDirectory)artifacts</ArtifactsPath>
15
+ <ArtifactsPath>$(MSBuildThisFileDirectory)artifacts\$(OS)</ArtifactsPath>
16
16
  </PropertyGroup>
17
17
  </Project>
@@ -18,6 +18,16 @@ internal static class BindingRedirectManager
18
18
  private static readonly XName DependentAssemblyName = AssemblyBinding.GetQualifiedName("dependentAssembly");
19
19
  private static readonly XName BindingRedirectName = AssemblyBinding.GetQualifiedName("bindingRedirect");
20
20
 
21
+ /// <summary>
22
+ /// Updates assembly binding redirects for a project build file.
23
+ /// </summary>
24
+ /// <remarks>
25
+ /// Assembly binding redirects are only applicable to projects targeting .NET Framework.
26
+ /// .NET Framework targets can appear in SDK-style OR non-SDK-style project files, using either packages.config OR `<PackageReference>` MSBuild items.
27
+ /// See: https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/redirect-assembly-versions
28
+ /// https://learn.microsoft.com/en-us/nuget/resources/check-project-format
29
+ /// </remarks>
30
+ /// <param name="projectBuildFile">The project build file (*.xproj) to be updated</param>
21
31
  public static async ValueTask UpdateBindingRedirectsAsync(ProjectBuildFile projectBuildFile)
22
32
  {
23
33
  var configFile = await TryGetRuntimeConfigurationFile(projectBuildFile);
@@ -33,7 +43,7 @@ internal static class BindingRedirectManager
33
43
  var bindings = BindingRedirectResolver.GetBindingRedirects(projectBuildFile.Path, references.Select(static x => x.Include));
34
44
  if (!bindings.Any())
35
45
  {
36
- // no bindings to update
46
+ // no bindings found in the project file, nothing to update
37
47
  return;
38
48
  }
39
49
 
@@ -6,7 +6,18 @@ using NuGet.Versioning;
6
6
 
7
7
  namespace NuGetUpdater.Core;
8
8
 
9
- internal static class SdkPackageUpdater
9
+ /// <summary>
10
+ /// Handles package updates for projects containing `<PackageReference>` MSBuild items.
11
+ /// </summary>
12
+ /// <remarks>
13
+ /// PackageReference items can appear in both SDK-style AND non-SDK-style project files.
14
+ /// By default, PackageReference is used by [SDK-style] projects targeting .NET Core, .NET Standard, and UWP.
15
+ /// By default, packages.config is used by [non-SDK-style] projects targeting .NET Framework; However, they can be migrated to PackageReference too.
16
+ /// See: https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#project-type-support
17
+ /// https://learn.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference
18
+ /// https://learn.microsoft.com/en-us/nuget/resources/check-project-format
19
+ /// </remarks>
20
+ internal static class PackageReferenceUpdater
10
21
  {
11
22
  public static async Task UpdateDependencyAsync(
12
23
  string repoRootPath,
@@ -17,8 +28,8 @@ internal static class SdkPackageUpdater
17
28
  bool isTransitive,
18
29
  ILogger logger)
19
30
  {
20
- // SDK-style project, modify the XML directly
21
- logger.Log(" Running for SDK-style project");
31
+ // PackageReference project; modify the XML directly
32
+ logger.Log(" Running 'PackageReference' project direct XML update");
22
33
 
23
34
  (ImmutableArray<ProjectBuildFile> buildFiles, string[] tfms) = await MSBuildHelper.LoadBuildFilesAndTargetFrameworksAsync(repoRootPath, projectPath);
24
35
 
@@ -30,19 +41,26 @@ internal static class SdkPackageUpdater
30
41
  return;
31
42
  }
32
43
 
33
- if (isTransitive)
44
+ var peerDependencies = await GetUpdatedPeerDependenciesAsync(repoRootPath, projectPath, tfms, dependencyName, newDependencyVersion, logger);
45
+ if (MSBuildHelper.UseNewDependencySolver())
34
46
  {
35
- await UpdateTransitiveDependencyAsync(repoRootPath, projectPath, dependencyName, newDependencyVersion, buildFiles, logger);
47
+ await UpdateDependencyWithConflictResolution(repoRootPath, buildFiles, tfms, projectPath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive, peerDependencies, logger);
36
48
  }
37
49
  else
38
50
  {
39
- var peerDependencies = await GetUpdatedPeerDependenciesAsync(repoRootPath, projectPath, tfms, dependencyName, newDependencyVersion, logger);
40
- if (peerDependencies is null)
51
+ if (isTransitive)
41
52
  {
42
- return;
53
+ await UpdateTransitiveDependencyAsync(repoRootPath, projectPath, dependencyName, newDependencyVersion, buildFiles, logger);
43
54
  }
55
+ else
56
+ {
57
+ if (peerDependencies is null)
58
+ {
59
+ return;
60
+ }
44
61
 
45
- await UpdateTopLevelDepdendency(repoRootPath, buildFiles, tfms, dependencyName, previousDependencyVersion, newDependencyVersion, peerDependencies, logger);
62
+ await UpdateTopLevelDepdendency(repoRootPath, buildFiles, tfms, dependencyName, previousDependencyVersion, newDependencyVersion, peerDependencies, logger);
63
+ }
46
64
  }
47
65
 
48
66
  if (!await AreDependenciesCoherentAsync(repoRootPath, projectPath, dependencyName, logger, buildFiles, tfms))
@@ -53,6 +71,61 @@ internal static class SdkPackageUpdater
53
71
  await SaveBuildFilesAsync(buildFiles, logger);
54
72
  }
55
73
 
74
+ public static async Task UpdateDependencyWithConflictResolution(
75
+ string repoRootPath,
76
+ ImmutableArray<ProjectBuildFile> buildFiles,
77
+ string[] targetFrameworks,
78
+ string projectPath,
79
+ string dependencyName,
80
+ string previousDependencyVersion,
81
+ string newDependencyVersion,
82
+ bool isTransitive,
83
+ IDictionary<string, string> peerDependencies,
84
+ ILogger logger)
85
+ {
86
+ var topLevelDependencies = MSBuildHelper.GetTopLevelPackageDependencyInfos(buildFiles).ToArray();
87
+ var isDependencyTopLevel = topLevelDependencies.Any(d => d.Name.Equals(dependencyName, StringComparison.OrdinalIgnoreCase));
88
+ var dependenciesToUpdate = new[] { new Dependency(dependencyName, newDependencyVersion, DependencyType.PackageReference) };
89
+
90
+ // update the initial dependency...
91
+ TryUpdateDependencyVersion(buildFiles, dependencyName, previousDependencyVersion, newDependencyVersion, logger);
92
+
93
+ // ...and the peer dependencies...
94
+ foreach (var (packageName, packageVersion) in peerDependencies.Where(kvp => string.Compare(kvp.Key, dependencyName, StringComparison.OrdinalIgnoreCase) != 0))
95
+ {
96
+ TryUpdateDependencyVersion(buildFiles, packageName, previousDependencyVersion: null, newDependencyVersion: packageVersion, logger);
97
+ }
98
+
99
+ // ...and everything else
100
+ foreach (var projectFile in buildFiles)
101
+ {
102
+ foreach (var tfm in targetFrameworks)
103
+ {
104
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRootPath, projectFile.Path, tfm, topLevelDependencies, dependenciesToUpdate, logger);
105
+ if (resolvedDependencies is null)
106
+ {
107
+ logger.Log($" Unable to resolve dependency conflicts for {projectFile.Path}.");
108
+ continue;
109
+ }
110
+
111
+ var isDependencyInResolutionSet = resolvedDependencies.Any(d => d.Name.Equals(dependencyName, StringComparison.OrdinalIgnoreCase));
112
+ if (isTransitive && !isDependencyTopLevel && isDependencyInResolutionSet)
113
+ {
114
+ // a transitive dependency had to be pinned; add it here
115
+ await UpdateTransitiveDependencyAsync(repoRootPath, projectPath, dependencyName, newDependencyVersion, buildFiles, logger);
116
+ }
117
+
118
+ // update all resolved dependencies that aren't the initial dependency
119
+ foreach (var resolvedDependency in resolvedDependencies
120
+ .Where(d => !d.Name.Equals(dependencyName, StringComparison.OrdinalIgnoreCase))
121
+ .Where(d => d.Version is not null))
122
+ {
123
+ TryUpdateDependencyVersion(buildFiles, resolvedDependency.Name, previousDependencyVersion: null, newDependencyVersion: resolvedDependency.Version!, logger);
124
+ }
125
+ }
126
+ }
127
+ }
128
+
56
129
  /// <summary>
57
130
  /// Verifies that the package does not already satisfy the requested dependency version.
58
131
  /// </summary>
@@ -307,7 +380,7 @@ internal static class SdkPackageUpdater
307
380
  IDictionary<string, string> peerDependencies,
308
381
  ILogger logger)
309
382
  {
310
-
383
+ // update dependencies...
311
384
  var result = TryUpdateDependencyVersion(buildFiles, dependencyName, previousDependencyVersion, newDependencyVersion, logger);
312
385
  if (result == UpdateResult.NotFound)
313
386
  {
@@ -320,26 +393,13 @@ internal static class SdkPackageUpdater
320
393
  TryUpdateDependencyVersion(buildFiles, packageName, previousDependencyVersion: null, newDependencyVersion: packageVersion, logger);
321
394
  }
322
395
 
323
- // now make all dependency requirements coherent
396
+ // ...and make them all coherent
324
397
  Dependency[] updatedTopLevelDependencies = MSBuildHelper.GetTopLevelPackageDependencyInfos(buildFiles).ToArray();
325
398
  foreach (ProjectBuildFile projectFile in buildFiles)
326
399
  {
327
400
  foreach (string tfm in targetFrameworks)
328
401
  {
329
- if (MSBuildHelper.UseNewDependencySolver())
330
- {
331
- // Find the index of the dependency we are updating and revert it to the previous version
332
- int dependencyIndex = Array.FindIndex(updatedTopLevelDependencies, d => string.Equals(d.Name, dependencyName, StringComparison.OrdinalIgnoreCase));
333
- if (dependencyIndex != -1)
334
- {
335
- var originalDependency = updatedTopLevelDependencies[dependencyIndex];
336
- updatedTopLevelDependencies[dependencyIndex] = originalDependency with { Version = previousDependencyVersion };
337
- }
338
-
339
- }
340
- Dependency[] update = [new Dependency(dependencyName, newDependencyVersion, DependencyType.PackageReference)];
341
- Dependency[]? resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRootPath, projectFile.Path, tfm, updatedTopLevelDependencies, update, logger);
342
-
402
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsWithBruteForce(repoRootPath, projectFile.Path, tfm, updatedTopLevelDependencies, logger);
343
403
  if (resolvedDependencies is null)
344
404
  {
345
405
  logger.Log($" Unable to resolve dependency conflicts for {projectFile.Path}.");
@@ -360,7 +420,7 @@ internal static class SdkPackageUpdater
360
420
  continue;
361
421
  }
362
422
 
363
- // update all dependencies
423
+ // update all versions
364
424
  foreach (Dependency resolvedDependency in resolvedDependencies
365
425
  .Where(d => !d.Name.Equals(dependencyName, StringComparison.OrdinalIgnoreCase))
366
426
  .Where(d => d.Version is not null))
@@ -13,6 +13,14 @@ using Console = System.Console;
13
13
 
14
14
  namespace NuGetUpdater.Core;
15
15
 
16
+ /// <summary>
17
+ /// Handles package updates for projects that use packages.config.
18
+ /// </summary>
19
+ /// <remarks>
20
+ /// packages.config can appear in non-SDK-style projects, but not in SDK-style projects.
21
+ /// See: https://learn.microsoft.com/en-us/nuget/reference/packages-config
22
+ /// https://learn.microsoft.com/en-us/nuget/resources/check-project-format
23
+ /// <remarks>
16
24
  internal static class PackagesConfigUpdater
17
25
  {
18
26
  public static async Task UpdateDependencyAsync(
@@ -25,9 +33,8 @@ internal static class PackagesConfigUpdater
25
33
  ILogger logger
26
34
  )
27
35
  {
28
- logger.Log($" Found {NuGetHelper.PackagesConfigFileName}; running with NuGet.exe");
29
-
30
- // use NuGet.exe to perform update
36
+ // packages.config project; use NuGet.exe to perform update
37
+ logger.Log($" Found '{NuGetHelper.PackagesConfigFileName}' project; running NuGet.exe update");
31
38
 
32
39
  // ensure local packages directory exists
33
40
  var projectBuildFile = ProjectBuildFile.Open(repoRootPath, projectPath);
@@ -126,10 +133,10 @@ internal static class PackagesConfigUpdater
126
133
  // and doesn't appear in the cache. The message in this case will be "Could not install package
127
134
  // '<name> <version>'...the package does not contain any assembly references or content files that
128
135
  // are compatible with that framework.".
136
+ // 3. Yet another possibility is that the project explicitly imports a targets file without a condition
137
+ // of `Exists(...)`.
129
138
  // The solution in all cases is to run `restore` then try the update again.
130
- if (!retryingAfterRestore &&
131
- (fullOutput.Contains("Existing packages must be restored before performing an install or update.") ||
132
- fullOutput.Contains("the package does not contain any assembly references or content files that are compatible with that framework.")))
139
+ if (!retryingAfterRestore && OutputIndicatesRestoreIsRequired(fullOutput))
133
140
  {
134
141
  retryingAfterRestore = true;
135
142
  logger.Log($" Running NuGet.exe with args: {string.Join(" ", restoreArgs)}");
@@ -139,6 +146,8 @@ internal static class PackagesConfigUpdater
139
146
 
140
147
  if (exitCodeAgain != 0)
141
148
  {
149
+ MSBuildHelper.ThrowOnMissingFile(fullOutput);
150
+ MSBuildHelper.ThrowOnMissingFile(restoreOutput);
142
151
  MSBuildHelper.ThrowOnMissingPackages(restoreOutput);
143
152
  throw new Exception($"Unable to restore.\nOutput:\n${restoreOutput}\n");
144
153
  }
@@ -174,6 +183,13 @@ internal static class PackagesConfigUpdater
174
183
  }
175
184
  }
176
185
 
186
+ private static bool OutputIndicatesRestoreIsRequired(string output)
187
+ {
188
+ return output.Contains("Existing packages must be restored before performing an install or update.")
189
+ || output.Contains("the package does not contain any assembly references or content files that are compatible with that framework.")
190
+ || MSBuildHelper.GetMissingFile(output) is not null;
191
+ }
192
+
177
193
  private static Process[] GetLikelyNuGetSpawnedProcesses()
178
194
  {
179
195
  var processes = Process.GetProcesses().Where(p => p.ProcessName.StartsWith("CredentialProvider", StringComparison.OrdinalIgnoreCase) == true).ToArray();
@@ -206,7 +222,7 @@ internal static class PackagesConfigUpdater
206
222
  {
207
223
  // exact match was found, use it
208
224
  var subpath = GetUpToIndexWithoutTrailingDirectorySeparator(hintPath, hintPathSubStringLocation);
209
- return subpath;
225
+ return subpath.NormalizePathToUnix();
210
226
  }
211
227
 
212
228
  if (partialPathMatch is null)
@@ -244,7 +260,7 @@ internal static class PackagesConfigUpdater
244
260
  }
245
261
  }
246
262
 
247
- return partialPathMatch;
263
+ return partialPathMatch?.NormalizePathToUnix();
248
264
  }
249
265
 
250
266
  private static bool IsHintPathNodeForDependency(this IXmlElementSyntax element, string dependencyName)
@@ -221,7 +221,7 @@ public class UpdaterWorker
221
221
  }
222
222
 
223
223
  // Some repos use a mix of packages.config and PackageReference
224
- await SdkPackageUpdater.UpdateDependencyAsync(repoRootPath, projectPath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive, _logger);
224
+ await PackageReferenceUpdater.UpdateDependencyAsync(repoRootPath, projectPath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive, _logger);
225
225
 
226
226
  // Update lock file if exists
227
227
  if (File.Exists(Path.Combine(Path.GetDirectoryName(projectPath), "packages.lock.json")))
@@ -341,18 +341,6 @@ internal static partial class MSBuildHelper
341
341
  }
342
342
 
343
343
  internal static async Task<Dependency[]?> ResolveDependencyConflicts(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Dependency[] update, ILogger logger)
344
- {
345
- if (UseNewDependencySolver())
346
- {
347
- return await ResolveDependencyConflictsNew(repoRoot, projectPath, targetFramework, packages, update, logger);
348
- }
349
- else
350
- {
351
- return await ResolveDependencyConflictsOld(repoRoot, projectPath, targetFramework, packages, logger);
352
- }
353
- }
354
-
355
- internal static async Task<Dependency[]?> ResolveDependencyConflictsNew(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Dependency[] update, ILogger logger)
356
344
  {
357
345
  var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
358
346
  PackageManager packageManager = new PackageManager(repoRoot, projectPath);
@@ -510,7 +498,7 @@ internal static partial class MSBuildHelper
510
498
  }
511
499
  }
512
500
 
513
- internal static async Task<Dependency[]?> ResolveDependencyConflictsOld(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, ILogger logger)
501
+ internal static async Task<Dependency[]?> ResolveDependencyConflictsWithBruteForce(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, ILogger logger)
514
502
  {
515
503
  var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
516
504
  try
@@ -713,6 +701,8 @@ internal static partial class MSBuildHelper
713
701
  <GenerateDependencyFile>true</GenerateDependencyFile>
714
702
  <RunAnalyzers>false</RunAnalyzers>
715
703
  <NuGetInteractive>false</NuGetInteractive>
704
+ <DesignTimeBuild>true</DesignTimeBuild>
705
+ <TargetPlatformVersion Condition=" $(TargetFramework.Contains('-')) ">1.0</TargetPlatformVersion>
716
706
  </PropertyGroup>
717
707
  <ItemGroup>
718
708
  {packageReferences}
@@ -824,13 +814,24 @@ internal static partial class MSBuildHelper
824
814
  }
825
815
  }
826
816
 
827
- internal static void ThrowOnMissingFile(string output)
817
+ internal static string? GetMissingFile(string output)
828
818
  {
829
819
  var missingFilePattern = new Regex(@"The imported project \""(?<FilePath>.*)\"" was not found");
830
820
  var match = missingFilePattern.Match(output);
831
821
  if (match.Success)
832
822
  {
833
- throw new MissingFileException(match.Groups["FilePath"].Value);
823
+ return match.Groups["FilePath"].Value;
824
+ }
825
+
826
+ return null;
827
+ }
828
+
829
+ internal static void ThrowOnMissingFile(string output)
830
+ {
831
+ var missingFile = GetMissingFile(output);
832
+ if (missingFile is not null)
833
+ {
834
+ throw new MissingFileException(missingFile);
834
835
  }
835
836
  }
836
837
 
@@ -0,0 +1,12 @@
1
+ namespace NuGetUpdater.Core.Test;
2
+
3
+ /// <summary>
4
+ /// Prepares the environment to use the new dependency solver.
5
+ /// </summary>
6
+ public class DependencySolverEnvironment : TemporaryEnvironment
7
+ {
8
+ public DependencySolverEnvironment(bool useDependencySolver = true)
9
+ : base([("UseNewNugetPackageResolver", useDependencySolver ? "true" : "false")])
10
+ {
11
+ }
12
+ }
@@ -30,7 +30,7 @@ public class PackagesConfigUpdaterTests : TestBase
30
30
  """,
31
31
  "Newtonsoft.Json",
32
32
  "7.0.1",
33
- @"..\packages"
33
+ "../packages"
34
34
  ];
35
35
 
36
36
  // project without namespace
@@ -48,7 +48,7 @@ public class PackagesConfigUpdaterTests : TestBase
48
48
  """,
49
49
  "Newtonsoft.Json",
50
50
  "7.0.1",
51
- @"..\packages"
51
+ "../packages"
52
52
  ];
53
53
 
54
54
  // project with non-standard packages path
@@ -66,7 +66,7 @@ public class PackagesConfigUpdaterTests : TestBase
66
66
  """,
67
67
  "Newtonsoft.Json",
68
68
  "7.0.1",
69
- @"..\not-a-path-you-would-expect"
69
+ "../not-a-path-you-would-expect"
70
70
  ];
71
71
  }
72
72
  }
@@ -10,7 +10,7 @@ namespace NuGetUpdater.Core.Test.Update;
10
10
 
11
11
  public partial class UpdateWorkerTests
12
12
  {
13
- public class Sdk : UpdateWorkerTestBase
13
+ public class PackageReference : UpdateWorkerTestBase
14
14
  {
15
15
  [Theory]
16
16
  [InlineData("net472")]
@@ -54,12 +54,12 @@ public partial class UpdateWorkerTests
54
54
  }
55
55
 
56
56
  [Theory]
57
- [InlineData("true")]
58
- [InlineData(null)]
59
- public async Task UpdateVersionChildElement_InProjectFile_ForPackageReferenceIncludeTheory(string variableValue)
57
+ [InlineData(true)]
58
+ [InlineData(false)]
59
+ public async Task UpdateVersionChildElement_InProjectFile_ForPackageReferenceIncludeTheory(bool useDependencySolver)
60
60
  {
61
61
  // update Some.Package from 9.0.1 to 13.0.1
62
- using var env = new TemporaryEnvironment([("UseNewNugetPackageResolver", variableValue)]);
62
+ using var _ = new DependencySolverEnvironment(useDependencySolver);
63
63
  await TestUpdateForProject("Some.Package", "9.0.1", "13.0.1",
64
64
  packages:
65
65
  [
@@ -95,11 +95,72 @@ public partial class UpdateWorkerTests
95
95
  );
96
96
  }
97
97
 
98
+ [Theory]
99
+ [InlineData(true)]
100
+ [InlineData(false)]
101
+ public async Task PeerDependenciesAreUpdatedEvenWhenNotExplicit(bool useDependencySolver)
102
+ {
103
+ using var _ = new DependencySolverEnvironment(useDependencySolver);
104
+ await TestUpdateForProject("Some.Package", "1.0.0", "2.0.0",
105
+ packages:
106
+ [
107
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0", [(null, [("Transitive.Package", "[1.0.0]")])]),
108
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "2.0.0", "net8.0", [(null, [("Transitive.Package", "[2.0.0]")])]),
109
+ MockNuGetPackage.CreateSimplePackage("Transitive.Package", "1.0.0", "net8.0"),
110
+ MockNuGetPackage.CreateSimplePackage("Transitive.Package", "2.0.0", "net8.0"),
111
+ ],
112
+ projectFile: ("a/a.csproj", """
113
+ <Project Sdk="Microsoft.NET.Sdk">
114
+ <PropertyGroup>
115
+ <TargetFramework>net8.0</TargetFramework>
116
+ <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
117
+ </PropertyGroup>
118
+ <ItemGroup>
119
+ <PackageReference Include="Some.Package" />
120
+ </ItemGroup>
121
+ </Project>
122
+ """),
123
+ additionalFiles:
124
+ [
125
+ ("Directory.Packages.props", """
126
+ <Project>
127
+ <ItemGroup>
128
+ <PackageVersion Include="Some.Package" Version="1.0.0" />
129
+ <PackageVersion Include="Transitive.Package" Version="1.0.0" />
130
+ </ItemGroup>
131
+ </Project>
132
+ """)
133
+ ],
134
+ expectedProjectContents: """
135
+ <Project Sdk="Microsoft.NET.Sdk">
136
+ <PropertyGroup>
137
+ <TargetFramework>net8.0</TargetFramework>
138
+ <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
139
+ </PropertyGroup>
140
+ <ItemGroup>
141
+ <PackageReference Include="Some.Package" />
142
+ </ItemGroup>
143
+ </Project>
144
+ """,
145
+ additionalFilesExpected:
146
+ [
147
+ ("Directory.Packages.props", """
148
+ <Project>
149
+ <ItemGroup>
150
+ <PackageVersion Include="Some.Package" Version="2.0.0" />
151
+ <PackageVersion Include="Transitive.Package" Version="2.0.0" />
152
+ </ItemGroup>
153
+ </Project>
154
+ """)
155
+ ]
156
+ );
157
+ }
158
+
98
159
  [Fact]
99
160
  public async Task CallingResolveDependencyConflictsNew()
100
161
  {
101
162
  // update Microsoft.CodeAnalysis.Common from 4.9.2 to 4.10.0
102
- using var env = new TemporaryEnvironment([("UseNewNugetPackageResolver", "true")]);
163
+ using var _ = new DependencySolverEnvironment();
103
164
  await TestUpdateForProject("Microsoft.CodeAnalysis.Common", "4.9.2", "4.10.0",
104
165
  // initial
105
166
  projectContents: $"""
@@ -535,11 +596,11 @@ public partial class UpdateWorkerTests
535
596
  }
536
597
 
537
598
  [Theory]
538
- [InlineData(null)]
539
- [InlineData("true")]
540
- public async Task AddPackageReference_InProjectFile_ForTransientDependency(string variableValue)
599
+ [InlineData(true)]
600
+ [InlineData(false)]
601
+ public async Task AddPackageReference_InProjectFile_ForTransientDependency(bool useDependencySolver)
541
602
  {
542
- using var env = new TemporaryEnvironment([("UseNewNugetPackageResolver", variableValue)]);
603
+ using var _ = new DependencySolverEnvironment(useDependencySolver);
543
604
  // add transient package Some.Transient.Dependency from 5.0.1 to 5.0.2
544
605
  await TestUpdateForProject("Some.Transient.Dependency", "5.0.1", "5.0.2", isTransitive: true,
545
606
  packages:
@@ -2914,12 +2975,51 @@ public partial class UpdateWorkerTests
2914
2975
  );
2915
2976
  }
2916
2977
 
2978
+ [Fact]
2979
+ public async Task UpdatingTransitiveDependencyWithNewSolverCanUpdateJustTheTopLevelPackage()
2980
+ {
2981
+ // we've been asked to explicitly update a transitive dependency, but we can solve it by updating the top-level package instead
2982
+ using var _ = new DependencySolverEnvironment();
2983
+ await TestUpdateForProject("Transitive.Package", "1.0.0", "2.0.0",
2984
+ isTransitive: true,
2985
+ packages:
2986
+ [
2987
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0", [("net8.0", [("Transitive.Package", "[1.0.0]")])]),
2988
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "2.0.0", "net8.0", [("net8.0", [("Transitive.Package", "[2.0.0]")])]),
2989
+ MockNuGetPackage.CreateSimplePackage("Transitive.Package", "1.0.0", "net8.0"),
2990
+ MockNuGetPackage.CreateSimplePackage("Transitive.Package", "2.0.0", "net8.0"),
2991
+ ],
2992
+ projectContents: """
2993
+ <Project Sdk="Microsoft.NET.Sdk">
2994
+ <PropertyGroup>
2995
+ <TargetFramework>net8.0</TargetFramework>
2996
+ <ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
2997
+ </PropertyGroup>
2998
+ <ItemGroup>
2999
+ <PackageReference Include="Some.Package" Version="1.0.0" />
3000
+ </ItemGroup>
3001
+ </Project>
3002
+ """,
3003
+ expectedProjectContents: """
3004
+ <Project Sdk="Microsoft.NET.Sdk">
3005
+ <PropertyGroup>
3006
+ <TargetFramework>net8.0</TargetFramework>
3007
+ <ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
3008
+ </PropertyGroup>
3009
+ <ItemGroup>
3010
+ <PackageReference Include="Some.Package" Version="2.0.0" />
3011
+ </ItemGroup>
3012
+ </Project>
3013
+ """
3014
+ );
3015
+ }
3016
+
2917
3017
  [Theory]
2918
- [InlineData("true")]
2919
- [InlineData(null)]
2920
- public async Task NoChange_IfThereAreIncoherentVersions(string variableValue)
3018
+ [InlineData(true)]
3019
+ [InlineData(false)]
3020
+ public async Task NoChange_IfThereAreIncoherentVersions(bool useDependencySolver)
2921
3021
  {
2922
- using var env = new TemporaryEnvironment([("UseNewNugetPackageResolver", variableValue)]);
3022
+ using var _ = new DependencySolverEnvironment(useDependencySolver);
2923
3023
 
2924
3024
  // trying to update `Transitive.Dependency` to 1.1.0 would normally pull `Some.Package` from 1.0.0 to 1.1.0,
2925
3025
  // but the TFM doesn't allow it
@@ -2968,6 +3068,42 @@ public partial class UpdateWorkerTests
2968
3068
  );
2969
3069
  }
2970
3070
 
3071
+ [Fact]
3072
+ public async Task ProcessingProjectWithWorkloadReferencesDoesNotFail()
3073
+ {
3074
+ // enumerating the build files will fail if the Aspire workload is not installed; this test ensures we can
3075
+ // still process the update
3076
+ await TestUpdateForProject("Some.Package", "7.0.1", "13.0.1",
3077
+ packages:
3078
+ [
3079
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "7.0.1", "net8.0"),
3080
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "13.0.1", "net8.0"),
3081
+ ],
3082
+ projectContents: """
3083
+ <Project Sdk="Microsoft.NET.Sdk">
3084
+ <PropertyGroup>
3085
+ <TargetFrameworks>net8.0-ios;net8.0-android;net8.0-macos;net8.0-maccatalyst;</TargetFrameworks>
3086
+ <IsAspireHost>true</IsAspireHost>
3087
+ </PropertyGroup>
3088
+ <ItemGroup>
3089
+ <PackageReference Include="Some.Package" Version="7.0.1" />
3090
+ </ItemGroup>
3091
+ </Project>
3092
+ """,
3093
+ expectedProjectContents: """
3094
+ <Project Sdk="Microsoft.NET.Sdk">
3095
+ <PropertyGroup>
3096
+ <TargetFrameworks>net8.0-ios;net8.0-android;net8.0-macos;net8.0-maccatalyst;</TargetFrameworks>
3097
+ <IsAspireHost>true</IsAspireHost>
3098
+ </PropertyGroup>
3099
+ <ItemGroup>
3100
+ <PackageReference Include="Some.Package" Version="13.0.1" />
3101
+ </ItemGroup>
3102
+ </Project>
3103
+ """
3104
+ );
3105
+ }
3106
+
2971
3107
  [Fact]
2972
3108
  public async Task ProcessingProjectWithAspireDoesNotFailEvenThoughWorkloadIsNotInstalled()
2973
3109
  {
@@ -3005,11 +3141,11 @@ public partial class UpdateWorkerTests
3005
3141
  }
3006
3142
 
3007
3143
  [Theory]
3008
- [InlineData("true")]
3009
- [InlineData(null)]
3010
- public async Task UnresolvablePropertyDoesNotStopOtherUpdates(string variableValue)
3144
+ [InlineData(true)]
3145
+ [InlineData(false)]
3146
+ public async Task UnresolvablePropertyDoesNotStopOtherUpdates(bool useDependencySolver)
3011
3147
  {
3012
- using var env = new TemporaryEnvironment([("UseNewNugetPackageResolver", variableValue)]);
3148
+ using var _ = new DependencySolverEnvironment(useDependencySolver);
3013
3149
 
3014
3150
  // the property `$(SomeUnresolvableProperty)` cannot be resolved
3015
3151
  await TestUpdateForProject("Some.Package", "7.0.1", "13.0.1",
@@ -3044,12 +3180,53 @@ public partial class UpdateWorkerTests
3044
3180
  );
3045
3181
  }
3046
3182
 
3183
+
3184
+ [Theory]
3185
+ [InlineData(true)]
3186
+ [InlineData(false)]
3187
+ public async Task ProjectWithWorkloadsShouldNotFail(bool useDependencySolver)
3188
+ {
3189
+ using var _ = new DependencySolverEnvironment(useDependencySolver);
3190
+
3191
+ // the property `$(SomeUnresolvableProperty)` cannot be resolved
3192
+ await TestUpdateForProject("Some.Package", "7.0.1", "13.0.1",
3193
+ packages:
3194
+ [
3195
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "7.0.1", "net8.0"),
3196
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "13.0.1", "net8.0"),
3197
+ MockNuGetPackage.CreateSimplePackage("Some.Other.Package", "1.0.0", "net8.0"),
3198
+ ],
3199
+ projectContents: """
3200
+ <Project Sdk="Microsoft.NET.Sdk">
3201
+ <PropertyGroup>
3202
+ <TargetFrameworks>net8.0;net8.0-ios;net8.0-android;net8.0-macos;net8.0-maccatalyst</TargetFrameworks>
3203
+ </PropertyGroup>
3204
+ <ItemGroup>
3205
+ <PackageReference Include="Some.Other.Package" Version="$(SomeUnresolvableProperty)" />
3206
+ <PackageReference Include="Some.Package" Version="7.0.1" />
3207
+ </ItemGroup>
3208
+ </Project>
3209
+ """,
3210
+ expectedProjectContents: """
3211
+ <Project Sdk="Microsoft.NET.Sdk">
3212
+ <PropertyGroup>
3213
+ <TargetFrameworks>net8.0;net8.0-ios;net8.0-android;net8.0-macos;net8.0-maccatalyst</TargetFrameworks>
3214
+ </PropertyGroup>
3215
+ <ItemGroup>
3216
+ <PackageReference Include="Some.Other.Package" Version="$(SomeUnresolvableProperty)" />
3217
+ <PackageReference Include="Some.Package" Version="13.0.1" />
3218
+ </ItemGroup>
3219
+ </Project>
3220
+ """
3221
+ );
3222
+ }
3223
+
3047
3224
  [Theory]
3048
- [InlineData("true")]
3049
- [InlineData(null)]
3050
- public async Task UpdatingPackageAlsoUpdatesAnythingWithADependencyOnTheUpdatedPackage(string variableValue)
3225
+ [InlineData(true)]
3226
+ [InlineData(false)]
3227
+ public async Task UpdatingPackageAlsoUpdatesAnythingWithADependencyOnTheUpdatedPackage(bool useDependencySolver)
3051
3228
  {
3052
- using var env = new TemporaryEnvironment([("UseNewNugetPackageResolver", variableValue)]);
3229
+ using var _ = new DependencySolverEnvironment(useDependencySolver);
3053
3230
 
3054
3231
  // updating Some.Package from 3.3.30 requires that Some.Package.Extensions also be updated
3055
3232
  await TestUpdateForProject("Some.Package", "3.3.30", "3.4.3",
@@ -308,6 +308,83 @@ public partial class UpdateWorkerTests
308
308
  );
309
309
  }
310
310
 
311
+ [Fact]
312
+ public async Task UpdatePackageWithTargetsFileWhereProjectUsesBackslashes()
313
+ {
314
+ // The bug that caused this test to be written did not repro on Windows. The reason is that the packages
315
+ // directory is determined to be `..\packages`, but the backslash was retained. Later when packages were
316
+ // restored to that location, a directory with a name like `..?packages` would be created which didn't
317
+ // match the <Import> element's path of "..\packages\..." that had no `Condition="Exists(path)"` attribute.
318
+ await TestUpdateForProject("Some.Package", "1.0.0", "2.0.0",
319
+ packages:
320
+ [
321
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net45"),
322
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "2.0.0", "net45"),
323
+ new MockNuGetPackage("Package.With.Targets", "1.0.0", Files: [("build/SomeFile.targets", Encoding.UTF8.GetBytes("<Project />"))]),
324
+ ],
325
+ // existing
326
+ projectFile: ("src/project.csproj", """
327
+ <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
328
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
329
+ <PropertyGroup>
330
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
331
+ </PropertyGroup>
332
+ <ItemGroup>
333
+ <None Include="packages.config" />
334
+ </ItemGroup>
335
+ <ItemGroup>
336
+ <Reference Include="Some.Package">
337
+ <HintPath>..\packages\Some.Package.1.0.0\lib\net45\Some.Package.dll</HintPath>
338
+ <Private>True</Private>
339
+ </Reference>
340
+ </ItemGroup>
341
+ <Import Project="..\packages\Package.With.Targets.1.0.0\build\SomeFile.targets" />
342
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
343
+ </Project>
344
+ """),
345
+ additionalFiles:
346
+ [
347
+ ("src/packages.config", """
348
+ <?xml version="1.0" encoding="utf-8"?>
349
+ <packages>
350
+ <package id="Package.With.Targets" version="1.0.0" targetFramework="net45" />
351
+ <package id="Some.Package" version="1.0.0" targetFramework="net45" />
352
+ </packages>
353
+ """)
354
+ ],
355
+ // expected
356
+ expectedProjectContents: """
357
+ <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
358
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
359
+ <PropertyGroup>
360
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
361
+ </PropertyGroup>
362
+ <ItemGroup>
363
+ <None Include="packages.config" />
364
+ </ItemGroup>
365
+ <ItemGroup>
366
+ <Reference Include="Some.Package">
367
+ <HintPath>..\packages\Some.Package.2.0.0\lib\net45\Some.Package.dll</HintPath>
368
+ <Private>True</Private>
369
+ </Reference>
370
+ </ItemGroup>
371
+ <Import Project="..\packages\Package.With.Targets.1.0.0\build\SomeFile.targets" />
372
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
373
+ </Project>
374
+ """,
375
+ additionalFilesExpected:
376
+ [
377
+ ("src/packages.config", """
378
+ <?xml version="1.0" encoding="utf-8"?>
379
+ <packages>
380
+ <package id="Package.With.Targets" version="1.0.0" targetFramework="net45" />
381
+ <package id="Some.Package" version="2.0.0" targetFramework="net45" />
382
+ </packages>
383
+ """)
384
+ ]
385
+ );
386
+ }
387
+
311
388
  [Fact]
312
389
  public async Task UpdateSingleDependencyInPackagesConfigButNotToLatest()
313
390
  {
@@ -442,9 +442,9 @@ public class MSBuildHelperTests : TestBase
442
442
  }
443
443
 
444
444
  [Fact]
445
- public async Task DependencyConflictsCanBeResolved()
445
+ public async Task DependencyConflictsCanBeResolvedWithBruteForce()
446
446
  {
447
- var repoRoot = Directory.CreateTempSubdirectory($"test_{nameof(DependencyConflictsCanBeResolved)}_");
447
+ var repoRoot = Directory.CreateTempSubdirectory($"test_{nameof(DependencyConflictsCanBeResolvedWithBruteForce)}_");
448
448
  MockNuGetPackage[] testPackages =
449
449
  [
450
450
  // some base packages
@@ -483,7 +483,7 @@ public class MSBuildHelperTests : TestBase
483
483
  {
484
484
  new Dependency("Some.Other.Package", "1.2.0", DependencyType.PackageReference),
485
485
  };
486
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
486
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsWithBruteForce(repoRoot.FullName, projectPath, "net8.0", dependencies, new TestLogger());
487
487
  Assert.NotNull(resolvedDependencies);
488
488
  Assert.Equal(2, resolvedDependencies.Length);
489
489
  Assert.Equal("Some.Package", resolvedDependencies[0].Name);
@@ -497,6 +497,44 @@ public class MSBuildHelperTests : TestBase
497
497
  }
498
498
  }
499
499
 
500
+ [Fact]
501
+ public void UpdateWithWorkloadsTargetFrameworks()
502
+ {
503
+ // Arrange
504
+ var projectContents = """
505
+ <Project>
506
+ <PropertyGroup>
507
+ <TargetFrameworks>net8.0-ios;net8.0-android;net8.0-macos;net8.0-maccatalyst;</TargetFrameworks>
508
+ </PropertyGroup>
509
+ <ItemGroup>
510
+ <PackageReference Include="Some.Package" Version="$(PackageVersion1)" />
511
+ </ItemGroup>
512
+ </Project>
513
+ """;
514
+ var propertyInfo = new Dictionary<string, Property>
515
+ {
516
+ { "PackageVersion1", new("PackageVersion1", "1.1.1", "Packages.props") },
517
+ };
518
+
519
+ // Act
520
+ var (resultType, _, evaluatedValue, _, _) = MSBuildHelper.GetEvaluatedValue(projectContents, propertyInfo);
521
+
522
+ Assert.Equal(EvaluationResultType.Success, resultType);
523
+
524
+ // Assert
525
+ Assert.Equal("""
526
+ <Project>
527
+ <PropertyGroup>
528
+ <TargetFrameworks>net8.0-ios;net8.0-android;net8.0-macos;net8.0-maccatalyst;</TargetFrameworks>
529
+ </PropertyGroup>
530
+ <ItemGroup>
531
+ <PackageReference Include="Some.Package" Version="1.1.1" />
532
+ </ItemGroup>
533
+ </Project>
534
+ """, evaluatedValue);
535
+ }
536
+
537
+
500
538
  #region
501
539
  // Updating root package
502
540
  // CS-Script Code to 2.0.0 requires its dependency Microsoft.CodeAnalysis.CSharp.Scripting to be 3.6.0 and its transitive dependency Microsoft.CodeAnalysis.Common to be 3.6.0
@@ -533,7 +571,7 @@ public class MSBuildHelperTests : TestBase
533
571
  new Dependency("CS-Script.Core", "2.0.0", DependencyType.PackageReference),
534
572
  };
535
573
 
536
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
574
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
537
575
  Assert.NotNull(resolvedDependencies);
538
576
  Assert.Equal(3, resolvedDependencies.Length);
539
577
  Assert.Equal("CS-Script.Core", resolvedDependencies[0].Name);
@@ -578,7 +616,7 @@ public class MSBuildHelperTests : TestBase
578
616
  new Dependency("Microsoft.Bcl.AsyncInterfaces", "1.1.1", DependencyType.Unknown)
579
617
  };
580
618
 
581
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
619
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
582
620
  Assert.NotNull(resolvedDependencies);
583
621
  Assert.Single(resolvedDependencies);
584
622
  Assert.Equal("Azure.Core", resolvedDependencies[0].Name);
@@ -621,7 +659,7 @@ public class MSBuildHelperTests : TestBase
621
659
  new Dependency("Newtonsoft.Json", "13.0.1", DependencyType.Unknown)
622
660
  };
623
661
 
624
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
662
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
625
663
  Assert.NotNull(resolvedDependencies);
626
664
  Assert.Equal(2, resolvedDependencies.Length);
627
665
  Assert.Equal("Newtonsoft.Json.Bson", resolvedDependencies[0].Name);
@@ -671,7 +709,7 @@ public class MSBuildHelperTests : TestBase
671
709
  new Dependency("Microsoft.CodeAnalysis.Common", "4.10.0", DependencyType.PackageReference)
672
710
  };
673
711
 
674
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
712
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
675
713
  Assert.NotNull(resolvedDependencies);
676
714
  Assert.Equal(3, resolvedDependencies.Length);
677
715
  Assert.Equal("Microsoft.CodeAnalysis.Compilers", resolvedDependencies[0].Name);
@@ -723,7 +761,7 @@ public class MSBuildHelperTests : TestBase
723
761
  new Dependency("Microsoft.CodeAnalysis.Common", "4.10.0", DependencyType.PackageReference)
724
762
  };
725
763
 
726
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
764
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
727
765
  Assert.NotNull(resolvedDependencies);
728
766
  Assert.Equal(4, resolvedDependencies.Length);
729
767
  Assert.Equal("Microsoft.CodeAnalysis.Compilers", resolvedDependencies[0].Name);
@@ -779,7 +817,7 @@ public class MSBuildHelperTests : TestBase
779
817
  new Dependency("Newtonsoft.Json", "13.0.1", DependencyType.Unknown)
780
818
  };
781
819
 
782
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
820
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
783
821
  Assert.NotNull(resolvedDependencies);
784
822
  Assert.Equal(5, resolvedDependencies.Length);
785
823
  Assert.Equal("Microsoft.CodeAnalysis.Compilers", resolvedDependencies[0].Name);
@@ -838,7 +876,7 @@ public class MSBuildHelperTests : TestBase
838
876
  new Dependency("Buildalyzer", "7.0.1", DependencyType.PackageReference),
839
877
  };
840
878
 
841
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
879
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
842
880
  Assert.NotNull(resolvedDependencies);
843
881
  Assert.Equal(4, resolvedDependencies.Length);
844
882
  Assert.Equal("Buildalyzer", resolvedDependencies[0].Name);
@@ -895,7 +933,7 @@ public class MSBuildHelperTests : TestBase
895
933
  new Dependency("Azure.Core", "1.22.0", DependencyType.PackageReference)
896
934
  };
897
935
 
898
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
936
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
899
937
  Assert.NotNull(resolvedDependencies);
900
938
  Assert.Equal(4, resolvedDependencies.Length);
901
939
  Assert.Equal("System.Collections.Immutable", resolvedDependencies[0].Name);
@@ -952,7 +990,7 @@ public class MSBuildHelperTests : TestBase
952
990
  new Dependency("Azure.Core", "1.22.0", DependencyType.PackageReference)
953
991
  };
954
992
 
955
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
993
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
956
994
  Assert.NotNull(resolvedDependencies);
957
995
  Assert.Equal(5, resolvedDependencies.Length);
958
996
  Assert.Equal("System.Collections.Immutable", resolvedDependencies[0].Name);
@@ -1007,7 +1045,7 @@ public class MSBuildHelperTests : TestBase
1007
1045
  new Dependency("AutoMapper.Collection", "10.0.0", DependencyType.PackageReference)
1008
1046
  };
1009
1047
 
1010
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1048
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1011
1049
  Assert.NotNull(resolvedDependencies);
1012
1050
  Assert.Equal(3, resolvedDependencies.Length);
1013
1051
  Assert.Equal("AutoMapper.Extensions.Microsoft.DependencyInjection", resolvedDependencies[0].Name);
@@ -1054,7 +1092,7 @@ public class MSBuildHelperTests : TestBase
1054
1092
  new Dependency("Microsoft.Extensions.Caching.Memory", "8.0.0", DependencyType.PackageReference)
1055
1093
  };
1056
1094
 
1057
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1095
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1058
1096
  Assert.NotNull(resolvedDependencies);
1059
1097
  Assert.Equal(2, resolvedDependencies.Length);
1060
1098
  Assert.Equal("Microsoft.EntityFrameworkCore", resolvedDependencies[0].Name);
@@ -1104,7 +1142,7 @@ public class MSBuildHelperTests : TestBase
1104
1142
  new Dependency("Microsoft.EntityFrameworkCore.Analyzers", "8.0.0", DependencyType.PackageReference)
1105
1143
  };
1106
1144
 
1107
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1145
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1108
1146
  Assert.NotNull(resolvedDependencies);
1109
1147
  Assert.Equal(4, resolvedDependencies.Length);
1110
1148
  Assert.Equal("Microsoft.EntityFrameworkCore.Design", resolvedDependencies[0].Name);
@@ -1156,7 +1194,7 @@ public class MSBuildHelperTests : TestBase
1156
1194
  new Dependency("Microsoft.EntityFrameworkCore.Analyzers", "8.0.0", DependencyType.PackageReference)
1157
1195
  };
1158
1196
 
1159
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1197
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1160
1198
  Assert.NotNull(resolvedDependencies);
1161
1199
  Assert.Equal(3, resolvedDependencies.Length);
1162
1200
  Assert.Equal("Microsoft.EntityFrameworkCore.Design", resolvedDependencies[0].Name);
@@ -1208,7 +1246,7 @@ public class MSBuildHelperTests : TestBase
1208
1246
  new Dependency("System.Collections.Immutable", "8.0.0", DependencyType.PackageReference),
1209
1247
  };
1210
1248
 
1211
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1249
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1212
1250
  Assert.NotNull(resolvedDependencies);
1213
1251
  Assert.Equal(4, resolvedDependencies.Length);
1214
1252
  Assert.Equal("System.Collections.Immutable", resolvedDependencies[0].Name);
@@ -1260,7 +1298,7 @@ public class MSBuildHelperTests : TestBase
1260
1298
  new Dependency("System.Collections.Immutable", "8.0.0", DependencyType.PackageReference),
1261
1299
  };
1262
1300
 
1263
- var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflictsNew(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1301
+ var resolvedDependencies = await MSBuildHelper.ResolveDependencyConflicts(repoRoot.FullName, projectPath, "net8.0", dependencies, update, new TestLogger());
1264
1302
  Assert.NotNull(resolvedDependencies);
1265
1303
  Assert.Equal(3, resolvedDependencies.Length);
1266
1304
  Assert.Equal("Microsoft.CodeAnalysis.CSharp.Workspaces", resolvedDependencies[0].Name);
@@ -121,15 +121,11 @@ module Dependabot
121
121
  def packages_config_files
122
122
  return @packages_config_files if @packages_config_files
123
123
 
124
- candidate_paths =
125
- [*project_files.map { |f| File.dirname(f.name) }, "."].uniq
124
+ imported_project_files = imported_property_files.filter { |f| f.name.match?(/\.(cs|vb|fs)proj$/) }
126
125
 
127
- @packages_config_files =
128
- candidate_paths.filter_map do |dir|
129
- file = repo_contents(dir: dir)
130
- .find { |f| f.name.casecmp("packages.config").zero? }
131
- fetch_file_from_host(File.join(dir, file.name)) if file
132
- end
126
+ @packages_config_files = [*project_files, *imported_project_files].filter_map do |f|
127
+ named_file_next_to_project_file(f, "packages.config")
128
+ end
133
129
  end
134
130
 
135
131
  sig { returns(T::Array[Dependabot::DependencyFile]) }
@@ -312,6 +308,32 @@ module Dependabot
312
308
  found_expected_file
313
309
  end
314
310
 
311
+ sig do
312
+ params(
313
+ project_file: Dependabot::DependencyFile,
314
+ expected_file_name: String
315
+ )
316
+ .returns(T.nilable(Dependabot::DependencyFile))
317
+ end
318
+ def named_file_next_to_project_file(project_file, expected_file_name)
319
+ found_expected_file = T.let(nil, T.nilable(Dependabot::DependencyFile))
320
+ directory_path = Pathname.new(directory)
321
+ full_project_dir = Pathname.new(project_file.directory).join(project_file.name).dirname
322
+
323
+ candidate_file_path = Pathname.new(full_project_dir).join(expected_file_name).cleanpath.to_path
324
+ candidate_directory = Pathname.new(File.dirname(candidate_file_path))
325
+ relative_candidate_directory = candidate_directory.relative_path_from(directory_path)
326
+ candidate_file = repo_contents(dir: relative_candidate_directory).find do |f|
327
+ f.name.casecmp?(expected_file_name)
328
+ end
329
+ if candidate_file
330
+ found_expected_file = fetch_file_from_host(File.join(relative_candidate_directory,
331
+ candidate_file.name))
332
+ end
333
+
334
+ found_expected_file
335
+ end
336
+
315
337
  sig { returns(T.nilable(Dependabot::DependencyFile)) }
316
338
  def global_json
317
339
  @global_json ||= T.let(fetch_file_if_present("global.json"), T.nilable(Dependabot::DependencyFile))
@@ -355,6 +377,7 @@ module Dependabot
355
377
  end
356
378
  def fetch_imported_property_files(file:, previously_fetched_files:)
357
379
  file_id = file.directory + "/" + file.name
380
+
358
381
  if @fetched_files[file_id]
359
382
  T.must(@fetched_files[file_id])
360
383
  else
@@ -363,23 +386,37 @@ module Dependabot
363
386
  ImportPathsFinder.new(project_file: file).project_reference_paths +
364
387
  ImportPathsFinder.new(project_file: file).project_file_paths
365
388
 
366
- paths.filter_map do |path|
389
+ # Initialize a set to hold fetched files temporarily to avoid duplicates
390
+ fetched_files_set = Set.new([file])
391
+
392
+ paths.each do |path|
367
393
  next if previously_fetched_files.map(&:name).include?(path)
368
394
  next if file.name == path
369
395
  next if path.include?("$(")
370
396
 
371
- fetched_file = fetch_file_from_host(path)
372
- grandchild_property_files = fetch_imported_property_files(
373
- file: fetched_file,
374
- previously_fetched_files: previously_fetched_files + [file]
375
- )
376
- @fetched_files[file_id] = [fetched_file, *grandchild_property_files]
377
- @fetched_files[file_id]
378
- rescue Dependabot::DependencyFileNotFound
379
- # Don't worry about missing files too much for now (at least
380
- # until we start resolving properties)
381
- nil
382
- end.flatten
397
+ begin
398
+ fetched_file = fetch_file_from_host(path)
399
+ grandchild_property_files = fetch_imported_property_files(
400
+ file: fetched_file,
401
+ previously_fetched_files: previously_fetched_files + [file]
402
+ )
403
+
404
+ # Add fetched file and grandchild property files to the set
405
+ fetched_files_set << fetched_file
406
+ fetched_files_set.merge(grandchild_property_files)
407
+ rescue Dependabot::DependencyFileNotFound
408
+ # Don't worry about missing files, just skip them for now
409
+ Dependabot.logger.info("unable to find expected file #{file.name}")
410
+ nil
411
+ end
412
+ end
413
+
414
+ # Convert the set to an array and cache the fetched files
415
+ fetched_files = fetched_files_set.to_a
416
+ @fetched_files[file_id] = fetched_files
417
+
418
+ # Return the fetched files
419
+ fetched_files
383
420
  end
384
421
  end
385
422
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-nuget
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.281.0
4
+ version: 0.282.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-17 00:00:00.000000000 Z
11
+ date: 2024-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.281.0
19
+ version: 0.282.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.281.0
26
+ version: 0.282.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rubyzip
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -134,28 +134,28 @@ dependencies:
134
134
  requirements:
135
135
  - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: 1.65.0
137
+ version: 1.67.0
138
138
  type: :development
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: 1.65.0
144
+ version: 1.67.0
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: rubocop-performance
147
147
  requirement: !ruby/object:Gem::Requirement
148
148
  requirements:
149
149
  - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: 1.21.0
151
+ version: 1.22.1
152
152
  type: :development
153
153
  prerelease: false
154
154
  version_requirements: !ruby/object:Gem::Requirement
155
155
  requirements:
156
156
  - - "~>"
157
157
  - !ruby/object:Gem::Version
158
- version: 1.21.0
158
+ version: 1.22.1
159
159
  - !ruby/object:Gem::Dependency
160
160
  name: rubocop-rspec
161
161
  requirement: !ruby/object:Gem::Requirement
@@ -310,6 +310,7 @@ files:
310
310
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/RequirementTests.cs
311
311
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/SecurityVulnerabilityExtensionsTests.cs
312
312
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/VersionFinderTests.cs
313
+ - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/DependencySolverEnvironment.cs
313
314
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs
314
315
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.DotNetToolsJson.cs
315
316
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.GlobalJson.cs
@@ -344,8 +345,8 @@ files:
344
345
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DotNetTools.cs
345
346
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs
346
347
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs
348
+ - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs
347
349
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs
348
- - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs
349
350
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/AssertEx.cs
350
351
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/DiffUtil.cs
351
352
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/JsonHelperTests.cs
@@ -425,8 +426,8 @@ files:
425
426
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/DotNetToolsJsonUpdater.cs
426
427
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/GlobalJsonUpdater.cs
427
428
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs
429
+ - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs
428
430
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs
429
- - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs
430
431
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdateOperationResult.cs
431
432
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdateResult.cs
432
433
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs
@@ -496,7 +497,7 @@ licenses:
496
497
  - MIT
497
498
  metadata:
498
499
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
499
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.281.0
500
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.282.0
500
501
  post_install_message:
501
502
  rdoc_options: []
502
503
  require_paths: