dependabot-nuget 0.279.0 → 0.281.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +4 -6
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs +4 -6
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/FrameworkCheckCommand.cs +4 -7
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +4 -6
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs +3 -5
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +7 -3
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +6 -0
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.FrameworkCheck.cs +0 -1
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Run.cs +1 -2
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +3 -6
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +17 -10
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +2 -2
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyFinder.cs +1 -1
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +2 -2
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +5 -5
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DirectoryPackagesPropsDiscovery.cs +1 -1
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +10 -4
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DotNetToolsJsonDiscovery.cs +1 -1
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/GlobalJsonDiscovery.cs +1 -1
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscovery.cs +1 -1
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +2 -2
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +2 -1
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/DotNetToolsJsonBuildFile.cs +2 -2
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/GlobalJsonBuildFile.cs +2 -2
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/JsonBuildFile.cs +2 -2
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/CompatabilityChecker.cs +1 -1
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/NativeResult.cs +1 -1
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +1 -1
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/UpdateNotPossible.cs +6 -0
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +9 -2
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/UpdateNotPossibleException.cs +11 -0
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +5 -5
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/DotNetToolsJsonUpdater.cs +1 -1
  35. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/GlobalJsonUpdater.cs +1 -1
  36. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +2 -2
  37. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +4 -2
  38. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +12 -12
  39. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +29 -6
  40. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ConsoleLogger.cs +9 -0
  41. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/DependencyConflictResolver.cs +14 -16
  42. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ILogger.cs +6 -0
  43. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +22 -10
  44. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +1 -1
  45. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +6 -10
  46. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +1 -1
  47. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/CompatibilityCheckerTests.cs +7 -7
  48. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +6 -9
  49. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Files/DotNetToolsJsonBuildFileTests.cs +1 -1
  50. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Files/GlobalJsonBuildFileTests.cs +1 -1
  51. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/FrameworkChecker/CompatibilityCheckerFacts.cs +4 -4
  52. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +1 -1
  53. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestLogger.cs +11 -0
  54. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/ExpectedUpdateOperationResult.cs +8 -0
  55. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +15 -12
  56. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs +1 -1
  57. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +1 -1
  58. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +223 -9
  59. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +1 -1
  60. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +16 -16
  61. data/lib/dependabot/nuget/file_updater.rb +1 -0
  62. data/lib/dependabot/nuget/native_helpers.rb +15 -19
  63. metadata +13 -8
  64. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/Logger.cs +0 -21
@@ -4,5 +4,5 @@ public record NativeResult
4
4
  {
5
5
  // TODO: nullable not required, `ErrorType.None` is the default anyway
6
6
  public ErrorType? ErrorType { get; init; }
7
- public string? ErrorDetails { get; init; }
7
+ public object? ErrorDetails { get; init; }
8
8
  }
@@ -7,5 +7,5 @@ public abstract record JobErrorBase
7
7
  [JsonPropertyName("error-type")]
8
8
  public abstract string Type { get; }
9
9
  [JsonPropertyName("error-details")]
10
- public required string Details { get; init; }
10
+ public required object Details { get; init; }
11
11
  }
@@ -0,0 +1,6 @@
1
+ namespace NuGetUpdater.Core.Run.ApiModel;
2
+
3
+ public record UpdateNotPossible : JobErrorBase
4
+ {
5
+ public override string Type => "update_not_possible";
6
+ }
@@ -12,7 +12,7 @@ namespace NuGetUpdater.Core.Run;
12
12
  public class RunWorker
13
13
  {
14
14
  private readonly IApiHandler _apiHandler;
15
- private readonly Logger _logger;
15
+ private readonly ILogger _logger;
16
16
 
17
17
  internal static readonly JsonSerializerOptions SerializerOptions = new()
18
18
  {
@@ -21,7 +21,7 @@ public class RunWorker
21
21
  Converters = { new JsonStringEnumConverter() },
22
22
  };
23
23
 
24
- public RunWorker(IApiHandler apiHandler, Logger logger)
24
+ public RunWorker(IApiHandler apiHandler, ILogger logger)
25
25
  {
26
26
  _apiHandler = apiHandler;
27
27
  _logger = logger;
@@ -88,6 +88,13 @@ public class RunWorker
88
88
  Details = ex.FilePath,
89
89
  };
90
90
  }
91
+ catch (UpdateNotPossibleException ex)
92
+ {
93
+ error = new UpdateNotPossible()
94
+ {
95
+ Details = ex.Dependencies,
96
+ };
97
+ }
91
98
  catch (Exception ex)
