dependabot-nuget 0.291.0 → 0.293.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/helpers/lib/NuGetUpdater/.editorconfig +1 -0
- data/helpers/lib/NuGetUpdater/.gitignore +1 -0
- data/helpers/lib/NuGetUpdater/Directory.Build.props +1 -0
- data/helpers/lib/NuGetUpdater/Directory.Packages.props +2 -1
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Correlator.cs +197 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/DotNetPackageCorrelation.csproj +12 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/PackageMapper.cs +68 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/PackageSet.cs +11 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/Release.cs +25 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/ReleasesFile.cs +9 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/RuntimePackages.cs +11 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/Sdk.cs +13 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/SemVerComparer.cs +16 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/SemVersionConverter.cs +42 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Cli/DotNetPackageCorrelation.Cli.csproj +16 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Cli/Program.cs +32 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Test/CorrelatorTests.cs +99 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Test/DotNetPackageCorrelation.Test.csproj +18 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Test/EndToEndTests.cs +30 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Test/RuntimePackagesTests.cs +206 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +6 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/CloneCommand.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs +19 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +5 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs +17 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +8 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +128 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +8 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +9 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyFinder.cs +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/Extensions.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/RequirementConverter.cs +19 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/BadRequirementException.cs +9 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Clone/CloneWorker.cs +40 -8
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencyDiscovery.targets +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +65 -23
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/ProjectDiscoveryResult.cs +3 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +99 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/EnsureDotNetPackageCorrelation.targets +25 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +15 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/PackagesConfigBuildFile.cs +5 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/MissingFileException.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/NativeResult.cs +3 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/NuGetUpdater.Core.csproj +4 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/BadRequirement.cs +10 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/CommitOptions.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyFileNotFound.cs +7 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyFileNotParseable.cs +15 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +25 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobRepoNotFound.cs +1 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PrivateSourceAuthenticationFailure.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/UnknownError.cs +6 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/UpdateNotPossible.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +9 -18
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/UnparseableFileException.cs +12 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +21 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +6 -30
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/WebApplicationTargetsConditionPatcher.cs +12 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/DependencyConflictResolver.cs +0 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/DotNetPackageCorrelationManager.cs +46 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +59 -30
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProjectHelper.cs +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +15 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +15 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Clone/CloneWorkerTests.cs +60 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +20 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs +56 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +108 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +16 -12
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +15 -28
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +5 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +84 -40
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestBase.cs +24 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/ExpectedUpdateOperationResult.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +25 -11
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.LockFile.cs +251 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +14 -8
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +154 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +71 -15
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +38 -20
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/ProjectHelperTests.cs +65 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.sln +18 -1
- data/helpers/lib/NuGetUpdater/global.json +1 -1
- data/lib/dependabot/nuget/language.rb +21 -5
- data/lib/dependabot/nuget/native_helpers.rb +41 -14
- data/lib/dependabot/nuget/package_manager.rb +4 -4
- metadata +30 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +0 -11
@@ -0,0 +1,206 @@
|
|
1
|
+
using Semver;
|
2
|
+
|
3
|
+
using Xunit;
|
4
|
+
|
5
|
+
namespace DotNetPackageCorrelation;
|
6
|
+
|
7
|
+
public class RuntimePackagesTests
|
8
|
+
{
|
9
|
+
[Theory]
|
10
|
+
[MemberData(nameof(CorrelatedPackageCanBeFoundData))]
|
11
|
+
public void CorrelatedPackageCanBeFound(RuntimePackages runtimePackages, string runtimePackageName, string runtimePackageVersion, string candidatePackageName, string? expectedPackageVersion)
|
12
|
+
{
|
13
|
+
var packageMapper = PackageMapper.Load(runtimePackages);
|
14
|
+
var actualPackageVersion = packageMapper.GetPackageVersionThatShippedWithOtherPackage(runtimePackageName, SemVersion.Parse(runtimePackageVersion), candidatePackageName);
|
15
|
+
if (expectedPackageVersion is null)
|
16
|
+
{
|
17
|
+
Assert.Null(actualPackageVersion);
|
18
|
+
}
|
19
|
+
else
|
20
|
+
{
|
21
|
+
Assert.NotNull(actualPackageVersion);
|
22
|
+
Assert.Equal(expectedPackageVersion, actualPackageVersion.ToString());
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
public static IEnumerable<object?[]> CorrelatedPackageCanBeFoundData()
|
27
|
+
{
|
28
|
+
// package not found in specified runtime, but it is in earlier runtime; more recent runtime has that package, but that's not returned
|
29
|
+
yield return
|
30
|
+
[
|
31
|
+
// runtimePackages
|
32
|
+
new RuntimePackages()
|
33
|
+
{
|
34
|
+
Runtimes = new SortedDictionary<SemVersion, PackageSet>(SemVerComparer.Instance)
|
35
|
+
{
|
36
|
+
{
|
37
|
+
SemVersion.Parse("1.0.100"),
|
38
|
+
new PackageSet()
|
39
|
+
{
|
40
|
+
Packages = new SortedDictionary<string, SemVersion>(StringComparer.OrdinalIgnoreCase)
|
41
|
+
{
|
42
|
+
{ "Runtime.Package", SemVersion.Parse("1.0.0") },
|
43
|
+
{ "Some.Package", SemVersion.Parse("1.0.1") }
|
44
|
+
}
|
45
|
+
}
|
46
|
+
},
|
47
|
+
{
|
48
|
+
SemVersion.Parse("1.0.101"),
|
49
|
+
new PackageSet()
|
50
|
+
{
|
51
|
+
Packages = new SortedDictionary<string, SemVersion>(StringComparer.OrdinalIgnoreCase)
|
52
|
+
{
|
53
|
+
// this runtime didn't ship with a new version of "Some.Package", but the earlier release did
|
54
|
+
{ "Runtime.Package", SemVersion.Parse("1.0.1") }
|
55
|
+
}
|
56
|
+
}
|
57
|
+
},
|
58
|
+
{
|
59
|
+
SemVersion.Parse("1.0.200"),
|
60
|
+
new PackageSet()
|
61
|
+
{
|
62
|
+
Packages = new SortedDictionary<string, SemVersion>(StringComparer.OrdinalIgnoreCase)
|
63
|
+
{
|
64
|
+
// the requested package shipped with this runtime, but this runtime isn't the correct version so it's not returned
|
65
|
+
{ "Runtime.Package", SemVersion.Parse("1.0.2") },
|
66
|
+
{ "Some.Package", SemVersion.Parse("1.0.2") }
|
67
|
+
}
|
68
|
+
}
|
69
|
+
},
|
70
|
+
}
|
71
|
+
},
|
72
|
+
// runtimePackageName
|
73
|
+
"Runtime.Package",
|
74
|
+
// runtimePackageVersion
|
75
|
+
"1.0.1",
|
76
|
+
// candidatePackageName
|
77
|
+
"Some.Package",
|
78
|
+
// expectedPackageVersion
|
79
|
+
"1.0.1"
|
80
|
+
];
|
81
|
+
|
82
|
+
// package differing in case is found
|
83
|
+
yield return
|
84
|
+
[
|
85
|
+
// runtimePackages
|
86
|
+
new RuntimePackages()
|
87
|
+
{
|
88
|
+
Runtimes = new SortedDictionary<SemVersion, PackageSet>(SemVerComparer.Instance)
|
89
|
+
{
|
90
|
+
{
|
91
|
+
SemVersion.Parse("1.0.100"),
|
92
|
+
new PackageSet()
|
93
|
+
{
|
94
|
+
Packages = new SortedDictionary<string, SemVersion>(StringComparer.OrdinalIgnoreCase)
|
95
|
+
{
|
96
|
+
{ "runtime.package", SemVersion.Parse("1.0.0") },
|
97
|
+
{ "some.package", SemVersion.Parse("1.0.1") }
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
},
|
103
|
+
// runtimePackageName
|
104
|
+
"Runtime.Package",
|
105
|
+
// runtimePackageVersion
|
106
|
+
"1.0.0",
|
107
|
+
// candidatePackageName
|
108
|
+
"Some.Package",
|
109
|
+
// expectedPackageVersion
|
110
|
+
"1.0.1"
|
111
|
+
];
|
112
|
+
|
113
|
+
// runtime package not found by name
|
114
|
+
yield return
|
115
|
+
[
|
116
|
+
// runtimePackages
|
117
|
+
new RuntimePackages()
|
118
|
+
{
|
119
|
+
Runtimes = new SortedDictionary<SemVersion, PackageSet>(SemVerComparer.Instance)
|
120
|
+
{
|
121
|
+
{
|
122
|
+
SemVersion.Parse("1.0.100"),
|
123
|
+
new PackageSet()
|
124
|
+
{
|
125
|
+
Packages = new SortedDictionary<string, SemVersion>(StringComparer.OrdinalIgnoreCase)
|
126
|
+
{
|
127
|
+
{ "runtime.package", SemVersion.Parse("1.0.0") },
|
128
|
+
{ "some.package", SemVersion.Parse("1.0.1") }
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
}
|
133
|
+
},
|
134
|
+
// runtimePackageName
|
135
|
+
"Different.Runtime.Package",
|
136
|
+
// runtimePackageVersion
|
137
|
+
"1.0.0",
|
138
|
+
// candidatePackageName
|
139
|
+
"Some.Package",
|
140
|
+
// expectedPackageVersion
|
141
|
+
null
|
142
|
+
];
|
143
|
+
|
144
|
+
// runtime package not found by version
|
145
|
+
yield return
|
146
|
+
[
|
147
|
+
// runtimePackages
|
148
|
+
new RuntimePackages()
|
149
|
+
{
|
150
|
+
Runtimes = new SortedDictionary<SemVersion, PackageSet>(SemVerComparer.Instance)
|
151
|
+
{
|
152
|
+
{
|
153
|
+
SemVersion.Parse("1.0.100"),
|
154
|
+
new PackageSet()
|
155
|
+
{
|
156
|
+
Packages = new SortedDictionary<string, SemVersion>(StringComparer.OrdinalIgnoreCase)
|
157
|
+
{
|
158
|
+
{ "runtime.package", SemVersion.Parse("1.0.0") },
|
159
|
+
{ "some.package", SemVersion.Parse("1.0.1") }
|
160
|
+
}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
},
|
165
|
+
// runtimePackageName
|
166
|
+
"Runtime.Package",
|
167
|
+
// runtimePackageVersion
|
168
|
+
"9.9.9",
|
169
|
+
// candidatePackageName
|
170
|
+
"Some.Package",
|
171
|
+
// expectedPackageVersion
|
172
|
+
null
|
173
|
+
];
|
174
|
+
|
175
|
+
// candidate package not found
|
176
|
+
yield return
|
177
|
+
[
|
178
|
+
// runtimePackages
|
179
|
+
new RuntimePackages()
|
180
|
+
{
|
181
|
+
Runtimes = new SortedDictionary<SemVersion, PackageSet>(SemVerComparer.Instance)
|
182
|
+
{
|
183
|
+
{
|
184
|
+
SemVersion.Parse("1.0.100"),
|
185
|
+
new PackageSet()
|
186
|
+
{
|
187
|
+
Packages = new SortedDictionary<string, SemVersion>(StringComparer.OrdinalIgnoreCase)
|
188
|
+
{
|
189
|
+
{ "runtime.package", SemVersion.Parse("1.0.0") },
|
190
|
+
{ "some.package", SemVersion.Parse("1.0.1") }
|
191
|
+
}
|
192
|
+
}
|
193
|
+
}
|
194
|
+
}
|
195
|
+
},
|
196
|
+
// runtimePackageName
|
197
|
+
"Runtime.Package",
|
198
|
+
// runtimePackageVersion
|
199
|
+
"1.0.0",
|
200
|
+
// candidatePackageName
|
201
|
+
"Package.Not.In.This.Runtime",
|
202
|
+
// expectedPackageVersion
|
203
|
+
null
|
204
|
+
];
|
205
|
+
}
|
206
|
+
}
|
@@ -7,6 +7,7 @@ namespace NuGetUpdater.Cli.Commands;
|
|
7
7
|
|
8
8
|
internal static class AnalyzeCommand
|
9
9
|
{
|
10
|
+
internal static readonly Option<string> JobIdOption = new("--job-id") { IsRequired = true };
|
10
11
|
internal static readonly Option<FileInfo> JobPathOption = new("--job-path") { IsRequired = true };
|
11
12
|
internal static readonly Option<DirectoryInfo> RepoRootOption = new("--repo-root") { IsRequired = true };
|
12
13
|
internal static readonly Option<FileInfo> DependencyFilePathOption = new("--dependency-file-path") { IsRequired = true };
|
@@ -17,6 +18,7 @@ internal static class AnalyzeCommand
|
|
17
18
|
{
|
18
19
|
Command command = new("analyze", "Determines how to update a dependency based on the workspace discovery information.")
|
19
20
|
{
|
21
|
+
JobIdOption,
|
20
22
|
JobPathOption,
|
21
23
|
RepoRootOption,
|
22
24
|
DependencyFilePathOption,
|
@@ -26,13 +28,13 @@ internal static class AnalyzeCommand
|
|
26
28
|
|
27
29
|
command.TreatUnmatchedTokensAsErrors = true;
|
28
30
|
|
29
|
-
command.SetHandler(async (jobPath, repoRoot, discoveryPath, dependencyPath, analysisDirectory) =>
|
31
|
+
command.SetHandler(async (jobId, jobPath, repoRoot, discoveryPath, dependencyPath, analysisDirectory) =>
|
30
32
|
{
|
31
33
|
var logger = new ConsoleLogger();
|
32
|
-
var experimentsManager = 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);
|
34
36
|
await worker.RunAsync(repoRoot.FullName, discoveryPath.FullName, dependencyPath.FullName, analysisDirectory.FullName);
|
35
|
-
}, JobPathOption, RepoRootOption, DiscoveryFilePathOption, DependencyFilePathOption, AnalysisFolderOption);
|
37
|
+
}, JobIdOption, JobPathOption, RepoRootOption, DiscoveryFilePathOption, DependencyFilePathOption, AnalysisFolderOption);
|
36
38
|
|
37
39
|
return command;
|
38
40
|
}
|
@@ -30,7 +30,7 @@ internal static class CloneCommand
|
|
30
30
|
var apiHandler = new HttpApiHandler(apiUrl.ToString(), jobId);
|
31
31
|
var logger = new ConsoleLogger();
|
32
32
|
var gitCommandHandler = new ShellGitCommandHandler(logger);
|
33
|
-
var worker = new CloneWorker(apiHandler, gitCommandHandler
|
33
|
+
var worker = new CloneWorker(jobId, apiHandler, gitCommandHandler);
|
34
34
|
var exitCode = await worker.RunAsync(jobPath, repoContentsPath);
|
35
35
|
setExitCode(exitCode);
|
36
36
|
}, JobPathOption, RepoContentsPathOption, ApiUrlOption, JobIdOption);
|
@@ -7,6 +7,7 @@ namespace NuGetUpdater.Cli.Commands;
|
|
7
7
|
|
8
8
|
internal static class DiscoverCommand
|
9
9
|
{
|
10
|
+
internal static readonly Option<string> JobIdOption = new("--job-id") { IsRequired = true };
|
10
11
|
internal static readonly Option<FileInfo> JobPathOption = new("--job-path") { IsRequired = true };
|
11
12
|
internal static readonly Option<DirectoryInfo> RepoRootOption = new("--repo-root") { IsRequired = true };
|
12
13
|
internal static readonly Option<string> WorkspaceOption = new("--workspace") { IsRequired = true };
|
@@ -16,6 +17,7 @@ internal static class DiscoverCommand
|
|
16
17
|
{
|
17
18
|
Command command = new("discover", "Generates a report of the workspace dependencies and where they are located.")
|
18
19
|
{
|
20
|
+
JobIdOption,
|
19
21
|
JobPathOption,
|
20
22
|
RepoRootOption,
|
21
23
|
WorkspaceOption,
|
@@ -24,13 +26,26 @@ internal static class DiscoverCommand
|
|
24
26
|
|
25
27
|
command.TreatUnmatchedTokensAsErrors = true;
|
26
28
|
|
27
|
-
command.SetHandler(async (jobPath, repoRoot, workspace, outputPath) =>
|
29
|
+
command.SetHandler(async (jobId, jobPath, repoRoot, workspace, outputPath) =>
|
28
30
|
{
|
31
|
+
var (experimentsManager, error) = await ExperimentsManager.FromJobFileAsync(jobId, jobPath.FullName);
|
32
|
+
if (error is not null)
|
33
|
+
{
|
34
|
+
// to make testing easier, this should be a `WorkspaceDiscoveryResult` object
|
35
|
+
var discoveryErrorResult = new WorkspaceDiscoveryResult
|
36
|
+
{
|
37
|
+
Error = error,
|
38
|
+
Path = workspace,
|
39
|
+
Projects = [],
|
40
|
+
};
|
41
|
+
await DiscoveryWorker.WriteResultsAsync(repoRoot.FullName, outputPath.FullName, discoveryErrorResult);
|
42
|
+
return;
|
43
|
+
}
|
44
|
+
|
29
45
|
var logger = new ConsoleLogger();
|
30
|
-
var
|
31
|
-
var worker = new DiscoveryWorker(experimentsManager, logger);
|
46
|
+
var worker = new DiscoveryWorker(jobId, experimentsManager, logger);
|
32
47
|
await worker.RunAsync(repoRoot.FullName, workspace, outputPath.FullName);
|
33
|
-
}, JobPathOption, RepoRootOption, WorkspaceOption, OutputOption);
|
48
|
+
}, JobIdOption, JobPathOption, RepoRootOption, WorkspaceOption, OutputOption);
|
34
49
|
|
35
50
|
return command;
|
36
51
|
}
|
@@ -33,12 +33,12 @@ internal static class RunCommand
|
|
33
33
|
command.SetHandler(async (jobPath, repoContentsPath, apiUrl, jobId, outputPath, baseCommitSha) =>
|
34
34
|
{
|
35
35
|
var apiHandler = new HttpApiHandler(apiUrl.ToString(), jobId);
|
36
|
+
var (experimentsManager, _errorResult) = await ExperimentsManager.FromJobFileAsync(jobId, jobPath.FullName);
|
36
37
|
var logger = new ConsoleLogger();
|
37
|
-
var
|
38
|
-
var
|
39
|
-
var
|
40
|
-
var
|
41
|
-
var worker = new RunWorker(apiHandler, discoverWorker, analyzeWorker, updateWorker, 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);
|
41
|
+
var worker = new RunWorker(jobId, apiHandler, discoverWorker, analyzeWorker, updateWorker, logger);
|
42
42
|
await worker.RunAsync(jobPath, repoContentsPath, baseCommitSha, outputPath);
|
43
43
|
}, JobPathOption, RepoContentsPathOption, ApiUrlOption, JobIdOption, OutputPathOption, BaseCommitShaOption);
|
44
44
|
|
@@ -6,6 +6,7 @@ namespace NuGetUpdater.Cli.Commands;
|
|
6
6
|
|
7
7
|
internal static class UpdateCommand
|
8
8
|
{
|
9
|
+
internal static readonly Option<string> JobIdOption = new("--job-id") { IsRequired = true };
|
9
10
|
internal static readonly Option<FileInfo> JobPathOption = new("--job-path") { IsRequired = true };
|
10
11
|
internal static readonly Option<DirectoryInfo> RepoRootOption = new("--repo-root", () => new DirectoryInfo(Environment.CurrentDirectory)) { IsRequired = false };
|
11
12
|
internal static readonly Option<FileInfo> SolutionOrProjectFileOption = new("--solution-or-project") { IsRequired = true };
|
@@ -19,6 +20,7 @@ internal static class UpdateCommand
|
|
19
20
|
{
|
20
21
|
Command command = new("update", "Applies the changes from an analysis report to update a dependency.")
|
21
22
|
{
|
23
|
+
JobIdOption,
|
22
24
|
JobPathOption,
|
23
25
|
RepoRootOption,
|
24
26
|
SolutionOrProjectFileOption,
|
@@ -30,15 +32,25 @@ internal static class UpdateCommand
|
|
30
32
|
};
|
31
33
|
|
32
34
|
command.TreatUnmatchedTokensAsErrors = true;
|
33
|
-
|
34
|
-
command.SetHandler(async (jobPath, repoRoot, solutionOrProjectFile, dependencyName, newVersion, previousVersion, isTransitive, resultOutputPath) =>
|
35
|
+
command.SetHandler(async (context) =>
|
35
36
|
{
|
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);
|
36
49
|
var logger = new ConsoleLogger();
|
37
|
-
var
|
38
|
-
var worker = new UpdaterWorker(experimentsManager, logger);
|
50
|
+
var worker = new UpdaterWorker(jobId, experimentsManager, logger);
|
39
51
|
await worker.RunAsync(repoRoot.FullName, solutionOrProjectFile.FullName, dependencyName, previousVersion, newVersion, isTransitive, resultOutputPath);
|
40
52
|
setExitCode(0);
|
41
|
-
}
|
53
|
+
});
|
42
54
|
|
43
55
|
return command;
|
44
56
|
}
|
@@ -26,6 +26,8 @@ public partial class EntryPointTests
|
|
26
26
|
await RunAsync(path =>
|
27
27
|
[
|
28
28
|
"analyze",
|
29
|
+
"--job-id",
|
30
|
+
"TEST-JOB-ID",
|
29
31
|
"--job-path",
|
30
32
|
Path.Combine(path, "job.json"),
|
31
33
|
"--repo-root",
|
@@ -146,6 +148,8 @@ public partial class EntryPointTests
|
|
146
148
|
await RunAsync(path =>
|
147
149
|
[
|
148
150
|
"analyze",
|
151
|
+
"--job-id",
|
152
|
+
"TEST-JOB-ID",
|
149
153
|
"--job-path",
|
150
154
|
Path.Combine(path, "job.json"),
|
151
155
|
"--repo-root",
|
@@ -235,6 +239,8 @@ public partial class EntryPointTests
|
|
235
239
|
await RunAsync(path =>
|
236
240
|
[
|
237
241
|
"analyze",
|
242
|
+
"--job-id",
|
243
|
+
"TEST-JOB-ID",
|
238
244
|
"--job-path",
|
239
245
|
Path.Combine(path, "job.json"),
|
240
246
|
"--repo-root",
|
@@ -345,7 +351,8 @@ public partial class EntryPointTests
|
|
345
351
|
{
|
346
352
|
if (args[i] == "--job-path")
|
347
353
|
{
|
348
|
-
|
354
|
+
var experimentsResult = await ExperimentsManager.FromJobFileAsync("TEST-JOB-ID", args[i + 1]);
|
355
|
+
experimentsManager = experimentsResult.ExperimentsManager;
|
349
356
|
}
|
350
357
|
}
|
351
358
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
using System.Text;
|
2
2
|
using System.Text.Json;
|
3
|
+
using System.Text.Json.Serialization;
|
3
4
|
|
4
5
|
using NuGetUpdater.Core;
|
5
6
|
using NuGetUpdater.Core.Discover;
|
@@ -25,6 +26,8 @@ public partial class EntryPointTests
|
|
25
26
|
await RunAsync(path =>
|
26
27
|
[
|
27
28
|
"discover",
|
29
|
+
"--job-id",
|
30
|
+
"TEST-JOB-ID",
|
28
31
|
"--job-path",
|
29
32
|
Path.Combine(path, "job.json"),
|
30
33
|
"--repo-root",
|
@@ -83,6 +86,8 @@ public partial class EntryPointTests
|
|
83
86
|
await RunAsync(path =>
|
84
87
|
[
|
85
88
|
"discover",
|
89
|
+
"--job-id",
|
90
|
+
"TEST-JOB-ID",
|
86
91
|
"--job-path",
|
87
92
|
Path.Combine(path, "job.json"),
|
88
93
|
"--repo-root",
|
@@ -178,6 +183,8 @@ public partial class EntryPointTests
|
|
178
183
|
await RunAsync(path =>
|
179
184
|
[
|
180
185
|
"discover",
|
186
|
+
"--job-id",
|
187
|
+
"TEST-JOB-ID",
|
181
188
|
"--job-path",
|
182
189
|
Path.Combine(path, "job.json"),
|
183
190
|
"--repo-root",
|
@@ -251,6 +258,8 @@ public partial class EntryPointTests
|
|
251
258
|
await RunAsync(path =>
|
252
259
|
[
|
253
260
|
"discover",
|
261
|
+
"--job-id",
|
262
|
+
"TEST-JOB-ID",
|
254
263
|
"--job-path",
|
255
264
|
Path.Combine(path, "job.json"),
|
256
265
|
"--repo-root",
|
@@ -321,6 +330,8 @@ public partial class EntryPointTests
|
|
321
330
|
await RunAsync(path =>
|
322
331
|
[
|
323
332
|
"discover",
|
333
|
+
"--job-id",
|
334
|
+
"TEST-JOB-ID",
|
324
335
|
"--job-path",
|
325
336
|
Path.Combine(path, "job.json"),
|
326
337
|
"--repo-root",
|
@@ -388,6 +399,85 @@ public partial class EntryPointTests
|
|
388
399
|
);
|
389
400
|
}
|
390
401
|
|
402
|
+
[Fact]
|
403
|
+
public async Task JobFileParseErrorIsReported_InvalidJson()
|
404
|
+
{
|
405
|
+
using var testDirectory = new TemporaryDirectory();
|
406
|
+
var jobFilePath = Path.Combine(testDirectory.DirectoryPath, "job.json");
|
407
|
+
var resultFilePath = Path.Combine(testDirectory.DirectoryPath, DiscoveryWorker.DiscoveryResultFileName);
|
408
|
+
await File.WriteAllTextAsync(jobFilePath, "not json");
|
409
|
+
await RunAsync(path =>
|
410
|
+
[
|
411
|
+
"discover",
|
412
|
+
"--job-id",
|
413
|
+
"TEST-JOB-ID",
|
414
|
+
"--job-path",
|
415
|
+
jobFilePath,
|
416
|
+
"--repo-root",
|
417
|
+
path,
|
418
|
+
"--workspace",
|
419
|
+
"/",
|
420
|
+
"--output",
|
421
|
+
resultFilePath
|
422
|
+
],
|
423
|
+
initialFiles: [],
|
424
|
+
expectedResult: new()
|
425
|
+
{
|
426
|
+
Path = "/",
|
427
|
+
Projects = [],
|
428
|
+
ErrorRegex = "Error deserializing job file contents",
|
429
|
+
}
|
430
|
+
);
|
431
|
+
}
|
432
|
+
|
433
|
+
[Fact]
|
434
|
+
public async Task JobFileParseErrorIsReported_BadRequirement()
|
435
|
+
{
|
436
|
+
using var testDirectory = new TemporaryDirectory();
|
437
|
+
var jobFilePath = Path.Combine(testDirectory.DirectoryPath, "job.json");
|
438
|
+
var resultFilePath = Path.Combine(testDirectory.DirectoryPath, DiscoveryWorker.DiscoveryResultFileName);
|
439
|
+
|
440
|
+
// write a job file with a valid shape, but invalid requirement
|
441
|
+
await File.WriteAllTextAsync(jobFilePath, """
|
442
|
+
{
|
443
|
+
"job": {
|
444
|
+
"source": {
|
445
|
+
"provider": "github",
|
446
|
+
"repo": "test/repo"
|
447
|
+
},
|
448
|
+
"security-advisories": [
|
449
|
+
{
|
450
|
+
"dependency-name": "Some.Dependency",
|
451
|
+
"affected-versions": ["not a valid requirement"]
|
452
|
+
}
|
453
|
+
]
|
454
|
+
}
|
455
|
+
}
|
456
|
+
""");
|
457
|
+
await RunAsync(path =>
|
458
|
+
[
|
459
|
+
"discover",
|
460
|
+
"--job-id",
|
461
|
+
"TEST-JOB-ID",
|
462
|
+
"--job-path",
|
463
|
+
jobFilePath,
|
464
|
+
"--repo-root",
|
465
|
+
path,
|
466
|
+
"--workspace",
|
467
|
+
"/",
|
468
|
+
"--output",
|
469
|
+
resultFilePath
|
470
|
+
],
|
471
|
+
initialFiles: [],
|
472
|
+
expectedResult: new()
|
473
|
+
{
|
474
|
+
Path = "/",
|
475
|
+
Projects = [],
|
476
|
+
Error = new Core.Run.ApiModel.BadRequirement("not a valid requirement"),
|
477
|
+
}
|
478
|
+
);
|
479
|
+
}
|
480
|
+
|
391
481
|
private static async Task RunAsync(
|
392
482
|
Func<string, string[]> getArgs,
|
393
483
|
TestFile[] initialFiles,
|
@@ -406,6 +496,7 @@ public partial class EntryPointTests
|
|
406
496
|
var originalErr = Console.Error;
|
407
497
|
Console.SetOut(writer);
|
408
498
|
Console.SetError(writer);
|
499
|
+
string? resultPath = null;
|
409
500
|
|
410
501
|
try
|
411
502
|
{
|
@@ -416,9 +507,15 @@ public partial class EntryPointTests
|
|
416
507
|
// manually pull out the experiments manager for the validate step below
|
417
508
|
for (int i = 0; i < args.Length - 1; i++)
|
418
509
|
{
|
419
|
-
|
510
|
+
switch (args[i])
|
420
511
|
{
|
421
|
-
|
512
|
+
case "--job-path":
|
513
|
+
var experimentsResult = await ExperimentsManager.FromJobFileAsync("TEST-JOB-ID", args[i + 1]);
|
514
|
+
experimentsManager = experimentsResult.ExperimentsManager;
|
515
|
+
break;
|
516
|
+
case "--output":
|
517
|
+
resultPath = args[i + 1];
|
518
|
+
break;
|
422
519
|
}
|
423
520
|
}
|
424
521
|
|
@@ -434,13 +531,40 @@ public partial class EntryPointTests
|
|
434
531
|
Console.SetError(originalErr);
|
435
532
|
}
|
436
533
|
|
437
|
-
|
534
|
+
resultPath ??= Path.Join(path, DiscoveryWorker.DiscoveryResultFileName);
|
438
535
|
var resultJson = await File.ReadAllTextAsync(resultPath);
|
439
|
-
var
|
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);
|
440
545
|
return resultObject!;
|
441
546
|
});
|
442
547
|
|
443
548
|
ValidateWorkspaceResult(expectedResult, actualResult, experimentsManager);
|
444
549
|
}
|
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
|
+
}
|
445
569
|
}
|
446
570
|
}
|
@@ -19,6 +19,8 @@ public partial class EntryPointTests
|
|
19
19
|
await Run(path =>
|
20
20
|
[
|
21
21
|
"update",
|
22
|
+
"--job-id",
|
23
|
+
"TEST-JOB-ID",
|
22
24
|
"--job-path",
|
23
25
|
Path.Combine(path, "job.json"),
|
24
26
|
"--repo-root",
|
@@ -122,6 +124,8 @@ public partial class EntryPointTests
|
|
122
124
|
await Run(path =>
|
123
125
|
[
|
124
126
|
"update",
|
127
|
+
"--job-id",
|
128
|
+
"TEST-JOB-ID",
|
125
129
|
"--job-path",
|
126
130
|
Path.Combine(path, "job.json"),
|
127
131
|
"--repo-root",
|
@@ -202,6 +206,8 @@ public partial class EntryPointTests
|
|
202
206
|
await Run(path =>
|
203
207
|
[
|
204
208
|
"update",
|
209
|
+
"--job-id",
|
210
|
+
"TEST-JOB-ID",
|
205
211
|
"--job-path",
|
206
212
|
Path.Combine(path, "job.json"),
|
207
213
|
"--repo-root",
|
@@ -361,6 +367,8 @@ public partial class EntryPointTests
|
|
361
367
|
IEnumerable<string> executableArgs = [
|
362
368
|
executableName,
|
363
369
|
"update",
|
370
|
+
"--job-id",
|
371
|
+
"TEST-JOB-ID",
|
364
372
|
"--job-path",
|
365
373
|
Path.Combine(tempDir.DirectoryPath, "job.json"),
|
366
374
|
"--repo-root",
|