dependabot-nuget 0.258.0 → 0.260.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/Directory.Packages.props +2 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +255 -191
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +63 -35
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +107 -14
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +9 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +18 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +6 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.DotNetToolsJson.cs +6 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.GlobalJson.cs +6 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs +11 -21
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Proj.cs +95 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +204 -62
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +64 -45
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +419 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/NuGetUpdater.Core.Test.csproj +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryDirectory.cs +7 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +77 -19
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs +120 -91
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DotNetTools.cs +132 -97
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs +93 -75
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +45 -42
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +1089 -956
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +1624 -1291
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +296 -293
- data/helpers/lib/NuGetUpdater/global.json +6 -0
- data/lib/dependabot/nuget/file_parser.rb +4 -5
- data/lib/dependabot/nuget/file_updater.rb +1 -1
- data/lib/dependabot/nuget/update_checker/dependency_finder.rb +7 -2
- data/lib/dependabot/nuget/update_checker/property_updater.rb +1 -0
- data/lib/dependabot/nuget/update_checker/version_finder.rb +2 -3
- data/lib/dependabot/nuget/update_checker.rb +1 -0
- metadata +8 -5
@@ -0,0 +1,419 @@
|
|
1
|
+
using System.IO.Compression;
|
2
|
+
using System.Security.Cryptography;
|
3
|
+
using System.Text;
|
4
|
+
using System.Text.Json.Nodes;
|
5
|
+
using System.Text.RegularExpressions;
|
6
|
+
using System.Xml;
|
7
|
+
using System.Xml.Linq;
|
8
|
+
using System.Xml.XPath;
|
9
|
+
|
10
|
+
using Microsoft.CodeAnalysis;
|
11
|
+
using Microsoft.CodeAnalysis.CSharp;
|
12
|
+
using Microsoft.CodeAnalysis.Emit;
|
13
|
+
|
14
|
+
namespace NuGetUpdater.Core.Test
|
15
|
+
{
|
16
|
+
public record MockNuGetPackage(
|
17
|
+
string Id,
|
18
|
+
string Version,
|
19
|
+
XElement[]? AdditionalMetadata = null,
|
20
|
+
(string? TargetFramework, (string Id, string Version)[] Packages)[]? DependencyGroups = null,
|
21
|
+
(string Path, byte[] Content)[]? Files = null)
|
22
|
+
{
|
23
|
+
private static readonly XNamespace Namespace = "http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd";
|
24
|
+
private static readonly XmlWriterSettings WriterSettings = new()
|
25
|
+
{
|
26
|
+
Encoding = Encoding.UTF8,
|
27
|
+
Indent = true,
|
28
|
+
};
|
29
|
+
|
30
|
+
private XDocument? _nuspec;
|
31
|
+
private Stream? _stream;
|
32
|
+
|
33
|
+
public void WriteToDirectory(string localPackageSourcePath)
|
34
|
+
{
|
35
|
+
string cachePath = Path.Join(localPackageSourcePath, "_nupkg_cache");
|
36
|
+
string nupkgPath = Path.Join(cachePath, $"{Id}.{Version}.nupkg");
|
37
|
+
Directory.CreateDirectory(cachePath);
|
38
|
+
Stream stream = GetZipStream();
|
39
|
+
using (FileStream fileStream = new(nupkgPath, FileMode.Create))
|
40
|
+
{
|
41
|
+
stream.CopyTo(fileStream);
|
42
|
+
}
|
43
|
+
|
44
|
+
// add the package to the local feed; this is equivalent to running
|
45
|
+
// nuget add <nupkgPath> -source <localPackageSourcePath>
|
46
|
+
// but running that in-process locks the files, so we have to do it manually
|
47
|
+
// the end result is 4 files:
|
48
|
+
// .nupkg.metadata // a JSON object with the package's content hash and some other fields
|
49
|
+
// <id>.<version>.nupkg // the package itself
|
50
|
+
// <id>.<version>.nupkg.sha512 // the SHA512 hash of the package
|
51
|
+
// <id>.nuspec // the package's nuspec file
|
52
|
+
string expandedPath = Path.Join(localPackageSourcePath, Id.ToLowerInvariant(), Version);
|
53
|
+
Directory.CreateDirectory(expandedPath);
|
54
|
+
File.Copy(nupkgPath, Path.Join(expandedPath, $"{Id}.{Version}.nupkg".ToLowerInvariant()));
|
55
|
+
using XmlWriter writer = XmlWriter.Create(Path.Join(expandedPath, $"{Id}.nuspec".ToLowerInvariant()), WriterSettings);
|
56
|
+
GetNuspec().WriteTo(writer);
|
57
|
+
using SHA512 sha512 = SHA512.Create();
|
58
|
+
byte[] hash = sha512.ComputeHash(File.ReadAllBytes(nupkgPath));
|
59
|
+
string hashString = Convert.ToBase64String(hash);
|
60
|
+
File.WriteAllText(Path.Join(expandedPath, $"{Id}.{Version}.nupkg.sha512".ToLowerInvariant()), hashString);
|
61
|
+
JsonObject metadata = new()
|
62
|
+
{
|
63
|
+
["version"] = 2,
|
64
|
+
["contentHash"] = hashString,
|
65
|
+
["source"] = null,
|
66
|
+
};
|
67
|
+
File.WriteAllText(Path.Join(expandedPath, ".nupkg.metadata"), metadata.ToString());
|
68
|
+
}
|
69
|
+
|
70
|
+
/// <summary>
|
71
|
+
/// Creates a mock NuGet package with a single assembly in the appropriate `lib/` directory. The assembly will
|
72
|
+
/// be empty.
|
73
|
+
/// </summary>
|
74
|
+
public static MockNuGetPackage CreateSimplePackage(string id, string version, string targetFramework, (string? TargetFramework, (string Id, string Version)[] Packages)[]? dependencyGroups = null)
|
75
|
+
{
|
76
|
+
return new(
|
77
|
+
id,
|
78
|
+
version,
|
79
|
+
AdditionalMetadata: null,
|
80
|
+
DependencyGroups: dependencyGroups,
|
81
|
+
Files:
|
82
|
+
[
|
83
|
+
($"lib/{targetFramework}/{id}.dll", Array.Empty<byte>())
|
84
|
+
]
|
85
|
+
);
|
86
|
+
}
|
87
|
+
|
88
|
+
/// <summary>
|
89
|
+
/// Creates a mock NuGet package with a single assembly in the appropriate `lib/` directory. The assembly will
|
90
|
+
/// contain the appropriate `AssemblyVersion` attribute and nothing else.
|
91
|
+
/// </summary>
|
92
|
+
public static MockNuGetPackage CreatePackageWithAssembly(string id, string version, string targetFramework, string assemblyVersion, (string? TargetFramework, (string Id, string Version)[] Packages)[]? dependencyGroups = null)
|
93
|
+
{
|
94
|
+
return new(
|
95
|
+
id,
|
96
|
+
version,
|
97
|
+
AdditionalMetadata: null,
|
98
|
+
DependencyGroups: dependencyGroups,
|
99
|
+
Files:
|
100
|
+
[
|
101
|
+
($"lib/{targetFramework}/{id}.dll", CreateAssembly(id, assemblyVersion))
|
102
|
+
]
|
103
|
+
);
|
104
|
+
}
|
105
|
+
|
106
|
+
/// <summary>
|
107
|
+
/// Creates a mock NuGet package with empty analyzer assemblies for both C# and VB.
|
108
|
+
/// </summary>
|
109
|
+
public static MockNuGetPackage CreateAnalyzerPackage(string id, string version, (string? TargetFramework, (string Id, string Version)[] Packages)[]? dependencyGroups = null)
|
110
|
+
{
|
111
|
+
return new(
|
112
|
+
id,
|
113
|
+
version,
|
114
|
+
AdditionalMetadata:
|
115
|
+
[
|
116
|
+
new XElement("developmentDependency", "true"),
|
117
|
+
],
|
118
|
+
DependencyGroups: dependencyGroups,
|
119
|
+
Files:
|
120
|
+
[
|
121
|
+
($"analyzers/dotnet/cs/{id}.dll", Array.Empty<byte>()),
|
122
|
+
($"analyzers/dotnet/vb/{id}.dll", Array.Empty<byte>()),
|
123
|
+
]
|
124
|
+
);
|
125
|
+
}
|
126
|
+
|
127
|
+
public static MockNuGetPackage CreateDotNetToolPackage(string id, string version, string targetFramework)
|
128
|
+
{
|
129
|
+
return new(
|
130
|
+
id,
|
131
|
+
version,
|
132
|
+
AdditionalMetadata:
|
133
|
+
[
|
134
|
+
new XElement("packageTypes",
|
135
|
+
new XElement("packageType",
|
136
|
+
new XAttribute("name", "DotnetTool")
|
137
|
+
)
|
138
|
+
)
|
139
|
+
],
|
140
|
+
Files:
|
141
|
+
[
|
142
|
+
($"tools/{targetFramework}/any/DotnetToolSettings.xml", Encoding.UTF8.GetBytes($"""
|
143
|
+
<DotNetCliTool Version="1">
|
144
|
+
<Commands>
|
145
|
+
<Command Name="{id}" EntryPoint="{id}.dll" Runner="dotnet" />
|
146
|
+
</Commands>
|
147
|
+
</DotNetCliTool>
|
148
|
+
""")),
|
149
|
+
($"tools/{targetFramework}/any/{id}.dll", Array.Empty<byte>()),
|
150
|
+
]
|
151
|
+
);
|
152
|
+
}
|
153
|
+
|
154
|
+
public static MockNuGetPackage CreateMSBuildSdkPackage(string id, string version, string? sdkPropsContent = null, string? sdkTargetsContent = null)
|
155
|
+
{
|
156
|
+
sdkPropsContent ??= """
|
157
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
158
|
+
</Project>
|
159
|
+
""";
|
160
|
+
sdkTargetsContent ??= """
|
161
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
162
|
+
</Project>
|
163
|
+
""";
|
164
|
+
return new(
|
165
|
+
id,
|
166
|
+
version,
|
167
|
+
AdditionalMetadata:
|
168
|
+
[
|
169
|
+
new XElement("packageTypes",
|
170
|
+
new XElement("packageType",
|
171
|
+
new XAttribute("name", "MSBuildSdk")
|
172
|
+
)
|
173
|
+
)
|
174
|
+
],
|
175
|
+
Files:
|
176
|
+
[
|
177
|
+
("Sdk/Sdk.props", Encoding.UTF8.GetBytes(sdkPropsContent)),
|
178
|
+
("Sdk/Sdk.targets", Encoding.UTF8.GetBytes(sdkTargetsContent)),
|
179
|
+
]
|
180
|
+
);
|
181
|
+
}
|
182
|
+
|
183
|
+
private XDocument GetNuspec()
|
184
|
+
{
|
185
|
+
if (_nuspec is null)
|
186
|
+
{
|
187
|
+
_nuspec = new XDocument(
|
188
|
+
new XElement(Namespace + "package",
|
189
|
+
new XElement(Namespace + "metadata",
|
190
|
+
new XElement(Namespace + "id", Id),
|
191
|
+
new XElement(Namespace + "version", Version),
|
192
|
+
new XElement(Namespace + "authors", "MockNuGetPackage"),
|
193
|
+
new XElement(Namespace + "description", "Mock NuGet package"),
|
194
|
+
AdditionalMetadata?.Select(a => WithNamespace(a, Namespace)),
|
195
|
+
new XElement(Namespace + "dependencies",
|
196
|
+
// dependencies with no target framework
|
197
|
+
DependencyGroups?.Where(g => g.TargetFramework is null).SelectMany(g =>
|
198
|
+
g.Packages.Select(p =>
|
199
|
+
new XElement(Namespace + "dependency",
|
200
|
+
new XAttribute("id", p.Id),
|
201
|
+
new XAttribute("version", p.Version)
|
202
|
+
)
|
203
|
+
)
|
204
|
+
),
|
205
|
+
// dependencies with a target framework
|
206
|
+
DependencyGroups?.Where(g => g.TargetFramework is not null).Select(g =>
|
207
|
+
new XElement(Namespace + "group",
|
208
|
+
new XAttribute("targetFramework", g.TargetFramework!),
|
209
|
+
g.Packages.Select(p =>
|
210
|
+
new XElement(Namespace + "dependency",
|
211
|
+
new XAttribute("id", p.Id),
|
212
|
+
new XAttribute("version", p.Version)
|
213
|
+
)
|
214
|
+
)
|
215
|
+
)
|
216
|
+
)
|
217
|
+
)
|
218
|
+
)
|
219
|
+
)
|
220
|
+
);
|
221
|
+
}
|
222
|
+
|
223
|
+
return _nuspec;
|
224
|
+
}
|
225
|
+
|
226
|
+
private static XElement WithNamespace(XElement element, XNamespace ns)
|
227
|
+
{
|
228
|
+
return new XElement(ns + element.Name.LocalName,
|
229
|
+
element.Attributes(),
|
230
|
+
element.Nodes().Select(n =>
|
231
|
+
{
|
232
|
+
if (n is XElement e)
|
233
|
+
{
|
234
|
+
return WithNamespace(e, ns);
|
235
|
+
}
|
236
|
+
|
237
|
+
return n;
|
238
|
+
})
|
239
|
+
);
|
240
|
+
}
|
241
|
+
|
242
|
+
private Stream GetZipStream()
|
243
|
+
{
|
244
|
+
if (_stream is null)
|
245
|
+
{
|
246
|
+
XDocument nuspec = GetNuspec();
|
247
|
+
_stream = new MemoryStream();
|
248
|
+
using ZipArchive zip = new(_stream, ZipArchiveMode.Create, leaveOpen: true);
|
249
|
+
ZipArchiveEntry nuspecEntry = zip.CreateEntry($"{Id}.nuspec");
|
250
|
+
using (Stream contentStream = nuspecEntry.Open())
|
251
|
+
using (XmlWriter writer = XmlWriter.Create(contentStream, WriterSettings))
|
252
|
+
{
|
253
|
+
nuspec.WriteTo(writer);
|
254
|
+
}
|
255
|
+
|
256
|
+
foreach (var file in Files ?? [])
|
257
|
+
{
|
258
|
+
ZipArchiveEntry fileEntry = zip.CreateEntry(file.Path);
|
259
|
+
using Stream contentStream = fileEntry.Open();
|
260
|
+
contentStream.Write(file.Content, 0, file.Content.Length);
|
261
|
+
}
|
262
|
+
}
|
263
|
+
|
264
|
+
_stream.Seek(0, SeekOrigin.Begin);
|
265
|
+
return _stream;
|
266
|
+
}
|
267
|
+
|
268
|
+
private static byte[] CreateAssembly(string assemblyName, string assemblyVersion)
|
269
|
+
{
|
270
|
+
CSharpCompilationOptions compilationOptions = new(OutputKind.DynamicallyLinkedLibrary);
|
271
|
+
CSharpCompilation compilation = CSharpCompilation.Create(assemblyName, options: compilationOptions)
|
272
|
+
.AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location))
|
273
|
+
.AddSyntaxTrees(CSharpSyntaxTree.ParseText($"[assembly: System.Reflection.AssemblyVersionAttribute(\"{assemblyVersion}\")]"));
|
274
|
+
MemoryStream assemblyStream = new();
|
275
|
+
EmitResult emitResult = compilation.Emit(assemblyStream);
|
276
|
+
if (!emitResult.Success)
|
277
|
+
{
|
278
|
+
throw new Exception($"Unable to create test assembly:\n\t{string.Join("\n\t", emitResult.Diagnostics.ToString())}");
|
279
|
+
}
|
280
|
+
|
281
|
+
return assemblyStream.ToArray();
|
282
|
+
}
|
283
|
+
|
284
|
+
// some well-known packages
|
285
|
+
public static MockNuGetPackage CentralPackageVersionsPackage =>
|
286
|
+
CreateMSBuildSdkPackage(
|
287
|
+
"Microsoft.Build.CentralPackageVersions",
|
288
|
+
"2.1.3",
|
289
|
+
sdkTargetsContent: """
|
290
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
291
|
+
<!-- this is a simplified version of this package used for testing -->
|
292
|
+
<PropertyGroup>
|
293
|
+
<CentralPackagesFile Condition=" '$(CentralPackagesFile)' == '' ">$([MSBuild]::GetPathOfFileAbove('Packages.props', $(MSBuildProjectDirectory)))</CentralPackagesFile>
|
294
|
+
</PropertyGroup>
|
295
|
+
<Import Project="$(CentralPackagesFile)" Condition="Exists('$(CentralPackagesFile)')" />
|
296
|
+
</Project>
|
297
|
+
"""
|
298
|
+
);
|
299
|
+
|
300
|
+
private static readonly Lazy<string> BundledVersionsPropsPath = new(() =>
|
301
|
+
{
|
302
|
+
// we need to find the file `Microsoft.NETCoreSdk.BundledVersions.props` in the SDK directory
|
303
|
+
|
304
|
+
DirectoryInfo projectDir = Directory.CreateTempSubdirectory("bundled_versions_props_path_discovery_");
|
305
|
+
try
|
306
|
+
{
|
307
|
+
// get the sdk version
|
308
|
+
string projectPath = Path.Combine(projectDir.FullName, "project.csproj");
|
309
|
+
File.WriteAllText(projectPath, """
|
310
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
311
|
+
<Target Name="_ReportCurrentSdkVersion">
|
312
|
+
<Message Text="_CurrentSdkVersion=$(NETCoreSdkVersion)" Importance="High" />
|
313
|
+
</Target>
|
314
|
+
</Project>
|
315
|
+
"""
|
316
|
+
);
|
317
|
+
var (exitCode, stdout, stderr) = ProcessEx.RunAsync("dotnet", $"msbuild {projectPath} /t:_ReportCurrentSdkVersion").Result;
|
318
|
+
if (exitCode != 0)
|
319
|
+
{
|
320
|
+
throw new Exception($"Failed to report the current SDK version:\n{stdout}\n{stderr}");
|
321
|
+
}
|
322
|
+
|
323
|
+
MatchCollection matches = Regex.Matches(stdout, "_CurrentSdkVersion=(?<SdkVersion>.*)$", RegexOptions.Multiline);
|
324
|
+
if (matches.Count == 0)
|
325
|
+
{
|
326
|
+
throw new Exception($"Failed to find the current SDK version in the output:\n{stdout}");
|
327
|
+
}
|
328
|
+
|
329
|
+
string sdkVersionString = matches.First().Groups["SdkVersion"].Value.Trim();
|
330
|
+
|
331
|
+
// find the actual SDK directory
|
332
|
+
string privateCoreLibPath = typeof(object).Assembly.Location; // e.g., C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.4\System.Private.CoreLib.dll
|
333
|
+
string sdkDirectory = Path.Combine(Path.GetDirectoryName(privateCoreLibPath)!, "..", "..", "..", "sdk", sdkVersionString); // e.g., C:\Program Files\dotnet\sdk\8.0.204
|
334
|
+
string bundledVersionsPropsPath = Path.Combine(sdkDirectory, "Microsoft.NETCoreSdk.BundledVersions.props");
|
335
|
+
FileInfo normalizedPath = new(bundledVersionsPropsPath);
|
336
|
+
return normalizedPath.FullName;
|
337
|
+
}
|
338
|
+
finally
|
339
|
+
{
|
340
|
+
projectDir.Delete(recursive: true);
|
341
|
+
}
|
342
|
+
});
|
343
|
+
|
344
|
+
private static readonly Dictionary<string, MockNuGetPackage> WellKnownPackages = new();
|
345
|
+
public static MockNuGetPackage WellKnownReferencePackage(string packageName, string targetFramework, (string Path, byte[] Content)[]? files = null)
|
346
|
+
{
|
347
|
+
string key = $"{packageName}/{targetFramework}";
|
348
|
+
if (!WellKnownPackages.ContainsKey(key))
|
349
|
+
{
|
350
|
+
// for the current SDK, the file `Microsoft.NETCoreSdk.BundledVersions.props` contains the version of the
|
351
|
+
// `Microsoft.WindowsDesktop.App.Ref` package that will be needed to build, so we find it by TFM
|
352
|
+
XDocument propsDocument = XDocument.Load(BundledVersionsPropsPath.Value);
|
353
|
+
XElement? matchingFrameworkElement = propsDocument.XPathSelectElement(
|
354
|
+
$"""
|
355
|
+
/Project/ItemGroup/KnownFrameworkReference
|
356
|
+
[
|
357
|
+
@Include='{packageName}' and
|
358
|
+
@TargetingPackName='{packageName}.Ref' and
|
359
|
+
@TargetFramework='{targetFramework}'
|
360
|
+
]
|
361
|
+
""");
|
362
|
+
if (matchingFrameworkElement is null)
|
363
|
+
{
|
364
|
+
throw new Exception($"Unable to find {packageName}.Ref version for target framework '{targetFramework}'");
|
365
|
+
}
|
366
|
+
|
367
|
+
string expectedVersion = matchingFrameworkElement.Attribute("TargetingPackVersion")!.Value;
|
368
|
+
return new(
|
369
|
+
$"{packageName}.Ref",
|
370
|
+
expectedVersion,
|
371
|
+
AdditionalMetadata:
|
372
|
+
[
|
373
|
+
new XElement("packageTypes",
|
374
|
+
new XElement("packageType",
|
375
|
+
new XAttribute("name", "DotnetPlatform")
|
376
|
+
)
|
377
|
+
)
|
378
|
+
],
|
379
|
+
Files: files
|
380
|
+
);
|
381
|
+
}
|
382
|
+
|
383
|
+
return WellKnownPackages[key];
|
384
|
+
}
|
385
|
+
|
386
|
+
public static MockNuGetPackage[] CommonPackages { get; } =
|
387
|
+
[
|
388
|
+
CreateSimplePackage("NETStandard.Library", "2.0.3", "netstandard2.0"),
|
389
|
+
new MockNuGetPackage("Microsoft.NETFramework.ReferenceAssemblies", "1.0.3"),
|
390
|
+
WellKnownReferencePackage("Microsoft.AspNetCore.App", "net6.0"),
|
391
|
+
WellKnownReferencePackage("Microsoft.AspNetCore.App", "net7.0"),
|
392
|
+
WellKnownReferencePackage("Microsoft.AspNetCore.App", "net8.0"),
|
393
|
+
WellKnownReferencePackage("Microsoft.NETCore.App", "net6.0",
|
394
|
+
[
|
395
|
+
("data/FrameworkList.xml", Encoding.UTF8.GetBytes("""
|
396
|
+
<FileList TargetFrameworkIdentifier=".NETCoreApp" TargetFrameworkVersion="6.0" FrameworkName="Microsoft.NETCore.App" Name=".NET Runtime">
|
397
|
+
</FileList>
|
398
|
+
"""))
|
399
|
+
]),
|
400
|
+
WellKnownReferencePackage("Microsoft.NETCore.App", "net7.0",
|
401
|
+
[
|
402
|
+
("data/FrameworkList.xml", Encoding.UTF8.GetBytes("""
|
403
|
+
<FileList TargetFrameworkIdentifier=".NETCoreApp" TargetFrameworkVersion="7.0" FrameworkName="Microsoft.NETCore.App" Name=".NET Runtime">
|
404
|
+
</FileList>
|
405
|
+
"""))
|
406
|
+
]),
|
407
|
+
WellKnownReferencePackage("Microsoft.NETCore.App", "net8.0",
|
408
|
+
[
|
409
|
+
("data/FrameworkList.xml", Encoding.UTF8.GetBytes("""
|
410
|
+
<FileList TargetFrameworkIdentifier=".NETCoreApp" TargetFrameworkVersion="8.0" FrameworkName="Microsoft.NETCore.App" Name=".NET Runtime">
|
411
|
+
</FileList>
|
412
|
+
"""))
|
413
|
+
]),
|
414
|
+
WellKnownReferencePackage("Microsoft.WindowsDesktop.App", "net6.0"),
|
415
|
+
WellKnownReferencePackage("Microsoft.WindowsDesktop.App", "net7.0"),
|
416
|
+
WellKnownReferencePackage("Microsoft.WindowsDesktop.App", "net8.0"),
|
417
|
+
];
|
418
|
+
}
|
419
|
+
}
|
@@ -12,6 +12,7 @@
|
|
12
12
|
|
13
13
|
<ItemGroup>
|
14
14
|
<PackageReference Include="DiffPlex" />
|
15
|
+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
|
15
16
|
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
16
17
|
<PackageReference Include="xunit" />
|
17
18
|
<PackageReference Include="xunit.runner.visualstudio" />
|
@@ -50,9 +50,14 @@ public sealed class TemporaryDirectory : IDisposable
|
|
50
50
|
var parentDirectory = Path.GetDirectoryName(temporaryDirectory.DirectoryPath)!;
|
51
51
|
|
52
52
|
// prevent directory crawling
|
53
|
-
await File.WriteAllTextAsync(Path.Combine(parentDirectory, "Directory.Build.props"), "
|
53
|
+
await File.WriteAllTextAsync(Path.Combine(parentDirectory, "Directory.Build.props"), """
|
54
|
+
<Project>
|
55
|
+
<PropertyGroup>
|
56
|
+
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
|
57
|
+
</PropertyGroup>
|
58
|
+
</Project>
|
59
|
+
""");
|
54
60
|
await File.WriteAllTextAsync(Path.Combine(parentDirectory, "Directory.Build.targets"), "<Project />");
|
55
|
-
await File.WriteAllTextAsync(Path.Combine(parentDirectory, "Directory.Packages.props"), "<Project />");
|
56
61
|
|
57
62
|
foreach (var (path, contents) in fileContents)
|
58
63
|
{
|
@@ -1,8 +1,3 @@
|
|
1
|
-
using System;
|
2
|
-
using System.IO;
|
3
|
-
using System.Linq;
|
4
|
-
using System.Threading.Tasks;
|
5
|
-
|
6
1
|
using Xunit;
|
7
2
|
|
8
3
|
namespace NuGetUpdater.Core.Test.Update;
|
@@ -20,11 +15,12 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
20
15
|
string projectContents,
|
21
16
|
bool isTransitive = false,
|
22
17
|
TestFile[]? additionalFiles = null,
|
18
|
+
MockNuGetPackage[]? packages = null,
|
23
19
|
string projectFilePath = "test-project.csproj")
|
24
20
|
{
|
25
21
|
return useSolution
|
26
|
-
? TestNoChangeforSolution(dependencyName, oldVersion, newVersion, projectFiles: [(projectFilePath, projectContents)], isTransitive, additionalFiles)
|
27
|
-
: TestNoChangeforProject(dependencyName, oldVersion, newVersion, projectContents, isTransitive, additionalFiles, projectFilePath);
|
22
|
+
? TestNoChangeforSolution(dependencyName, oldVersion, newVersion, projectFiles: [(projectFilePath, projectContents)], isTransitive, additionalFiles, packages)
|
23
|
+
: TestNoChangeforProject(dependencyName, oldVersion, newVersion, projectContents, isTransitive, additionalFiles, packages, projectFilePath);
|
28
24
|
}
|
29
25
|
|
30
26
|
protected static Task TestUpdate(
|
@@ -37,11 +33,12 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
37
33
|
bool isTransitive = false,
|
38
34
|
TestFile[]? additionalFiles = null,
|
39
35
|
TestFile[]? additionalFilesExpected = null,
|
36
|
+
MockNuGetPackage[]? packages = null,
|
40
37
|
string projectFilePath = "test-project.csproj")
|
41
38
|
{
|
42
39
|
return useSolution
|
43
|
-
? TestUpdateForSolution(dependencyName, oldVersion, newVersion, projectFiles: [(projectFilePath, projectContents)], projectFilesExpected: [(projectFilePath, expectedProjectContents)], isTransitive, additionalFiles, additionalFilesExpected)
|
44
|
-
: TestUpdateForProject(dependencyName, oldVersion, newVersion, projectFile: (projectFilePath, projectContents), expectedProjectContents, isTransitive, additionalFiles, additionalFilesExpected);
|
40
|
+
? TestUpdateForSolution(dependencyName, oldVersion, newVersion, projectFiles: [(projectFilePath, projectContents)], projectFilesExpected: [(projectFilePath, expectedProjectContents)], isTransitive, additionalFiles, additionalFilesExpected, packages)
|
41
|
+
: TestUpdateForProject(dependencyName, oldVersion, newVersion, projectFile: (projectFilePath, projectContents), expectedProjectContents, isTransitive, additionalFiles, additionalFilesExpected, packages);
|
45
42
|
}
|
46
43
|
|
47
44
|
protected static Task TestUpdate(
|
@@ -53,11 +50,12 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
53
50
|
string expectedProjectContents,
|
54
51
|
bool isTransitive = false,
|
55
52
|
TestFile[]? additionalFiles = null,
|
56
|
-
TestFile[]? additionalFilesExpected = null
|
53
|
+
TestFile[]? additionalFilesExpected = null,
|
54
|
+
MockNuGetPackage[]? packages = null)
|
57
55
|
{
|
58
56
|
return useSolution
|
59
|
-
? TestUpdateForSolution(dependencyName, oldVersion, newVersion, projectFiles: [projectFile], projectFilesExpected: [(projectFile.Path, expectedProjectContents)], isTransitive, additionalFiles, additionalFilesExpected)
|
60
|
-
: TestUpdateForProject(dependencyName, oldVersion, newVersion, projectFile, expectedProjectContents, isTransitive, additionalFiles, additionalFilesExpected);
|
57
|
+
? TestUpdateForSolution(dependencyName, oldVersion, newVersion, projectFiles: [projectFile], projectFilesExpected: [(projectFile.Path, expectedProjectContents)], isTransitive, additionalFiles, additionalFilesExpected, packages)
|
58
|
+
: TestUpdateForProject(dependencyName, oldVersion, newVersion, projectFile, expectedProjectContents, isTransitive, additionalFiles, additionalFilesExpected, packages);
|
61
59
|
}
|
62
60
|
|
63
61
|
protected static Task TestNoChangeforProject(
|
@@ -67,6 +65,7 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
67
65
|
string projectContents,
|
68
66
|
bool isTransitive = false,
|
69
67
|
TestFile[]? additionalFiles = null,
|
68
|
+
MockNuGetPackage[]? packages = null,
|
70
69
|
string projectFilePath = "test-project.csproj")
|
71
70
|
=> TestUpdateForProject(
|
72
71
|
dependencyName,
|
@@ -76,7 +75,8 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
76
75
|
expectedProjectContents: projectContents,
|
77
76
|
isTransitive,
|
78
77
|
additionalFiles,
|
79
|
-
additionalFilesExpected: additionalFiles
|
78
|
+
additionalFilesExpected: additionalFiles,
|
79
|
+
packages: packages);
|
80
80
|
|
81
81
|
protected static Task TestUpdateForProject(
|
82
82
|
string dependencyName,
|
@@ -87,6 +87,7 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
87
87
|
bool isTransitive = false,
|
88
88
|
TestFile[]? additionalFiles = null,
|
89
89
|
TestFile[]? additionalFilesExpected = null,
|
90
|
+
MockNuGetPackage[]? packages = null,
|
90
91
|
string projectFilePath = "test-project.csproj")
|
91
92
|
=> TestUpdateForProject(
|
92
93
|
dependencyName,
|
@@ -96,7 +97,8 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
96
97
|
expectedProjectContents,
|
97
98
|
isTransitive,
|
98
99
|
additionalFiles,
|
99
|
-
additionalFilesExpected
|
100
|
+
additionalFilesExpected,
|
101
|
+
packages);
|
100
102
|
|
101
103
|
protected static async Task TestUpdateForProject(
|
102
104
|
string dependencyName,
|
@@ -106,21 +108,36 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
106
108
|
string expectedProjectContents,
|
107
109
|
bool isTransitive = false,
|
108
110
|
TestFile[]? additionalFiles = null,
|
109
|
-
TestFile[]? additionalFilesExpected = null
|
111
|
+
TestFile[]? additionalFilesExpected = null,
|
112
|
+
MockNuGetPackage[]? packages = null)
|
110
113
|
{
|
111
114
|
additionalFiles ??= [];
|
112
115
|
additionalFilesExpected ??= [];
|
113
116
|
|
117
|
+
var placeFilesInSrc = packages is not null;
|
118
|
+
|
114
119
|
var projectFilePath = projectFile.Path;
|
115
120
|
var testFiles = new[] { projectFile }.Concat(additionalFiles).ToArray();
|
121
|
+
if (placeFilesInSrc)
|
122
|
+
{
|
123
|
+
testFiles = testFiles.Select(f => ($"src/{f.Path}", f.Content)).ToArray();
|
124
|
+
}
|
116
125
|
|
117
126
|
var actualResult = await RunUpdate(testFiles, async temporaryDirectory =>
|
118
127
|
{
|
128
|
+
await MockNuGetPackagesInDirectory(packages, temporaryDirectory);
|
129
|
+
|
130
|
+
// run update
|
119
131
|
var worker = new UpdaterWorker(new Logger(verbose: true));
|
120
|
-
|
132
|
+
var projectPath = placeFilesInSrc ? $"src/{projectFilePath}" : projectFilePath;
|
133
|
+
await worker.RunAsync(temporaryDirectory, projectPath, dependencyName, oldVersion, newVersion, isTransitive);
|
121
134
|
});
|
122
135
|
|
123
136
|
var expectedResult = additionalFilesExpected.Prepend((projectFilePath, expectedProjectContents)).ToArray();
|
137
|
+
if (placeFilesInSrc)
|
138
|
+
{
|
139
|
+
expectedResult = expectedResult.Select(er => ($"src/{er.Item1}", er.Item2)).ToArray();
|
140
|
+
}
|
124
141
|
|
125
142
|
AssertContainsFiles(expectedResult, actualResult);
|
126
143
|
}
|
@@ -131,7 +148,8 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
131
148
|
string newVersion,
|
132
149
|
TestFile[] projectFiles,
|
133
150
|
bool isTransitive = false,
|
134
|
-
TestFile[]? additionalFiles = null
|
151
|
+
TestFile[]? additionalFiles = null,
|
152
|
+
MockNuGetPackage[]? packages = null)
|
135
153
|
=> TestUpdateForSolution(
|
136
154
|
dependencyName,
|
137
155
|
oldVersion,
|
@@ -140,7 +158,8 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
140
158
|
projectFilesExpected: projectFiles,
|
141
159
|
isTransitive,
|
142
160
|
additionalFiles,
|
143
|
-
additionalFilesExpected: additionalFiles
|
161
|
+
additionalFilesExpected: additionalFiles,
|
162
|
+
packages: packages);
|
144
163
|
|
145
164
|
protected static async Task TestUpdateForSolution(
|
146
165
|
string dependencyName,
|
@@ -150,7 +169,8 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
150
169
|
TestFile[] projectFilesExpected,
|
151
170
|
bool isTransitive = false,
|
152
171
|
TestFile[]? additionalFiles = null,
|
153
|
-
TestFile[]? additionalFilesExpected = null
|
172
|
+
TestFile[]? additionalFilesExpected = null,
|
173
|
+
MockNuGetPackage[]? packages = null)
|
154
174
|
{
|
155
175
|
additionalFiles ??= [];
|
156
176
|
additionalFilesExpected ??= [];
|
@@ -191,6 +211,8 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
191
211
|
|
192
212
|
var actualResult = await RunUpdate(testFiles, async temporaryDirectory =>
|
193
213
|
{
|
214
|
+
await MockNuGetPackagesInDirectory(packages, temporaryDirectory);
|
215
|
+
|
194
216
|
var slnPath = Path.Combine(temporaryDirectory, slnName);
|
195
217
|
var worker = new UpdaterWorker(new Logger(verbose: true));
|
196
218
|
await worker.RunAsync(temporaryDirectory, slnPath, dependencyName, oldVersion, newVersion, isTransitive);
|
@@ -201,6 +223,42 @@ public abstract class UpdateWorkerTestBase : TestBase
|
|
201
223
|
AssertContainsFiles(expectedResult, actualResult);
|
202
224
|
}
|
203
225
|
|
226
|
+
public static async Task MockNuGetPackagesInDirectory(MockNuGetPackage[]? packages, string temporaryDirectory)
|
227
|
+
{
|
228
|
+
if (packages is not null)
|
229
|
+
{
|
230
|
+
string localFeedPath = Path.Join(temporaryDirectory, "local-feed");
|
231
|
+
Directory.CreateDirectory(localFeedPath);
|
232
|
+
MockNuGetPackage[] allPackages = packages.Concat(MockNuGetPackage.CommonPackages).ToArray();
|
233
|
+
|
234
|
+
// write all packages to disk
|
235
|
+
foreach (MockNuGetPackage package in allPackages)
|
236
|
+
{
|
237
|
+
package.WriteToDirectory(localFeedPath);
|
238
|
+
}
|
239
|
+
|
240
|
+
// override various nuget locations
|
241
|
+
foreach (var envName in new[] { "NUGET_PACKAGES", "NUGET_HTTP_CACHE_PATH", "NUGET_SCRATCH", "NUGET_PLUGINS_CACHE_PATH" })
|
242
|
+
{
|
243
|
+
string dir = Path.Join(temporaryDirectory, envName);
|
244
|
+
Directory.CreateDirectory(dir);
|
245
|
+
Environment.SetEnvironmentVariable(envName, dir);
|
246
|
+
}
|
247
|
+
|
248
|
+
// ensure only the test feed is used
|
249
|
+
await File.WriteAllTextAsync(Path.Join(temporaryDirectory, "NuGet.Config"), $"""
|
250
|
+
<?xml version="1.0" encoding="utf-8"?>
|
251
|
+
<configuration>
|
252
|
+
<packageSources>
|
253
|
+
<clear />
|
254
|
+
<add key="local-feed" value="{localFeedPath}" />
|
255
|
+
</packageSources>
|
256
|
+
</configuration>
|
257
|
+
"""
|
258
|
+
);
|
259
|
+
}
|
260
|
+
}
|
261
|
+
|
204
262
|
protected static async Task<TestFile[]> RunUpdate(TestFile[] files, Func<string, Task> action)
|
205
263
|
{
|
206
264
|
// write initial files
|