dependabot-nuget 0.267.0 → 0.270.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/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +6 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +16 -13
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/Requirement.cs +8 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +33 -14
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/DependencyConflictResolver.cs +689 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +226 -23
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +84 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/RequirementTests.cs +14 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryEnvironment.cs +23 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +164 -55
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +186 -10
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +785 -1
- data/lib/dependabot/nuget/file_updater.rb +44 -22
- data/lib/dependabot/nuget/native_helpers.rb +6 -1
- metadata +7 -5
@@ -13,9 +13,12 @@ using Microsoft.Build.Exceptions;
|
|
13
13
|
using Microsoft.Build.Locator;
|
14
14
|
using Microsoft.Extensions.FileSystemGlobbing;
|
15
15
|
|
16
|
+
using NuGet;
|
16
17
|
using NuGet.Configuration;
|
18
|
+
using NuGet.Frameworks;
|
17
19
|
using NuGet.Versioning;
|
18
20
|
|
21
|
+
using NuGetUpdater.Core.Analyze;
|
19
22
|
using NuGetUpdater.Core.Utilities;
|
20
23
|
|
21
24
|
namespace NuGetUpdater.Core;
|
@@ -31,29 +34,54 @@ internal static partial class MSBuildHelper
|
|
31
34
|
// Ensure MSBuild types are registered before calling a method that loads the types
|
32
35
|
if (!IsMSBuildRegistered)
|
33
36
|
{
|
34
|
-
|
35
|
-
var globalJsonPaths = candidateDirectories.Select(d => Path.Combine(d, "global.json")).Where(File.Exists).Select(p => (p, p + Guid.NewGuid().ToString())).ToArray();
|
36
|
-
foreach (var (globalJsonPath, tempGlobalJsonPath) in globalJsonPaths)
|
37
|
-
{
|
38
|
-
Console.WriteLine($"Temporarily removing `global.json` from `{Path.GetDirectoryName(globalJsonPath)}` for MSBuild detection.");
|
39
|
-
File.Move(globalJsonPath, tempGlobalJsonPath);
|
40
|
-
}
|
41
|
-
|
42
|
-
try
|
37
|
+
SidelineGlobalJsonAsync(currentDirectory, rootDirectory, () =>
|
43
38
|
{
|
44
39
|
var defaultInstance = MSBuildLocator.QueryVisualStudioInstances().First();
|
45
40
|
MSBuildPath = defaultInstance.MSBuildPath;
|
46
41
|
MSBuildLocator.RegisterInstance(defaultInstance);
|
47
|
-
|
48
|
-
|
42
|
+
return Task.CompletedTask;
|
43
|
+
}).Wait();
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
public static async Task SidelineGlobalJsonAsync(string currentDirectory, string rootDirectory, Func<Task> action, bool retainMSBuildSdks = false)
|
48
|
+
{
|
49
|
+
var candidateDirectories = PathHelper.GetAllDirectoriesToRoot(currentDirectory, rootDirectory);
|
50
|
+
var globalJsonPaths = candidateDirectories.Select(d => Path.Combine(d, "global.json")).Where(File.Exists).Select(p => (p, p + Guid.NewGuid().ToString())).ToArray();
|
51
|
+
foreach (var (globalJsonPath, tempGlobalJsonPath) in globalJsonPaths)
|
52
|
+
{
|
53
|
+
Console.WriteLine($"Temporarily removing `global.json` from `{Path.GetDirectoryName(globalJsonPath)}`{(retainMSBuildSdks ? " and retaining MSBuild SDK declarations" : string.Empty)}.");
|
54
|
+
File.Move(globalJsonPath, tempGlobalJsonPath);
|
55
|
+
if (retainMSBuildSdks)
|
49
56
|
{
|
50
|
-
|
57
|
+
// custom SDKs might need to be retained for other operations; rebuild `global.json` with only the relevant key
|
58
|
+
var originalContent = await File.ReadAllTextAsync(tempGlobalJsonPath);
|
59
|
+
var jsonNode = JsonHelper.ParseNode(originalContent);
|
60
|
+
if (jsonNode is JsonObject obj &&
|
61
|
+
obj.TryGetPropertyValue("msbuild-sdks", out var sdks) &&
|
62
|
+
sdks is not null)
|
51
63
|
{
|
52
|
-
|
53
|
-
|
64
|
+
var newObj = new JsonObject()
|
65
|
+
{
|
66
|
+
["msbuild-sdks"] = sdks.DeepClone(),
|
67
|
+
};
|
68
|
+
await File.WriteAllTextAsync(globalJsonPath, newObj.ToJsonString());
|
54
69
|
}
|
55
70
|
}
|
56
71
|
}
|
72
|
+
|
73
|
+
try
|
74
|
+
{
|
75
|
+
await action();
|
76
|
+
}
|
77
|
+
finally
|
78
|
+
{
|
79
|
+
foreach (var (globalJsonpath, tempGlobalJsonPath) in globalJsonPaths)
|
80
|
+
{
|
81
|
+
Console.WriteLine($"Restoring `global.json` to `{Path.GetDirectoryName(globalJsonpath)}`.");
|
82
|
+
File.Move(tempGlobalJsonPath, globalJsonpath, overwrite: retainMSBuildSdks);
|
83
|
+
}
|
84
|
+
}
|
57
85
|
}
|
58
86
|
|
59
87
|
public static IEnumerable<string> GetProjectPathsFromSolution(string solutionPath)
|
@@ -306,7 +334,182 @@ internal static partial class MSBuildHelper
|
|
306
334
|
}
|
307
335
|
}
|
308
336
|
|
309
|
-
internal static
|
337
|
+
internal static bool UseNewDependencySolver()
|
338
|
+
{
|
339
|
+
return Environment.GetEnvironmentVariable("UseNewNugetPackageResolver") == "true";
|
340
|
+
}
|
341
|
+
|
342
|
+
internal static async Task<Dependency[]?> ResolveDependencyConflicts(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Dependency[] update, Logger logger)
|
343
|
+
{
|
344
|
+
if (UseNewDependencySolver())
|
345
|
+
{
|
346
|
+
return await ResolveDependencyConflictsNew(repoRoot, projectPath, targetFramework, packages, update, logger);
|
347
|
+
}
|
348
|
+
else
|
349
|
+
{
|
350
|
+
return await ResolveDependencyConflictsOld(repoRoot, projectPath, targetFramework, packages, logger);
|
351
|
+
}
|
352
|
+
}
|
353
|
+
|
354
|
+
internal static async Task<Dependency[]?> ResolveDependencyConflictsNew(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Dependency[] update, Logger logger)
|
355
|
+
{
|
356
|
+
var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
|
357
|
+
PackageManager packageManager = new PackageManager(repoRoot, projectPath);
|
358
|
+
|
359
|
+
try
|
360
|
+
{
|
361
|
+
string tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages);
|
362
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunAsync("dotnet", $"restore \"{tempProjectPath}\"", workingDirectory: tempDirectory.FullName);
|
363
|
+
|
364
|
+
// Add Dependency[] packages to List<PackageToUpdate> existingPackages
|
365
|
+
List<PackageToUpdate> existingPackages = packages
|
366
|
+
.Select(existingPackage => new PackageToUpdate
|
367
|
+
{
|
368
|
+
PackageName = existingPackage.Name,
|
369
|
+
CurrentVersion = existingPackage.Version
|
370
|
+
})
|
371
|
+
.ToList();
|
372
|
+
|
373
|
+
// Add Dependency[] update to List<PackageToUpdate> packagesToUpdate
|
374
|
+
List<PackageToUpdate> packagesToUpdate = update
|
375
|
+
.Where(package => package.Version != null)
|
376
|
+
.Select(package => new PackageToUpdate
|
377
|
+
{
|
378
|
+
PackageName = package.Name,
|
379
|
+
NewVersion = package.Version.ToString()
|
380
|
+
})
|
381
|
+
.ToList();
|
382
|
+
|
383
|
+
foreach (PackageToUpdate existing in existingPackages)
|
384
|
+
{
|
385
|
+
var foundPackage = packagesToUpdate.Where(p => string.Equals(p.PackageName, existing.PackageName, StringComparison.OrdinalIgnoreCase));
|
386
|
+
if (!foundPackage.Any())
|
387
|
+
{
|
388
|
+
existing.NewVersion = existing.CurrentVersion;
|
389
|
+
}
|
390
|
+
}
|
391
|
+
|
392
|
+
// Create a duplicate set of existingPackages for flexible package reference addition and removal
|
393
|
+
List<PackageToUpdate> existingDuplicate = new List<PackageToUpdate>(existingPackages);
|
394
|
+
|
395
|
+
// Bool to keep track of if anything was added to the existingDuplicate list
|
396
|
+
bool added = false;
|
397
|
+
|
398
|
+
// If package 'isnt there, add it to the existingDuplicate list
|
399
|
+
foreach (PackageToUpdate package in packagesToUpdate)
|
400
|
+
{
|
401
|
+
if (!existingDuplicate.Any(p => string.Equals(p.PackageName, package.PackageName, StringComparison.OrdinalIgnoreCase)))
|
402
|
+
{
|
403
|
+
existingDuplicate.Add(package);
|
404
|
+
added = true;
|
405
|
+
}
|
406
|
+
}
|
407
|
+
|
408
|
+
// If you have to use the existingDuplicate list
|
409
|
+
if (added == true)
|
410
|
+
{
|
411
|
+
// Add existing versions to existing list
|
412
|
+
packageManager.UpdateExistingPackagesWithNewVersions(existingDuplicate, packagesToUpdate);
|
413
|
+
|
414
|
+
// Make relationships
|
415
|
+
await packageManager.PopulatePackageDependenciesAsync(existingDuplicate, targetFramework, Path.GetDirectoryName(projectPath));
|
416
|
+
|
417
|
+
// Update all to new versions
|
418
|
+
foreach (var package in existingDuplicate)
|
419
|
+
{
|
420
|
+
string updateResult = await packageManager.UpdateVersion(existingDuplicate, package, targetFramework, Path.GetDirectoryName(projectPath));
|
421
|
+
}
|
422
|
+
}
|
423
|
+
|
424
|
+
// Editing existing list because nothing was added to existingDuplicate
|
425
|
+
else
|
426
|
+
{
|
427
|
+
// Add existing versions to existing list
|
428
|
+
packageManager.UpdateExistingPackagesWithNewVersions(existingPackages, packagesToUpdate);
|
429
|
+
|
430
|
+
// Make relationships
|
431
|
+
await packageManager.PopulatePackageDependenciesAsync(existingPackages, targetFramework, Path.GetDirectoryName(projectPath));
|
432
|
+
|
433
|
+
// Update all to new versions
|
434
|
+
foreach (var package in existingPackages)
|
435
|
+
{
|
436
|
+
string updateResult = await packageManager.UpdateVersion(existingPackages, package, targetFramework, Path.GetDirectoryName(projectPath));
|
437
|
+
}
|
438
|
+
}
|
439
|
+
|
440
|
+
// Make new list to remove and differentiate between existingDuplicate and existingPackages lists
|
441
|
+
List<PackageToUpdate> packagesToRemove = existingDuplicate
|
442
|
+
.Where(existingPackageDupe => !existingPackages.Contains(existingPackageDupe) && existingPackageDupe.IsSpecific == true)
|
443
|
+
.ToList();
|
444
|
+
|
445
|
+
foreach (PackageToUpdate package in packagesToRemove)
|
446
|
+
{
|
447
|
+
existingDuplicate.Remove(package);
|
448
|
+
}
|
449
|
+
|
450
|
+
if (existingDuplicate != null)
|
451
|
+
{
|
452
|
+
existingPackages = existingDuplicate;
|
453
|
+
}
|
454
|
+
|
455
|
+
// Convert back to Dependency [], use NewVersion if available, otherwise use CurrentVersion
|
456
|
+
List<Dependency> candidatePackages = existingPackages
|
457
|
+
.Select(package => new Dependency(
|
458
|
+
package.PackageName,
|
459
|
+
package.NewVersion ?? package.CurrentVersion,
|
460
|
+
DependencyType.Unknown,
|
461
|
+
null,
|
462
|
+
null,
|
463
|
+
false,
|
464
|
+
false,
|
465
|
+
false,
|
466
|
+
false,
|
467
|
+
false
|
468
|
+
))
|
469
|
+
.ToList();
|
470
|
+
|
471
|
+
// Return as array
|
472
|
+
Dependency[] candidatePackagesArray = candidatePackages.ToArray();
|
473
|
+
|
474
|
+
var targetFrameworks = new NuGetFramework[] { NuGetFramework.Parse(targetFramework) };
|
475
|
+
|
476
|
+
var resolveProjectPath = projectPath;
|
477
|
+
|
478
|
+
if (!Path.IsPathRooted(resolveProjectPath) || !File.Exists(resolveProjectPath))
|
479
|
+
{
|
480
|
+
resolveProjectPath = Path.GetFullPath(Path.Join(repoRoot, resolveProjectPath));
|
481
|
+
}
|
482
|
+
|
483
|
+
NuGetContext nugetContext = new NuGetContext(Path.GetDirectoryName(resolveProjectPath));
|
484
|
+
|
485
|
+
// Target framework compatibility check
|
486
|
+
foreach (var package in candidatePackages)
|
487
|
+
{
|
488
|
+
if (!NuGetVersion.TryParse(package.Version, out var nuGetVersion))
|
489
|
+
{
|
490
|
+
// If version is not valid, return original packages and revert
|
491
|
+
return packages;
|
492
|
+
}
|
493
|
+
|
494
|
+
var packageIdentity = new NuGet.Packaging.Core.PackageIdentity(package.Name, nuGetVersion);
|
495
|
+
|
496
|
+
bool isNewPackageCompatible = await CompatibilityChecker.CheckAsync(packageIdentity, targetFrameworks.ToImmutableArray(), nugetContext, logger, CancellationToken.None);
|
497
|
+
if (!isNewPackageCompatible)
|
498
|
+
{
|
499
|
+
// If the package target framework is not compatible, return original packages and revert
|
500
|
+
return packages;
|
501
|
+
}
|
502
|
+
}
|
503
|
+
|
504
|
+
return candidatePackagesArray;
|
505
|
+
}
|
506
|
+
finally
|
507
|
+
{
|
508
|
+
tempDirectory.Delete(recursive: true);
|
509
|
+
}
|
510
|
+
}
|
511
|
+
|
512
|
+
internal static async Task<Dependency[]?> ResolveDependencyConflictsOld(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Logger logger)
|
310
513
|
{
|
311
514
|
var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
|
312
515
|
try
|
@@ -334,22 +537,22 @@ internal static partial class MSBuildHelper
|
|
334
537
|
Dictionary<string, HashSet<NuGetVersion>> badPackagesAndCandidateVersionsDictionary = new(StringComparer.OrdinalIgnoreCase);
|
335
538
|
|
336
539
|
// and for each of those packages, find all versions greater than the one that's currently installed
|
337
|
-
foreach ((string
|
540
|
+
foreach ((string PackageName, NuGetVersion packageVersion) in badPackagesAndVersions)
|
338
541
|
{
|
339
542
|
// this command dumps a JSON object with all versions of the specified package from all package sources
|
340
|
-
(exitCode, stdOut, stdErr) = await ProcessEx.RunAsync("dotnet", $"package search {
|
543
|
+
(exitCode, stdOut, stdErr) = await ProcessEx.RunAsync("dotnet", $"package search {PackageName} --exact-match --format json", workingDirectory: tempDirectory.FullName);
|
341
544
|
if (exitCode != 0)
|
342
545
|
{
|
343
546
|
continue;
|
344
547
|
}
|
345
548
|
|
346
549
|
// ensure collection exists
|
347
|
-
if (!badPackagesAndCandidateVersionsDictionary.ContainsKey(
|
550
|
+
if (!badPackagesAndCandidateVersionsDictionary.ContainsKey(PackageName))
|
348
551
|
{
|
349
|
-
badPackagesAndCandidateVersionsDictionary.Add(
|
552
|
+
badPackagesAndCandidateVersionsDictionary.Add(PackageName, new HashSet<NuGetVersion>());
|
350
553
|
}
|
351
554
|
|
352
|
-
HashSet<NuGetVersion> foundVersions = badPackagesAndCandidateVersionsDictionary[
|
555
|
+
HashSet<NuGetVersion> foundVersions = badPackagesAndCandidateVersionsDictionary[PackageName];
|
353
556
|
|
354
557
|
var json = JsonHelper.ParseNode(stdOut);
|
355
558
|
if (json?["searchResult"] is JsonArray searchResults)
|
@@ -580,9 +783,9 @@ internal static partial class MSBuildHelper
|
|
580
783
|
.Where(match => match.Success)
|
581
784
|
.Select(match =>
|
582
785
|
{
|
583
|
-
var
|
584
|
-
var isTransitive = !topLevelPackagesNames.Contains(
|
585
|
-
return new Dependency(
|
786
|
+
var PackageName = match.Groups["PackageName"].Value;
|
787
|
+
var isTransitive = !topLevelPackagesNames.Contains(PackageName);
|
788
|
+
return new Dependency(PackageName, match.Groups["PackageVersion"].Value, DependencyType.Unknown, TargetFrameworks: tfms, IsTransitive: isTransitive);
|
586
789
|
})
|
587
790
|
.ToArray();
|
588
791
|
|
@@ -264,6 +264,46 @@ public partial class AnalyzeWorkerTests : AnalyzeWorkerTestBase
|
|
264
264
|
|
265
265
|
[Fact]
|
266
266
|
public async Task ReturnsUpToDate_ForMissingDependency()
|
267
|
+
{
|
268
|
+
await TestAnalyzeAsync(
|
269
|
+
packages:
|
270
|
+
[
|
271
|
+
// no packages listed
|
272
|
+
],
|
273
|
+
discovery: new()
|
274
|
+
{
|
275
|
+
Path = "/",
|
276
|
+
Projects = [
|
277
|
+
new()
|
278
|
+
{
|
279
|
+
FilePath = "./project.csproj",
|
280
|
+
TargetFrameworks = ["net8.0"],
|
281
|
+
Dependencies = [
|
282
|
+
new("Some.Package", "1.0.0", DependencyType.PackageReference), // this was found in the source, but doesn't exist in any feed
|
283
|
+
],
|
284
|
+
},
|
285
|
+
],
|
286
|
+
},
|
287
|
+
dependencyInfo: new()
|
288
|
+
{
|
289
|
+
Name = "Some.Package",
|
290
|
+
Version = "1.0.0",
|
291
|
+
IgnoredVersions = [],
|
292
|
+
IsVulnerable = false,
|
293
|
+
Vulnerabilities = [],
|
294
|
+
},
|
295
|
+
expectedResult: new()
|
296
|
+
{
|
297
|
+
UpdatedVersion = "1.0.0",
|
298
|
+
CanUpdate = false,
|
299
|
+
VersionComesFromMultiDependencyProperty = false,
|
300
|
+
UpdatedDependencies = [],
|
301
|
+
}
|
302
|
+
);
|
303
|
+
}
|
304
|
+
|
305
|
+
[Fact]
|
306
|
+
public async Task ReturnsUpToDate_ForIgnoredRequirements()
|
267
307
|
{
|
268
308
|
await TestAnalyzeAsync(
|
269
309
|
packages:
|
@@ -307,6 +347,50 @@ public partial class AnalyzeWorkerTests : AnalyzeWorkerTestBase
|
|
307
347
|
);
|
308
348
|
}
|
309
349
|
|
350
|
+
[Fact]
|
351
|
+
public async Task IgnoredVersionsCanHandleWildcardSpecification()
|
352
|
+
{
|
353
|
+
await TestAnalyzeAsync(
|
354
|
+
packages:
|
355
|
+
[
|
356
|
+
MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0"), // initially this
|
357
|
+
MockNuGetPackage.CreateSimplePackage("Some.Package", "1.1.0", "net8.0"), // should update to this
|
358
|
+
MockNuGetPackage.CreateSimplePackage("Some.Package", "1.2.0", "net8.0"), // `IgnoredVersions` should prevent this from being selected
|
359
|
+
],
|
360
|
+
discovery: new()
|
361
|
+
{
|
362
|
+
Path = "/",
|
363
|
+
Projects = [
|
364
|
+
new()
|
365
|
+
{
|
366
|
+
FilePath = "./project.csproj",
|
367
|
+
TargetFrameworks = ["net8.0"],
|
368
|
+
Dependencies = [
|
369
|
+
new("Some.Package", "1.0.0", DependencyType.PackageReference),
|
370
|
+
],
|
371
|
+
},
|
372
|
+
],
|
373
|
+
},
|
374
|
+
dependencyInfo: new()
|
375
|
+
{
|
376
|
+
Name = "Some.Package",
|
377
|
+
Version = "1.0.0",
|
378
|
+
IgnoredVersions = [Requirement.Parse("> 1.1.*")],
|
379
|
+
IsVulnerable = false,
|
380
|
+
Vulnerabilities = [],
|
381
|
+
},
|
382
|
+
expectedResult: new()
|
383
|
+
{
|
384
|
+
UpdatedVersion = "1.1.0",
|
385
|
+
CanUpdate = true,
|
386
|
+
VersionComesFromMultiDependencyProperty = false,
|
387
|
+
UpdatedDependencies = [
|
388
|
+
new("Some.Package", "1.1.0", DependencyType.Unknown, TargetFrameworks: ["net8.0"]),
|
389
|
+
],
|
390
|
+
}
|
391
|
+
);
|
392
|
+
}
|
393
|
+
|
310
394
|
[Fact]
|
311
395
|
public async Task VersionFinderCanHandle404FromPackageSource_V2()
|
312
396
|
{
|
@@ -33,6 +33,8 @@ public class RequirementTests
|
|
33
33
|
[InlineData("1", "~> 1", true)]
|
34
34
|
[InlineData("2", "~> 1", false)]
|
35
35
|
[InlineData("5.3.8", "< 6, > 5.2.4", true)]
|
36
|
+
[InlineData("1.0-preview", ">= 1.x", false)] // wildcards
|
37
|
+
[InlineData("1.1-preview", ">= 1.x", true)]
|
36
38
|
public void IsSatisfiedBy(string versionString, string requirementString, bool expected)
|
37
39
|
{
|
38
40
|
var version = NuGetVersion.Parse(versionString);
|
@@ -43,6 +45,18 @@ public class RequirementTests
|
|
43
45
|
Assert.Equal(expected, actual);
|
44
46
|
}
|
45
47
|
|
48
|
+
[Theory]
|
49
|
+
[InlineData("> 1.*", "> 1.0")] // standard wildcard, single digit
|
50
|
+
[InlineData("> 1.2.*", "> 1.2.0")] // standard wildcard, multiple digit
|
51
|
+
[InlineData("> 1.a", "> 1.0")] // alternate wildcard, single digit
|
52
|
+
[InlineData("> 1.2.a", "> 1.2.0")] // alternate wildcard, multiple digit
|
53
|
+
public void Parse_ConvertsWildcardInVersion(string givenRequirementString, string expectedRequirementString)
|
54
|
+
{
|
55
|
+
var parsedRequirement = Requirement.Parse(givenRequirementString);
|
56
|
+
var actualRequirementString = parsedRequirement.ToString();
|
57
|
+
Assert.Equal(expectedRequirementString, actualRequirementString);
|
58
|
+
}
|
59
|
+
|
46
60
|
[Theory]
|
47
61
|
[InlineData("> = 1.0.0")] // Invalid format
|
48
62
|
[InlineData("<>= 1.0.0")] // Invalid Operator
|
@@ -0,0 +1,23 @@
|
|
1
|
+
namespace NuGetUpdater.Core.Test;
|
2
|
+
|
3
|
+
public class TemporaryEnvironment : IDisposable
|
4
|
+
{
|
5
|
+
private readonly List<(string Name, string? Value)> _originalVariables = new();
|
6
|
+
|
7
|
+
public TemporaryEnvironment((string Name, string Value)[] variables)
|
8
|
+
{
|
9
|
+
foreach (var (name, value) in variables)
|
10
|
+
{
|
11
|
+
_originalVariables.Add((name, Environment.GetEnvironmentVariable(name)));
|
12
|
+
Environment.SetEnvironmentVariable(name, value);
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
public void Dispose()
|
17
|
+
{
|
18
|
+
foreach (var (name, value) in _originalVariables)
|
19
|
+
{
|
20
|
+
Environment.SetEnvironmentVariable(name, value);
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|