92
99
  {
93
100
  error = new UnknownError()
@@ -0,0 +1,11 @@
1
+ namespace NuGetUpdater.Core;
2
+
3
+ internal class UpdateNotPossibleException : Exception
4
+ {
5
+ public string[] Dependencies { get; }
6
+
7
+ public UpdateNotPossibleException(string[] dependencies)
8
+ {
9
+ Dependencies = dependencies;
10
+ }
11
+ }
@@ -116,19 +116,19 @@ internal static class BindingRedirectManager
116
116
  return null;
117
117
  }
118
118
 
119
- var configFilePath = Path.GetFullPath(Path.Combine(directoryPath, GetContent(configFile)));
119
+ var configFilePath = Path.GetFullPath(Path.Combine(directoryPath, GetValue(configFile)));
120
120
  var configFileContents = await File.ReadAllTextAsync(configFilePath);
121
121
  return new ConfigurationFile(configFilePath, configFileContents, false);
122
122
 
123
- static string GetContent(IXmlElementSyntax element)
123
+ static string GetValue(IXmlElementSyntax element)
124
124
  {
125
- var content = element.GetContentValue();
125
+ var content = element.GetAttributeValue("Include");
126
126
  if (!string.IsNullOrEmpty(content))
127
127
  {
128
128
  return content;
129
129
  }
130
130
 
131
- content = element.GetAttributeValue("Include");
131
+ content = element.GetContentValue();
132
132
  if (!string.IsNullOrEmpty(content))
133
133
  {
134
134
  return content;
@@ -139,7 +139,7 @@ internal static class BindingRedirectManager
139
139
 
140
140
  static bool IsConfigFile(IXmlElementSyntax element)
141
141
  {
142
- var content = GetContent(element);
142
+ var content = GetValue(element);
143
143
  if (content is null)
144
144
  {
145
145
  return false;
@@ -8,7 +8,7 @@ internal static class DotNetToolsJsonUpdater
8
8
  string dependencyName,
9
9
  string previousDependencyVersion,
10
10
  string newDependencyVersion,
11
- Logger logger)
11
+ ILogger logger)
12
12
  {
13
13
  if (!MSBuildHelper.TryGetDotNetToolsJsonPath(repoRootPath, workspacePath, out var dotnetToolsJsonPath))
14
14
  {
@@ -8,7 +8,7 @@ internal static class GlobalJsonUpdater
8
8
  string dependencyName,
9
9
  string previousDependencyVersion,
10
10
  string newDependencyVersion,
11
- Logger logger)
11
+ ILogger logger)
12
12
  {
13
13
  if (!MSBuildHelper.TryGetGlobalJsonPath(repoRootPath, workspacePath, out var globalJsonPath))
14
14
  {
@@ -5,7 +5,7 @@ internal static class LockFileUpdater
5
5
  public static async Task UpdateLockFileAsync(
6
6
  string repoRootPath,
7
7
  string projectPath,
8
- Logger logger)
8
+ ILogger logger)
9
9
  {
10
10
  var projectDirectory = Path.GetDirectoryName(projectPath);
11
11
  var lockPath = Path.Combine(projectDirectory, "packages.lock.json");
@@ -23,6 +23,6 @@ internal static class LockFileUpdater
23
23
  {
24
24
  logger.Log($" Lock file update failed.\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}");
25
25
  }
26
- }, retainMSBuildSdks: true);
26
+ }, logger, retainMSBuildSdks: true);
27
27
  }
28
28
  }
@@ -22,7 +22,7 @@ internal static class PackagesConfigUpdater
22
22
  string previousDependencyVersion,
23
23
  string newDependencyVersion,
24
24
  string packagesConfigPath,
25
- Logger logger
25
+ ILogger logger
26
26
  )
27
27
  {
28
28
  logger.Log($" Found {NuGetHelper.PackagesConfigFileName}; running with NuGet.exe");
@@ -92,7 +92,7 @@ internal static class PackagesConfigUpdater
92
92
  await projectBuildFile.SaveAsync();
93
93
  }
94
94
 
95
- private static void RunNugetUpdate(List<string> updateArgs, List<string> restoreArgs, string projectDirectory, Logger logger)
95
+ private static void RunNugetUpdate(List<string> updateArgs, List<string> restoreArgs, string projectDirectory, ILogger logger)
96
96
  {
97
97
  var outputBuilder = new StringBuilder();
98
98
  var writer = new StringWriter(outputBuilder);
@@ -139,6 +139,7 @@ internal static class PackagesConfigUpdater
139
139
 
140
140
  if (exitCodeAgain != 0)
141
141
  {
142
+ MSBuildHelper.ThrowOnMissingPackages(restoreOutput);
142
143
  throw new Exception($"Unable to restore.\nOutput:\n${restoreOutput}\n");
143
144
  }
144
145
 
@@ -147,6 +148,7 @@ internal static class PackagesConfigUpdater
147
148
 
148
149
  MSBuildHelper.ThrowOnUnauthenticatedFeed(fullOutput);
149
150
  MSBuildHelper.ThrowOnMissingFile(fullOutput);
151
+ MSBuildHelper.ThrowOnMissingPackages(fullOutput);
150
152
  throw new Exception(fullOutput);
151
153
  }
