dependabot-nuget 0.252.0 → 0.254.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +27 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +66 -65
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +21 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +44 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/JsonHelper.cs +4 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +181 -93
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +18 -13
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +24 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs +18 -10
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +25 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestBase.cs +10 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackagesConfigUpdaterTests.cs +1 -8
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs +0 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DotNetTools.cs +0 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs +0 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +0 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +55 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +30 -23
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/JsonHelperTests.cs +57 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +44 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/SdkPackageUpdaterHelperTests.cs +1 -1
- data/lib/dependabot/nuget/discovery/discovery_json_reader.rb +0 -2
- data/lib/dependabot/nuget/file_parser.rb +14 -6
- metadata +16 -29
@@ -2,6 +2,7 @@ using System.Collections.Immutable;
|
|
2
2
|
using System.Diagnostics.CodeAnalysis;
|
3
3
|
using System.Text;
|
4
4
|
using System.Text.Json;
|
5
|
+
using System.Text.Json.Nodes;
|
5
6
|
using System.Text.RegularExpressions;
|
6
7
|
using System.Xml;
|
7
8
|
|
@@ -13,6 +14,7 @@ using Microsoft.Build.Locator;
|
|
13
14
|
using Microsoft.Extensions.FileSystemGlobbing;
|
14
15
|
|
15
16
|
using NuGet.Configuration;
|
17
|
+
using NuGet.Versioning;
|
16
18
|
|
17
19
|
using NuGetUpdater.Core.Utilities;
|
18
20
|
|
@@ -24,106 +26,34 @@ internal static partial class MSBuildHelper
|
|
24
26
|
|
25
27
|
public static bool IsMSBuildRegistered => MSBuildPath.Length > 0;
|
26
28
|
|
27
|
-
static
|
28
|
-
{
|
29
|
-
RegisterMSBuild();
|
30
|
-
}
|
31
|
-
|
32
|
-
public static void RegisterMSBuild()
|
29
|
+
public static void RegisterMSBuild(string currentDirectory, string rootDirectory)
|
33
30
|
{
|
34
31
|
// Ensure MSBuild types are registered before calling a method that loads the types
|
35
32
|
if (!IsMSBuildRegistered)
|
36
33
|
{
|
37
|
-
var
|
38
|
-
var
|
39
|
-
var
|
40
|
-
try
|
34
|
+
var candidateDirectories = PathHelper.GetAllDirectoriesToRoot(currentDirectory, rootDirectory);
|
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)
|
41
37
|
{
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
File.Move(globalJsonPath, tempGlobalJsonPath);
|
46
|
-
}
|
38
|
+
Console.WriteLine($"Temporarily removing `global.json` from `{Path.GetDirectoryName(globalJsonPath)}` for MSBuild detection.");
|
39
|
+
File.Move(globalJsonPath, tempGlobalJsonPath);
|
40
|
+
}
|
47
41
|
|
42
|
+
try
|
43
|
+
{
|
48
44
|
var defaultInstance = MSBuildLocator.QueryVisualStudioInstances().First();
|
49
45
|
MSBuildPath = defaultInstance.MSBuildPath;
|
50
46
|
MSBuildLocator.RegisterInstance(defaultInstance);
|
51
47
|
}
|
52
48
|
finally
|
53
49
|
{
|
54
|
-
|
55
|
-
{
|
56
|
-
Console.WriteLine("Restoring `global.json` after MSBuild detection.");
|
57
|
-
File.Move(tempGlobalJsonPath, globalJsonPath);
|
58
|
-
}
|
59
|
-
}
|
60
|
-
}
|
61
|
-
}
|
62
|
-
|
63
|
-
public static string[] GetTargetFrameworkMonikers(ImmutableArray<ProjectBuildFile> buildFiles)
|
64
|
-
{
|
65
|
-
HashSet<string> targetFrameworkValues = new(StringComparer.OrdinalIgnoreCase);
|
66
|
-
Dictionary<string, Property> propertyInfo = new(StringComparer.OrdinalIgnoreCase);
|
67
|
-
|
68
|
-
foreach (var buildFile in buildFiles)
|
69
|
-
{
|
70
|
-
var projectRoot = CreateProjectRootElement(buildFile);
|
71
|
-
|
72
|
-
foreach (var property in projectRoot.Properties)
|
73
|
-
{
|
74
|
-
if (property.Name.Equals("TargetFramework", StringComparison.OrdinalIgnoreCase) ||
|
75
|
-
property.Name.Equals("TargetFrameworks", StringComparison.OrdinalIgnoreCase))
|
76
|
-
{
|
77
|
-
if (buildFile.IsOutsideBasePath)
|
78
|
-
{
|
79
|
-
continue;
|
80
|
-
}
|
81
|
-
|
82
|
-
foreach (var tfm in property.Value.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
83
|
-
{
|
84
|
-
targetFrameworkValues.Add(tfm);
|
85
|
-
}
|
86
|
-
}
|
87
|
-
else if (property.Name.Equals("TargetFrameworkVersion", StringComparison.OrdinalIgnoreCase))
|
50
|
+
foreach (var (globalJsonpath, tempGlobalJsonPath) in globalJsonPaths)
|
88
51
|
{
|
89
|
-
|
90
|
-
|
91
|
-
continue;
|
92
|
-
}
|
93
|
-
|
94
|
-
// For packages.config projects that use TargetFrameworkVersion, we need to convert it to TargetFramework
|
95
|
-
targetFrameworkValues.Add($"net{property.Value.TrimStart('v').Replace(".", "")}");
|
52
|
+
Console.WriteLine($"Restoring `global.json` to `{Path.GetDirectoryName(globalJsonpath)}` after MSBuild discovery.");
|
53
|
+
File.Move(tempGlobalJsonPath, globalJsonpath);
|
96
54
|
}
|
97
|
-
else
|
98
|
-
{
|
99
|
-
propertyInfo[property.Name] = new(property.Name, property.Value, buildFile.RelativePath);
|
100
|
-
}
|
101
|
-
}
|
102
|
-
}
|
103
|
-
|
104
|
-
HashSet<string> targetFrameworks = new(StringComparer.OrdinalIgnoreCase);
|
105
|
-
|
106
|
-
foreach (var targetFrameworkValue in targetFrameworkValues)
|
107
|
-
{
|
108
|
-
var (resultType, _, tfms, _, errorMessage) =
|
109
|
-
GetEvaluatedValue(targetFrameworkValue, propertyInfo, propertiesToIgnore: ["TargetFramework", "TargetFrameworks"]);
|
110
|
-
if (resultType != EvaluationResultType.Success)
|
111
|
-
{
|
112
|
-
continue;
|
113
|
-
}
|
114
|
-
|
115
|
-
if (string.IsNullOrEmpty(tfms))
|
116
|
-
{
|
117
|
-
continue;
|
118
|
-
}
|
119
|
-
|
120
|
-
foreach (var tfm in tfms.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
121
|
-
{
|
122
|
-
targetFrameworks.Add(tfm);
|
123
55
|
}
|
124
56
|
}
|
125
|
-
|
126
|
-
return targetFrameworks.ToArray();
|
127
57
|
}
|
128
58
|
|
129
59
|
public static IEnumerable<string> GetProjectPathsFromSolution(string solutionPath)
|
@@ -379,6 +309,124 @@ internal static partial class MSBuildHelper
|
|
379
309
|
}
|
380
310
|
}
|
381
311
|
|
312
|
+
internal static async Task<Dependency[]?> ResolveDependencyConflicts(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Logger logger)
|
313
|
+
{
|
314
|
+
var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
|
315
|
+
try
|
316
|
+
{
|
317
|
+
var tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages);
|
318
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunAsync("dotnet", $"restore \"{tempProjectPath}\"", workingDirectory: tempDirectory.FullName);
|
319
|
+
|
320
|
+
// simple cases first
|
321
|
+
// if restore failed, nothing we can do
|
322
|
+
if (exitCode != 0)
|
323
|
+
{
|
324
|
+
return null;
|
325
|
+
}
|
326
|
+
|
327
|
+
// if no problems found, just return the current set
|
328
|
+
if (!stdOut.Contains("NU1608"))
|
329
|
+
{
|
330
|
+
return packages;
|
331
|
+
}
|
332
|
+
|
333
|
+
// now it gets complicated; look for the packages with issues
|
334
|
+
MatchCollection matches = PackageIncompatibilityWarningPattern().Matches(stdOut);
|
335
|
+
(string, NuGetVersion)[] badPackagesAndVersions = matches.Select(m => (m.Groups["PackageName"].Value, NuGetVersion.Parse(m.Groups["PackageVersion"].Value))).ToArray();
|
336
|
+
Dictionary<string, HashSet<NuGetVersion>> badPackagesAndCandidateVersionsDictionary = new(StringComparer.OrdinalIgnoreCase);
|
337
|
+
|
338
|
+
// and for each of those packages, find all versions greater than the one that's currently installed
|
339
|
+
foreach ((string packageName, NuGetVersion packageVersion) in badPackagesAndVersions)
|
340
|
+
{
|
341
|
+
// this command dumps a JSON object with all versions of the specified package from all package sources
|
342
|
+
(exitCode, stdOut, stdErr) = await ProcessEx.RunAsync("dotnet", $"package search {packageName} --exact-match --format json", workingDirectory: tempDirectory.FullName);
|
343
|
+
if (exitCode != 0)
|
344
|
+
{
|
345
|
+
continue;
|
346
|
+
}
|
347
|
+
|
348
|
+
// ensure collection exists
|
349
|
+
if (!badPackagesAndCandidateVersionsDictionary.ContainsKey(packageName))
|
350
|
+
{
|
351
|
+
badPackagesAndCandidateVersionsDictionary.Add(packageName, new HashSet<NuGetVersion>());
|
352
|
+
}
|
353
|
+
|
354
|
+
HashSet<NuGetVersion> foundVersions = badPackagesAndCandidateVersionsDictionary[packageName];
|
355
|
+
|
356
|
+
var json = JsonHelper.ParseNode(stdOut);
|
357
|
+
if (json?["searchResult"] is JsonArray searchResults)
|
358
|
+
{
|
359
|
+
foreach (var searchResult in searchResults)
|
360
|
+
{
|
361
|
+
if (searchResult?["packages"] is JsonArray packagesArray)
|
362
|
+
{
|
363
|
+
foreach (var package in packagesArray)
|
364
|
+
{
|
365
|
+
// in 8.0.xxx SDKs, the package version is in the `latestVersion` property, but in 9.0.xxx, it's `version`
|
366
|
+
var packageVersionProperty = package?["version"] ?? package?["latestVersion"];
|
367
|
+
if (packageVersionProperty is JsonValue latestVersion &&
|
368
|
+
latestVersion.GetValueKind() == JsonValueKind.String &&
|
369
|
+
NuGetVersion.TryParse(latestVersion.ToString(), out var nugetVersion) &&
|
370
|
+
nugetVersion > packageVersion)
|
371
|
+
{
|
372
|
+
foundVersions.Add(nugetVersion);
|
373
|
+
}
|
374
|
+
}
|
375
|
+
}
|
376
|
+
}
|
377
|
+
}
|
378
|
+
}
|
379
|
+
|
380
|
+
// generate all possible combinations
|
381
|
+
(string Key, NuGetVersion v)[][] expandedLists = badPackagesAndCandidateVersionsDictionary.Select(kvp => kvp.Value.Order().Select(v => (kvp.Key, v)).ToArray()).ToArray();
|
382
|
+
IEnumerable<(string PackageName, NuGetVersion PackageVersion)>[] product = expandedLists.CartesianProduct().ToArray();
|
383
|
+
|
384
|
+
// FUTURE WORK: pre-filter individual known package incompatibilities to reduce the number of combinations, e.g., if Package.A v1.0.0
|
385
|
+
// is incompatible with Package.B v2.0.0, then remove _all_ combinations with that pair
|
386
|
+
|
387
|
+
// this is the slow part
|
388
|
+
foreach (IEnumerable<(string PackageName, NuGetVersion PackageVersion)> candidateSet in product)
|
389
|
+
{
|
390
|
+
// rebuild candidate dependency list with the relevant versions
|
391
|
+
Dictionary<string, NuGetVersion> packageVersions = candidateSet.ToDictionary(candidateSet => candidateSet.PackageName, candidateSet => candidateSet.PackageVersion);
|
392
|
+
Dependency[] candidatePackages = packages.Select(p =>
|
393
|
+
{
|
394
|
+
if (packageVersions.TryGetValue(p.Name, out var version))
|
395
|
+
{
|
396
|
+
// create a new dependency with the updated version
|
397
|
+
return new Dependency(p.Name, version.ToString(), p.Type, IsDevDependency: p.IsDevDependency, IsOverride: p.IsOverride, IsUpdate: p.IsUpdate);
|
398
|
+
}
|
399
|
+
|
400
|
+
// not the dependency we're looking for, use whatever it already was in this set
|
401
|
+
return p;
|
402
|
+
}).ToArray();
|
403
|
+
|
404
|
+
if (await DependenciesAreCoherentAsync(repoRoot, projectPath, targetFramework, candidatePackages, logger))
|
405
|
+
{
|
406
|
+
// return as soon as we find a coherent set
|
407
|
+
return candidatePackages;
|
408
|
+
}
|
409
|
+
}
|
410
|
+
|
411
|
+
// no package resolution set found
|
412
|
+
return null;
|
413
|
+
}
|
414
|
+
finally
|
415
|
+
{
|
416
|
+
tempDirectory.Delete(recursive: true);
|
417
|
+
}
|
418
|
+
}
|
419
|
+
|
420
|
+
// fully expand all possible combinations using the algorithm from here:
|
421
|
+
// https://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/
|
422
|
+
private static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
|
423
|
+
{
|
424
|
+
IEnumerable<IEnumerable<T>> emptyProduct = [[]];
|
425
|
+
return sequences.Aggregate(emptyProduct, (accumulator, sequence) => from accseq in accumulator
|
426
|
+
from item in sequence
|
427
|
+
select accseq.Concat([item]));
|
428
|
+
}
|
429
|
+
|
382
430
|
private static ProjectRootElement CreateProjectRootElement(ProjectBuildFile buildFile)
|
383
431
|
{
|
384
432
|
var xmlString = buildFile.Contents.ToFullString();
|
@@ -569,7 +617,7 @@ internal static partial class MSBuildHelper
|
|
569
617
|
return directoryPackagesPropsPath is not null;
|
570
618
|
}
|
571
619
|
|
572
|
-
internal static async Task<ImmutableArray<ProjectBuildFile
|
620
|
+
internal static async Task<(ImmutableArray<ProjectBuildFile> ProjectBuildFiles, string[] TargetFrameworks)> LoadBuildFilesAndTargetFrameworksAsync(string repoRootPath, string projectPath)
|
573
621
|
{
|
574
622
|
var buildFileList = new List<string>
|
575
623
|
{
|
@@ -579,6 +627,7 @@ internal static partial class MSBuildHelper
|
|
579
627
|
// a global.json file might cause problems with the dotnet msbuild command; create a safe version temporarily
|
580
628
|
TryGetGlobalJsonPath(repoRootPath, projectPath, out var globalJsonPath);
|
581
629
|
var safeGlobalJsonName = $"{globalJsonPath}{Guid.NewGuid()}";
|
630
|
+
HashSet<string> targetFrameworks = new(StringComparer.OrdinalIgnoreCase);
|
582
631
|
|
583
632
|
try
|
584
633
|
{
|
@@ -607,16 +656,51 @@ internal static partial class MSBuildHelper
|
|
607
656
|
// load the project even if it imports a file that doesn't exist (e.g. a file that's generated at restore
|
608
657
|
// or build time).
|
609
658
|
using var projectCollection = new ProjectCollection(); // do this in a one-off instance and don't pollute the global collection
|
610
|
-
|
659
|
+
Project project = Project.FromFile(projectPath, new ProjectOptions
|
611
660
|
{
|
612
661
|
LoadSettings = ProjectLoadSettings.IgnoreMissingImports,
|
613
662
|
ProjectCollection = projectCollection,
|
614
663
|
});
|
615
664
|
buildFileList.AddRange(project.Imports.Select(i => i.ImportedProject.FullPath.NormalizePathToUnix()));
|
665
|
+
|
666
|
+
// use the MSBuild-evaluated value so we don't have to try to manually parse XML
|
667
|
+
IEnumerable<ProjectProperty> targetFrameworkProperties = project.Properties.Where(p => p.Name.Equals("TargetFramework", StringComparison.OrdinalIgnoreCase)).ToList();
|
668
|
+
IEnumerable<ProjectProperty> targetFrameworksProperties = project.Properties.Where(p => p.Name.Equals("TargetFrameworks", StringComparison.OrdinalIgnoreCase)).ToList();
|
669
|
+
IEnumerable<ProjectProperty> targetFrameworkVersionProperties = project.Properties.Where(p => p.Name.Equals("TargetFrameworkVersion", StringComparison.OrdinalIgnoreCase)).ToList();
|
670
|
+
foreach (ProjectProperty tfm in targetFrameworkProperties)
|
671
|
+
{
|
672
|
+
if (!string.IsNullOrWhiteSpace(tfm.EvaluatedValue))
|
673
|
+
{
|
674
|
+
targetFrameworks.Add(tfm.EvaluatedValue);
|
675
|
+
}
|
676
|
+
}
|
677
|
+
|
678
|
+
foreach (ProjectProperty tfms in targetFrameworksProperties)
|
679
|
+
{
|
680
|
+
foreach (string tfmValue in tfms.EvaluatedValue.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
681
|
+
{
|
682
|
+
targetFrameworks.Add(tfmValue);
|
683
|
+
}
|
684
|
+
}
|
685
|
+
|
686
|
+
if (targetFrameworks.Count == 0)
|
687
|
+
{
|
688
|
+
// Only try this if we haven't been able to resolve anything yet. This is because deep in the SDK, a
|
689
|
+
// `TargetFramework` of `netstandard2.0` (eventually) gets turned into `v2.0` and we don't want to
|
690
|
+
// interpret that as a .NET Framework 2.0 project.
|
691
|
+
foreach (ProjectProperty tfvm in targetFrameworkVersionProperties)
|
692
|
+
{
|
693
|
+
// `v0.0` is an error case where no TFM could be evaluated
|
694
|
+
if (tfvm.EvaluatedValue != "v0.0")
|
695
|
+
{
|
696
|
+
targetFrameworks.Add($"net{tfvm.EvaluatedValue.TrimStart('v').Replace(".", "")}");
|
697
|
+
}
|
698
|
+
}
|
699
|
+
}
|
616
700
|
}
|
617
701
|
catch (InvalidProjectFileException)
|
618
702
|
{
|
619
|
-
return [];
|
703
|
+
return ([], []);
|
620
704
|
}
|
621
705
|
finally
|
622
706
|
{
|
@@ -627,18 +711,22 @@ internal static partial class MSBuildHelper
|
|
627
711
|
}
|
628
712
|
|
629
713
|
var repoRootPathPrefix = repoRootPath.NormalizePathToUnix() + "/";
|
630
|
-
var buildFiles =
|
631
|
-
|
632
|
-
|
633
|
-
.Where(f => f.StartsWith(repoRootPathPrefix, StringComparison.OrdinalIgnoreCase))
|
634
|
-
.Distinct();
|
714
|
+
var buildFiles = buildFileList
|
715
|
+
.Where(f => f.StartsWith(repoRootPathPrefix, StringComparison.OrdinalIgnoreCase))
|
716
|
+
.Distinct();
|
635
717
|
var result = buildFiles
|
636
718
|
.Where(File.Exists)
|
637
719
|
.Select(path => ProjectBuildFile.Open(repoRootPath, path))
|
638
720
|
.ToImmutableArray();
|
639
|
-
return result;
|
721
|
+
return (result, targetFrameworks.ToArray());
|
640
722
|
}
|
641
723
|
|
642
724
|
[GeneratedRegex("^\\s*NuGetData::Package=(?<PackageName>[^,]+), Version=(?<PackageVersion>.+)$")]
|
643
725
|
private static partial Regex PackagePattern();
|
726
|
+
|
727
|
+
// Example output:
|
728
|
+
// NU1608: Detected package version outside of dependency constraint: SpecFlow.Tools.MsBuild.Generation 3.3.30 requires SpecFlow(= 3.3.30) but version SpecFlow 3.9.74 was resolved.
|
729
|
+
// PackageName-|+++++++++++++++++++++++++++++++| |++++|-PackageVersion
|
730
|
+
[GeneratedRegex("NU1608: [^:]+: (?<PackageName>[^ ]+) (?<PackageVersion>[^ ]+)")]
|
731
|
+
private static partial Regex PackageIncompatibilityWarningPattern();
|
644
732
|
}
|
@@ -34,20 +34,11 @@ internal static class PathHelper
|
|
34
34
|
public static string GetFullPathFromRelative(string rootPath, string relativePath)
|
35
35
|
=> Path.GetFullPath(JoinPath(rootPath, relativePath.NormalizePathToUnix()));
|
36
36
|
|
37
|
-
|
38
|
-
/// Check in every directory from <paramref name="initialPath"/> up to <paramref name="rootPath"/> for the file specified in <paramref name="fileName"/>.
|
39
|
-
/// </summary>
|
40
|
-
/// <returns>The path of the found file or null.</returns>
|
41
|
-
public static string? GetFileInDirectoryOrParent(string initialPath, string rootPath, string fileName, bool caseSensitive = true)
|
37
|
+
public static string[] GetAllDirectoriesToRoot(string initialDirectoryPath, string rootDirectoryPath)
|
42
38
|
{
|
43
|
-
if (File.Exists(initialPath))
|
44
|
-
{
|
45
|
-
initialPath = Path.GetDirectoryName(initialPath)!;
|
46
|
-
}
|
47
|
-
|
48
39
|
var candidatePaths = new List<string>();
|
49
|
-
var rootDirectory = new DirectoryInfo(
|
50
|
-
var candidateDirectory = new DirectoryInfo(
|
40
|
+
var rootDirectory = new DirectoryInfo(rootDirectoryPath);
|
41
|
+
var candidateDirectory = new DirectoryInfo(initialDirectoryPath);
|
51
42
|
while (candidateDirectory.FullName != rootDirectory.FullName)
|
52
43
|
{
|
53
44
|
candidatePaths.Add(candidateDirectory.FullName);
|
@@ -58,8 +49,22 @@ internal static class PathHelper
|
|
58
49
|
}
|
59
50
|
}
|
60
51
|
|
61
|
-
candidatePaths.Add(
|
52
|
+
candidatePaths.Add(rootDirectoryPath);
|
53
|
+
return candidatePaths.ToArray();
|
54
|
+
}
|
55
|
+
|
56
|
+
/// <summary>
|
57
|
+
/// Check in every directory from <paramref name="initialPath"/> up to <paramref name="rootPath"/> for the file specified in <paramref name="fileName"/>.
|
58
|
+
/// </summary>
|
59
|
+
/// <returns>The path of the found file or null.</returns>
|
60
|
+
public static string? GetFileInDirectoryOrParent(string initialPath, string rootPath, string fileName, bool caseSensitive = true)
|
61
|
+
{
|
62
|
+
if (File.Exists(initialPath))
|
63
|
+
{
|
64
|
+
initialPath = Path.GetDirectoryName(initialPath)!;
|
65
|
+
}
|
62
66
|
|
67
|
+
var candidatePaths = GetAllDirectoriesToRoot(initialPath, rootPath);
|
63
68
|
foreach (var candidatePath in candidatePaths)
|
64
69
|
{
|
65
70
|
try
|
@@ -1,4 +1,5 @@
|
|
1
1
|
using System.Collections.Immutable;
|
2
|
+
using System.Diagnostics.CodeAnalysis;
|
2
3
|
using System.Text.Json;
|
3
4
|
|
4
5
|
using NuGetUpdater.Core.Discover;
|
@@ -29,7 +30,7 @@ public class DiscoveryWorkerTestBase
|
|
29
30
|
protected static void ValidateWorkspaceResult(ExpectedWorkspaceDiscoveryResult expectedResult, WorkspaceDiscoveryResult actualResult)
|
30
31
|
{
|
31
32
|
Assert.NotNull(actualResult);
|
32
|
-
Assert.Equal(expectedResult.FilePath, actualResult.FilePath);
|
33
|
+
Assert.Equal(expectedResult.FilePath.NormalizePathToUnix(), actualResult.FilePath.NormalizePathToUnix());
|
33
34
|
ValidateDirectoryPackagesProps(expectedResult.DirectoryPackagesProps, actualResult.DirectoryPackagesProps);
|
34
35
|
ValidateResultWithDependencies(expectedResult.GlobalJson, actualResult.GlobalJson);
|
35
36
|
ValidateResultWithDependencies(expectedResult.DotNetToolsJson, actualResult.DotNetToolsJson);
|
@@ -50,7 +51,7 @@ public class DiscoveryWorkerTestBase
|
|
50
51
|
Assert.NotNull(actualResult);
|
51
52
|
}
|
52
53
|
|
53
|
-
Assert.Equal(expectedResult.FilePath, actualResult.FilePath);
|
54
|
+
Assert.Equal(expectedResult.FilePath.NormalizePathToUnix(), actualResult.FilePath.NormalizePathToUnix());
|
54
55
|
ValidateDependencies(expectedResult.Dependencies, actualResult.Dependencies);
|
55
56
|
Assert.Equal(expectedResult.ExpectedDependencyCount ?? expectedResult.Dependencies.Length, actualResult.Dependencies.Length);
|
56
57
|
}
|
@@ -64,12 +65,12 @@ public class DiscoveryWorkerTestBase
|
|
64
65
|
|
65
66
|
foreach (var expectedProject in expectedProjects)
|
66
67
|
{
|
67
|
-
var actualProject = actualProjects.Single(p => p.FilePath == expectedProject.FilePath);
|
68
|
+
var actualProject = actualProjects.Single(p => p.FilePath.NormalizePathToUnix() == expectedProject.FilePath.NormalizePathToUnix());
|
68
69
|
|
69
|
-
Assert.Equal(expectedProject.FilePath, actualProject.FilePath);
|
70
|
-
AssertEx.Equal(expectedProject.Properties, actualProject.Properties);
|
70
|
+
Assert.Equal(expectedProject.FilePath.NormalizePathToUnix(), actualProject.FilePath.NormalizePathToUnix());
|
71
|
+
AssertEx.Equal(expectedProject.Properties, actualProject.Properties, PropertyComparer.Instance);
|
71
72
|
AssertEx.Equal(expectedProject.TargetFrameworks, actualProject.TargetFrameworks);
|
72
|
-
AssertEx.Equal(expectedProject.ReferencedProjectPaths, actualProject.ReferencedProjectPaths);
|
73
|
+
AssertEx.Equal(expectedProject.ReferencedProjectPaths.Select(PathHelper.NormalizePathToUnix), actualProject.ReferencedProjectPaths.Select(PathHelper.NormalizePathToUnix));
|
73
74
|
ValidateDependencies(expectedProject.Dependencies, actualProject.Dependencies);
|
74
75
|
Assert.Equal(expectedProject.ExpectedDependencyCount ?? expectedProject.Dependencies.Length, actualProject.Dependencies.Length);
|
75
76
|
}
|
@@ -114,4 +115,21 @@ public class DiscoveryWorkerTestBase
|
|
114
115
|
var resultJson = await File.ReadAllTextAsync(resultPath);
|
115
116
|
return JsonSerializer.Deserialize<WorkspaceDiscoveryResult>(resultJson, DiscoveryWorker.SerializerOptions)!;
|
116
117
|
}
|
118
|
+
|
119
|
+
internal class PropertyComparer : IEqualityComparer<Property>
|
120
|
+
{
|
121
|
+
public static PropertyComparer Instance { get; } = new();
|
122
|
+
|
123
|
+
public bool Equals(Property? x, Property? y)
|
124
|
+
{
|
125
|
+
return x?.Name == y?.Name &&
|
126
|
+
x?.Value == y?.Value &&
|
127
|
+
x?.SourceFilePath.NormalizePathToUnix() == y?.SourceFilePath.NormalizePathToUnix();
|
128
|
+
}
|
129
|
+
|
130
|
+
public int GetHashCode([DisallowNull] Property obj)
|
131
|
+
{
|
132
|
+
throw new NotImplementedException();
|
133
|
+
}
|
134
|
+
}
|
117
135
|
}
|
data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs
CHANGED
@@ -25,11 +25,14 @@ public partial class DiscoveryWorkerTests
|
|
25
25
|
<package id="NuGet.Core" version="2.11.1" targetFramework="net46" />
|
26
26
|
<package id="NuGet.Server" version="2.11.2" targetFramework="net46" />
|
27
27
|
<package id="RouteMagic" version="1.3" targetFramework="net46" />
|
28
|
-
<package id="WebActivatorEx" version="2.1.0" targetFramework="net46"
|
28
|
+
<package id="WebActivatorEx" version="2.1.0" targetFramework="net46" />
|
29
29
|
</packages>
|
30
30
|
"""),
|
31
31
|
("myproj.csproj", """
|
32
32
|
<Project>
|
33
|
+
<PropertyGroup>
|
34
|
+
<TargetFramework>net46</TargetFramework>
|
35
|
+
</PropertyGroup>
|
33
36
|
</Project>
|
34
37
|
""")
|
35
38
|
],
|
@@ -40,16 +43,21 @@ public partial class DiscoveryWorkerTests
|
|
40
43
|
new()
|
41
44
|
{
|
42
45
|
FilePath = "myproj.csproj",
|
46
|
+
Properties = [
|
47
|
+
new("TargetFramework", "net46", "myproj.csproj"),
|
48
|
+
],
|
49
|
+
TargetFrameworks = ["net46"],
|
43
50
|
Dependencies = [
|
44
|
-
new("Microsoft.
|
45
|
-
new("Microsoft.
|
46
|
-
new("Microsoft.
|
47
|
-
new("Microsoft.Web.
|
48
|
-
new("
|
49
|
-
new("
|
50
|
-
new("NuGet.
|
51
|
-
new("
|
52
|
-
new("
|
51
|
+
new("Microsoft.NETFramework.ReferenceAssemblies", "1.0.3", DependencyType.Unknown, TargetFrameworks: ["net46"], IsTransitive: true),
|
52
|
+
new("Microsoft.CodeDom.Providers.DotNetCompilerPlatform", "1.0.0", DependencyType.PackagesConfig, TargetFrameworks: ["net46"]),
|
53
|
+
new("Microsoft.Net.Compilers", "1.0.1", DependencyType.PackagesConfig, TargetFrameworks: ["net46"]),
|
54
|
+
new("Microsoft.Web.Infrastructure", "1.0.0.0", DependencyType.PackagesConfig, TargetFrameworks: ["net46"]),
|
55
|
+
new("Microsoft.Web.Xdt", "2.1.1", DependencyType.PackagesConfig, TargetFrameworks: ["net46"]),
|
56
|
+
new("Newtonsoft.Json", "8.0.3", DependencyType.PackagesConfig, TargetFrameworks: ["net46"]),
|
57
|
+
new("NuGet.Core", "2.11.1", DependencyType.PackagesConfig, TargetFrameworks: ["net46"]),
|
58
|
+
new("NuGet.Server", "2.11.2", DependencyType.PackagesConfig, TargetFrameworks: ["net46"]),
|
59
|
+
new("RouteMagic", "1.3", DependencyType.PackagesConfig, TargetFrameworks: ["net46"]),
|
60
|
+
new("WebActivatorEx", "2.1.0", DependencyType.PackagesConfig, TargetFrameworks: ["net46"]),
|
53
61
|
],
|
54
62
|
}
|
55
63
|
],
|
data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs
CHANGED
@@ -376,5 +376,30 @@ public partial class DiscoveryWorkerTests
|
|
376
376
|
],
|
377
377
|
});
|
378
378
|
}
|
379
|
+
|
380
|
+
[Fact]
|
381
|
+
|
382
|
+
public async Task NoDependenciesReturnedIfNoTargetFrameworkCanBeResolved()
|
383
|
+
{
|
384
|
+
await TestDiscoveryAsync(
|
385
|
+
workspacePath: "",
|
386
|
+
files: [
|
387
|
+
("myproj.csproj", """
|
388
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
389
|
+
<PropertyGroup>
|
390
|
+
<TargetFramework>$(SomeCommonTfmThatCannotBeResolved)</TargetFramework>
|
391
|
+
</PropertyGroup>
|
392
|
+
<ItemGroup>
|
393
|
+
<PackageReference Include="Some.Package" Version="1.2.3" />
|
394
|
+
</ItemGroup>
|
395
|
+
</Project>
|
396
|
+
""")
|
397
|
+
],
|
398
|
+
expectedResult: new()
|
399
|
+
{
|
400
|
+
FilePath = "",
|
401
|
+
Projects = []
|
402
|
+
});
|
403
|
+
}
|
379
404
|
}
|
380
405
|
}
|
@@ -1,16 +1,9 @@
|
|
1
|
-
using System.Collections.Generic;
|
2
|
-
|
3
1
|
using Xunit;
|
4
2
|
|
5
3
|
namespace NuGetUpdater.Core.Test.Update;
|
6
4
|
|
7
|
-
public class PackagesConfigUpdaterTests
|
5
|
+
public class PackagesConfigUpdaterTests : TestBase
|
8
6
|
{
|
9
|
-
public PackagesConfigUpdaterTests()
|
10
|
-
{
|
11
|
-
MSBuildHelper.RegisterMSBuild();
|
12
|
-
}
|
13
|
-
|
14
7
|
[Theory]
|
15
8
|
[MemberData(nameof(PackagesDirectoryPathTestData))]
|
16
9
|
public void PathToPackagesDirectoryCanBeDetermined(string projectContents, string dependencyName, string dependencyVersion, string expectedPackagesDirectoryPath)
|
@@ -10,7 +10,7 @@ namespace NuGetUpdater.Core.Test.Update;
|
|
10
10
|
using TestFile = (string Path, string Content);
|
11
11
|
using TestProject = (string Path, string Content, Guid ProjectId);
|
12
12
|
|
13
|
-
public abstract class UpdateWorkerTestBase
|
13
|
+
public abstract class UpdateWorkerTestBase : TestBase
|
14
14
|
{
|
15
15
|
protected static Task TestNoChange(
|
16
16
|
string dependencyName,
|