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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 833b170b34a1cef53346970cdfc208b39f49899aaeeb1d2da285463eabf2aea3
|
4
|
+
data.tar.gz: aea74663e1ec787d2496c6d63f97c531d6ccd5415cdd810ce7d8518080b027cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 889ab157302c7dbb0be345ca4e5204fe5518d6aafbd61d7992008404fa84200240e6f88655027ddb4a77611964cb97e2ea7857ad6453d33e498e4d6416b79eb8
|
7
|
+
data.tar.gz: 17f3003ef471825cf980d00da41c528bb051dc64285d6ca808ca84bea09a89b91a197a388d8f62c4e089427a52e77ba24d13b452ec9bc7231b46d18c9c84d697
|
@@ -26,6 +26,7 @@
|
|
26
26
|
<PackageVersion Include="MSBuild.StructuredLogger" Version="2.2.386" />
|
27
27
|
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
28
28
|
<PackageVersion Include="NuGet.Core" Version="2.14.0" Aliases="CoreV2" />
|
29
|
+
<PackageVersion Include="Semver" Version="3.0.0" />
|
29
30
|
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
|
30
31
|
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.0" />
|
31
32
|
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
|
@@ -0,0 +1,197 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
using System.Text.Json;
|
3
|
+
using System.Text.RegularExpressions;
|
4
|
+
|
5
|
+
using Semver;
|
6
|
+
|
7
|
+
namespace DotNetPackageCorrelation;
|
8
|
+
|
9
|
+
public partial class Correlator
|
10
|
+
{
|
11
|
+
public static readonly JsonSerializerOptions SerializerOptions = new()
|
12
|
+
{
|
13
|
+
WriteIndented = true,
|
14
|
+
Converters = { new SemVersionConverter() },
|
15
|
+
};
|
16
|
+
|
17
|
+
private readonly DirectoryInfo _releaseNotesDirectory;
|
18
|
+
|
19
|
+
public Correlator(DirectoryInfo releaseNotesDirectory)
|
20
|
+
{
|
21
|
+
_releaseNotesDirectory = releaseNotesDirectory;
|
22
|
+
}
|
23
|
+
|
24
|
+
public async Task<(RuntimePackages RuntimePackages, IEnumerable<string> Warnings)> RunAsync()
|
25
|
+
{
|
26
|
+
var runtimeVersions = new List<Version>();
|
27
|
+
foreach (var directory in Directory.EnumerateDirectories(_releaseNotesDirectory.FullName))
|
28
|
+
{
|
29
|
+
var directoryName = Path.GetFileName(directory);
|
30
|
+
if (Version.TryParse(directoryName, out var version))
|
31
|
+
{
|
32
|
+
runtimeVersions.Add(version);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
var runtimePackages = new RuntimePackages();
|
37
|
+
var warnings = new List<string>();
|
38
|
+
foreach (var majorVersion in runtimeVersions)
|
39
|
+
{
|
40
|
+
var releasesJsonPath = Path.Combine(_releaseNotesDirectory.FullName, majorVersion.ToString(), "releases.json");
|
41
|
+
if (!File.Exists(releasesJsonPath))
|
42
|
+
{
|
43
|
+
warnings.Add($"Unable to find releases.json file for version {majorVersion}");
|
44
|
+
continue;
|
45
|
+
}
|
46
|
+
|
47
|
+
var releasesJson = await File.ReadAllTextAsync(releasesJsonPath);
|
48
|
+
var releasesFile = JsonSerializer.Deserialize<ReleasesFile>(releasesJson, SerializerOptions)!;
|
49
|
+
|
50
|
+
foreach (var release in releasesFile.Releases)
|
51
|
+
{
|
52
|
+
foreach (var sdk in release.GetSdks())
|
53
|
+
{
|
54
|
+
if (sdk.Version is null)
|
55
|
+
{
|
56
|
+
warnings.Add($"Skipping release with missing version information from {releasesJson}");
|
57
|
+
continue;
|
58
|
+
}
|
59
|
+
|
60
|
+
if (sdk.RuntimeVersion is null)
|
61
|
+
{
|
62
|
+
warnings.Add($"Skipping release with missing runtime version information from {releasesJson}");
|
63
|
+
continue;
|
64
|
+
}
|
65
|
+
|
66
|
+
if (runtimePackages.Runtimes.ContainsKey(sdk.RuntimeVersion))
|
67
|
+
{
|
68
|
+
// already processed this runtime
|
69
|
+
continue;
|
70
|
+
}
|
71
|
+
|
72
|
+
var packagesAndVersions = new PackageSet();
|
73
|
+
runtimePackages.Runtimes.Add(sdk.RuntimeVersion, packagesAndVersions);
|
74
|
+
var runtimeDirectory = new DirectoryInfo(Path.Combine(_releaseNotesDirectory.FullName, majorVersion.ToString(), sdk.RuntimeVersion.ToString()));
|
75
|
+
var runtimeMarkdownPath = Path.Combine(runtimeDirectory.FullName, $"{sdk.RuntimeVersion}.md");
|
76
|
+
if (!File.Exists(runtimeMarkdownPath))
|
77
|
+
{
|
78
|
+
warnings.Add($"Unable to find expected markdown file {runtimeMarkdownPath}");
|
79
|
+
continue;
|
80
|
+
}
|
81
|
+
|
82
|
+
var markdownContent = await File.ReadAllTextAsync(runtimeMarkdownPath);
|
83
|
+
var packages = GetPackagesFromMarkdown(runtimeMarkdownPath, markdownContent, warnings);
|
84
|
+
foreach (var (packageName, packageVersion) in packages)
|
85
|
+
{
|
86
|
+
packagesAndVersions.Packages[packageName] = packageVersion;
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
return (runtimePackages, warnings);
|
93
|
+
}
|
94
|
+
|
95
|
+
public static ImmutableArray<(string Name, SemVersion Version)> GetPackagesFromMarkdown(string markdownPath, string markdownContent, List<string> warnings)
|
96
|
+
{
|
97
|
+
var lines = markdownContent.Split("\n").Select(l => l.Trim()).ToArray();
|
98
|
+
|
99
|
+
// the markdown file contains a table that looks like this:
|
100
|
+
// Package name | Version
|
101
|
+
// :----------- | :------------------
|
102
|
+
// Some.Package | 1.2.3
|
103
|
+
// ...
|
104
|
+
// however there are some formatting issues with some elements that prevent markdown parsers from
|
105
|
+
// discovering it, so we fall back to manual parsing
|
106
|
+
|
107
|
+
var tableStartLine = -1;
|
108
|
+
for (int i = 0; i < lines.Length; i++)
|
109
|
+
{
|
110
|
+
if (Regex.IsMatch(lines[i], "Package name.*Version"))
|
111
|
+
{
|
112
|
+
tableStartLine = i;
|
113
|
+
break;
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
if (tableStartLine == -1)
|
118
|
+
{
|
119
|
+
warnings.Add($"Unable to find table start in file {markdownPath}");
|
120
|
+
return [];
|
121
|
+
}
|
122
|
+
|
123
|
+
// skip the column names and separator line
|
124
|
+
tableStartLine += 2;
|
125
|
+
|
126
|
+
var tableEndLine = lines.Length; // assume the end of the file unless we find a blank line
|
127
|
+
for (int i = tableStartLine; i < lines.Length; i++)
|
128
|
+
{
|
129
|
+
if (string.IsNullOrEmpty(lines[i]))
|
130
|
+
{
|
131
|
+
tableEndLine = i;
|
132
|
+
break;
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
var packages = new List<(string Name, SemVersion Version)>();
|
137
|
+
for (int i = tableStartLine; i < tableEndLine; i++)
|
138
|
+
{
|
139
|
+
var line = lines[i].Trim();
|
140
|
+
var foundMatch = false;
|
141
|
+
foreach (var pattern in SpecialCasePatterns)
|
142
|
+
{
|
143
|
+
var match = pattern.Match(line);
|
144
|
+
if (match.Success)
|
145
|
+
{
|
146
|
+
var packageName = match.Groups["PackageName"].Value;
|
147
|
+
var packageVersionString = match.Groups["PackageVersion"].Value;
|
148
|
+
if (SemVersion.TryParse(packageVersionString, out var packageVersion))
|
149
|
+
{
|
150
|
+
packages.Add((packageName, packageVersion));
|
151
|
+
foundMatch = true;
|
152
|
+
break; ;
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
if (!foundMatch)
|
158
|
+
{
|
159
|
+
warnings.Add($"Unable to parse package and version from string [{line}] in file [{markdownPath}]:{i}");
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
return packages.ToImmutableArray();
|
164
|
+
}
|
165
|
+
|
166
|
+
// The different patterns the lines in the markdown might take. Due to issues with regular expressions, this list
|
167
|
+
// is in a very specific order.
|
168
|
+
private static ImmutableArray<Regex> SpecialCasePatterns { get; } = [
|
169
|
+
StandardLineWithFileExtensions(),
|
170
|
+
StandardLine(),
|
171
|
+
PackageNameDotVersion(),
|
172
|
+
PackageFileNameWithOptionalTrailingPipe(),
|
173
|
+
MultiColumnWithOptionalFileSuffix(),
|
174
|
+
];
|
175
|
+
|
176
|
+
[GeneratedRegex(@"^(?<PackageName>[^|\s]+)\s*\|\s*(?<PackageVersion>[^|\s]+?)(\.symbols)?\.nupkg$", RegexOptions.Compiled)]
|
177
|
+
// Some.Package | 1.2.3.nupkg
|
178
|
+
// Some.Package | 1.2.3.symbols.nupkg
|
179
|
+
private static partial Regex StandardLineWithFileExtensions();
|
180
|
+
|
181
|
+
[GeneratedRegex(@"^(?<PackageName>[^|\s]+)\s*\|\s*(?<PackageVersion>[^|\s]+)$", RegexOptions.Compiled)]
|
182
|
+
// Some.Package | 1.2.3
|
183
|
+
private static partial Regex StandardLine();
|
184
|
+
|
185
|
+
[GeneratedRegex(@"^(?<PackageName>[^\d]+)\.(?<PackageVersion>[\d].+)$", RegexOptions.Compiled)]
|
186
|
+
// Some.Package.1.2.3
|
187
|
+
private static partial Regex PackageNameDotVersion();
|
188
|
+
|
189
|
+
[GeneratedRegex(@"^(?<PackageName>[^\d]+)\.(?<PackageVersion>\d.+?)\.nupkg(\s+\|)?$", RegexOptions.Compiled)]
|
190
|
+
// some.package.1.2.3.nupkg
|
191
|
+
// some.package.1.2.3.nupkg |
|
192
|
+
private static partial Regex PackageFileNameWithOptionalTrailingPipe();
|
193
|
+
|
194
|
+
[GeneratedRegex(@"^(?<PackageName>[^|\s]+)\s*\|[^|]*\|\s*(?<PackageVersion>.*?)(\.nupkg)?$", RegexOptions.Compiled)]
|
195
|
+
// Some.Package | 1.2 | 1.2.3.nupkg
|
196
|
+
private static partial Regex MultiColumnWithOptionalFileSuffix();
|
197
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
2
|
+
|
3
|
+
<PropertyGroup>
|
4
|
+
<TargetFramework>$(CommonTargetFramework)</TargetFramework>
|
5
|
+
</PropertyGroup>
|
6
|
+
|
7
|
+
<ItemGroup>
|
8
|
+
<PackageReference Include="Semver" />
|
9
|
+
<PackageReference Include="System.Text.Json" />
|
10
|
+
</ItemGroup>
|
11
|
+
|
12
|
+
</Project>
|
@@ -0,0 +1,68 @@
|
|
1
|
+
using Semver;
|
2
|
+
|
3
|
+
namespace DotNetPackageCorrelation;
|
4
|
+
|
5
|
+
public class PackageMapper
|
6
|
+
{
|
7
|
+
public RuntimePackages RuntimePackages { get; }
|
8
|
+
|
9
|
+
private PackageMapper(RuntimePackages runtimePackages)
|
10
|
+
{
|
11
|
+
RuntimePackages = runtimePackages;
|
12
|
+
}
|
13
|
+
|
14
|
+
/// <summary>
|
15
|
+
/// Find the version of <paramref name="candidatePackageName"/> that shipped at the same time as
|
16
|
+
/// "<paramref name="packageName"/>/<paramref name="packageVersion"/>".
|
17
|
+
/// </summary>
|
18
|
+
public SemVersion? GetPackageVersionThatShippedWithOtherPackage(string packageName, SemVersion packageVersion, string candidatePackageName)
|
19
|
+
{
|
20
|
+
var runtimeVersion = GetRuntimeVersionFromPackage(packageName, packageVersion);
|
21
|
+
if (runtimeVersion is null)
|
22
|
+
{
|
23
|
+
// no runtime found that contains the package
|
24
|
+
return null;
|
25
|
+
}
|
26
|
+
|
27
|
+
var candidateRuntimeVersions = RuntimePackages.Runtimes.Keys
|
28
|
+
.Where(v => v.Major == runtimeVersion.Major)
|
29
|
+
.Where(v => v.ComparePrecedenceTo(runtimeVersion) <= 0)
|
30
|
+
.OrderBy(v => v, SemVerComparer.Instance)
|
31
|
+
.Reverse()
|
32
|
+
.ToArray();
|
33
|
+
foreach (var candidateRuntimeVersion in candidateRuntimeVersions)
|
34
|
+
{
|
35
|
+
if (!RuntimePackages.Runtimes.TryGetValue(candidateRuntimeVersion, out var packageSet))
|
36
|
+
{
|
37
|
+
continue;
|
38
|
+
}
|
39
|
+
|
40
|
+
if (packageSet.Packages.TryGetValue(candidatePackageName, out var foundPackageVersion))
|
41
|
+
{
|
42
|
+
return foundPackageVersion;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
return null;
|
47
|
+
}
|
48
|
+
|
49
|
+
private SemVersion? GetRuntimeVersionFromPackage(string packageName, SemVersion packageVersion)
|
50
|
+
{
|
51
|
+
// TODO: linear search is slow
|
52
|
+
foreach (var runtime in RuntimePackages.Runtimes)
|
53
|
+
{
|
54
|
+
if (runtime.Value.Packages.TryGetValue(packageName, out var foundPackageVersion) &&
|
55
|
+
foundPackageVersion == packageVersion)
|
56
|
+
{
|
57
|
+
return runtime.Key;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
return null;
|
62
|
+
}
|
63
|
+
|
64
|
+
public static PackageMapper Load(RuntimePackages runtimePackages)
|
65
|
+
{
|
66
|
+
return new PackageMapper(runtimePackages);
|
67
|
+
}
|
68
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
using System.Text.Json.Serialization;
|
2
|
+
|
3
|
+
using Semver;
|
4
|
+
|
5
|
+
namespace DotNetPackageCorrelation;
|
6
|
+
|
7
|
+
public record PackageSet
|
8
|
+
{
|
9
|
+
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
|
10
|
+
public SortedDictionary<string, SemVersion> Packages { get; init; } = new(StringComparer.OrdinalIgnoreCase);
|
11
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
using System.Text.Json.Serialization;
|
3
|
+
|
4
|
+
namespace DotNetPackageCorrelation;
|
5
|
+
|
6
|
+
public record Release
|
7
|
+
{
|
8
|
+
[JsonPropertyName("sdk")]
|
9
|
+
public required Sdk Sdk { get; init; }
|
10
|
+
|
11
|
+
[JsonPropertyName("sdks")]
|
12
|
+
public ImmutableArray<Sdk>? Sdks { get; init; } = [];
|
13
|
+
}
|
14
|
+
|
15
|
+
public static class ReleaseExtensions
|
16
|
+
{
|
17
|
+
public static IEnumerable<Sdk> GetSdks(this Release release)
|
18
|
+
{
|
19
|
+
yield return release.Sdk;
|
20
|
+
foreach (var sdk in release.Sdks ?? [])
|
21
|
+
{
|
22
|
+
yield return sdk;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
using System.Text.Json.Serialization;
|
2
|
+
|
3
|
+
using Semver;
|
4
|
+
|
5
|
+
namespace DotNetPackageCorrelation;
|
6
|
+
|
7
|
+
public record RuntimePackages
|
8
|
+
{
|
9
|
+
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
|
10
|
+
public SortedDictionary<SemVersion, PackageSet> Runtimes { get; init; } = new(SemVerComparer.Instance);
|
11
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
using System.Text.Json.Serialization;
|
2
|
+
|
3
|
+
using Semver;
|
4
|
+
|
5
|
+
namespace DotNetPackageCorrelation;
|
6
|
+
|
7
|
+
public record Sdk
|
8
|
+
{
|
9
|
+
[JsonPropertyName("version")]
|
10
|
+
public required SemVersion? Version { get; init; }
|
11
|
+
[JsonPropertyName("runtime-version")]
|
12
|
+
public SemVersion? RuntimeVersion { get; init; }
|
13
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
using Semver;
|
2
|
+
|
3
|
+
namespace DotNetPackageCorrelation;
|
4
|
+
|
5
|
+
public class SemVerComparer : IComparer<SemVersion>
|
6
|
+
{
|
7
|
+
public static SemVerComparer Instance = new();
|
8
|
+
|
9
|
+
public int Compare(SemVersion? x, SemVersion? y)
|
10
|
+
{
|
11
|
+
ArgumentNullException.ThrowIfNull(x);
|
12
|
+
ArgumentNullException.ThrowIfNull(y);
|
13
|
+
|
14
|
+
return x.ComparePrecedenceTo(y);
|
15
|
+
}
|
16
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
using System.Diagnostics.CodeAnalysis;
|
2
|
+
using System.Text.Json;
|
3
|
+
using System.Text.Json.Serialization;
|
4
|
+
|
5
|
+
using Semver;
|
6
|
+
|
7
|
+
namespace DotNetPackageCorrelation;
|
8
|
+
|
9
|
+
public class SemVersionConverter : JsonConverter<SemVersion?>
|
10
|
+
{
|
11
|
+
public override SemVersion? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
12
|
+
{
|
13
|
+
var value = reader.GetString();
|
14
|
+
if (SemVersion.TryParse(value, out var result))
|
15
|
+
{
|
16
|
+
return result;
|
17
|
+
}
|
18
|
+
|
19
|
+
return null;
|
20
|
+
}
|
21
|
+
|
22
|
+
public override SemVersion ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
23
|
+
{
|
24
|
+
var value = Read(ref reader, typeToConvert, options);
|
25
|
+
if (value is null)
|
26
|
+
{
|
27
|
+
throw new JsonException($"Unable to read {nameof(SemVersion)} as property name.");
|
28
|
+
}
|
29
|
+
|
30
|
+
return value;
|
31
|
+
}
|
32
|
+
|
33
|
+
public override void Write(Utf8JsonWriter writer, SemVersion? value, JsonSerializerOptions options)
|
34
|
+
{
|
35
|
+
writer.WriteStringValue(value?.ToString());
|
36
|
+
}
|
37
|
+
|
38
|
+
public override void WriteAsPropertyName(Utf8JsonWriter writer, [DisallowNull] SemVersion value, JsonSerializerOptions options)
|
39
|
+
{
|
40
|
+
writer.WritePropertyName(value.ToString());
|
41
|
+
}
|
42
|
+
}
|
data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Cli/DotNetPackageCorrelation.Cli.csproj
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
2
|
+
|
3
|
+
<PropertyGroup>
|
4
|
+
<TargetFramework>$(CommonTargetFramework)</TargetFramework>
|
5
|
+
<OutputType>Exe</OutputType>
|
6
|
+
</PropertyGroup>
|
7
|
+
|
8
|
+
<ItemGroup>
|
9
|
+
<PackageReference Include="System.CommandLine" />
|
10
|
+
</ItemGroup>
|
11
|
+
|
12
|
+
<ItemGroup>
|
13
|
+
<ProjectReference Include="..\DotNetPackageCorrelation\DotNetPackageCorrelation.csproj" />
|
14
|
+
</ItemGroup>
|
15
|
+
|
16
|
+
</Project>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
using System.CommandLine;
|
2
|
+
using System.Text.Json;
|
3
|
+
|
4
|
+
using DotNetPackageCorrelation;
|
5
|
+
|
6
|
+
namespace DotNetPackageCorrelation.Cli;
|
7
|
+
|
8
|
+
public class Program
|
9
|
+
{
|
10
|
+
public static async Task<int> Main(string[] args)
|
11
|
+
{
|
12
|
+
var coreLocationOption = new Option<DirectoryInfo>("--core-location", "The location of the .NET Core source code.") { IsRequired = true };
|
13
|
+
var outputOption = new Option<FileInfo>("--output", "The location to write the result.") { IsRequired = true };
|
14
|
+
var command = new Command("build")
|
15
|
+
{
|
16
|
+
coreLocationOption,
|
17
|
+
outputOption,
|
18
|
+
};
|
19
|
+
command.TreatUnmatchedTokensAsErrors = true;
|
20
|
+
command.SetHandler(async (coreLocationDirectory, output) =>
|
21
|
+
{
|
22
|
+
// the tool is expected to be given the path to the .NET Core repository, but the correlator only needs a specific subdirectory
|
23
|
+
var releaseNotesDirectory = new DirectoryInfo(Path.Combine(coreLocationDirectory.FullName, "release-notes"));
|
24
|
+
var correlator = new Correlator(releaseNotesDirectory);
|
25
|
+
var (sdkPackages, _warnings) = await correlator.RunAsync();
|
26
|
+
var json = JsonSerializer.Serialize(sdkPackages, Correlator.SerializerOptions);
|
27
|
+
await File.WriteAllTextAsync(output.FullName, json);
|
28
|
+
}, coreLocationOption, outputOption);
|
29
|
+
var exitCode = await command.InvokeAsync(args);
|
30
|
+
return exitCode;
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,99 @@
|
|
1
|
+
using Semver;
|
2
|
+
|
3
|
+
using Xunit;
|
4
|
+
|
5
|
+
namespace DotNetPackageCorrelation.Tests;
|
6
|
+
|
7
|
+
public class CorrelatorTests
|
8
|
+
{
|
9
|
+
[Fact]
|
10
|
+
public async Task FileHandling_AllFilesShapedAppropriately()
|
11
|
+
{
|
12
|
+
// the JSON and markdown are shaped as expected
|
13
|
+
// we're able to determine from `Runtime.Package/8.0.0` that the corresponding version of `Some.Package` is `1.2.3`
|
14
|
+
var (packageMapper, warnings) = await PackageMapperFromFilesAsync(
|
15
|
+
("8.0/releases.json", """
|
16
|
+
{
|
17
|
+
"releases": [
|
18
|
+
{
|
19
|
+
"sdk": {
|
20
|
+
"version": "8.0.100",
|
21
|
+
"runtime-version": "8.0.0"
|
22
|
+
}
|
23
|
+
}
|
24
|
+
]
|
25
|
+
}
|
26
|
+
"""),
|
27
|
+
("8.0/8.0.0/8.0.0.md", """
|
28
|
+
Package name | Version
|
29
|
+
:-- | :--
|
30
|
+
Runtime.Package | 8.0.0
|
31
|
+
Some.Package | 1.2.3
|
32
|
+
""")
|
33
|
+
);
|
34
|
+
Assert.Empty(warnings);
|
35
|
+
AssertPackageVersion(packageMapper, "Runtime.Package", "8.0.0", "Some.Package", "1.2.3");
|
36
|
+
}
|
37
|
+
|
38
|
+
[Theory]
|
39
|
+
[InlineData("Some.Package | 1.2.3", "Some.Package", "1.2.3")] // happy path
|
40
|
+
[InlineData("Some.Package.1.2.3", "Some.Package", "1.2.3")] // looks like a restore directory
|
41
|
+
[InlineData("Some.Package | 1.2 | 1.2.3.nupkg", "Some.Package", "1.2.3")] // extra columns from a bad filename split
|
42
|
+
[InlineData("Some.Package | 1.2.3.nupkg", "Some.Package", "1.2.3")] // version contains package extension
|
43
|
+
[InlineData("Some.Package | 1.2.3.symbols.nupkg", "Some.Package", "1.2.3")] // version contains symbols package extension
|
44
|
+
[InlineData("some.package.1.2.3.nupkg", "some.package", "1.2.3")] // first column is a filename, second column is missing
|
45
|
+
[InlineData("some.package.1.2.3.nupkg |", "some.package", "1.2.3")] // first column is a filename, second column is empty
|
46
|
+
public void PackagesParsedFromMarkdown(string markdownLine, string expectedPackageName, string expectedPackageVersion)
|
47
|
+
{
|
48
|
+
var markdownContent = $"""
|
49
|
+
Package name | Version
|
50
|
+
:-- | :--
|
51
|
+
{markdownLine}
|
52
|
+
""";
|
53
|
+
var warnings = new List<string>();
|
54
|
+
var packages = Correlator.GetPackagesFromMarkdown("test.md", markdownContent, warnings);
|
55
|
+
Assert.Empty(warnings);
|
56
|
+
var actualpackage = Assert.Single(packages);
|
57
|
+
Assert.Equal(expectedPackageName, actualpackage.Name);
|
58
|
+
Assert.Equal(expectedPackageVersion, actualpackage.Version.ToString());
|
59
|
+
}
|
60
|
+
|
61
|
+
private static void AssertPackageVersion(PackageMapper packageMapper, string runtimePackageName, string runtimePackageVersion, string candidatePackageName, string? expectedPackageVersion)
|
62
|
+
{
|
63
|
+
var actualPackageVersion = packageMapper.GetPackageVersionThatShippedWithOtherPackage(runtimePackageName, SemVersion.Parse(runtimePackageVersion), candidatePackageName);
|
64
|
+
if (expectedPackageVersion is null)
|
65
|
+
{
|
66
|
+
Assert.Null(actualPackageVersion);
|
67
|
+
}
|
68
|
+
else
|
69
|
+
{
|
70
|
+
Assert.NotNull(actualPackageVersion);
|
71
|
+
Assert.Equal(expectedPackageVersion, actualPackageVersion.ToString());
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
private static async Task<(PackageMapper PackageMapper, IEnumerable<string> Warnings)> PackageMapperFromFilesAsync(params (string Path, string Content)[] files)
|
76
|
+
{
|
77
|
+
var testDirectory = Path.Combine(Path.GetDirectoryName(typeof(CorrelatorTests).Assembly.Location)!, "test-data", Guid.NewGuid().ToString("D"));
|
78
|
+
Directory.CreateDirectory(testDirectory);
|
79
|
+
|
80
|
+
try
|
81
|
+
{
|
82
|
+
foreach (var (path, content) in files)
|
83
|
+
{
|
84
|
+
var fullPath = Path.Combine(testDirectory, path);
|
85
|
+
Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!);
|
86
|
+
await File.WriteAllTextAsync(fullPath, content);
|
87
|
+
}
|
88
|
+
|
89
|
+
var correlator = new Correlator(new DirectoryInfo(testDirectory));
|
90
|
+
var (runtimePackages, warnings) = await correlator.RunAsync();
|
91
|
+
var packageMapper = PackageMapper.Load(runtimePackages);
|
92
|
+
return (packageMapper, warnings);
|
93
|
+
}
|
94
|
+
finally
|
95
|
+
{
|
96
|
+
Directory.Delete(testDirectory, recursive: true);
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Test/DotNetPackageCorrelation.Test.csproj
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
2
|
+
|
3
|
+
<PropertyGroup>
|
4
|
+
<TargetFramework>$(CommonTargetFramework)</TargetFramework>
|
5
|
+
<OutputType>Exe</OutputType>
|
6
|
+
</PropertyGroup>
|
7
|
+
|
8
|
+
<ItemGroup>
|
9
|
+
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
10
|
+
<PackageReference Include="xunit" />
|
11
|
+
<PackageReference Include="xunit.runner.visualstudio" />
|
12
|
+
</ItemGroup>
|
13
|
+
|
14
|
+
<ItemGroup>
|
15
|
+
<ProjectReference Include="..\DotNetPackageCorrelation\DotNetPackageCorrelation.csproj" />
|
16
|
+
</ItemGroup>
|
17
|
+
|
18
|
+
</Project>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
using System.Runtime.CompilerServices;
|
2
|
+
|
3
|
+
using Semver;
|
4
|
+
|
5
|
+
using Xunit;
|
6
|
+
|
7
|
+
namespace DotNetPackageCorrelation.Tests;
|
8
|
+
|
9
|
+
public class EndToEndTests
|
10
|
+
{
|
11
|
+
[Fact]
|
12
|
+
public async Task IntegrationTest()
|
13
|
+
{
|
14
|
+
// arrange
|
15
|
+
var thisFileDirectory = Path.GetDirectoryName(GetThisFilePath())!;
|
16
|
+
var dotnetCoreDirectory = Path.Combine(thisFileDirectory, "..", "..", "dotnet-core");
|
17
|
+
var correlator = new Correlator(new DirectoryInfo(Path.Combine(dotnetCoreDirectory, "release-notes")));
|
18
|
+
|
19
|
+
// act
|
20
|
+
var (runtimePackages, _warnings) = await correlator.RunAsync();
|
21
|
+
var packageMapper = PackageMapper.Load(runtimePackages);
|
22
|
+
|
23
|
+
// assert
|
24
|
+
// Microsoft.NETCore.App.Ref/8.0.8 didn't ship with System.Text.Json, but the previous version 8.0.7 shipped at the same time as System.Text.Json/8.0.4
|
25
|
+
var systemTextJsonVersion = packageMapper.GetPackageVersionThatShippedWithOtherPackage("Microsoft.NETCore.App.Ref", SemVersion.Parse("8.0.8"), "System.Text.Json");
|
26
|
+
Assert.Equal("8.0.4", systemTextJsonVersion?.ToString());
|
27
|
+
}
|
28
|
+
|
29
|
+
private static string GetThisFilePath([CallerFilePath] string? path = null) => path ?? throw new ArgumentNullException(nameof(path));
|
30
|
+
}
|