152
154
  }
@@ -15,7 +15,7 @@ internal static class SdkPackageUpdater
15
15
  string previousDependencyVersion,
16
16
  string newDependencyVersion,
17
17
  bool isTransitive,
18
- Logger logger)
18
+ ILogger logger)
19
19
  {
20
20
  // SDK-style project, modify the XML directly
21
21
  logger.Log(" Running for SDK-style project");
@@ -64,7 +64,7 @@ internal static class SdkPackageUpdater
64
64
  Dependency[] topLevelDependencies,
65
65
  string dependencyName,
66
66
  string newDependencyVersion,
67
- Logger logger)
67
+ ILogger logger)
68
68
  {
69
69
  var newDependencyNuGetVersion = NuGetVersion.Parse(newDependencyVersion);
70
70
 
@@ -124,7 +124,7 @@ internal static class SdkPackageUpdater
124
124
  return true;
125
125
  }
126
126
 
127
- private static async Task UpdateTransitiveDependencyAsync(string repoRootPath, string projectPath, string dependencyName, string newDependencyVersion, ImmutableArray<ProjectBuildFile> buildFiles, Logger logger)
127
+ private static async Task UpdateTransitiveDependencyAsync(string repoRootPath, string projectPath, string dependencyName, string newDependencyVersion, ImmutableArray<ProjectBuildFile> buildFiles, ILogger logger)
128
128
  {
129
129
  var directoryPackagesWithPinning = buildFiles.OfType<ProjectBuildFile>()
130
130
  .FirstOrDefault(bf => IsCpmTransitivePinningEnabled(bf));
@@ -160,7 +160,7 @@ internal static class SdkPackageUpdater
160
160
  return isTransitivePinningEnabled is not null && string.Equals(isTransitivePinningEnabled, "true", StringComparison.OrdinalIgnoreCase);
161
161
  }
162
162
 
163
- private static void PinTransitiveDependency(ProjectBuildFile directoryPackages, string dependencyName, string newDependencyVersion, Logger logger)
163
+ private static void PinTransitiveDependency(ProjectBuildFile directoryPackages, string dependencyName, string newDependencyVersion, ILogger logger)
164
164
  {
165
165
  var existingPackageVersionElement = directoryPackages.ItemNodes
166
166
  .Where(e => e.Name.Equals("PackageVersion", StringComparison.OrdinalIgnoreCase) &&
@@ -223,7 +223,7 @@ internal static class SdkPackageUpdater
223
223
  directoryPackages.Update(updatedXml);
224
224
  }
225
225
 
226
- private static async Task AddTransitiveDependencyAsync(string repoRootPath, string projectPath, string dependencyName, string newDependencyVersion, Logger logger)
226
+ private static async Task AddTransitiveDependencyAsync(string repoRootPath, string projectPath, string dependencyName, string newDependencyVersion, ILogger logger)
227
227
  {
228
228
  var projectDirectory = Path.GetDirectoryName(projectPath)!;
229
229
  await MSBuildHelper.SidelineGlobalJsonAsync(projectDirectory, repoRootPath, async () =>
@@ -237,7 +237,7 @@ internal static class SdkPackageUpdater
237
237
  {
238
238
  logger.Log($" Transitive dependency [{dependencyName}/{newDependencyVersion}] was not added.\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}");
239
239
  }
240
- }, retainMSBuildSdks: true);
240
+ }, logger, retainMSBuildSdks: true);
241
241
  }
242
242
 
243
243
  /// <summary>
@@ -250,7 +250,7 @@ internal static class SdkPackageUpdater
250
250
  string[] tfms,
251
251
  string dependencyName,
252
252
  string newDependencyVersion,
