Skip to content

Commit 47316b7

Browse files
authored
Merge pull request #11303 from dependabot/dev/brettfo/nuget-packages-config-parse
validate shape of `packages.config` and consolidate error handling
2 parents b7fc60b + 692d989 commit 47316b7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+510
-292
lines changed

nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public async Task FindsUpdatedPackageAndReturnsTheCorrectData()
2626
await RunAsync(path =>
2727
[
2828
"analyze",
29+
"--job-id",
30+
"TEST-JOB-ID",
2931
"--job-path",
3032
Path.Combine(path, "job.json"),
3133
"--repo-root",
@@ -146,6 +148,8 @@ public async Task DotNetToolsJsonCanBeAnalyzed()
146148
await RunAsync(path =>
147149
[
148150
"analyze",
151+
"--job-id",
152+
"TEST-JOB-ID",
149153
"--job-path",
150154
Path.Combine(path, "job.json"),
151155
"--repo-root",
@@ -235,6 +239,8 @@ public async Task GlobalJsonCanBeAnalyzed()
235239
await RunAsync(path =>
236240
[
237241
"analyze",
242+
"--job-id",
243+
"TEST-JOB-ID",
238244
"--job-path",
239245
Path.Combine(path, "job.json"),
240246
"--repo-root",
@@ -345,7 +351,7 @@ private static async Task RunAsync(
345351
{
346352
if (args[i] == "--job-path")
347353
{
348-
var experimentsResult = await ExperimentsManager.FromJobFileAsync(args[i + 1]);
354+
var experimentsResult = await ExperimentsManager.FromJobFileAsync("TEST-JOB-ID", args[i + 1]);
349355
experimentsManager = experimentsResult.ExperimentsManager;
350356
}
351357
}

nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs

+46-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Text;
22
using System.Text.Json;
3+
using System.Text.Json.Serialization;
34

45
using NuGetUpdater.Core;
56
using NuGetUpdater.Core.Discover;
@@ -25,6 +26,8 @@ public async Task PathWithSpaces(bool useDirectDiscovery)
2526
await RunAsync(path =>
2627
[
2728
"discover",
29+
"--job-id",
30+
"TEST-JOB-ID",
2831
"--job-path",
2932
Path.Combine(path, "job.json"),
3033
"--repo-root",
@@ -83,6 +86,8 @@ public async Task WithSolution(bool useDirectDiscovery)
8386
await RunAsync(path =>
8487
[
8588
"discover",
89+
"--job-id",
90+
"TEST-JOB-ID",
8691
"--job-path",
8792
Path.Combine(path, "job.json"),
8893
"--repo-root",
@@ -178,6 +183,8 @@ public async Task WithProject(bool useDirectDiscovery)
178183
await RunAsync(path =>
179184
[
180185
"discover",
186+
"--job-id",
187+
"TEST-JOB-ID",
181188
"--job-path",
182189
Path.Combine(path, "job.json"),
183190
"--repo-root",
@@ -251,6 +258,8 @@ public async Task WithDirectory(bool useDirectDiscovery)
251258
await RunAsync(path =>
252259
[
253260
"discover",
261+
"--job-id",
262+
"TEST-JOB-ID",
254263
"--job-path",
255264
Path.Combine(path, "job.json"),
256265
"--repo-root",
@@ -321,6 +330,8 @@ public async Task WithDuplicateDependenciesOfDifferentTypes()
321330
await RunAsync(path =>
322331
[
323332
"discover",
333+
"--job-id",
334+
"TEST-JOB-ID",
324335
"--job-path",
325336
Path.Combine(path, "job.json"),
326337
"--repo-root",
@@ -398,6 +409,8 @@ public async Task JobFileParseErrorIsReported_InvalidJson()
398409
await RunAsync(path =>
399410
[
400411
"discover",
412+
"--job-id",
413+
"TEST-JOB-ID",
401414
"--job-path",
402415
jobFilePath,
403416
"--repo-root",
@@ -412,8 +425,7 @@ await RunAsync(path =>
412425
{
413426
Path = "/",
414427
Projects = [],
415-
ErrorType = ErrorType.Unknown,
416-
ErrorDetailsPattern = "JsonException",
428+
ErrorRegex = "Error deserializing job file contents",
417429
}
418430
);
419431
}
@@ -445,6 +457,8 @@ await File.WriteAllTextAsync(jobFilePath, """
445457
await RunAsync(path =>
446458
[
447459
"discover",
460+
"--job-id",
461+
"TEST-JOB-ID",
448462
"--job-path",
449463
jobFilePath,
450464
"--repo-root",
@@ -459,8 +473,7 @@ await RunAsync(path =>
459473
{
460474
Path = "/",
461475
Projects = [],
462-
ErrorType = ErrorType.BadRequirement,
463-
ErrorDetailsPattern = "not a valid requirement",
476+
Error = new Core.Run.ApiModel.BadRequirement("not a valid requirement"),
464477
}
465478
);
466479
}
@@ -497,7 +510,7 @@ private static async Task RunAsync(
497510
switch (args[i])
498511
{
499512
case "--job-path":
500-
var experimentsResult = await ExperimentsManager.FromJobFileAsync(args[i + 1]);
513+
var experimentsResult = await ExperimentsManager.FromJobFileAsync("TEST-JOB-ID", args[i + 1]);
501514
experimentsManager = experimentsResult.ExperimentsManager;
502515
break;
503516
case "--output":
@@ -520,11 +533,38 @@ private static async Task RunAsync(
520533

521534
resultPath ??= Path.Join(path, DiscoveryWorker.DiscoveryResultFileName);
522535
var resultJson = await File.ReadAllTextAsync(resultPath);
523-
var resultObject = JsonSerializer.Deserialize<WorkspaceDiscoveryResult>(resultJson, DiscoveryWorker.SerializerOptions);
536+
var serializerOptions = new JsonSerializerOptions()
537+
{
538+
Converters = { new TestJobErrorBaseConverter() }
539+
};
540+
foreach (var converter in DiscoveryWorker.SerializerOptions.Converters)
541+
{
542+
serializerOptions.Converters.Add(converter);
543+
}
544+
var resultObject = JsonSerializer.Deserialize<WorkspaceDiscoveryResult>(resultJson, serializerOptions);
524545
return resultObject!;
525546
});
526547

527548
ValidateWorkspaceResult(expectedResult, actualResult, experimentsManager);
528549
}
550+
551+
private class TestJobErrorBaseConverter : JsonConverter<Core.Run.ApiModel.JobErrorBase>
552+
{
553+
public override Core.Run.ApiModel.JobErrorBase? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
554+
{
555+
var dict = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(ref reader, options)!;
556+
return dict["error-type"].GetString() switch
557+
{
558+
"illformed_requirement" => new Core.Run.ApiModel.BadRequirement(dict["error-details"].GetProperty("message").GetString()!),
559+
"unknown_error" => new Core.Run.ApiModel.UnknownError(new Exception("Error deserializing job file contents"), "TEST-JOB-ID"),
560+
_ => throw new NotImplementedException($"Unknown error type: {dict["error-type"]}"),
561+
};
562+
}
563+
564+
public override void Write(Utf8JsonWriter writer, Core.Run.ApiModel.JobErrorBase value, JsonSerializerOptions options)
565+
{
566+
throw new NotImplementedException();
567+
}
568+
}
529569
}
530570
}

nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs

+8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ public async Task WithSolution()
1919
await Run(path =>
2020
[
2121
"update",
22+
"--job-id",
23+
"TEST-JOB-ID",
2224
"--job-path",
2325
Path.Combine(path, "job.json"),
2426
"--repo-root",
@@ -122,6 +124,8 @@ public async Task WithProject()
122124
await Run(path =>
123125
[
124126
"update",
127+
"--job-id",
128+
"TEST-JOB-ID",
125129
"--job-path",
126130
Path.Combine(path, "job.json"),
127131
"--repo-root",
@@ -202,6 +206,8 @@ public async Task WithDirsProjAndDirectoryBuildPropsThatIsOutOfDirectoryButStill
202206
await Run(path =>
203207
[
204208
"update",
209+
"--job-id",
210+
"TEST-JOB-ID",
205211
"--job-path",
206212
Path.Combine(path, "job.json"),
207213
"--repo-root",
@@ -361,6 +367,8 @@ await File.WriteAllTextAsync(projectPath, """
361367
IEnumerable<string> executableArgs = [
362368
executableName,
363369
"update",
370+
"--job-id",
371+
"TEST-JOB-ID",
364372
"--job-path",
365373
Path.Combine(tempDir.DirectoryPath, "job.json"),
366374
"--repo-root",

nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs

+6-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace NuGetUpdater.Cli.Commands;
77

88
internal static class AnalyzeCommand
99
{
10+
internal static readonly Option<string> JobIdOption = new("--job-id") { IsRequired = true };
1011
internal static readonly Option<FileInfo> JobPathOption = new("--job-path") { IsRequired = true };
1112
internal static readonly Option<DirectoryInfo> RepoRootOption = new("--repo-root") { IsRequired = true };
1213
internal static readonly Option<FileInfo> DependencyFilePathOption = new("--dependency-file-path") { IsRequired = true };
@@ -17,6 +18,7 @@ internal static Command GetCommand(Action<int> setExitCode)
1718
{
1819
Command command = new("analyze", "Determines how to update a dependency based on the workspace discovery information.")
1920
{
21+
JobIdOption,
2022
JobPathOption,
2123
RepoRootOption,
2224
DependencyFilePathOption,
@@ -26,13 +28,13 @@ internal static Command GetCommand(Action<int> setExitCode)
2628

2729
command.TreatUnmatchedTokensAsErrors = true;
2830

29-
command.SetHandler(async (jobPath, repoRoot, discoveryPath, dependencyPath, analysisDirectory) =>
31+
command.SetHandler(async (jobId, jobPath, repoRoot, discoveryPath, dependencyPath, analysisDirectory) =>
3032
{
3133
var logger = new ConsoleLogger();
32-
var (experimentsManager, _errorResult) = await ExperimentsManager.FromJobFileAsync(jobPath.FullName);
33-
var worker = new AnalyzeWorker(experimentsManager, logger);
34+
var (experimentsManager, _errorResult) = await ExperimentsManager.FromJobFileAsync(jobId, jobPath.FullName);
35+
var worker = new AnalyzeWorker(jobId, experimentsManager, logger);
3436
await worker.RunAsync(repoRoot.FullName, discoveryPath.FullName, dependencyPath.FullName, analysisDirectory.FullName);
35-
}, JobPathOption, RepoRootOption, DiscoveryFilePathOption, DependencyFilePathOption, AnalysisFolderOption);
37+
}, JobIdOption, JobPathOption, RepoRootOption, DiscoveryFilePathOption, DependencyFilePathOption, AnalysisFolderOption);
3638

3739
return command;
3840
}

nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs

+8-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace NuGetUpdater.Cli.Commands;
77

88
internal static class DiscoverCommand
99
{
10+
internal static readonly Option<string> JobIdOption = new("--job-id") { IsRequired = true };
1011
internal static readonly Option<FileInfo> JobPathOption = new("--job-path") { IsRequired = true };
1112
internal static readonly Option<DirectoryInfo> RepoRootOption = new("--repo-root") { IsRequired = true };
1213
internal static readonly Option<string> WorkspaceOption = new("--workspace") { IsRequired = true };
@@ -16,6 +17,7 @@ internal static Command GetCommand(Action<int> setExitCode)
1617
{
1718
Command command = new("discover", "Generates a report of the workspace dependencies and where they are located.")
1819
{
20+
JobIdOption,
1921
JobPathOption,
2022
RepoRootOption,
2123
WorkspaceOption,
@@ -24,27 +26,26 @@ internal static Command GetCommand(Action<int> setExitCode)
2426

2527
command.TreatUnmatchedTokensAsErrors = true;
2628

27-
command.SetHandler(async (jobPath, repoRoot, workspace, outputPath) =>
29+
command.SetHandler(async (jobId, jobPath, repoRoot, workspace, outputPath) =>
2830
{
29-
var (experimentsManager, errorResult) = await ExperimentsManager.FromJobFileAsync(jobPath.FullName);
30-
if (errorResult is not null)
31+
var (experimentsManager, error) = await ExperimentsManager.FromJobFileAsync(jobId, jobPath.FullName);
32+
if (error is not null)
3133
{
3234
// to make testing easier, this should be a `WorkspaceDiscoveryResult` object
3335
var discoveryErrorResult = new WorkspaceDiscoveryResult
3436
{
37+
Error = error,
3538
Path = workspace,
3639
Projects = [],
37-
ErrorType = errorResult.ErrorType,
38-
ErrorDetails = errorResult.ErrorDetails,
3940
};
4041
await DiscoveryWorker.WriteResultsAsync(repoRoot.FullName, outputPath.FullName, discoveryErrorResult);
4142
return;
4243
}
4344

4445
var logger = new ConsoleLogger();
45-
var worker = new DiscoveryWorker(experimentsManager, logger);
46+
var worker = new DiscoveryWorker(jobId, experimentsManager, logger);
4647
await worker.RunAsync(repoRoot.FullName, workspace, outputPath.FullName);
47-
}, JobPathOption, RepoRootOption, WorkspaceOption, OutputOption);
48+
}, JobIdOption, JobPathOption, RepoRootOption, WorkspaceOption, OutputOption);
4849

4950
return command;
5051
}

nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ internal static Command GetCommand(Action<int> setExitCode)
3333
command.SetHandler(async (jobPath, repoContentsPath, apiUrl, jobId, outputPath, baseCommitSha) =>
3434
{
3535
var apiHandler = new HttpApiHandler(apiUrl.ToString(), jobId);
36-
var (experimentsManager, _errorResult) = await ExperimentsManager.FromJobFileAsync(jobPath.FullName);
36+
var (experimentsManager, _errorResult) = await ExperimentsManager.FromJobFileAsync(jobId, jobPath.FullName);
3737
var logger = new ConsoleLogger();
38-
var discoverWorker = new DiscoveryWorker(experimentsManager, logger);
39-
var analyzeWorker = new AnalyzeWorker(experimentsManager, logger);
40-
var updateWorker = new UpdaterWorker(experimentsManager, logger);
38+
var discoverWorker = new DiscoveryWorker(jobId, experimentsManager, logger);
39+
var analyzeWorker = new AnalyzeWorker(jobId, experimentsManager, logger);
40+
var updateWorker = new UpdaterWorker(jobId, experimentsManager, logger);
4141
var worker = new RunWorker(jobId, apiHandler, discoverWorker, analyzeWorker, updateWorker, logger);
4242
await worker.RunAsync(jobPath, repoContentsPath, baseCommitSha, outputPath);
4343
}, JobPathOption, RepoContentsPathOption, ApiUrlOption, JobIdOption, OutputPathOption, BaseCommitShaOption);

nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs

+17-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace NuGetUpdater.Cli.Commands;
66

77
internal static class UpdateCommand
88
{
9+
internal static readonly Option<string> JobIdOption = new("--job-id") { IsRequired = true };
910
internal static readonly Option<FileInfo> JobPathOption = new("--job-path") { IsRequired = true };
1011
internal static readonly Option<DirectoryInfo> RepoRootOption = new("--repo-root", () => new DirectoryInfo(Environment.CurrentDirectory)) { IsRequired = false };
1112
internal static readonly Option<FileInfo> SolutionOrProjectFileOption = new("--solution-or-project") { IsRequired = true };
@@ -19,6 +20,7 @@ internal static Command GetCommand(Action<int> setExitCode)
1920
{
2021
Command command = new("update", "Applies the changes from an analysis report to update a dependency.")
2122
{
23+
JobIdOption,
2224
JobPathOption,
2325
RepoRootOption,
2426
SolutionOrProjectFileOption,
@@ -30,15 +32,25 @@ internal static Command GetCommand(Action<int> setExitCode)
3032
};
3133

3234
command.TreatUnmatchedTokensAsErrors = true;
33-
34-
command.SetHandler(async (jobPath, repoRoot, solutionOrProjectFile, dependencyName, newVersion, previousVersion, isTransitive, resultOutputPath) =>
35+
command.SetHandler(async (context) =>
3536
{
36-
var (experimentsManager, _errorResult) = await ExperimentsManager.FromJobFileAsync(jobPath.FullName);
37+
// since we have more than 8 arguments, we have to pull them out manually
38+
var jobId = context.ParseResult.GetValueForOption(JobIdOption)!;
39+
var jobPath = context.ParseResult.GetValueForOption(JobPathOption)!;
40+
var repoRoot = context.ParseResult.GetValueForOption(RepoRootOption)!;
41+
var solutionOrProjectFile = context.ParseResult.GetValueForOption(SolutionOrProjectFileOption)!;
42+
var dependencyName = context.ParseResult.GetValueForOption(DependencyNameOption)!;
43+
var newVersion = context.ParseResult.GetValueForOption(NewVersionOption)!;
44+
var previousVersion = context.ParseResult.GetValueForOption(PreviousVersionOption)!;
45+
var isTransitive = context.ParseResult.GetValueForOption(IsTransitiveOption);
46+
var resultOutputPath = context.ParseResult.GetValueForOption(ResultOutputPathOption);
47+
48+
var (experimentsManager, _error) = await ExperimentsManager.FromJobFileAsync(jobId, jobPath.FullName);
3749
var logger = new ConsoleLogger();
38-
var worker = new UpdaterWorker(experimentsManager, logger);
50+
var worker = new UpdaterWorker(jobId, experimentsManager, logger);
3951
await worker.RunAsync(repoRoot.FullName, solutionOrProjectFile.FullName, dependencyName, previousVersion, newVersion, isTransitive, resultOutputPath);
4052
setExitCode(0);
41-
}, JobPathOption, RepoRootOption, SolutionOrProjectFileOption, DependencyNameOption, NewVersionOption, PreviousVersionOption, IsTransitiveOption, ResultOutputPathOption);
53+
});
4254

4355
return command;
4456
}

0 commit comments

Comments
 (0)