dependabot-nuget 0.278.0 → 0.279.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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/build +1 -1
  3. data/helpers/lib/NuGetUpdater/.editorconfig +1 -0
  4. data/helpers/lib/NuGetUpdater/Directory.Build.props +1 -0
  5. data/helpers/lib/NuGetUpdater/Directory.Common.props +1 -1
  6. data/helpers/lib/NuGetUpdater/Directory.Packages.props +6 -1
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +2 -3
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +87 -83
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/Requirement.cs +2 -2
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +47 -46
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyFileNotFound.cs +6 -0
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +11 -0
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PrivateSourceAuthenticationFailure.cs +6 -0
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/UnknownError.cs +6 -0
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/HttpApiHandler.cs +5 -0
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/IApiHandler.cs +1 -0
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +60 -15
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +1 -1
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +1 -1
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +50 -46
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +5 -5
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +1 -1
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProcessExtensions.cs +2 -4
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/RequirementTests.cs +4 -1
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +10 -1
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +92 -0
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/TestApiHandler.cs +10 -4
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +8 -8
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +10 -1
  30. data/helpers/lib/NuGetUpdater/global.json +1 -1
  31. data/lib/dependabot/nuget/file_updater.rb +5 -1
  32. data/lib/dependabot/nuget/native_helpers.rb +4 -1
  33. data/lib/dependabot/nuget/requirement.rb +2 -0
  34. data/lib/dependabot/nuget/update_checker/repository_finder.rb +26 -2
  35. metadata +9 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d29298584fd13989b51d63574bc462c199b1db8144a2a28b6c893ae90bf41dec
4
- data.tar.gz: f2fc3a71de6471f5cca05fe294ce492bb4dbb1837ce2feb03bf40cfcec9ff4cb
3
+ metadata.gz: 644fb3ec407649eb15e5e9ab7be78a85f8f03900adcc93819e3be781610cf78e
4
+ data.tar.gz: 408ef4e6a5d517d159256429a2d68d61bc0e0188e3f0c13a4c0aa6b00b55e74b
5
5
  SHA512:
6
- metadata.gz: 80ad942cbaf12ad2bec0eacf04124a26cb37b4a8f54cda4f3290f9a4b8c776f16a907cd963099634be43d925c64f0bef54ef5247632360954e9e28064bcda676
7
- data.tar.gz: f413dfafd425032365e31d9c0969a94c6c8ac8195efe0de8b922ab464575fac246276012a6ceca8b1f9f55b10e3d8fb49d9cd5c4390f281674782a04a91b15ca
6
+ metadata.gz: 25125733df999707391798277975f970cfcf4bd87809165612d600a245d758e9bad553e046c8a0ff566446a90426c6719fedffa3a82139212c6f106de412bea7
7
+ data.tar.gz: 5db427ffb67c418e0f99dcc3f83a5f320a7fc3aaff177425a5c32d9b48b3296495c9fdc5f0fbd0959c2da0cc0b35132a532b1ec83af494950df15d3fa076435e
data/helpers/build CHANGED
@@ -32,7 +32,7 @@ cd "$install_dir/lib/NuGetUpdater/NuGetUpdater.Cli"
32
32
  dotnet publish \
33
33
  --configuration Release \
34
34
  --output "$install_dir/NuGetUpdater" \
35
- --framework net8.0 \
35
+ --framework net9.0 \
36
36
  --runtime "$os-$arch"
37
37
  dotnet clean
38
38
 
@@ -20,6 +20,7 @@ tab_width = 4
20
20
 
21
21
  # New line preferences
22
22
  insert_final_newline = true
23
+ end_of_line = lf
23
24
 
24
25
  #### .NET Coding Conventions ####
25
26
  [*.{cs,vb}]
@@ -1,6 +1,7 @@
1
1
  <Project>
2
2
 
3
3
  <PropertyGroup>
4
+ <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
4
5
  <NoWarn>$(NoWarn);NU1701</NoWarn>
5
6
  <Nullable>enable</Nullable>
6
7
  </PropertyGroup>
@@ -9,7 +9,7 @@
9
9
  NuGetUpdater\NuGetUpdater.Core\FrameworkChecker\SupportedFrameworks.cs