253
- Logger logger)
253
+ ILogger logger)
254
254
  {
255
255
  var newDependency = new[] { new Dependency(dependencyName, newDependencyVersion, DependencyType.Unknown) };
256
256
  var tfmsAndDependencies = new Dictionary<string, Dependency[]>();
@@ -305,7 +305,7 @@ internal static class SdkPackageUpdater
305
305
  string previousDependencyVersion,
306
306
  string newDependencyVersion,
307
307
  IDictionary<string, string> peerDependencies,
308
- Logger logger)
308
+ ILogger logger)
309
309
  {
310
310
 
311
311
  var result = TryUpdateDependencyVersion(buildFiles, dependencyName, previousDependencyVersion, newDependencyVersion, logger);
@@ -350,7 +350,7 @@ internal static class SdkPackageUpdater
350
350
  var specificResolvedDependency = resolvedDependencies.Where(d => d.Name.Equals(dependencyName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
351
351
  if (specificResolvedDependency is null)
352
352
  {
353
- logger.Log($" Unable resolve requested dependency for {dependencyName} in {projectFile.Path}.");
353
+ logger.Log($" Unable to resolve requested dependency for {dependencyName} in {projectFile.Path}.");
354
354
  continue;
355
355
  }
356
356
 
@@ -376,7 +376,7 @@ internal static class SdkPackageUpdater
376
376
  string dependencyName,
377
377
  string? previousDependencyVersion,
378
378
  string newDependencyVersion,
379
- Logger logger)
379
+ ILogger logger)
380
380
  {
381
381
  var foundCorrect = false;
382
382
  var foundUnsupported = false;
@@ -619,7 +619,7 @@ internal static class SdkPackageUpdater
619
619
  StringComparison.OrdinalIgnoreCase) &&
620
620
  (e.GetAttributeOrSubElementValue("Version", StringComparison.OrdinalIgnoreCase) ?? e.GetAttributeOrSubElementValue("VersionOverride", StringComparison.OrdinalIgnoreCase)) is not null);
621
621
 
622
- private static async Task<bool> AreDependenciesCoherentAsync(string repoRootPath, string projectPath, string dependencyName, Logger logger, ImmutableArray<ProjectBuildFile> buildFiles, string[] tfms)
622
+ private static async Task<bool> AreDependenciesCoherentAsync(string repoRootPath, string projectPath, string dependencyName, ILogger logger, ImmutableArray<ProjectBuildFile> buildFiles, string[] tfms)
623
623
  {
624
624
  var updatedTopLevelDependencies = MSBuildHelper.GetTopLevelPackageDependencyInfos(buildFiles).ToArray();
625
625
  foreach (var tfm in tfms)
@@ -636,7 +636,7 @@ internal static class SdkPackageUpdater
636
636
  return true;
637
637
  }
638
638
 
639
- private static async Task SaveBuildFilesAsync(ImmutableArray<ProjectBuildFile> buildFiles, Logger logger)
639
+ private static async Task SaveBuildFilesAsync(ImmutableArray<ProjectBuildFile> buildFiles, ILogger logger)
640
640
  {
641
641
  foreach (var buildFile in buildFiles)
642
642
  {
@@ -9,7 +9,7 @@ namespace NuGetUpdater.Core;
9
9
 
10
10
  public class UpdaterWorker
11
11
  {
12
- private readonly Logger _logger;
12
+ private readonly ILogger _logger;
13
13
  private readonly HashSet<string> _processedProjectPaths = new(StringComparer.OrdinalIgnoreCase);
14
14
 
15
15
  internal static readonly JsonSerializerOptions SerializerOptions = new()
@@ -18,12 +18,22 @@ public class UpdaterWorker
18
18
  Converters = { new JsonStringEnumConverter() },
19
19
  };
20
20
 
21
- public UpdaterWorker(Logger logger)
21
+ public UpdaterWorker(ILogger logger)
22
22
  {
23
23
  _logger = logger;
24
24
  }
25
25
 
26
26
  public async Task RunAsync(string repoRootPath, string workspacePath, string dependencyName, string previousDependencyVersion, string newDependencyVersion, bool isTransitive, string? resultOutputPath = null)
27
+ {
28
+ var result = await RunWithErrorHandlingAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive);
29
+ if (resultOutputPath is { })
30
+ {
31
+ await WriteResultFile(result, resultOutputPath, _logger);
32
+ }
33
+ }
34
+
35
+ // this is a convenient method for tests
36
+ internal async Task<UpdateOperationResult> RunWithErrorHandlingAsync(string repoRootPath, string workspacePath, string dependencyName, string previousDependencyVersion, string newDependencyVersion, bool isTransitive)
27
37
  {
28
38
  UpdateOperationResult result = new(); // assumed to be ok until proven otherwise
29
39
  try
@@ -52,11 +62,24 @@ public class UpdaterWorker
52
62
  ErrorDetails = ex.FilePath,
53
63
  };
54
64
  }
55
-
56
- if (resultOutputPath is { })
65
+ catch (UpdateNotPossibleException ex)
57
66
  {
58
- await WriteResultFile(result, resultOutputPath, _logger);
67
+ result = new()
68
+ {
69
+ ErrorType = ErrorType.UpdateNotPossible,
70
+ ErrorDetails = ex.Dependencies,
71
+ };
59
72
  }
73
+ catch (Exception ex)
74
+ {
75
+ result = new()
76
+ {
77
+ ErrorType = ErrorType.Unknown,
78
+ ErrorDetails = ex.ToString(),
79
+ };
80
+ }
81
+
82
+ return result;
60
83
  }
