dependabot-nuget 0.278.0 → 0.279.0

Sign up to get free protection for your applications and to get access to all the features.
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
  {