dependabot-nuget 0.265.0 → 0.267.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs +6 -6
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +173 -0
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalysisResult.cs +1 -1
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +92 -79
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +21 -8
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +36 -9
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/Requirement.cs +88 -45
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +33 -16
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +44 -25
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs +1 -1
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +9 -0
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/ProjectBuildFile.cs +2 -2
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/MissingFileException.cs +11 -0
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/NativeResult.cs +8 -0
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +45 -42
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +19 -1
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +2 -1
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdateOperationResult.cs +5 -0
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +70 -22
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +29 -1
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +6 -2
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +450 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/CompatibilityCheckerTests.cs +23 -0
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/RequirementTests.cs +1 -0
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +2 -0
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +148 -0
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +1 -1
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +17 -22
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestHttpServer.cs +81 -0
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +27 -7
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +32 -0
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +447 -2
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +88 -0
  35. data/lib/dependabot/nuget/analysis/dependency_analysis.rb +3 -0
  36. data/lib/dependabot/nuget/file_fetcher.rb +30 -11
  37. data/lib/dependabot/nuget/file_updater.rb +2 -0
  38. data/lib/dependabot/nuget/metadata_finder.rb +160 -2
  39. data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +3 -0
  40. data/lib/dependabot/nuget/native_helpers.rb +36 -3
  41. data/lib/dependabot/nuget/native_update_checker/native_update_checker.rb +1 -0
  42. data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +3 -0
  43. metadata +12 -7
@@ -1,3 +1,10 @@
1
+ using System.Net;
2
+ using System.Text.Json;
3
+ using System.Text.Json.Serialization;
4
+
5
+ using NuGetUpdater.Core.Analyze;
6
+ using NuGetUpdater.Core.Updater;
7
+
1
8
  namespace NuGetUpdater.Core;
2
9
 
3
10
  public class UpdaterWorker
@@ -5,48 +12,89 @@ public class UpdaterWorker
5
12
  private readonly Logger _logger;
6
13
  private readonly HashSet<string> _processedProjectPaths = new(StringComparer.OrdinalIgnoreCase);
7
14
 
15
+ internal static readonly JsonSerializerOptions SerializerOptions = new()
16
+ {
17
+ WriteIndented = true,
18
+ Converters = { new JsonStringEnumConverter() },
19
+ };
20
+
8
21
  public UpdaterWorker(Logger logger)
9
22
  {
10
23
  _logger = logger;
11
24
  }
12
25
 
13
- public async Task RunAsync(string repoRootPath, string workspacePath, string dependencyName, string previousDependencyVersion, string newDependencyVersion, bool isTransitive)
26
+ public async Task RunAsync(string repoRootPath, string workspacePath, string dependencyName, string previousDependencyVersion, string newDependencyVersion, bool isTransitive, string? resultOutputPath = null)
14
27
  {
15
28
  MSBuildHelper.RegisterMSBuild(Environment.CurrentDirectory, repoRootPath);
29
+ UpdateOperationResult result;
16
30
 
17
31
  if (!Path.IsPathRooted(workspacePath) || !File.Exists(workspacePath))
18
32
  {
19
33
  workspacePath = Path.GetFullPath(Path.Join(repoRootPath, workspacePath));
20
34
  }
21
35
 
22
- if (!isTransitive)
36
+ try
37
+ {
38
+ if (!isTransitive)
39
+ {
40
+ await DotNetToolsJsonUpdater.UpdateDependencyAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, _logger);
41
+ await GlobalJsonUpdater.UpdateDependencyAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, _logger);
42
+ }
43
+
44
+ var extension = Path.GetExtension(workspacePath).ToLowerInvariant();
45
+ switch (extension)
46
+ {
47
+ case ".sln":
48
+ await RunForSolutionAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive);
49
+ break;
50
+ case ".proj":
51
+ await RunForProjFileAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive);
52
+ break;
53
+ case ".csproj":
54
+ case ".fsproj":
55
+ case ".vbproj":
56
+ await RunForProjectAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive);
57
+ break;
58
+ default:
59
+ _logger.Log($"File extension [{extension}] is not supported.");
60
+ break;
61
+ }
62
+
63
+ result = new(); // all ok
64
+ _logger.Log("Update complete.");
65
+ }
66
+ catch (HttpRequestException ex)
67
+ when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
68
+ {
69
+ // TODO: consolidate this error handling between AnalyzeWorker, DiscoveryWorker, and UpdateWorker
70
+ result = new()
71
+ {
72
+ ErrorType = ErrorType.AuthenticationFailure,
73
+ ErrorDetails = "(" + string.Join("|", NuGetContext.GetPackageSourceUrls(workspacePath)) + ")",
74
+ };
75
+ }
76
+ catch (MissingFileException ex)
23
77
  {
24
- await DotNetToolsJsonUpdater.UpdateDependencyAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, _logger);
25
- await GlobalJsonUpdater.UpdateDependencyAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, _logger);
78
+ result = new()
79
+ {
80
+ ErrorType = ErrorType.MissingFile,
81
+ ErrorDetails = ex.FilePath,
82
+ };
26
83
  }