61
84
 
62
85
  public async Task<UpdateOperationResult> RunAsync(string repoRootPath, string workspacePath, string dependencyName, string previousDependencyVersion, string newDependencyVersion, bool isTransitive)
@@ -99,7 +122,7 @@ public class UpdaterWorker
99
122
  return new UpdateOperationResult();
100
123
  }
101
124
 
102
- internal static async Task WriteResultFile(UpdateOperationResult result, string resultOutputPath, Logger logger)
125
+ internal static async Task WriteResultFile(UpdateOperationResult result, string resultOutputPath, ILogger logger)
103
126
  {
104
127
  logger.Log($" Writing update result to [{resultOutputPath}].");
105
128
 
@@ -0,0 +1,9 @@
1
+ namespace NuGetUpdater.Core;
2
+
3
+ public sealed class ConsoleLogger : ILogger
4
+ {
5
+ public void Log(string message)
6
+ {
7
+ Console.WriteLine(message);
8
+ }
9
+ }
@@ -55,7 +55,7 @@ public class PackageManager
55
55
  string CurrentDirectory = currentDirectory ?? Environment.CurrentDirectory;
56
56
  SourceCacheContext SourceCacheContext = new SourceCacheContext();
57
57
  PackageDownloadContext PackageDownloadContext = new PackageDownloadContext(SourceCacheContext);
58
- ILogger Logger = NullLogger.Instance;
58
+ var Logger = NullLogger.Instance;
59
59
 
60
60
  IMachineWideSettings MachineWideSettings = new NuGet.CommandLine.CommandLineMachineWideSettings();
61
61
  ISettings Settings = NuGet.Configuration.Settings.LoadDefaultSettings(
@@ -328,7 +328,7 @@ public class PackageManager
328
328
  }
329
329
 
330
330
  // Method to update the version of a desired package based off framework
331
- public async Task<string> UpdateVersion(List<PackageToUpdate> existingPackages, PackageToUpdate package, string targetFramework, string projectDirectory)
331
+ public async Task<string> UpdateVersion(List<PackageToUpdate> existingPackages, PackageToUpdate package, string targetFramework, string projectDirectory, ILogger logger)
332
332
  {
333
333
  // Bool to track if the package was in the original existing list
334
334
  bool inExisting = true;
@@ -392,12 +392,12 @@ public class PackageManager
392
392
  existingPackage.CurrentVersion = dependency.CurrentVersion;
393
393
 
394
394
  // If the family is compatible with the dependency's version, update with the dependency version
395
- if (await AreAllParentsCompatibleAsync(existingPackages, existingPackage, targetFramework, projectDirectory) == true)
395
+ if (await AreAllParentsCompatibleAsync(existingPackages, existingPackage, targetFramework, projectDirectory, logger) == true)
396
396
  {
397
397
  existingPackage.CurrentVersion = dependencyOldVersion;
398
398
  string NewVersion = dependency.CurrentVersion;
399
399
  existingPackage.NewVersion = dependency.CurrentVersion;
400
- await UpdateVersion(existingPackages, existingPackage, targetFramework, projectDirectory);
400
+ await UpdateVersion(existingPackages, existingPackage, targetFramework, projectDirectory, logger);
401
401
  }
402
402
  // If not, resort to putting version back to normal and remove new version
403
403
  else
@@ -417,7 +417,7 @@ public class PackageManager
417
417
  dependency.IsSpecific = true;
418
418
  }
419
419
 
420
- await UpdateVersion(existingPackages, dependency, targetFramework, projectDirectory);
420
+ await UpdateVersion(existingPackages, dependency, targetFramework, projectDirectory, logger);
421
421
  }
422
422
  }
423
423
 
@@ -432,7 +432,7 @@ public class PackageManager
432
432
  if (!isCompatible)