10
10
  2. Update tests as needed at `NuGetUpdater\NuGetUpdater.Core.Test\FrameworkChecker\CompatibilityCheckerFacts.cs`
11
11
  -->
12
- <CommonTargetFramework>net8.0</CommonTargetFramework>
12
+ <CommonTargetFramework>net9.0</CommonTargetFramework>
13
13
  <ImplicitUsings>enable</ImplicitUsings>
14
14
  <UseArtifactsOutput>true</UseArtifactsOutput>
15
15
  <ArtifactsPath>$(MSBuildThisFileDirectory)artifacts</ArtifactsPath>
@@ -7,7 +7,7 @@
7
7
  <ItemGroup>
8
8
  <PackageVersion Include="DiffPlex" Version="1.7.1" />
9
9
 
10
- <PackageVersion Include="GuiLabs.Language.Xml" Version="1.2.60" />
10
+ <PackageVersion Include="GuiLabs.Language.Xml" Version="1.2.93" />
11
11
 
12
12
  <PackageVersion Include="Microsoft.Build.Locator" Version="1.6.1" />
13
13
  <PackageVersion Include="Microsoft.Build" Version="17.5.0" ExcludeAssets="Runtime" PrivateAssets="All" />
@@ -20,6 +20,11 @@
20
20
  <PackageVersion Include="NuGet.Core" Version="2.14.0-rtm-832" Aliases="CoreV2" />
21
21
 
22
22
  <PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
23
+ <PackageVersion Include="System.Net.Http" Version="4.3.4" />
24
+ <PackageVersion Include="System.Formats.Asn1" Version="8.0.1" />
25
+ <PackageVersion Include="System.Security.Cryptography.Pkcs" Version="8.0.0" />
26
+ <PackageVersion Include="System.Text.Json" Version="8.0.4" />
27
+ <PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
23
28
 
24
29
  <PackageVersion Include="xunit" Version="2.4.2" />
25
30
  <PackageVersion Include="xunit.runner.visualstudio" Version="2.4.5" />
@@ -352,8 +352,7 @@ public partial class EntryPointTests
352
352
  </Project>
