dependabot-nuget 0.321.2 → 0.321.3
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/DotNetPackageCorrelation/Model/PackageMapper.cs +9 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencyDiscoveryTargetingPacks.props +2 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencySolver/IDependencySolver.cs +8 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencySolver/MSBuildDependencySolver.cs +32 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/ProjectDiscoveryResult.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +10 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs +6 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +3 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/DotNetToolsJsonUpdater.cs +6 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/FileWriterWorker.cs +326 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/IFileWriter.cs +14 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/XmlFileWriter.cs +465 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/GlobalJsonUpdater.cs +9 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +26 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/DependencySolver/MSBuildDependencySolverTests.cs +633 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +49 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/EndToEndTests.cs +484 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/DotNetToolsJsonUpdaterTests.cs +181 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/FileWriterTestsBase.cs +61 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/FileWriterWorkerTests.cs +917 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/FileWriterWorkerTests_MiscellaneousTests.cs +109 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/TestFileWriterReturnsConstantResult.cs +20 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/XmlFileWriterTests.cs +1594 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/XmlFileWriterTests_CreateUpdatedVersionRangeTests.cs +25 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/GlobalJsonUpdaterTests.cs +139 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackagesConfigUpdaterTests.cs +1961 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateOperationResultTests.cs +116 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +0 -1043
- metadata +19 -10
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DotNetTools.cs +0 -375
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs +0 -296
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.LockFile.cs +0 -251
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +0 -201
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +0 -3821
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +0 -2706
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 832ab457e727f6583a33319b04bc49b5142d33aae4f95873137c580f838b5abf
|
4
|
+
data.tar.gz: 0dca08fa4a87530852652d0264c13e4bd79024561cb3e3fe397551c12fa1b921
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 756d833b0d1616230f5ce980d1410ae8ea9883ab441837847a18eda7c41180032d20ae84cbc986231d293a2bf1e846b81f93fb8b40fd8419edcfd51e5bfd276e
|
7
|
+
data.tar.gz: 1acab8370fe0a8b0bd8719613e783c1c2e1d5cc7f7a22355ce1e80d10eb242c0545df65d6cbaba3964cd551345d02c0e43a7c94b7da76d6a10ccdd1c354ab3c4
|
@@ -46,6 +46,15 @@ public class PackageMapper
|
|
46
46
|
return null;
|
47
47
|
}
|
48
48
|
|
49
|
+
public bool IsSdkReplacementPackage(string packageName)
|
50
|
+
{
|
51
|
+
var isSdkReplacementPackage = RuntimePackages.Runtimes.Any(r =>
|
52
|
+
{
|
53
|
+
return r.Value.Packages.Any(p => packageName.Equals(p.Key, StringComparison.Ordinal));
|
54
|
+
});
|
55
|
+
return isSdkReplacementPackage;
|
56
|
+
}
|
57
|
+
|
49
58
|
private SemVersion? GetRuntimeVersionFromPackage(string packageName, SemVersion packageVersion)
|
50
59
|
{
|
51
60
|
// TODO: linear search is slow
|
@@ -6,5 +6,7 @@
|
|
6
6
|
because that's irrelevant to dependency discovery.
|
7
7
|
-->
|
8
8
|
<NoWarn>$(NoWarn);MSB3644</NoWarn>
|
9
|
+
<!-- A package downgrade warning shouldn't be lifted to an error because that would prevent discovery. -->
|
10
|
+
<NoWarn>$(NoWarn);NU1605</NoWarn>
|
9
11
|
</PropertyGroup>
|
10
12
|
</Project>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
|
3
|
+
namespace NuGetUpdater.Core.DependencySolver;
|
4
|
+
|
5
|
+
public interface IDependencySolver
|
6
|
+
{
|
7
|
+
Task<ImmutableArray<Dependency>?> SolveAsync(ImmutableArray<Dependency> existingTopLevelDependencies, ImmutableArray<Dependency> desiredDependencies, string targetFramework);
|
8
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
|
3
|
+
namespace NuGetUpdater.Core.DependencySolver;
|
4
|
+
|
5
|
+
public class MSBuildDependencySolver : IDependencySolver
|
6
|
+
{
|
7
|
+
private readonly DirectoryInfo _repoContentsPath;
|
8
|
+
private readonly FileInfo _projectPath;
|
9
|
+
private readonly ExperimentsManager _experimentsManager;
|
10
|
+
private readonly ILogger _logger;
|
11
|
+
|
12
|
+
public MSBuildDependencySolver(DirectoryInfo repoContentsPath, FileInfo projectPath, ExperimentsManager experimentsManager, ILogger logger)
|
13
|
+
{
|
14
|
+
_repoContentsPath = repoContentsPath;
|
15
|
+
_projectPath = projectPath;
|
16
|
+
_experimentsManager = experimentsManager;
|
17
|
+
_logger = logger;
|
18
|
+
}
|
19
|
+
|
20
|
+
public async Task<ImmutableArray<Dependency>?> SolveAsync(ImmutableArray<Dependency> existingTopLevelDependencies, ImmutableArray<Dependency> desiredDependencies, string targetFramework)
|
21
|
+
{
|
22
|
+
var result = await MSBuildHelper.ResolveDependencyConflicts(
|
23
|
+
_repoContentsPath.FullName,
|
24
|
+
_projectPath.FullName,
|
25
|
+
targetFramework,
|
26
|
+
existingTopLevelDependencies,
|
27
|
+
desiredDependencies,
|
28
|
+
_experimentsManager,
|
29
|
+
_logger);
|
30
|
+
return result;
|
31
|
+
}
|
32
|
+
}
|
@@ -15,4 +15,5 @@ public record ProjectDiscoveryResult : IDiscoveryResultWithDependencies
|
|
15
15
|
public ImmutableArray<string> ReferencedProjectPaths { get; init; } = [];
|
16
16
|
public required ImmutableArray<string> ImportedFiles { get; init; }
|
17
17
|
public required ImmutableArray<string> AdditionalFiles { get; init; }
|
18
|
+
public bool CentralPackageTransitivePinningEnabled { get; init; } = false;
|
18
19
|
}
|
@@ -526,7 +526,8 @@ internal static class SdkProjectDiscovery
|
|
526
526
|
.ToImmutableArray();
|
527
527
|
|
528
528
|
// others
|
529
|
-
var
|
529
|
+
var projectProperties = resolvedProperties[projectPath];
|
530
|
+
var properties = projectProperties
|
530
531
|
.Where(pkvp => projectPropertyNames.Contains(pkvp.Key))
|
531
532
|
.Select(pkvp => new Property(pkvp.Key, pkvp.Value, Path.GetRelativePath(repoRootPath, projectPath).NormalizePathToUnix()))
|
532
533
|
.OrderBy(p => p.Name)
|
@@ -547,6 +548,13 @@ internal static class SdkProjectDiscovery
|
|
547
548
|
.Select(p => p.NormalizePathToUnix())
|
548
549
|
.OrderBy(p => p)
|
549
550
|
.ToImmutableArray();
|
551
|
+
var useCpmTransitivePinning =
|
552
|
+
projectProperties.TryGetValue("ManagePackageVersionsCentrally", out var useCpmString) &&
|
553
|
+
bool.TryParse(useCpmString, out var useCpm) &&
|
554
|
+
useCpm &&
|
555
|
+
projectProperties.TryGetValue("CentralPackageTransitivePinningEnabled", out var useTransitivePinningString) &&
|
556
|
+
bool.TryParse(useTransitivePinningString, out var useTransitivePinning) &&
|
557
|
+
useTransitivePinning;
|
550
558
|
|
551
559
|
var projectDiscoveryResult = new ProjectDiscoveryResult()
|
552
560
|
{
|
@@ -557,6 +565,7 @@ internal static class SdkProjectDiscovery
|
|
557
565
|
ReferencedProjectPaths = referenced,
|
558
566
|
ImportedFiles = imported,
|
559
567
|
AdditionalFiles = additional,
|
568
|
+
CentralPackageTransitivePinningEnabled = useCpmTransitivePinning,
|
560
569
|
};
|
561
570
|
projectDiscoveryResults.Add(projectDiscoveryResult);
|
562
571
|
}
|
@@ -15,4 +15,10 @@ public sealed record WorkspaceDiscoveryResult : NativeResult
|
|
15
15
|
var projectDiscovery = Projects.FirstOrDefault(p => System.IO.Path.Join(Path, p.FilePath).FullyNormalizedRootedPath().Equals(repoPath, StringComparison.OrdinalIgnoreCase));
|
16
16
|
return projectDiscovery;
|
17
17
|
}
|
18
|
+
|
19
|
+
public ProjectDiscoveryResult? GetProjectDiscoveryFromFullPath(DirectoryInfo repoContentsPath, FileInfo projectPath)
|
20
|
+
{
|
21
|
+
var projectDiscovery = Projects.FirstOrDefault(p => System.IO.Path.Join(repoContentsPath.FullName, Path, p.FilePath).FullyNormalizedRootedPath().Equals(projectPath.FullName.FullyNormalizedRootedPath(), StringComparison.OrdinalIgnoreCase));
|
22
|
+
return projectDiscovery;
|
23
|
+
}
|
18
24
|
}
|
@@ -12,6 +12,7 @@ public record ExperimentsManager
|
|
12
12
|
public bool UseLegacyDependencySolver { get; init; } = false;
|
13
13
|
public bool UseLegacyUpdateHandler { get; init; } = false;
|
14
14
|
public bool UseDirectDiscovery { get; init; } = false;
|
15
|
+
public bool UseNewFileUpdater { get; init; } = false;
|
15
16
|
|
16
17
|
public Dictionary<string, object> ToDictionary()
|
17
18
|
{
|
@@ -22,6 +23,7 @@ public record ExperimentsManager
|
|
22
23
|
["nuget_legacy_dependency_solver"] = UseLegacyDependencySolver,
|
23
24
|
["nuget_use_legacy_update_handler"] = UseLegacyUpdateHandler,
|
24
25
|
["nuget_use_direct_discovery"] = UseDirectDiscovery,
|
26
|
+
["nuget_use_new_file_updater"] = UseNewFileUpdater,
|
25
27
|
};
|
26
28
|
}
|
27
29
|
|
@@ -34,6 +36,7 @@ public record ExperimentsManager
|
|
34
36
|
UseLegacyDependencySolver = IsEnabled(experiments, "nuget_legacy_dependency_solver"),
|
35
37
|
UseLegacyUpdateHandler = IsEnabled(experiments, "nuget_use_legacy_update_handler"),
|
36
38
|
UseDirectDiscovery = IsEnabled(experiments, "nuget_use_direct_discovery"),
|
39
|
+
UseNewFileUpdater = IsEnabled(experiments, "nuget_use_new_file_updater"),
|
37
40
|
};
|
38
41
|
}
|
39
42
|
|
@@ -2,7 +2,7 @@ namespace NuGetUpdater.Core;
|
|
2
2
|
|
3
3
|
internal static class DotNetToolsJsonUpdater
|
4
4
|
{
|
5
|
-
public static async Task UpdateDependencyAsync(
|
5
|
+
public static async Task<string?> UpdateDependencyAsync(
|
6
6
|
string repoRootPath,
|
7
7
|
string workspacePath,
|
8
8
|
string dependencyName,
|
@@ -13,7 +13,7 @@ internal static class DotNetToolsJsonUpdater
|
|
13
13
|
if (!MSBuildHelper.TryGetDotNetToolsJsonPath(repoRootPath, workspacePath, out var dotnetToolsJsonPath))
|
14
14
|
{
|
15
15
|
logger.Info(" No dotnet-tools.json file found.");
|
16
|
-
return;
|
16
|
+
return null;
|
17
17
|
}
|
18
18
|
|
19
19
|
var dotnetToolsJsonFile = DotNetToolsJsonBuildFile.Open(repoRootPath, dotnetToolsJsonPath, logger);
|
@@ -24,7 +24,7 @@ internal static class DotNetToolsJsonUpdater
|
|
24
24
|
if (!containsDependency)
|
25
25
|
{
|
26
26
|
logger.Info($" Dependency [{dependencyName}] not found.");
|
27
|
-
return;
|
27
|
+
return null;
|
28
28
|
}
|
29
29
|
|
30
30
|
var tool = dotnetToolsJsonFile.Tools
|
@@ -40,7 +40,10 @@ internal static class DotNetToolsJsonUpdater
|
|
40
40
|
if (await dotnetToolsJsonFile.SaveAsync())
|
41
41
|
{
|
42
42
|
logger.Info($" Saved [{dotnetToolsJsonFile.RelativePath}].");
|
43
|
+
return dotnetToolsJsonFile.Path;
|
43
44
|
}
|
44
45
|
}
|
46
|
+
|
47
|
+
return null;
|
45
48
|
}
|
46
49
|
}
|
@@ -0,0 +1,326 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
|
3
|
+
using NuGet.Versioning;
|
4
|
+
|
5
|
+
using NuGetUpdater.Core.DependencySolver;
|
6
|
+
using NuGetUpdater.Core.Discover;
|
7
|
+
using NuGetUpdater.Core.Utilities;
|
8
|
+
|
9
|
+
namespace NuGetUpdater.Core.Updater.FileWriters;
|
10
|
+
|
11
|
+
public class FileWriterWorker
|
12
|
+
{
|
13
|
+
private readonly IDiscoveryWorker _discoveryWorker;
|
14
|
+
private readonly IDependencySolver _dependencySolver;
|
15
|
+
private readonly IFileWriter _fileWriter;
|
16
|
+
private readonly ILogger _logger;
|
17
|
+
|
18
|
+
public FileWriterWorker(IDiscoveryWorker discoveryWorker, IDependencySolver dependencySolver, IFileWriter fileWriter, ILogger logger)
|
19
|
+
{
|
20
|
+
_discoveryWorker = discoveryWorker;
|
21
|
+
_dependencySolver = dependencySolver;
|
22
|
+
_fileWriter = fileWriter;
|
23
|
+
_logger = logger;
|
24
|
+
}
|
25
|
+
|
26
|
+
public async Task<ImmutableArray<UpdateOperationBase>> RunAsync(
|
27
|
+
DirectoryInfo repoContentsPath,
|
28
|
+
FileInfo projectPath,
|
29
|
+
string dependencyName,
|
30
|
+
NuGetVersion oldDependencyVersion,
|
31
|
+
NuGetVersion newDependencyVersion
|
32
|
+
)
|
33
|
+
{
|
34
|
+
var updateOperations = new List<UpdateOperationBase>();
|
35
|
+
var projectDirectory = Path.GetDirectoryName(projectPath.FullName)!;
|
36
|
+
var projectDirectoryRelativeToRepoRoot = Path.GetRelativePath(repoContentsPath.FullName, projectDirectory).FullyNormalizedRootedPath();
|
37
|
+
|
38
|
+
// first try non-project updates
|
39
|
+
var updatedDotNetToolsPath = await DotNetToolsJsonUpdater.UpdateDependencyAsync(
|
40
|
+
repoContentsPath.FullName,
|
41
|
+
projectDirectory,
|
42
|
+
dependencyName,
|
43
|
+
oldDependencyVersion.ToString(),
|
44
|
+
newDependencyVersion.ToString(),
|
45
|
+
_logger
|
46
|
+
);
|
47
|
+
if (updatedDotNetToolsPath is not null)
|
48
|
+
{
|
49
|
+
updateOperations.Add(new DirectUpdate()
|
50
|
+
{
|
51
|
+
DependencyName = dependencyName,
|
52
|
+
OldVersion = oldDependencyVersion,
|
53
|
+
NewVersion = newDependencyVersion,
|
54
|
+
UpdatedFiles = [Path.GetRelativePath(repoContentsPath.FullName, updatedDotNetToolsPath).FullyNormalizedRootedPath()]
|
55
|
+
});
|
56
|
+
}
|
57
|
+
|
58
|
+
var updatedGlobalJsonPath = await GlobalJsonUpdater.UpdateDependencyAsync(
|
59
|
+
repoContentsPath.FullName,
|
60
|
+
projectDirectory,
|
61
|
+
dependencyName,
|
62
|
+
oldDependencyVersion.ToString(),
|
63
|
+
newDependencyVersion.ToString(),
|
64
|
+
_logger
|
65
|
+
);
|
66
|
+
if (updatedGlobalJsonPath is not null)
|
67
|
+
{
|
68
|
+
updateOperations.Add(new DirectUpdate()
|
69
|
+
{
|
70
|
+
DependencyName = dependencyName,
|
71
|
+
OldVersion = oldDependencyVersion,
|
72
|
+
NewVersion = newDependencyVersion,
|
73
|
+
UpdatedFiles = [Path.GetRelativePath(repoContentsPath.FullName, updatedGlobalJsonPath).FullyNormalizedRootedPath()]
|
74
|
+
});
|
75
|
+
}
|
76
|
+
|
77
|
+
// then try packages.config updates
|
78
|
+
var additionalFiles = ProjectHelper.GetAllAdditionalFilesFromProject(projectPath.FullName, ProjectHelper.PathFormat.Full);
|
79
|
+
var packagesConfigFullPath = additionalFiles.Where(p => Path.GetFileName(p).Equals(ProjectHelper.PackagesConfigFileName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
|
80
|
+
if (packagesConfigFullPath is not null)
|
81
|
+
{
|
82
|
+
var packagesConfigOperations = await PackagesConfigUpdater.UpdateDependencyAsync(
|
83
|
+
repoContentsPath.FullName,
|
84
|
+
projectPath.FullName,
|
85
|
+
dependencyName,
|
86
|
+
oldDependencyVersion.ToString(),
|
87
|
+
newDependencyVersion.ToString(),
|
88
|
+
packagesConfigFullPath,
|
89
|
+
_logger
|
90
|
+
);
|
91
|
+
var packagesConfigOperationsWithNormalizedPaths = packagesConfigOperations
|
92
|
+
.Select(op => op with { UpdatedFiles = [.. op.UpdatedFiles.Select(f => Path.GetRelativePath(repoContentsPath.FullName, f).FullyNormalizedRootedPath())] })
|
93
|
+
.ToArray();
|
94
|
+
updateOperations.AddRange(packagesConfigOperationsWithNormalizedPaths);
|
95
|
+
}
|
96
|
+
|
97
|
+
// then try project updates
|
98
|
+
var initialDiscoveryResult = await _discoveryWorker.RunAsync(repoContentsPath.FullName, projectDirectoryRelativeToRepoRoot);
|
99
|
+
var initialProjectDiscovery = initialDiscoveryResult.GetProjectDiscoveryFromFullPath(repoContentsPath, projectPath);
|
100
|
+
if (initialProjectDiscovery is null)
|
101
|
+
{
|
102
|
+
_logger.Info($"Unable to find project discovery for project {projectPath}.");
|
103
|
+
return [.. updateOperations];
|
104
|
+
}
|
105
|
+
|
106
|
+
var initialRequestedDependency = initialProjectDiscovery.Dependencies
|
107
|
+
.FirstOrDefault(d => d.Name.Equals(dependencyName, StringComparison.OrdinalIgnoreCase));
|
108
|
+
if (initialRequestedDependency is null || initialRequestedDependency.Version is null)
|
109
|
+
{
|
110
|
+
_logger.Info($"Dependency {dependencyName} not found in initial project discovery.");
|
111
|
+
return [.. updateOperations];
|
112
|
+
}
|
113
|
+
|
114
|
+
var initialDependencyVersion = NuGetVersion.Parse(initialRequestedDependency.Version);
|
115
|
+
if (initialDependencyVersion >= newDependencyVersion)
|
116
|
+
{
|
117
|
+
_logger.Info($"Dependency {dependencyName} is already at version {initialDependencyVersion}, no update needed.");
|
118
|
+
return [.. updateOperations];
|
119
|
+
}
|
120
|
+
|
121
|
+
var initialTopLevelDependencies = initialProjectDiscovery.Dependencies
|
122
|
+
.Where(d => !d.IsTransitive)
|
123
|
+
.ToImmutableArray();
|
124
|
+
var newDependency = new Dependency(dependencyName, newDependencyVersion.ToString(), DependencyType.Unknown);
|
125
|
+
var desiredDependencies = initialTopLevelDependencies.Any(d => d.Name.Equals(dependencyName, StringComparison.OrdinalIgnoreCase))
|
126
|
+
? initialTopLevelDependencies.Select(d => d.Name.Equals(dependencyName, StringComparison.OrdinalIgnoreCase) ? newDependency : d).ToImmutableArray()
|
127
|
+
: initialTopLevelDependencies.Concat([newDependency]).ToImmutableArray();
|
128
|
+
|
129
|
+
foreach (var targetFramework in initialProjectDiscovery.TargetFrameworks)
|
130
|
+
{
|
131
|
+
var resolvedDependencies = await _dependencySolver.SolveAsync(initialTopLevelDependencies, desiredDependencies, targetFramework);
|
132
|
+
if (resolvedDependencies is null)
|
133
|
+
{
|
134
|
+
_logger.Warn($"Unable to solve dependency conflicts for target framework {targetFramework}.");
|
135
|
+
continue;
|
136
|
+
}
|
137
|
+
|
138
|
+
var resolvedRequestedDependency = resolvedDependencies.Value
|
139
|
+
.SingleOrDefault(d => d.Name.Equals(dependencyName, StringComparison.OrdinalIgnoreCase));
|
140
|
+
if (resolvedRequestedDependency is null || resolvedRequestedDependency.Version is null)
|
141
|
+
{
|
142
|
+
_logger.Warn($"Dependency resolution failed to include {dependencyName}.");
|
143
|
+
continue;
|
144
|
+
}
|
145
|
+
|
146
|
+
var resolvedRequestedDependencyVersion = NuGetVersion.Parse(resolvedRequestedDependency.Version);
|
147
|
+
if (resolvedRequestedDependencyVersion != newDependencyVersion)
|
148
|
+
{
|
149
|
+
_logger.Warn($"Requested dependency resolution to include {dependencyName}/{newDependencyVersion} but it was instead resolved to {resolvedRequestedDependencyVersion}.");
|
150
|
+
continue;
|
151
|
+
}
|
152
|
+
|
153
|
+
// process all projects bottom up
|
154
|
+
var orderedProjectDiscovery = GetProjectDiscoveryEvaluationOrder(repoContentsPath, initialDiscoveryResult, projectPath, _logger);
|
155
|
+
|
156
|
+
// track original contents
|
157
|
+
var originalFileContents = await GetOriginalFileContentsAsync(repoContentsPath, new DirectoryInfo(projectDirectory), orderedProjectDiscovery);
|
158
|
+
|
159
|
+
var allUpdatedFiles = new List<string>();
|
160
|
+
foreach (var projectDiscovery in orderedProjectDiscovery)
|
161
|
+
{
|
162
|
+
var projectFullPath = Path.Join(repoContentsPath.FullName, initialDiscoveryResult.Path, projectDiscovery.FilePath).FullyNormalizedRootedPath();
|
163
|
+
var updatedFiles = await TryPerformFileWritesAsync(repoContentsPath, new FileInfo(projectFullPath), projectDiscovery, resolvedDependencies.Value);
|
164
|
+
allUpdatedFiles.AddRange(updatedFiles);
|
165
|
+
}
|
166
|
+
|
167
|
+
if (allUpdatedFiles.Count == 0)
|
168
|
+
{
|
169
|
+
_logger.Warn("Failed to write new dependency versions.");
|
170
|
+
await RestoreOriginalFileContentsAsync(originalFileContents);
|
171
|
+
continue;
|
172
|
+
}
|
173
|
+
|
174
|
+
// this final call to discover has the benefit of also updating the lock file if it exists
|
175
|
+
var finalDiscoveryResult = await _discoveryWorker.RunAsync(repoContentsPath.FullName, projectDirectoryRelativeToRepoRoot);
|
176
|
+
var finalProjectDiscovery = finalDiscoveryResult.GetProjectDiscoveryFromFullPath(repoContentsPath, projectPath);
|
177
|
+
if (finalProjectDiscovery is null)
|
178
|
+
{
|
179
|
+
_logger.Warn($"Unable to find final project discovery for project {projectPath}.");
|
180
|
+
await RestoreOriginalFileContentsAsync(originalFileContents);
|
181
|
+
continue;
|
182
|
+
}
|
183
|
+
|
184
|
+
var finalRequestedDependency = finalProjectDiscovery.Dependencies
|
185
|
+
.FirstOrDefault(d => d.Name.Equals(dependencyName, StringComparison.OrdinalIgnoreCase));
|
186
|
+
if (finalRequestedDependency is null || finalRequestedDependency.Version is null)
|
187
|
+
{
|
188
|
+
_logger.Warn($"Dependency {dependencyName} not found in final project discovery.");
|
189
|
+
await RestoreOriginalFileContentsAsync(originalFileContents);
|
190
|
+
continue;
|
191
|
+
}
|
192
|
+
|
193
|
+
var resolvedVersion = NuGetVersion.Parse(finalRequestedDependency.Version);
|
194
|
+
if (resolvedVersion != newDependencyVersion)
|
195
|
+
{
|
196
|
+
_logger.Warn($"Final dependency version for {dependencyName} is {resolvedVersion}, expected {newDependencyVersion}.");
|
197
|
+
await RestoreOriginalFileContentsAsync(originalFileContents);
|
198
|
+
continue;
|
199
|
+
}
|
200
|
+
|
201
|
+
var computedUpdateOperations = await PackageReferenceUpdater.ComputeUpdateOperations(
|
202
|
+
repoContentsPath.FullName,
|
203
|
+
projectPath.FullName,
|
204
|
+
targetFramework,
|
205
|
+
initialTopLevelDependencies,
|
206
|
+
desiredDependencies,
|
207
|
+
resolvedDependencies.Value,
|
208
|
+
new ExperimentsManager() { UseDirectDiscovery = true },
|
209
|
+
_logger);
|
210
|
+
var filteredUpdateOperations = computedUpdateOperations
|
211
|
+
.Where(op =>
|
212
|
+
{
|
213
|
+
var initialDependency = initialProjectDiscovery.Dependencies.FirstOrDefault(d => d.Name.Equals(op.DependencyName, StringComparison.OrdinalIgnoreCase));
|
214
|
+
return initialDependency is not null
|
215
|
+
&& initialDependency.Version is not null
|
216
|
+
&& NuGetVersion.Parse(initialDependency.Version) < op.NewVersion;
|
217
|
+
})
|
218
|
+
.ToImmutableArray();
|
219
|
+
var computedOperationsWithUpdatedFiles = filteredUpdateOperations
|
220
|
+
.Select(op => op with { UpdatedFiles = [.. allUpdatedFiles] })
|
221
|
+
.ToImmutableArray();
|
222
|
+
updateOperations.AddRange(computedOperationsWithUpdatedFiles);
|
223
|
+
}
|
224
|
+
|
225
|
+
var normalizedUpdateOperations = UpdateOperationBase.NormalizeUpdateOperationCollection(repoContentsPath.FullName, updateOperations);
|
226
|
+
return normalizedUpdateOperations;
|
227
|
+
}
|
228
|
+
|
229
|
+
internal static async Task<Dictionary<string, string>> GetOriginalFileContentsAsync(DirectoryInfo repoContentsPath, DirectoryInfo initialStartingDirectory, IEnumerable<ProjectDiscoveryResult> projectDiscoveryResults)
|
230
|
+
{
|
231
|
+
var filesAndContents = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
232
|
+
foreach (var projectDiscoveryResult in projectDiscoveryResults)
|
233
|
+
{
|
234
|
+
var fullProjectPath = Path.Join(initialStartingDirectory.FullName, projectDiscoveryResult.FilePath).FullyNormalizedRootedPath();
|
235
|
+
var projectContents = await File.ReadAllTextAsync(fullProjectPath);
|
236
|
+
filesAndContents[fullProjectPath] = projectContents;
|
237
|
+
|
238
|
+
foreach (var file in projectDiscoveryResult.ImportedFiles.Concat(projectDiscoveryResult.AdditionalFiles))
|
239
|
+
{
|
240
|
+
var filePath = Path.Join(Path.GetDirectoryName(fullProjectPath)!, file).FullyNormalizedRootedPath();
|
241
|
+
var fileContents = await File.ReadAllTextAsync(filePath);
|
242
|
+
filesAndContents[filePath] = fileContents;
|
243
|
+
}
|
244
|
+
}
|
245
|
+
|
246
|
+
return filesAndContents;
|
247
|
+
}
|
248
|
+
|
249
|
+
internal static async Task RestoreOriginalFileContentsAsync(Dictionary<string, string> originalFilesAndContents)
|
250
|
+
{
|
251
|
+
foreach (var (path, contents) in originalFilesAndContents)
|
252
|
+
{
|
253
|
+
await File.WriteAllTextAsync(path, contents);
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
257
|
+
internal static ImmutableArray<ProjectDiscoveryResult> GetProjectDiscoveryEvaluationOrder(DirectoryInfo repoContentsPath, WorkspaceDiscoveryResult discoveryResult, FileInfo projectPath, ILogger logger)
|
258
|
+
{
|
259
|
+
var visitedProjectPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
260
|
+
var projectsToProcess = new Queue<ProjectDiscoveryResult>();
|
261
|
+
var startingProjectDiscovery = discoveryResult.GetProjectDiscoveryFromFullPath(repoContentsPath, projectPath);
|
262
|
+
if (startingProjectDiscovery is null)
|
263
|
+
{
|
264
|
+
logger.Warn($"Unable to find project discovery for project {projectPath.FullName} in discovery result.");
|
265
|
+
return [];
|
266
|
+
}
|
267
|
+
|
268
|
+
projectsToProcess.Enqueue(startingProjectDiscovery);
|
269
|
+
|
270
|
+
var reversedProjectDiscoveryOrder = new List<ProjectDiscoveryResult>();
|
271
|
+
while (projectsToProcess.TryDequeue(out var projectDiscovery))
|
272
|
+
{
|
273
|
+
var projectFullPath = Path.Join(repoContentsPath.FullName, discoveryResult.Path, projectDiscovery.FilePath).FullyNormalizedRootedPath();
|
274
|
+
if (visitedProjectPaths.Add(projectFullPath))
|
275
|
+
{
|
276
|
+
reversedProjectDiscoveryOrder.Add(projectDiscovery);
|
277
|
+
foreach (var referencedProjectPath in projectDiscovery.ReferencedProjectPaths)
|
278
|
+
{
|
279
|
+
var referencedProjectFullPath = Path.Join(repoContentsPath.FullName, discoveryResult.Path, referencedProjectPath).FullyNormalizedRootedPath();
|
280
|
+
var referencedProjectDiscovery = discoveryResult.GetProjectDiscoveryFromFullPath(repoContentsPath, new FileInfo(referencedProjectFullPath));
|
281
|
+
if (referencedProjectDiscovery is not null)
|
282
|
+
{
|
283
|
+
projectsToProcess.Enqueue(referencedProjectDiscovery);
|
284
|
+
}
|
285
|
+
}
|
286
|
+
}
|
287
|
+
}
|
288
|
+
|
289
|
+
var projectDiscoveryOrder = ((IEnumerable<ProjectDiscoveryResult>)reversedProjectDiscoveryOrder)
|
290
|
+
.Reverse()
|
291
|
+
.ToImmutableArray();
|
292
|
+
return projectDiscoveryOrder;
|
293
|
+
}
|
294
|
+
|
295
|
+
private async Task<ImmutableArray<string>> TryPerformFileWritesAsync(DirectoryInfo repoContentsPath, FileInfo projectPath, ProjectDiscoveryResult projectDiscovery, ImmutableArray<Dependency> requiredPackageVersions)
|
296
|
+
{
|
297
|
+
var originalFileContents = await GetOriginalFileContentsAsync(repoContentsPath, projectPath.Directory!, [projectDiscovery]);
|
298
|
+
var relativeFilePaths = originalFileContents.Keys
|
299
|
+
.Select(p => Path.GetRelativePath(repoContentsPath.FullName, p).FullyNormalizedRootedPath())
|
300
|
+
.ToImmutableArray();
|
301
|
+
|
302
|
+
// try update
|
303
|
+
var addPackageReferenceElementForPinnedPackages = !projectDiscovery.CentralPackageTransitivePinningEnabled;
|
304
|
+
var success = await _fileWriter.UpdatePackageVersionsAsync(repoContentsPath, [.. relativeFilePaths], projectDiscovery.Dependencies, requiredPackageVersions, addPackageReferenceElementForPinnedPackages);
|
305
|
+
var updatedFiles = new List<string>();
|
306
|
+
foreach (var (filePath, originalContents) in originalFileContents)
|
307
|
+
{
|
308
|
+
var currentContents = await File.ReadAllTextAsync(filePath);
|
309
|
+
var currentContentsNormalized = currentContents.Replace("\r", "");
|
310
|
+
var originalContentsNormalized = originalContents.Replace("\r", "");
|
311
|
+
if (currentContentsNormalized != originalContentsNormalized)
|
312
|
+
{
|
313
|
+
var relativeUpdatedPath = Path.GetRelativePath(repoContentsPath.FullName, filePath).FullyNormalizedRootedPath();
|
314
|
+
updatedFiles.Add(relativeUpdatedPath);
|
315
|
+
}
|
316
|
+
}
|
317
|
+
|
318
|
+
if (!success)
|
319
|
+
{
|
320
|
+
await RestoreOriginalFileContentsAsync(originalFileContents);
|
321
|
+
}
|
322
|
+
|
323
|
+
var sortedUpdatedFiles = updatedFiles.OrderBy(p => p, StringComparer.Ordinal);
|
324
|
+
return [.. sortedUpdatedFiles];
|
325
|
+
}
|
326
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
|
3
|
+
namespace NuGetUpdater.Core.Updater.FileWriters;
|
4
|
+
|
5
|
+
public interface IFileWriter
|
6
|
+
{
|
7
|
+
Task<bool> UpdatePackageVersionsAsync(
|
8
|
+
DirectoryInfo repoContentsPath,
|
9
|
+
ImmutableArray<string> relativeFilePaths,
|
10
|
+
ImmutableArray<Dependency> originalDependencies,
|
11
|
+
ImmutableArray<Dependency> requiredPackageVersions,
|
12
|
+
bool addPackageReferenceElementForPinnedPackages
|
13
|
+
);
|
14
|
+
}
|