433
433
  {
434
434
  // Attempt to find and update to a compatible version between the two
435
- NuGetVersion compatibleVersion = await FindCompatibleVersionAsync(existingPackages, parent, package, targetFramework);
435
+ NuGetVersion compatibleVersion = await FindCompatibleVersionAsync(existingPackages, parent, package, targetFramework, logger);
436
436
  if (compatibleVersion == null)
437
437
  {
438
438
  return "Failed to update";
@@ -440,7 +440,7 @@ public class PackageManager
440
440
 
441
441
  // If a version is found, update to that version
442
442
  parent.NewVersion = compatibleVersion.ToString();
443
- await UpdateVersion(existingPackages, parent, targetFramework, projectDirectory);
443
+ await UpdateVersion(existingPackages, parent, targetFramework, projectDirectory, logger);
444
444
  }
445
445
 
446
446
  // If it's compatible and the package you updated wasn't in the existing package, check if the parent's dependencies version is the same as the current version
@@ -455,7 +455,6 @@ public class PackageManager
455
455
  {
456
456
  // Create a NugetContext instance to get the latest versions of the parent
457
457
  NuGetContext nugetContext = new NuGetContext(Path.GetDirectoryName(projectPath));
458
- Logger logger = null;
459
458
 
460
459
  string currentVersionString = parent.CurrentVersion;
461
460
  NuGetVersion currentVersionParent = NuGetVersion.Parse(currentVersionString);
@@ -487,7 +486,7 @@ public class PackageManager
487
486
  {
488
487
  parent.NewVersion = parentVersion;
489
488
  parent.CurrentVersion = null;
490
- await UpdateVersion(existingPackages, parent, targetFramework, projectDirectory);
489
+ await UpdateVersion(existingPackages, parent, targetFramework, projectDirectory, logger);
491
490
  package.IsSpecific = true;
492
491
  return "Success";
493
492
  }
@@ -557,7 +556,7 @@ public class PackageManager
557
556
  }
558
557
 
559
558
  // Method to find a compatible version with the child for the parent to update to
560
- public async Task<NuGetVersion> FindCompatibleVersionAsync(List<PackageToUpdate> existingPackages, PackageToUpdate possibleParent, PackageToUpdate possibleDependency, string targetFramework)
559
+ public async Task<NuGetVersion> FindCompatibleVersionAsync(List<PackageToUpdate> existingPackages, PackageToUpdate possibleParent, PackageToUpdate possibleDependency, string targetFramework, ILogger logger)
561
560
  {
562
561
  string packageId = possibleParent.PackageName;
563
562
  string currentVersionString = possibleParent.CurrentVersion;
@@ -567,7 +566,6 @@ public class PackageManager
567
566
 
568
567
  // Create a NugetContext instance to get the latest versions of the parent
569
568
  NuGetContext nugetContext = new NuGetContext(Path.GetDirectoryName(projectPath));
570
- Logger logger = null;
571
569
 
572
570
  var result = await VersionFinder.GetVersionsAsync(possibleParent.PackageName, CurrentVersion, nugetContext, logger, CancellationToken.None);
573
571
  var versions = result.GetVersions();
@@ -618,7 +616,7 @@ public class PackageManager
618
616
  if (await IsCompatibleAsync(possibleParent, possibleDependency, targetFramework, nugetContext.CurrentDirectory))
619
617
  {
620
618
  // Check if parents are compatible, recursively
621
- if (await AreAllParentsCompatibleAsync(existingPackages, possibleParent, targetFramework, nugetContext.CurrentDirectory))
619
+ if (await AreAllParentsCompatibleAsync(existingPackages, possibleParent, targetFramework, nugetContext.CurrentDirectory, logger))
622
620
  {
623
621
  // If compatible, return the new version
624
622
  if (Regex.IsMatch(possibleParent.NewVersion, @"[a-zA-Z]"))
@@ -635,7 +633,7 @@ public class PackageManager
635
633
  }
636
634
 
637
635
  // Method to determine if all the parents of a given package are compatible with the parent's desired version
638
- public async Task<bool> AreAllParentsCompatibleAsync(List<PackageToUpdate> existingPackages, PackageToUpdate possibleParent, string targetFramework, string projectDirectory)
636
+ public async Task<bool> AreAllParentsCompatibleAsync(List<PackageToUpdate> existingPackages, PackageToUpdate possibleParent, string targetFramework, string projectDirectory, ILogger logger)
639
637
  {
640
638
  // Get the possibleParent parentPackages
641
639
  HashSet<PackageToUpdate> parentPackages = GetParentPackages(possibleParent);
@@ -649,18 +647,18 @@ public class PackageManager
649
647
  if (!isCompatible)
650
648
  {
651
649
  // Find a compatible version if possible
652
- NuGetVersion compatibleVersion = await FindCompatibleVersionAsync(existingPackages, parent, possibleParent, targetFramework);
650
+ NuGetVersion compatibleVersion = await FindCompatibleVersionAsync(existingPackages, parent, possibleParent, targetFramework, logger);
653
651
  if (compatibleVersion == null)
654
652
  {
655
653
  return false;
656
654
  }
657
655
 
658
656
  parent.NewVersion = compatibleVersion.ToString();
659
- await UpdateVersion(existingPackages, parent, targetFramework, projectDirectory);
657
+ await UpdateVersion(existingPackages, parent, targetFramework, projectDirectory, logger);
660
658
  }
661
659
 
662
660
  // Recursively check if all ancestors are compatible
663
- if (!await AreAllParentsCompatibleAsync(existingPackages, parent, targetFramework, projectDirectory))
661
+ if (!await AreAllParentsCompatibleAsync(existingPackages, parent, targetFramework, projectDirectory, logger))
664
662
  {
665
663
  return false;
666
664
  }
@@ -0,0 +1,6 @@
1
+ namespace NuGetUpdater.Core;
2
+
3
+ public interface ILogger
4
+ {
5
+ void Log(string message);
6
+ }
@@ -44,13 +44,14 @@ internal static partial class MSBuildHelper
44
44
  }
45
45
  }
46
46
 
47
- public static async Task SidelineGlobalJsonAsync(string currentDirectory, string rootDirectory, Func<Task> action, bool retainMSBuildSdks = false)
47
+ public static async Task SidelineGlobalJsonAsync(string currentDirectory, string rootDirectory, Func<Task> action, ILogger? logger = null, bool retainMSBuildSdks = false)
48
48
  {
49
+ logger ??= new ConsoleLogger();
49
50
  var candidateDirectories = PathHelper.GetAllDirectoriesToRoot(currentDirectory, rootDirectory);
50
51
  var globalJsonPaths = candidateDirectories.Select(d => Path.Combine(d, "global.json")).Where(File.Exists).Select(p => (p, p + Guid.NewGuid().ToString())).ToArray();
51
52
  foreach (var (globalJsonPath, tempGlobalJsonPath) in globalJsonPaths)
52
53
  {
53
- Console.WriteLine($"Temporarily removing `global.json` from `{Path.GetDirectoryName(globalJsonPath)}`{(retainMSBuildSdks ? " and retaining MSBuild SDK declarations" : string.Empty)}.");
54
+ logger.Log($"Temporarily removing `global.json` from `{Path.GetDirectoryName(globalJsonPath)}`{(retainMSBuildSdks ? " and retaining MSBuild SDK declarations" : string.Empty)}.");
54
55
  File.Move(globalJsonPath, tempGlobalJsonPath);
55
56
  if (retainMSBuildSdks)
56
57
  {
@@ -78,7 +79,7 @@ internal static partial class MSBuildHelper
78
79
  {
79
80
  foreach (var (globalJsonpath, tempGlobalJsonPath) in globalJsonPaths)
80
81
  {
81
- Console.WriteLine($"Restoring `global.json` to `{Path.GetDirectoryName(globalJsonpath)}`.");
82
+ logger.Log($"Restoring `global.json` to `{Path.GetDirectoryName(globalJsonpath)}`.");
82
83
  File.Move(tempGlobalJsonPath, globalJsonpath, overwrite: retainMSBuildSdks);
83
84
  }
84
85
  }
@@ -316,7 +317,7 @@ internal static partial class MSBuildHelper
316
317
  return false;
317
318
  }
318
319
 
319
- internal static async Task<bool> DependenciesAreCoherentAsync(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Logger logger)
320
+ internal static async Task<bool> DependenciesAreCoherentAsync(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, ILogger logger)
320
321
  {
321
322
  var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
322
323
  try
@@ -339,7 +340,7 @@ internal static partial class MSBuildHelper
339
340
  return Environment.GetEnvironmentVariable("UseNewNugetPackageResolver") == "true";
340
341
  }
341
342
 
342
- internal static async Task<Dependency[]?> ResolveDependencyConflicts(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Dependency[] update, Logger logger)
343
+ internal static async Task<Dependency[]?> ResolveDependencyConflicts(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Dependency[] update, ILogger logger)
343
344
  {
344
345
  if (UseNewDependencySolver())
345
346
  {
@@ -351,7 +352,7 @@ internal static partial class MSBuildHelper
351
352
  }
352
353
  }
353
354
 
354
- internal static async Task<Dependency[]?> ResolveDependencyConflictsNew(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Dependency[] update, Logger logger)
355
+ internal static async Task<Dependency[]?> ResolveDependencyConflictsNew(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Dependency[] update, ILogger logger)
355
356
  {
356
357
  var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
357
358
  PackageManager packageManager = new PackageManager(repoRoot, projectPath);
@@ -417,7 +418,7 @@ internal static partial class MSBuildHelper
417
418
  // Update all to new versions
418
419
  foreach (var package in existingDuplicate)
419
420
  {
420
- string updateResult = await packageManager.UpdateVersion(existingDuplicate, package, targetFramework, Path.GetDirectoryName(projectPath));
421
+ string updateResult = await packageManager.UpdateVersion(existingDuplicate, package, targetFramework, Path.GetDirectoryName(projectPath), logger);
421
422
  }
422
423
  }
423
424
 
@@ -433,7 +434,7 @@ internal static partial class MSBuildHelper
433
434
  // Update all to new versions
434
435
  foreach (var package in existingPackages)
435
436
  {
436
- string updateResult = await packageManager.UpdateVersion(existingPackages, package, targetFramework, Path.GetDirectoryName(projectPath));
437
+ string updateResult = await packageManager.UpdateVersion(existingPackages, package, targetFramework, Path.GetDirectoryName(projectPath), logger);
437
438
  }
438
439
  }
439
440
 
@@ -509,7 +510,7 @@ internal static partial class MSBuildHelper
509
510
  }
510
511
  }
511
512
 
512
- internal static async Task<Dependency[]?> ResolveDependencyConflictsOld(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Logger logger)
513
+ internal static async Task<Dependency[]?> ResolveDependencyConflictsOld(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, ILogger logger)
513
514
  {
514
515
  var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
515
516
  try
@@ -762,7 +763,7 @@ internal static partial class MSBuildHelper
762
763
  string projectPath,
763
764
  string targetFramework,
764
765
  IReadOnlyCollection<Dependency> packages,
765
- Logger? logger = null)
766
+ ILogger? logger = null)
766
767
  {
767
768
  var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-resolution_");
768
769
  try
@@ -833,6 +834,17 @@ internal static partial class MSBuildHelper
833
834
  }
