dependabot-nuget 0.292.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/.gitignore +1 -0
- data/helpers/lib/NuGetUpdater/Directory.Packages.props +1 -0
- 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/DiscoverCommand.cs +8 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs +17 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +7 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +46 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +8 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +8 -17
- 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/Clone/CloneWorker.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencyDiscovery.targets +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +7 -20
- 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 +9 -22
- 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 +3 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyFileNotFound.cs +7 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyFileNotParseable.cs +15 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +24 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +6 -21
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/UnparseableFileException.cs +12 -0
- 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/Utilities/DotNetPackageCorrelationManager.cs +46 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +51 -27
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +1 -1
- 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/Discover/DiscoveryWorkerTestBase.cs +20 -12
- 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 -1
- 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 +9 -1
- 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 +11 -15
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +14 -8
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +148 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +12 -14
- data/helpers/lib/NuGetUpdater/NuGetUpdater.sln +18 -1
- data/lib/dependabot/nuget/native_helpers.rb +41 -16
- metadata +25 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +0 -12
@@ -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, _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);
|
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
|
}
|
@@ -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,27 +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
|
{
|
29
|
-
var (experimentsManager,
|
30
|
-
if (
|
31
|
+
var (experimentsManager, error) = await ExperimentsManager.FromJobFileAsync(jobId, jobPath.FullName);
|
32
|
+
if (error is not null)
|
31
33
|
{
|
32
34
|
// to make testing easier, this should be a `WorkspaceDiscoveryResult` object
|
33
35
|
var discoveryErrorResult = new WorkspaceDiscoveryResult
|
34
36
|
{
|
37
|
+
Error = error,
|
35
38
|
Path = workspace,
|
36
39
|
Projects = [],
|
37
|
-
ErrorType = errorResult.ErrorType,
|
38
|
-
ErrorDetails = errorResult.ErrorDetails,
|
39
40
|
};
|
40
41
|
await DiscoveryWorker.WriteResultsAsync(repoRoot.FullName, outputPath.FullName, discoveryErrorResult);
|
41
42
|
return;
|
42
43
|
}
|
43
44
|
|
44
45
|
var logger = new ConsoleLogger();
|
45
|
-
var worker = new DiscoveryWorker(experimentsManager, logger);
|
46
|
+
var worker = new DiscoveryWorker(jobId, experimentsManager, logger);
|
46
47
|
await worker.RunAsync(repoRoot.FullName, workspace, outputPath.FullName);
|
47
|
-
}, JobPathOption, RepoRootOption, WorkspaceOption, OutputOption);
|
48
|
+
}, JobIdOption, JobPathOption, RepoRootOption, WorkspaceOption, OutputOption);
|
48
49
|
|
49
50
|
return command;
|
50
51
|
}
|
@@ -33,11 +33,11 @@ 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(jobPath.FullName);
|
36
|
+
var (experimentsManager, _errorResult) = await ExperimentsManager.FromJobFileAsync(jobId, jobPath.FullName);
|
37
37
|
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);
|
41
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);
|
@@ -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
|
{
|
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);
|
37
49
|
var logger = new ConsoleLogger();
|
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,7 @@ public partial class EntryPointTests
|
|
345
351
|
{
|
346
352
|
if (args[i] == "--job-path")
|
347
353
|
{
|
348
|
-
var experimentsResult = await ExperimentsManager.FromJobFileAsync(args[i + 1]);
|
354
|
+
var experimentsResult = await ExperimentsManager.FromJobFileAsync("TEST-JOB-ID", args[i + 1]);
|
349
355
|
experimentsManager = experimentsResult.ExperimentsManager;
|
350
356
|
}
|
351
357
|
}
|
@@ -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",
|
@@ -398,6 +409,8 @@ public partial class EntryPointTests
|
|
398
409
|
await RunAsync(path =>
|
399
410
|
[
|
400
411
|
"discover",
|
412
|
+
"--job-id",
|
413
|
+
"TEST-JOB-ID",
|
401
414
|
"--job-path",
|
402
415
|
jobFilePath,
|
403
416
|
"--repo-root",
|
@@ -412,8 +425,7 @@ public partial class EntryPointTests
|
|
412
425
|
{
|
413
426
|
Path = "/",
|
414
427
|
Projects = [],
|
415
|
-
|
416
|
-
ErrorDetailsPattern = "JsonException",
|
428
|
+
ErrorRegex = "Error deserializing job file contents",
|
417
429
|
}
|
418
430
|
);
|
419
431
|
}
|
@@ -445,6 +457,8 @@ public partial class EntryPointTests
|
|
445
457
|
await RunAsync(path =>
|
446
458
|
[
|
447
459
|
"discover",
|
460
|
+
"--job-id",
|
461
|
+
"TEST-JOB-ID",
|
448
462
|
"--job-path",
|
449
463
|
jobFilePath,
|
450
464
|
"--repo-root",
|
@@ -459,8 +473,7 @@ public partial class EntryPointTests
|
|
459
473
|
{
|
460
474
|
Path = "/",
|
461
475
|
Projects = [],
|
462
|
-
|
463
|
-
ErrorDetailsPattern = "not a valid requirement",
|
476
|
+
Error = new Core.Run.ApiModel.BadRequirement("not a valid requirement"),
|
464
477
|
}
|
465
478
|
);
|
466
479
|
}
|
@@ -497,7 +510,7 @@ public partial class EntryPointTests
|
|
497
510
|
switch (args[i])
|
498
511
|
{
|
499
512
|
case "--job-path":
|
500
|
-
var experimentsResult = await ExperimentsManager.FromJobFileAsync(args[i + 1]);
|
513
|
+
var experimentsResult = await ExperimentsManager.FromJobFileAsync("TEST-JOB-ID", args[i + 1]);
|
501
514
|
experimentsManager = experimentsResult.ExperimentsManager;
|
502
515
|
break;
|
503
516
|
case "--output":
|
@@ -520,11 +533,38 @@ public partial class EntryPointTests
|
|
520
533
|
|
521
534
|
resultPath ??= Path.Join(path, DiscoveryWorker.DiscoveryResultFileName);
|
522
535
|
var resultJson = await File.ReadAllTextAsync(resultPath);
|
523
|
-
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);
|
524
545
|
return resultObject!;
|
525
546
|
});
|
526
547
|
|
527
548
|
ValidateWorkspaceResult(expectedResult, actualResult, experimentsManager);
|
528
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
|
+
}
|
529
569
|
}
|
530
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",
|
@@ -7,6 +7,7 @@ using NuGet.Frameworks;
|
|
7
7
|
using NuGet.Versioning;
|
8
8
|
|
9
9
|
using NuGetUpdater.Core.Discover;
|
10
|
+
using NuGetUpdater.Core.Run.ApiModel;
|
10
11
|
|
11
12
|
namespace NuGetUpdater.Core.Analyze;
|
12
13
|
|
@@ -16,6 +17,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
16
17
|
{
|
17
18
|
public const string AnalysisDirectoryName = "./.dependabot/analysis";
|
18
19
|
|
20
|
+
private readonly string _jobId;
|
19
21
|
private readonly ExperimentsManager _experimentsManager;
|
20
22
|
private readonly ILogger _logger;
|
21
23
|
|
@@ -25,8 +27,9 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
25
27
|
Converters = { new JsonStringEnumConverter(), new RequirementArrayConverter() },
|
26
28
|
};
|
27
29
|
|
28
|
-
public AnalyzeWorker(ExperimentsManager experimentsManager, ILogger logger)
|
30
|
+
public AnalyzeWorker(string jobId, ExperimentsManager experimentsManager, ILogger logger)
|
29
31
|
{
|
32
|
+
_jobId = jobId;
|
30
33
|
_experimentsManager = experimentsManager;
|
31
34
|
_logger = logger;
|
32
35
|
}
|
@@ -48,26 +51,11 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
48
51
|
{
|
49
52
|
analysisResult = await RunAsync(repoRoot, discovery, dependencyInfo);
|
50
53
|
}
|
51
|
-
catch (HttpRequestException ex)
|
52
|
-
when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
|
53
|
-
{
|
54
|
-
var localPath = PathHelper.JoinPath(repoRoot, discovery.Path);
|
55
|
-
using var nugetContext = new NuGetContext(localPath);
|
56
|
-
analysisResult = new AnalysisResult
|
57
|
-
{
|
58
|
-
ErrorType = ErrorType.AuthenticationFailure,
|
59
|
-
ErrorDetails = "(" + string.Join("|", nugetContext.PackageSources.Select(s => s.Source)) + ")",
|
60
|
-
UpdatedVersion = string.Empty,
|
61
|
-
CanUpdate = false,
|
62
|
-
UpdatedDependencies = [],
|
63
|
-
};
|
64
|
-
}
|
65
54
|
catch (Exception ex)
|
66
55
|
{
|
67
56
|
analysisResult = new AnalysisResult
|
68
57
|
{
|
69
|
-
|
70
|
-
ErrorDetails = ex.ToString(),
|
58
|
+
Error = JobErrorBase.ErrorFromException(ex, _jobId, PathHelper.JoinPath(repoRoot, discovery.Path)),
|
71
59
|
UpdatedVersion = string.Empty,
|
72
60
|
CanUpdate = false,
|
73
61
|
UpdatedDependencies = [],
|
@@ -79,6 +67,8 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
79
67
|
|
80
68
|
public async Task<AnalysisResult> RunAsync(string repoRoot, WorkspaceDiscoveryResult discovery, DependencyInfo dependencyInfo)
|
81
69
|
{
|
70
|
+
MSBuildHelper.RegisterMSBuild(repoRoot, repoRoot);
|
71
|
+
|
82
72
|
var startingDirectory = PathHelper.JoinPath(repoRoot, discovery.Path);
|
83
73
|
|
84
74
|
_logger.Info($"Starting analysis of {dependencyInfo.Name}...");
|
@@ -423,6 +413,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
423
413
|
.SelectMany(p => p.TargetFrameworks)
|
424
414
|
.Select(NuGetFramework.Parse)
|
425
415
|
.Distinct()
|
416
|
+
.Select(f => f.GetShortFolderName())
|
426
417
|
.ToImmutableArray();
|
427
418
|
|
428
419
|
// When updating peer dependencies, we only need to consider top-level dependencies.
|
@@ -7,10 +7,10 @@ namespace NuGetUpdater.Core.Analyze;
|
|
7
7
|
|
8
8
|
internal static class DependencyFinder
|
9
9
|
{
|
10
|
-
public static async Task<ImmutableDictionary<
|
10
|
+
public static async Task<ImmutableDictionary<string, ImmutableArray<Dependency>>> GetDependenciesAsync(
|
11
11
|
string repoRoot,
|
12
12
|
string projectPath,
|
13
|
-
IEnumerable<
|
13
|
+
IEnumerable<string> frameworks,
|
14
14
|
ImmutableHashSet<string> packageIds,
|
15
15
|
NuGetVersion version,
|
16
16
|
NuGetContext nugetContext,
|
@@ -23,13 +23,13 @@ internal static class DependencyFinder
|
|
23
23
|
.Select(id => new Dependency(id, versionString, DependencyType.Unknown))
|
24
24
|
.ToImmutableArray();
|
25
25
|
|
26
|
-
var result = ImmutableDictionary.CreateBuilder<
|
26
|
+
var result = ImmutableDictionary.CreateBuilder<string, ImmutableArray<Dependency>>();
|
27
27
|
foreach (var framework in frameworks)
|
28
28
|
{
|
29
29
|
var dependencies = await MSBuildHelper.GetAllPackageDependenciesAsync(
|
30
30
|
repoRoot,
|
31
31
|
projectPath,
|
32
|
-
framework
|
32
|
+
framework,
|
33
33
|
packages,
|
34
34
|
experimentsManager,
|
35
35
|
logger);
|
@@ -7,7 +7,7 @@ using NuGetUpdater.Core;
|
|
7
7
|
|
8
8
|
internal static class Extensions
|
9
9
|
{
|
10
|
-
public static ImmutableArray<Dependency> GetDependencies(this ImmutableDictionary<
|
10
|
+
public static ImmutableArray<Dependency> GetDependencies(this ImmutableDictionary<string, ImmutableArray<Dependency>> dependenciesByTfm)
|
11
11
|
{
|
12
12
|
Dictionary<string, Dependency> dependencies = [];
|
13
13
|
foreach (var (_framework, dependenciesForTfm) in dependenciesByTfm)
|