27
84
 
28
- var extension = Path.GetExtension(workspacePath).ToLowerInvariant();
29
- switch (extension)
85
+ _processedProjectPaths.Clear();
86
+ if (resultOutputPath is { })
30
87
  {
31
- case ".sln":
32
- await RunForSolutionAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive);
33
- break;
34
- case ".proj":
35
- await RunForProjFileAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive);
36
- break;
37
- case ".csproj":
38
- case ".fsproj":
39
- case ".vbproj":
40
- await RunForProjectAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive);
41
- break;
42
- default:
43
- _logger.Log($"File extension [{extension}] is not supported.");
44
- break;
88
+ await WriteResultFile(result, resultOutputPath, _logger);
45
89
  }
90
+ }
46
91
 
47
- _logger.Log("Update complete.");
92
+ internal static async Task WriteResultFile(UpdateOperationResult result, string resultOutputPath, Logger logger)
93
+ {
94
+ logger.Log($" Writing update result to [{resultOutputPath}].");
48
95
 
49
- _processedProjectPaths.Clear();
96
+ var resultJson = JsonSerializer.Serialize(result, SerializerOptions);
97
+ await File.WriteAllTextAsync(resultOutputPath, resultJson);
50
98
  }
51
99
 
52
100
  private async Task RunForSolutionAsync(
@@ -185,8 +185,9 @@ internal static partial class MSBuildHelper
185
185
  var versionSpecification = packageItem.Metadata.FirstOrDefault(m => m.Name.Equals("Version", StringComparison.OrdinalIgnoreCase))?.Value
186
186
  ?? packageItem.Metadata.FirstOrDefault(m => m.Name.Equals("VersionOverride", StringComparison.OrdinalIgnoreCase))?.Value
187
187
  ?? string.Empty;
188
- foreach (var attributeValue in new[] { packageItem.Include, packageItem.Update })
188
+ foreach (var rawAttributeValue in new[] { packageItem.Include, packageItem.Update })
189
189
  {
190
+ var attributeValue = rawAttributeValue?.Trim();
190
191
  if (!string.IsNullOrWhiteSpace(attributeValue))
191
192
  {
192
193
  if (packageInfo.TryGetValue(attributeValue, out var existingInfo))
@@ -312,6 +313,7 @@ internal static partial class MSBuildHelper
312
313
  {
313
314
  var tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages);
314
315
  var (exitCode, stdOut, stdErr) = await ProcessEx.RunAsync("dotnet", $"restore \"{tempProjectPath}\"", workingDirectory: tempDirectory.FullName);
316
+ ThrowOnUnauthenticatedFeed(stdOut);
315
317
 
316
318
  // simple cases first
317
319
  // if restore failed, nothing we can do
@@ -506,6 +508,7 @@ internal static partial class MSBuildHelper
506
508
  <TargetFramework>{targetFramework}</TargetFramework>
507
509
  <GenerateDependencyFile>true</GenerateDependencyFile>
508
510
  <RunAnalyzers>false</RunAnalyzers>
511
+ <NuGetInteractive>false</NuGetInteractive>
509
512
  </PropertyGroup>
510
513
  <ItemGroup>
511
514
  {packageReferences}
@@ -565,6 +568,7 @@ internal static partial class MSBuildHelper
565
568
  var tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages);
566
569
 
567
570
  var (exitCode, stdout, stderr) = await ProcessEx.RunAsync("dotnet", $"build \"{tempProjectPath}\" /t:_ReportDependencies", workingDirectory: tempDirectory.FullName);
571
+ ThrowOnUnauthenticatedFeed(stdout);
568
572
 
569
573
  if (exitCode == 0)
570
574
  {
@@ -602,6 +606,30 @@ internal static partial class MSBuildHelper
602
606
  }
603
607
  }
604
608
 
609
+ internal static void ThrowOnUnauthenticatedFeed(string stdout)
610
+ {
611
+ var unauthorizedMessageSnippets = new string[]
612
+ {
613
+ "The plugin credential provider could not acquire credentials",
614
+ "401 (Unauthorized)",
615
+ "error NU1301: Unable to load the service index for source",
616
+ };
617
+ if (unauthorizedMessageSnippets.Any(stdout.Contains))
618
+ {
619
+ throw new HttpRequestException(message: stdout, inner: null, statusCode: System.Net.HttpStatusCode.Unauthorized);
620
+ }
621
+ }
622
+
623
+ internal static void ThrowOnMissingFile(string output)
624
+ {
625
+ var missingFilePattern = new Regex(@"The imported project \""(?<FilePath>.*)\"" was not found");
626
+ var match = missingFilePattern.Match(output);
627
+ if (match.Success)
628
+ {
629
+ throw new MissingFileException(match.Groups["FilePath"].Value);
630
+ }
631
+ }
632
+
605
633
  internal static bool TryGetGlobalJsonPath(string repoRootPath, string workspacePath, [NotNullWhen(returnValue: true)] out string? globalJsonPath)
606
634
  {
607
635
  globalJsonPath = PathHelper.GetFileInDirectoryOrParent(workspacePath, repoRootPath, "global.json", caseSensitive: false);
@@ -18,7 +18,8 @@ public class AnalyzeWorkerTestBase
18
18
  WorkspaceDiscoveryResult discovery,
19
19
  DependencyInfo dependencyInfo,
20
20
  ExpectedAnalysisResult expectedResult,
21
- MockNuGetPackage[]? packages = null)
21
+ MockNuGetPackage[]? packages = null,
22
+ TestFile[]? extraFiles = null)
22
23
  {
23
24
  var relativeDependencyPath = $"./dependabot/dependency/{dependencyInfo.Name}.json";
24
25
 
@@ -27,7 +28,8 @@ public class AnalyzeWorkerTestBase
27
28
  (relativeDependencyPath, JsonSerializer.Serialize(dependencyInfo, AnalyzeWorker.SerializerOptions)),
28
29
  ];
29
30
 
30
- var actualResult = await RunAnalyzerAsync(dependencyInfo.Name, files, async directoryPath =>
31
+ var allFiles = files.Concat(extraFiles ?? []).ToArray();
32
+ var actualResult = await RunAnalyzerAsync(dependencyInfo.Name, allFiles, async directoryPath =>
31
33
  {
32
34
  await UpdateWorkerTestBase.MockNuGetPackagesInDirectory(packages, directoryPath);
33
35
 
@@ -50,6 +52,8 @@ public class AnalyzeWorkerTestBase
50
52
  Assert.Equal(expectedResult.VersionComesFromMultiDependencyProperty, actualResult.VersionComesFromMultiDependencyProperty);
51
53
  ValidateDependencies(expectedResult.UpdatedDependencies, actualResult.UpdatedDependencies);
52
54
  Assert.Equal(expectedResult.ExpectedUpdatedDependenciesCount ?? expectedResult.UpdatedDependencies.Length, actualResult.UpdatedDependencies.Length);
55
+ Assert.Equal(expectedResult.ErrorType, actualResult.ErrorType);
56
+ Assert.Equal(expectedResult.ErrorDetails, actualResult.ErrorDetails);
53
57
 
54
58
  return;
55
59