834
835
  }
835
836
 
837
+ internal static void ThrowOnMissingPackages(string output)
838
+ {
839
+ var missingPackagesPattern = new Regex(@"Package '(?<PackageName>[^'].*)' is not found on source");
840
+ var matchCollection = missingPackagesPattern.Matches(output);
841
+ var missingPackages = matchCollection.Select(m => m.Groups["PackageName"].Value).Distinct().ToArray();
842
+ if (missingPackages.Length > 0)
843
+ {
844
+ throw new UpdateNotPossibleException(missingPackages);
845
+ }
846
+ }
847
+
836
848
  internal static bool TryGetGlobalJsonPath(string repoRootPath, string workspacePath, [NotNullWhen(returnValue: true)] out string? globalJsonPath)
837
849
  {
838
850
  globalJsonPath = PathHelper.GetFileInDirectoryOrParent(workspacePath, repoRootPath, "global.json", caseSensitive: false);
@@ -20,7 +20,7 @@ internal static class NuGetHelper
20
20
  return false;
21
21
  }
22
22
 
23
- internal static async Task<bool> DownloadNuGetPackagesAsync(string repoRoot, string projectPath, IReadOnlyCollection<Dependency> packages, Logger logger)
23
+ internal static async Task<bool> DownloadNuGetPackagesAsync(string repoRoot, string projectPath, IReadOnlyCollection<Dependency> packages, ILogger logger)
24
24
  {
25
25
  var tempDirectory = Directory.CreateTempSubdirectory("msbuild_sdk_restore_");
26
26
  try
@@ -35,10 +35,10 @@ public class AnalyzeWorkerTestBase
35
35
 
36
36
  var discoveryPath = Path.GetFullPath(DiscoveryWorker.DiscoveryResultFileName, directoryPath);
37
37
  var dependencyPath = Path.GetFullPath(relativeDependencyPath, directoryPath);
38
- var analysisPath = Path.GetFullPath(AnalyzeWorker.AnalysisDirectoryName, directoryPath);
39
38
 
40
- var worker = new AnalyzeWorker(new Logger(verbose: true));
41
- await worker.RunAsync(directoryPath, discoveryPath, dependencyPath, analysisPath);
39
+ var worker = new AnalyzeWorker(new TestLogger());
40
+ var result = await worker.RunWithErrorHandlingAsync(directoryPath, discoveryPath, dependencyPath);
41
+ return result;
42
42
  });