353
353
  """);
354
354
  var executableName = Path.Join(Path.GetDirectoryName(GetType().Assembly.Location), "NuGetUpdater.Cli.dll");
355
- var executableArgs = string.Join(" ",
356
- [
355
+ IEnumerable<string> executableArgs = [
357
356
  executableName,
358
357
  "update",
359
358
  "--repo-root",
@@ -367,7 +366,7 @@ public partial class EntryPointTests
367
366
  "--previous-version",
368
367
  "7.0.1",
369
368
  "--verbose"
370
- ]);
369
+ ];
371
370
 
372
371
  // verify base run
373
372
  var workingDirectory = tempDir.DirectoryPath;
@@ -31,9 +31,29 @@ public partial class AnalyzeWorker
31
31
 
32
32
  public async Task RunAsync(string repoRoot, string discoveryPath, string dependencyPath, string analysisDirectory)
33
33
  {
34
+ AnalysisResult analysisResult;
34
35
  var discovery = await DeserializeJsonFileAsync<WorkspaceDiscoveryResult>(discoveryPath, nameof(WorkspaceDiscoveryResult));
35
36
  var dependencyInfo = await DeserializeJsonFileAsync<DependencyInfo>(dependencyPath, nameof(DependencyInfo));
36
- var analysisResult = await RunAsync(repoRoot, discovery, dependencyInfo);
37
+
38
+ try
39
+ {
40
+ analysisResult = await RunAsync(repoRoot, discovery, dependencyInfo);
41
+ }
42
+ catch (HttpRequestException ex)
43
+ when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
44
+ {
45
+ var localPath = PathHelper.JoinPath(repoRoot, discovery.Path);
46
+ var nugetContext = new NuGetContext(localPath);
47
+ analysisResult = new AnalysisResult
48
+ {
49
+ ErrorType = ErrorType.AuthenticationFailure,
50
+ ErrorDetails = "(" + string.Join("|", nugetContext.PackageSources.Select(s => s.Source)) + ")",
51
+ UpdatedVersion = string.Empty,
52
+ CanUpdate = false,
53
+ UpdatedDependencies = [],
54
+ };
55
+ }
56
+
37
57
  await WriteResultsAsync(analysisDirectory, dependencyInfo.Name, analysisResult, _logger);
38
58
  }
39
59
 
@@ -68,100 +88,84 @@ public partial class AnalyzeWorker
68
88
  var isUpdateNecessary = isProjectUpdateNecessary || dotnetToolsHasDependency || globalJsonHasDependency;
69
89
  using var nugetContext = new NuGetContext(startingDirectory);
70
90
  AnalysisResult analysisResult;
71
- try
91
+ if (isUpdateNecessary)
72
92
  {
73
- if (isUpdateNecessary)
93
+ _logger.Log($" Determining multi-dependency property.");
94
+ var multiDependencies = DetermineMultiDependencyDetails(
95
+ discovery,
96
+ dependencyInfo.Name,
97
+ propertyBasedDependencies);
98
+
99
+ usesMultiDependencyProperty = multiDependencies.Any(md => md.DependencyNames.Count > 1);
100
+ var dependenciesToUpdate = usesMultiDependencyProperty
101
+ ? multiDependencies
102
+ .SelectMany(md => md.DependencyNames)
103
+ .ToImmutableHashSet(StringComparer.OrdinalIgnoreCase)
104
+ : [dependencyInfo.Name];
105
+ var applicableTargetFrameworks = usesMultiDependencyProperty
106
+ ? multiDependencies
107
+ .SelectMany(md => md.TargetFrameworks)
108
+ .ToImmutableHashSet(StringComparer.OrdinalIgnoreCase)
109
+ .Select(NuGetFramework.Parse)
110
+ .ToImmutableArray()
111
+ : projectFrameworks;
112
+
113
+ _logger.Log($" Finding updated version.");
114
+ updatedVersion = await FindUpdatedVersionAsync(
115
+ startingDirectory,
116
+ dependencyInfo,
117
+ dependenciesToUpdate,
118
+ applicableTargetFrameworks,
119
+ nugetContext,
120
+ _logger,
121
+ CancellationToken.None);
122
+
123
+ _logger.Log($" Finding updated peer dependencies.");
124
+ if (updatedVersion is null)
125
+ {
126
+ updatedDependencies = [];
127
+ }
128
+ else if (isProjectUpdateNecessary)
74
129
  {
75
- _logger.Log($" Determining multi-dependency property.");
76
- var multiDependencies = DetermineMultiDependencyDetails(
130
+ updatedDependencies = await FindUpdatedDependenciesAsync(
131
+ repoRoot,
77
132
  discovery,
78
- dependencyInfo.Name,
79
- propertyBasedDependencies);
80
-
81
- usesMultiDependencyProperty = multiDependencies.Any(md => md.DependencyNames.Count > 1);
82
- var dependenciesToUpdate = usesMultiDependencyProperty
83
- ? multiDependencies
84
- .SelectMany(md => md.DependencyNames)
85
- .ToImmutableHashSet(StringComparer.OrdinalIgnoreCase)
86
- : [dependencyInfo.Name];
87
- var applicableTargetFrameworks = usesMultiDependencyProperty
88
- ? multiDependencies
89
- .SelectMany(md => md.TargetFrameworks)
90
- .ToImmutableHashSet(StringComparer.OrdinalIgnoreCase)
91
- .Select(NuGetFramework.Parse)
92
- .ToImmutableArray()
93
- : projectFrameworks;
94
-
95
- _logger.Log($" Finding updated version.");
96
- updatedVersion = await FindUpdatedVersionAsync(
97
- startingDirectory,
98
- dependencyInfo,
99
133
  dependenciesToUpdate,
100
- applicableTargetFrameworks,
134
+ updatedVersion,
101
135
  nugetContext,
102
136
  _logger,
103
137
  CancellationToken.None);
104
-
105
- _logger.Log($" Finding updated peer dependencies.");
106
- if (updatedVersion is null)
107
- {
108
- updatedDependencies = [];
109
- }
110
- else if (isProjectUpdateNecessary)
111
- {
112
- updatedDependencies = await FindUpdatedDependenciesAsync(
113
- repoRoot,
114
- discovery,
115
- dependenciesToUpdate,
116
- updatedVersion,
117
- nugetContext,
118
- _logger,
119
- CancellationToken.None);
120
- }
121
- else if (dotnetToolsHasDependency)
122
- {
123
- var infoUrl = await nugetContext.GetPackageInfoUrlAsync(dependencyInfo.Name, updatedVersion.ToNormalizedString(), CancellationToken.None);
124
- updatedDependencies = [new Dependency(dependencyInfo.Name, updatedVersion.ToNormalizedString(), DependencyType.DotNetTool, IsDirect: true, InfoUrl: infoUrl)];
125
- }
126
- else if (globalJsonHasDependency)
127
- {
128
- var infoUrl = await nugetContext.GetPackageInfoUrlAsync(dependencyInfo.Name, updatedVersion.ToNormalizedString(), CancellationToken.None);
129
- updatedDependencies = [new Dependency(dependencyInfo.Name, updatedVersion.ToNormalizedString(), DependencyType.MSBuildSdk, IsDirect: true, InfoUrl: infoUrl)];
130
- }
131
- else
132
- {
133
- throw new InvalidOperationException("Unreachable.");
134
- }
135
-
136
- //TODO: At this point we should add the peer dependencies to a queue where
137
- // we will analyze them one by one to see if they themselves are part of a
138
- // multi-dependency property. Basically looping this if-body until we have
139
- // emptied the queue and have a complete list of updated dependencies. We
140
- // should track the dependenciesToUpdate as they have already been analyzed.
141
138
  }
142
-
143
- analysisResult = new AnalysisResult
139
+ else if (dotnetToolsHasDependency)
144
140
  {
145
- UpdatedVersion = updatedVersion?.ToNormalizedString() ?? dependencyInfo.Version,
146
- CanUpdate = updatedVersion is not null,
147
- VersionComesFromMultiDependencyProperty = usesMultiDependencyProperty,
148
- UpdatedDependencies = updatedDependencies,
149
- };
150
- }
151
- catch (HttpRequestException ex)
152
- when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
153
- {
154
- // TODO: consolidate this error handling between AnalyzeWorker, DiscoveryWorker, and UpdateWorker
155
- analysisResult = new AnalysisResult
141
+ var infoUrl = await nugetContext.GetPackageInfoUrlAsync(dependencyInfo.Name, updatedVersion.ToNormalizedString(), CancellationToken.None);
142
+ updatedDependencies = [new Dependency(dependencyInfo.Name, updatedVersion.ToNormalizedString(), DependencyType.DotNetTool, IsDirect: true, InfoUrl: infoUrl)];
143
+ }
144
+ else if (globalJsonHasDependency)
156
145
  {
157
- ErrorType = ErrorType.AuthenticationFailure,
158
- ErrorDetails = "(" + string.Join("|", nugetContext.PackageSources.Select(s => s.Source)) + ")",
159
- UpdatedVersion = string.Empty,
160
- CanUpdate = false,
161
- UpdatedDependencies = [],
162
- };
146
+ var infoUrl = await nugetContext.GetPackageInfoUrlAsync(dependencyInfo.Name, updatedVersion.ToNormalizedString(), CancellationToken.None);
147
+ updatedDependencies = [new Dependency(dependencyInfo.Name, updatedVersion.ToNormalizedString(), DependencyType.MSBuildSdk, IsDirect: true, InfoUrl: infoUrl)];
148
+ }
149
+ else
150
+ {
151
+ throw new InvalidOperationException("Unreachable.");
152
+ }
153
+
154
+ //TODO: At this point we should add the peer dependencies to a queue where
155
+ // we will analyze them one by one to see if they themselves are part of a
156
+ // multi-dependency property. Basically looping this if-body until we have
157
+ // emptied the queue and have a complete list of updated dependencies. We
158
+ // should track the dependenciesToUpdate as they have already been analyzed.
163
159
  }
164
160
 
161
+ analysisResult = new AnalysisResult
162
+ {
163
+ UpdatedVersion = updatedVersion?.ToNormalizedString() ?? dependencyInfo.Version,
164
+ CanUpdate = updatedVersion is not null,
165
+ VersionComesFromMultiDependencyProperty = usesMultiDependencyProperty,
166
+ UpdatedDependencies = updatedDependencies,
167
+ };
168
+
165
169
  _logger.Log($"Analysis complete.");
166
170
  return analysisResult;
167
171
  }
@@ -52,10 +52,10 @@ public abstract class Requirement
52
52
 
53
53
  public static Requirement Parse(string requirement)
54
54
  {
55
- var specificParts = requirement.Split(',');
55
+ var specificParts = requirement.Split(',').Where(p => !string.IsNullOrWhiteSpace(p)).ToArray();
56
56
  if (specificParts.Length == 1)
57
57
  {
58
- return IndividualRequirement.ParseIndividual(requirement);
58
+ return IndividualRequirement.ParseIndividual(specificParts[0]);
59
59
  }
60
60
 
61
61
  var specificRequirements = specificParts.Select(IndividualRequirement.ParseIndividual).ToArray();
@@ -30,7 +30,29 @@ public partial class DiscoveryWorker
30
30
  _logger = logger;
31
31
  }
32
32
 
33
- public async Task<WorkspaceDiscoveryResult> RunAsync(string repoRootPath, string workspacePath)
33
+ public async Task RunAsync(string repoRootPath, string workspacePath, string outputPath)
34
+ {
35
+ WorkspaceDiscoveryResult result;
36
+ try
37
+ {
38
+ result = await RunAsync(repoRootPath, workspacePath);
39
+ }
40
+ catch (HttpRequestException ex)
41
+ when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
42
+ {
43
+ result = new WorkspaceDiscoveryResult
44
+ {
45
+ ErrorType = ErrorType.AuthenticationFailure,
46
+ ErrorDetails = "(" + string.Join("|", NuGetContext.GetPackageSourceUrls(PathHelper.JoinPath(repoRootPath, workspacePath))) + ")",
47
+ Path = workspacePath,
48
+ Projects = [],
49
+ };
50
+ }
51
+
52
+ await WriteResultsAsync(repoRootPath, outputPath, result);
53
+ }
54
+
55
+ internal async Task<WorkspaceDiscoveryResult> RunAsync(string repoRootPath, string workspacePath)
34
56
  {
35
57
  MSBuildHelper.RegisterMSBuild(Environment.CurrentDirectory, repoRootPath);
36
58
 
@@ -51,69 +73,48 @@ public partial class DiscoveryWorker
51
73
  ImmutableArray<ProjectDiscoveryResult> projectResults = [];
52
74
  WorkspaceDiscoveryResult result;
53
75
 
54
- try
76
+ if (Directory.Exists(workspacePath))
55
77
  {
56
- if (Directory.Exists(workspacePath))
57
- {
58
- _logger.Log($"Discovering build files in workspace [{workspacePath}].");
78
+ _logger.Log($"Discovering build files in workspace [{workspacePath}].");
59
79
 
60
- dotNetToolsJsonDiscovery = DotNetToolsJsonDiscovery.Discover(repoRootPath, workspacePath, _logger);
61
- globalJsonDiscovery = GlobalJsonDiscovery.Discover(repoRootPath, workspacePath, _logger);
80
+ dotNetToolsJsonDiscovery = DotNetToolsJsonDiscovery.Discover(repoRootPath, workspacePath, _logger);
81
+ globalJsonDiscovery = GlobalJsonDiscovery.Discover(repoRootPath, workspacePath, _logger);
62
82
 
63
- if (globalJsonDiscovery is not null)
64
- {
65
- await TryRestoreMSBuildSdksAsync(repoRootPath, workspacePath, globalJsonDiscovery.Dependencies, _logger);
66
- }
83
+ if (globalJsonDiscovery is not null)
84
+ {
85
+ await TryRestoreMSBuildSdksAsync(repoRootPath, workspacePath, globalJsonDiscovery.Dependencies, _logger);
86
+ }
67
87
 
68
- // this next line should throw or something
69
- projectResults = await RunForDirectoryAsnyc(repoRootPath, workspacePath);
88
+ // this next line should throw or something
89
+ projectResults = await RunForDirectoryAsnyc(repoRootPath, workspacePath);
70
90
 
71
- directoryPackagesPropsDiscovery = DirectoryPackagesPropsDiscovery.Discover(repoRootPath, workspacePath, projectResults, _logger);
91
+ directoryPackagesPropsDiscovery = DirectoryPackagesPropsDiscovery.Discover(repoRootPath, workspacePath, projectResults, _logger);
72
92
 
73
- if (directoryPackagesPropsDiscovery is not null)
74
- {
75
- projectResults = projectResults.Remove(projectResults.First(p => p.FilePath.Equals(directoryPackagesPropsDiscovery.FilePath, StringComparison.OrdinalIgnoreCase)));
76
- }
77
- }
78
- else
93
+ if (directoryPackagesPropsDiscovery is not null)
79
94
  {
80
- _logger.Log($"Workspace path [{workspacePath}] does not exist.");
95
+ projectResults = projectResults.Remove(projectResults.First(p => p.FilePath.Equals(directoryPackagesPropsDiscovery.FilePath, StringComparison.OrdinalIgnoreCase)));
81
96
  }
82
-
83
- result = new WorkspaceDiscoveryResult
84
- {
85
- Path = initialWorkspacePath,
86
- DotNetToolsJson = dotNetToolsJsonDiscovery,
87
- GlobalJson = globalJsonDiscovery,
88
- DirectoryPackagesProps = directoryPackagesPropsDiscovery,
89
- Projects = projectResults.OrderBy(p => p.FilePath).ToImmutableArray(),
90
- };
91
97
  }
92
- catch (HttpRequestException ex)
93
- when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
98
+ else
94
99
  {
95
- // TODO: consolidate this error handling between AnalyzeWorker, DiscoveryWorker, and UpdateWorker
96
- result = new WorkspaceDiscoveryResult
97
- {
98
- ErrorType = ErrorType.AuthenticationFailure,
99
- ErrorDetails = "(" + string.Join("|", NuGetContext.GetPackageSourceUrls(workspacePath)) + ")",
100
- Path = initialWorkspacePath,
101
- Projects = [],
102
- };
100
+ _logger.Log($"Workspace path [{workspacePath}] does not exist.");
103
101
  }
104
102
 
103
+ result = new WorkspaceDiscoveryResult
104
+ {
105
+ Path = initialWorkspacePath,
106
+ DotNetToolsJson = dotNetToolsJsonDiscovery,
107
+ GlobalJson = globalJsonDiscovery,
108
+ DirectoryPackagesProps = directoryPackagesPropsDiscovery,
109
+ Projects = projectResults.OrderBy(p => p.FilePath).ToImmutableArray(),
110
+ };
111
+
105
112
  _logger.Log("Discovery complete.");
106
113
  _processedProjectPaths.Clear();
107
114
 
108
115
  return result;
109
116
  }
110
117
 
111
- public async Task RunAsync(string repoRootPath, string workspacePath, string outputPath)
112
- {
113
- var result = await RunAsync(repoRootPath, workspacePath);
114
- await WriteResultsAsync(repoRootPath, outputPath, result);
115
- }
116
-
117
118
  /// <summary>
118
119
  /// Restores MSBuild SDKs from the given dependencies.
119
120
  /// </summary>
@@ -0,0 +1,6 @@
1
+ namespace NuGetUpdater.Core.Run.ApiModel;
2
+
3
+ public record DependencyFileNotFound : JobErrorBase
4
+ {
5
+ public override string Type => "dependency_file_not_found";
6
+ }
@@ -0,0 +1,11 @@
1
+ using System.Text.Json.Serialization;
2
+
3
+ namespace NuGetUpdater.Core.Run.ApiModel;
4
+
5
+ public abstract record JobErrorBase
6
+ {
7
+ [JsonPropertyName("error-type")]
8
+ public abstract string Type { get; }
9
+ [JsonPropertyName("error-details")]
10
+ public required string Details { get; init; }
11
+ }
@@ -0,0 +1,6 @@
1
+ namespace NuGetUpdater.Core.Run.ApiModel;
2
+
3
+ public record PrivateSourceAuthenticationFailure : JobErrorBase
4
+ {
5
+ public override string Type => "private_source_authentication_failure";
6
+ }
@@ -0,0 +1,6 @@
1
+ namespace NuGetUpdater.Core.Run.ApiModel;
2
+
3
+ public record UnknownError : JobErrorBase
4
+ {
5
+ public override string Type => "unknown_error";
6
+ }
@@ -25,6 +25,11 @@ public class HttpApiHandler : IApiHandler
25
25
  _jobId = jobId;
26
26
  }
27
27
 
28
+ public async Task RecordUpdateJobError(JobErrorBase error)
29
+ {
30
+ await PostAsJson("record_update_job_error", error);
31
+ }
32
+
28
33
  public async Task UpdateDependencyList(UpdatedDependencyList updatedDependencyList)
29
34
  {
30
35
  await PostAsJson("update_dependency_list", updatedDependencyList);
@@ -4,6 +4,7 @@ namespace NuGetUpdater.Core.Run;
4
4
 
5
5
  public interface IApiHandler
6
6
  {
7
+ Task RecordUpdateJobError(JobErrorBase error);
7
8
  Task UpdateDependencyList(UpdatedDependencyList updatedDependencyList);
8
9
  Task IncrementMetric(IncrementMetric incrementMetric);
9
10
  Task CreatePullRequest(CreatePullRequest createPullRequest);
@@ -1,3 +1,4 @@
1
+ using System.Net;
1
2
  using System.Text;
2
3
  using System.Text.Json;
3
4
  using System.Text.Json.Serialization;
@@ -35,25 +36,73 @@ public class RunWorker
35
36
  await File.WriteAllTextAsync(outputFilePath.FullName, resultJson);
36
37
  }
37
38
 
38
- public async Task<RunResult> RunAsync(Job job, DirectoryInfo repoContentsPath, string baseCommitSha)
39
+ public Task<RunResult> RunAsync(Job job, DirectoryInfo repoContentsPath, string baseCommitSha)
39
40
  {
40
- MSBuildHelper.RegisterMSBuild(repoContentsPath.FullName, repoContentsPath.FullName);
41
+ return RunWithErrorHandlingAsync(job, repoContentsPath, baseCommitSha);
42
+ }
43
+
44
+ private async Task<RunResult> RunWithErrorHandlingAsync(Job job, DirectoryInfo repoContentsPath, string baseCommitSha)
45
+ {
46
+ JobErrorBase? error = null;
47
+ string[] lastUsedPackageSourceUrls = []; // used for error reporting below
48
+ var runResult = new RunResult()
49
+ {
50
+ Base64DependencyFiles = [],
51
+ BaseCommitSha = baseCommitSha,
52
+ };
41
53
 
42
- var allDependencyFiles = new Dictionary<string, DependencyFile>();
43
- foreach (var directory in job.GetAllDirectories())
54
+ try
44
55
  {
45
- var result = await RunForDirectory(job, repoContentsPath, directory, baseCommitSha);
46
- foreach (var dependencyFile in result.Base64DependencyFiles)
56
+ MSBuildHelper.RegisterMSBuild(repoContentsPath.FullName, repoContentsPath.FullName);
57
+
58
+ var allDependencyFiles = new Dictionary<string, DependencyFile>();
59
+ foreach (var directory in job.GetAllDirectories())
47
60
  {
48
- allDependencyFiles[dependencyFile.Name] = dependencyFile;
61
+ var localPath = PathHelper.JoinPath(repoContentsPath.FullName, directory);
62
+ lastUsedPackageSourceUrls = NuGetContext.GetPackageSourceUrls(localPath);
63
+ var result = await RunForDirectory(job, repoContentsPath, directory, baseCommitSha);
64
+ foreach (var dependencyFile in result.Base64DependencyFiles)
65
+ {
66
+ allDependencyFiles[dependencyFile.Name] = dependencyFile;
67
+ }
49
68
  }
69
+
70
+ runResult = new RunResult()
71
+ {
72
+ Base64DependencyFiles = allDependencyFiles.Values.ToArray(),
73
+ BaseCommitSha = baseCommitSha,
74
+ };
75
+ }
76
+ catch (HttpRequestException ex)
77
+ when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
78
+ {
79
+ error = new PrivateSourceAuthenticationFailure()
80
+ {
81
+ Details = $"({string.Join("|", lastUsedPackageSourceUrls)})",
82
+ };
83
+ }
84
+ catch (MissingFileException ex)
85
+ {
86
+ error = new DependencyFileNotFound()
87
+ {
88
+ Details = ex.FilePath,
89
+ };
90
+ }
91
+ catch (Exception ex)
92
+ {
93
+ error = new UnknownError()
94
+ {
95
+ Details = ex.ToString(),
96
+ };
50
97
  }
51
98
 
52
- var runResult = new RunResult()
99
+ if (error is not null)
53
100
  {
54
- Base64DependencyFiles = allDependencyFiles.Values.ToArray(),
55
- BaseCommitSha = baseCommitSha,
56
- };
101
+ await _apiHandler.RecordUpdateJobError(error);
102
+ }
103
+
104
+ await _apiHandler.MarkAsProcessed(new() { BaseCommitSha = baseCommitSha });
105
+
57
106
  return runResult;
58
107
  }
59
108
 
@@ -61,7 +110,6 @@ public class RunWorker
61
110
  {
62
111
  var discoveryWorker = new DiscoveryWorker(_logger);
63
112
  var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, repoDirectory);
64
- // TODO: check discoveryResult.ErrorType
65
113
 
66
114
  _logger.Log("Discovery JSON content:");
67
115
  _logger.Log(JsonSerializer.Serialize(discoveryResult, DiscoveryWorker.SerializerOptions));
@@ -123,7 +171,6 @@ public class RunWorker
123
171
  };
124
172
  var analysisResult = await analyzeWorker.RunAsync(repoContentsPath.FullName, discoveryResult, dependencyInfo);
125
173
  // TODO: log analysisResult
126
- // TODO: check analysisResult.ErrorType
127
174
  if (analysisResult.CanUpdate)
128
175
  {
129
176
  // TODO: this is inefficient, but not likely causing a bottleneck
@@ -153,7 +200,6 @@ public class RunWorker
153
200
  var updateWorker = new UpdaterWorker(_logger);
154
201
  var dependencyFilePath = Path.Join(discoveryResult.Path, project.FilePath).NormalizePathToUnix();
155
202
  var updateResult = await updateWorker.RunAsync(repoContentsPath.FullName, dependencyFilePath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, isTransitive: false);
156
- // TODO: check specific contents of result.ErrorType
157
203
  // TODO: need to report if anything was actually updated
158
204
  if (updateResult.ErrorType is null || updateResult.ErrorType == ErrorType.None)
159
205
  {
@@ -206,7 +252,6 @@ public class RunWorker
206
252
  // TODO: throw if no updates performed
207
253
  }
208
254
 
209
- await _apiHandler.MarkAsProcessed(new() { BaseCommitSha = baseCommitSha });
210
255
  var result = new RunResult()
211
256
  {
212
257
  Base64DependencyFiles = originalDependencyFileContents.Select(kvp => new DependencyFile()
@@ -18,7 +18,7 @@ internal static class LockFileUpdater
18
18
 
19
19
  await MSBuildHelper.SidelineGlobalJsonAsync(projectDirectory, repoRootPath, async () =>
20
20
  {
21
- var (exitCode, stdout, stderr) = await ProcessEx.RunAsync("dotnet", $"restore --force-evaluate {projectPath}", workingDirectory: projectDirectory);
21
+ var (exitCode, stdout, stderr) = await ProcessEx.RunAsync("dotnet", ["restore", "--force-evaluate", projectPath], workingDirectory: projectDirectory);
22
22
  if (exitCode != 0)
23
23
  {
24
24
  logger.Log($" Lock file update failed.\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}");
@@ -231,7 +231,7 @@ internal static class SdkPackageUpdater
231
231
  logger.Log($" Adding [{dependencyName}/{newDependencyVersion}] as a top-level package reference.");
232
232
 
233
233
  // see https://learn.microsoft.com/nuget/consume-packages/install-use-packages-dotnet-cli
234
- var (exitCode, stdout, stderr) = await ProcessEx.RunAsync("dotnet", $"add {projectPath} package {dependencyName} --version {newDependencyVersion}", workingDirectory: projectDirectory);
234
+ var (exitCode, stdout, stderr) = await ProcessEx.RunAsync("dotnet", ["add", projectPath, "package", dependencyName, "--version", newDependencyVersion], workingDirectory: projectDirectory);
235
235
  MSBuildHelper.ThrowOnUnauthenticatedFeed(stdout);
236
236
  if (exitCode != 0)
237
237
  {