43
43
 
44
44
  ValidateAnalysisResult(expectedResult, actualResult);
@@ -78,17 +78,13 @@ public class AnalyzeWorkerTestBase
78
78
  }
79
79
  }
80
80
 
81
- protected static async Task<AnalysisResult> RunAnalyzerAsync(string dependencyName, TestFile[] files, Func<string, Task> action)
81
+ protected static async Task<AnalysisResult> RunAnalyzerAsync(string dependencyName, TestFile[] files, Func<string, Task<AnalysisResult>> action)
82
82
  {
83
83
  // write initial files
84
84
  using var temporaryDirectory = await TemporaryDirectory.CreateWithContentsAsync(files);
85
85
 
86
86
  // run discovery
87
- await action(temporaryDirectory.DirectoryPath);
88
-
89
- // gather results
90
- var resultPath = Path.Join(temporaryDirectory.DirectoryPath, AnalyzeWorker.AnalysisDirectoryName, $"{dependencyName}.json");
91
- var resultJson = await File.ReadAllTextAsync(resultPath);
92
- return JsonSerializer.Deserialize<AnalysisResult>(resultJson, DiscoveryWorker.SerializerOptions)!;
87
+ var result = await action(temporaryDirectory.DirectoryPath);
88
+ return result;
93
89
  }
94
90
  }