dependabot-nuget 0.351.0 → 0.353.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.Core/Discover/DiscoveryWorker.cs +17 -43
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +102 -46
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +0 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyGroup.cs +19 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +23 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +4 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/OutOfDisk.cs +9 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/IApiHandler.cs +11 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +25 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/GroupUpdateAllVersionsHandler.cs +48 -35
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandler.cs +3 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshSecurityUpdatePullRequestHandler.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshVersionUpdatePullRequestHandler.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +20 -23
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +41 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +93 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs +2 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +21 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +51 -96
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +1 -66
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/ApiModel/JobTests.cs +39 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/EndToEndTests.cs +142 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/HttpApiHandlerTests.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/JobErrorBaseTests.cs +7 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MessageReportTests.cs +11 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +76 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +8 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/GroupUpdateAllVersionsHandlerTests.cs +242 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackageReferenceUpdaterTests.cs +30 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +25 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/PathHelperTests.cs +250 -0
- metadata +5 -4
data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/GroupUpdateAllVersionsHandler.cs
CHANGED
|
@@ -51,19 +51,12 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
|
|
|
51
51
|
var repoContentsPath = caseInsensitiveRepoContentsPath ?? originalRepoContentsPath;
|
|
52
52
|
foreach (var group in job.DependencyGroups)
|
|
53
53
|
{
|
|
54
|
-
var existingGroupPr = job.ExistingGroupPullRequests.FirstOrDefault(pr => pr.DependencyGroupName == group.Name);
|
|
55
|
-
if (existingGroupPr is not null)
|
|
56
|
-
{
|
|
57
|
-
logger.Info($"Existing pull request found for group {group.Name}. Skipping pull request creation.");
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
54
|
logger.Info($"Starting update for group {group.Name}");
|
|
62
55
|
var groupMatcher = group.GetGroupMatcher();
|
|
63
56
|
var updateOperationsPerformed = new List<UpdateOperationBase>();
|
|
64
57
|
var updatedDependencies = new List<ReportedDependency>();
|
|
65
58
|
var allUpdatedDependencyFiles = ImmutableArray.Create<DependencyFile>();
|
|
66
|
-
foreach (var directory in job.GetAllDirectories())
|
|
59
|
+
foreach (var directory in job.GetAllDirectories(repoContentsPath.FullName))
|
|
67
60
|
{
|
|
68
61
|
var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, directory);
|
|
69
62
|
logger.ReportDiscovery(discoveryResult);
|
|
@@ -98,7 +91,7 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
|
|
|
98
91
|
continue;
|
|
99
92
|
}
|
|
100
93
|
|
|
101
|
-
var dependencyInfo = RunWorker.GetDependencyInfo(job, dependency, allowCooldown: true);
|
|
94
|
+
var dependencyInfo = RunWorker.GetDependencyInfo(job, dependency, groupMatchers: [groupMatcher], allowCooldown: true);
|
|
102
95
|
var analysisResult = await analyzeWorker.RunAsync(repoContentsPath.FullName, discoveryResult, dependencyInfo);
|
|
103
96
|
if (analysisResult.Error is not null)
|
|
104
97
|
{
|
|
@@ -146,19 +139,29 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
|
|
|
146
139
|
|
|
147
140
|
if (updateOperationsPerformed.Count > 0)
|
|
148
141
|
{
|
|
149
|
-
var
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
142
|
+
var existingPullRequest = job.GetExistingPullRequestForDependencies(
|
|
143
|
+
dependencies: updatedDependencies.Select(d => new Dependency(d.Name, d.Version, DependencyType.Unknown)),
|
|
144
|
+
considerVersions: true);
|
|
145
|
+
if (existingPullRequest is not null)
|
|
153
146
|
{
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
147
|
+
logger.Info($"Pull request already exists for {string.Join(", ", existingPullRequest!.Item2.Select(d => $"{d.DependencyName}/{d.DependencyVersion}"))}");
|
|
148
|
+
}
|
|
149
|
+
else
|
|
150
|
+
{
|
|
151
|
+
var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], group.Name);
|
|
152
|
+
var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], group.Name);
|
|
153
|
+
var prBody = await PullRequestTextGenerator.GetPullRequestBodyAsync(job, [.. updateOperationsPerformed], [.. updatedDependencies], experimentsManager);
|
|
154
|
+
await apiHandler.CreatePullRequest(new CreatePullRequest()
|
|
155
|
+
{
|
|
156
|
+
Dependencies = [.. updatedDependencies],
|
|
157
|
+
UpdatedDependencyFiles = [.. allUpdatedDependencyFiles],
|
|
158
|
+
BaseCommitSha = baseCommitSha,
|
|
159
|
+
CommitMessage = commitMessage,
|
|
160
|
+
PrTitle = prTitle,
|
|
161
|
+
PrBody = prBody,
|
|
162
|
+
DependencyGroup = group.Name,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
162
165
|
}
|
|
163
166
|
}
|
|
164
167
|
}
|
|
@@ -166,7 +169,7 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
|
|
|
166
169
|
private async Task RunUngroupedDependencyUpdates(Job job, DirectoryInfo originalRepoContentsPath, DirectoryInfo? caseInsensitiveRepoContentsPath, string baseCommitSha, IDiscoveryWorker discoveryWorker, IAnalyzeWorker analyzeWorker, IUpdaterWorker updaterWorker, IApiHandler apiHandler, ExperimentsManager experimentsManager, ILogger logger)
|
|
167
170
|
{
|
|
168
171
|
var repoContentsPath = caseInsensitiveRepoContentsPath ?? originalRepoContentsPath;
|
|
169
|
-
foreach (var directory in job.GetAllDirectories())
|
|
172
|
+
foreach (var directory in job.GetAllDirectories(repoContentsPath.FullName))
|
|
170
173
|
{
|
|
171
174
|
var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, directory);
|
|
172
175
|
logger.ReportDiscovery(discoveryResult);
|
|
@@ -210,7 +213,7 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
|
|
|
210
213
|
continue;
|
|
211
214
|
}
|
|
212
215
|
|
|
213
|
-
var dependencyInfo = RunWorker.GetDependencyInfo(job, dependency, allowCooldown: true);
|
|
216
|
+
var dependencyInfo = RunWorker.GetDependencyInfo(job, dependency, groupMatchers: [], allowCooldown: true);
|
|
214
217
|
var analysisResult = await analyzeWorker.RunAsync(repoContentsPath.FullName, discoveryResult, dependencyInfo);
|
|
215
218
|
if (analysisResult.Error is not null)
|
|
216
219
|
{
|
|
@@ -254,19 +257,29 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
|
|
|
254
257
|
var updatedDependencyFiles = await tracker.StopTrackingAsync(restoreOriginalContents: true);
|
|
255
258
|
if (updateOperationsPerformed.Count > 0)
|
|
256
259
|
{
|
|
257
|
-
var
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
260
|
+
var existingPullRequest = job.GetExistingPullRequestForDependencies(
|
|
261
|
+
dependencies: updatedDependencies.Select(d => new Dependency(d.Name, d.Version, DependencyType.Unknown)),
|
|
262
|
+
considerVersions: true);
|
|
263
|
+
if (existingPullRequest is not null)
|
|
261
264
|
{
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
265
|
+
logger.Info($"Pull request already exists for {string.Join(", ", existingPullRequest!.Item2.Select(d => $"{d.DependencyName}/{d.DependencyVersion}"))}");
|
|
266
|
+
}
|
|
267
|
+
else
|
|
268
|
+
{
|
|
269
|
+
var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], null);
|
|
270
|
+
var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], null);
|
|
271
|
+
var prBody = await PullRequestTextGenerator.GetPullRequestBodyAsync(job, [.. updateOperationsPerformed], [.. updatedDependencies], experimentsManager);
|
|
272
|
+
await apiHandler.CreatePullRequest(new CreatePullRequest()
|
|
273
|
+
{
|
|
274
|
+
Dependencies = [.. updatedDependencies],
|
|
275
|
+
UpdatedDependencyFiles = [.. updatedDependencyFiles],
|
|
276
|
+
BaseCommitSha = baseCommitSha,
|
|
277
|
+
CommitMessage = commitMessage,
|
|
278
|
+
PrTitle = prTitle,
|
|
279
|
+
PrBody = prBody,
|
|
280
|
+
DependencyGroup = null,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
270
283
|
}
|
|
271
284
|
}
|
|
272
285
|
}
|
|
@@ -21,7 +21,7 @@ internal class RefreshGroupUpdatePullRequestHandler : IUpdateHandler
|
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
if (job.
|
|
24
|
+
if (job.GetRawDirectories().Length > 1)
|
|
25
25
|
{
|
|
26
26
|
return true;
|
|
27
27
|
}
|
|
@@ -62,7 +62,7 @@ internal class RefreshGroupUpdatePullRequestHandler : IUpdateHandler
|
|
|
62
62
|
|
|
63
63
|
var groupMatcher = group.GetGroupMatcher();
|
|
64
64
|
var jobDependencies = job.Dependencies.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
65
|
-
foreach (var directory in job.GetAllDirectories())
|
|
65
|
+
foreach (var directory in job.GetAllDirectories(repoContentsPath.FullName))
|
|
66
66
|
{
|
|
67
67
|
var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, directory);
|
|
68
68
|
logger.ReportDiscovery(discoveryResult);
|
|
@@ -93,7 +93,7 @@ internal class RefreshGroupUpdatePullRequestHandler : IUpdateHandler
|
|
|
93
93
|
var dependencyName = dependencyGroupToUpdate.Key;
|
|
94
94
|
var relevantDependenciesToUpdate = dependencyGroupToUpdate.Value
|
|
95
95
|
.Where(o => !job.IsDependencyIgnoredByNameOnly(o.Dependency.Name))
|
|
96
|
-
.Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency, allowCooldown: true)))
|
|
96
|
+
.Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency, groupMatchers: [groupMatcher], allowCooldown: true)))
|
|
97
97
|
.ToArray();
|
|
98
98
|
|
|
99
99
|
foreach (var (projectPath, dependency, dependencyInfo) in relevantDependenciesToUpdate)
|
|
@@ -30,7 +30,7 @@ internal class RefreshSecurityUpdatePullRequestHandler : IUpdateHandler
|
|
|
30
30
|
{
|
|
31
31
|
var repoContentsPath = caseInsensitiveRepoContentsPath ?? originalRepoContentsPath;
|
|
32
32
|
var jobDependencies = job.Dependencies.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
33
|
-
foreach (var directory in job.GetAllDirectories())
|
|
33
|
+
foreach (var directory in job.GetAllDirectories(repoContentsPath.FullName))
|
|
34
34
|
{
|
|
35
35
|
var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, directory);
|
|
36
36
|
logger.ReportDiscovery(discoveryResult);
|
|
@@ -82,7 +82,7 @@ internal class RefreshSecurityUpdatePullRequestHandler : IUpdateHandler
|
|
|
82
82
|
var dependencyName = dependencyGroupToUpdate.Key;
|
|
83
83
|
var vulnerableDependenciesToUpdate = dependencyGroupToUpdate.Value
|
|
84
84
|
.Where(o => !job.IsDependencyIgnoredByNameOnly(o.Dependency.Name))
|
|
85
|
-
.Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency, allowCooldown: false)))
|
|
85
|
+
.Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency, groupMatchers: [], allowCooldown: false)))
|
|
86
86
|
.Where(set => set.Item3.IsVulnerable)
|
|
87
87
|
.ToArray();
|
|
88
88
|
|
|
@@ -30,7 +30,7 @@ internal class RefreshVersionUpdatePullRequestHandler : IUpdateHandler
|
|
|
30
30
|
{
|
|
31
31
|
var repoContentsPath = caseInsensitiveRepoContentsPath ?? originalRepoContentsPath;
|
|
32
32
|
var jobDependencies = job.Dependencies.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
33
|
-
foreach (var directory in job.GetAllDirectories())
|
|
33
|
+
foreach (var directory in job.GetAllDirectories(repoContentsPath.FullName))
|
|
34
34
|
{
|
|
35
35
|
var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, directory);
|
|
36
36
|
logger.ReportDiscovery(discoveryResult);
|
|
@@ -81,7 +81,7 @@ internal class RefreshVersionUpdatePullRequestHandler : IUpdateHandler
|
|
|
81
81
|
var dependencyName = dependencyUpdatesToPerform.Key;
|
|
82
82
|
var dependencyInfosToUpdate = dependencyUpdatesToPerform.Value
|
|
83
83
|
.Where(o => !job.IsDependencyIgnoredByNameOnly(o.Dependency.Name))
|
|
84
|
-
.Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency, allowCooldown: true)))
|
|
84
|
+
.Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency, groupMatchers: [], allowCooldown: true)))
|
|
85
85
|
.ToArray();
|
|
86
86
|
|
|
87
87
|
foreach (var (projectPath, dependency, dependencyInfo) in dependencyInfosToUpdate)
|
|
@@ -108,7 +108,7 @@ internal static class PackageReferenceUpdater
|
|
|
108
108
|
return [.. updateOperations];
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
internal static async Task<(Dictionary<string, HashSet<string>> PackageParents, Dictionary<string, NuGetVersion> PackageVersions)> GetPackageGraphForDependencies(string repoRoot, string projectPath, string targetFramework, ImmutableArray<Dependency> topLevelDependencies, ILogger logger)
|
|
112
112
|
{
|
|
113
113
|
var packageParents = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
|
|
114
114
|
var packageVersions = new Dictionary<string, NuGetVersion>(StringComparer.OrdinalIgnoreCase);
|
|
@@ -117,37 +117,34 @@ internal static class PackageReferenceUpdater
|
|
|
117
117
|
{
|
|
118
118
|
// generate project.assets.json
|
|
119
119
|
var parsedTargetFramework = NuGetFramework.Parse(targetFramework);
|
|
120
|
-
var tempProject = await MSBuildHelper.CreateTempProjectAsync(tempDir, repoRoot, projectPath, targetFramework, topLevelDependencies, logger, importDependencyTargets:
|
|
121
|
-
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["
|
|
120
|
+
var tempProject = await MSBuildHelper.CreateTempProjectAsync(tempDir, repoRoot, projectPath, targetFramework, topLevelDependencies, logger, importDependencyTargets: true);
|
|
121
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["msbuild", tempProject, "/t:Restore,GenerateBuildDependencyFile"], tempDir.FullName);
|
|
122
122
|
var assetsJsonPath = Path.Join(tempDir.FullName, "obj", "project.assets.json");
|
|
123
123
|
var assetsJsonContent = await File.ReadAllTextAsync(assetsJsonPath);
|
|
124
124
|
|
|
125
125
|
// build reverse dependency graph
|
|
126
126
|
var assets = JsonDocument.Parse(assetsJsonContent).RootElement;
|
|
127
|
-
|
|
127
|
+
var tfmObjects = assets.GetProperty("targets").EnumerateObject().ToImmutableArray();
|
|
128
|
+
if (tfmObjects.Length != 1)
|
|
128
129
|
{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
// not interested in this target framework
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
130
|
+
logger.Error($"Expected exactly one target framework group compatible with {targetFramework} but found {tfmObjects.Length}. Values: {tfmObjects.Select(t => t.Name)}");
|
|
131
|
+
return (packageParents, packageVersions);
|
|
132
|
+
}
|
|
135
133
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
134
|
+
foreach (var parentObject in tfmObjects[0].Value.EnumerateObject())
|
|
135
|
+
{
|
|
136
|
+
var parts = parentObject.Name.Split('/');
|
|
137
|
+
var parentName = parts[0];
|
|
138
|
+
var parentVersion = parts[1];
|
|
139
|
+
packageVersions[parentName] = NuGetVersion.Parse(parentVersion);
|
|
142
140
|
|
|
143
|
-
|
|
141
|
+
if (parentObject.Value.TryGetProperty("dependencies", out var dependencies))
|
|
142
|
+
{
|
|
143
|
+
foreach (var childObject in dependencies.EnumerateObject())
|
|
144
144
|
{
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
var parentSet = packageParents.GetOrAdd(childName, () => new(StringComparer.OrdinalIgnoreCase));
|
|
149
|
-
parentSet.Add(parentName);
|
|
150
|
-
}
|
|
145
|
+
var childName = childObject.Name;
|
|
146
|
+
var parentSet = packageParents.GetOrAdd(childName, () => new(StringComparer.OrdinalIgnoreCase));
|
|
147
|
+
parentSet.Add(parentName);
|
|
151
148
|
}
|
|
152
149
|
}
|
|
153
150
|
}
|
|
@@ -493,7 +493,7 @@ internal static partial class MSBuildHelper
|
|
|
493
493
|
var topLevelPackagesNames = packages.Select(p => p.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
494
494
|
var tempProjectPath = await CreateTempProjectAsync(tempDirectory, repoRoot, projectPath, targetFramework, packages, logger, importDependencyTargets: false);
|
|
495
495
|
|
|
496
|
-
var experimentsManager = new ExperimentsManager()
|
|
496
|
+
var experimentsManager = new ExperimentsManager();
|
|
497
497
|
var projectDiscovery = await SdkProjectDiscovery.DiscoverAsync(repoRoot, tempDirectory.FullName, tempProjectPath, experimentsManager, logger);
|
|
498
498
|
var allDependencies = projectDiscovery
|
|
499
499
|
.Where(p => p.FilePath == Path.GetFileName(tempProjectPath))
|
|
@@ -545,6 +545,37 @@ internal static partial class MSBuildHelper
|
|
|
545
545
|
return targets;
|
|
546
546
|
}
|
|
547
547
|
|
|
548
|
+
internal static async Task<ImmutableArray<string>> GetProjectTargetFrameworksAsync(string projectPath, ILogger logger)
|
|
549
|
+
{
|
|
550
|
+
var extension = Path.GetExtension(projectPath)?.ToLowerInvariant();
|
|
551
|
+
if (extension == ".sln" || extension == ".slnx")
|
|
552
|
+
{
|
|
553
|
+
// solution files don't specify target frameworks, so we can skip the process invocation
|
|
554
|
+
return [];
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
var projectDirectory = Path.GetDirectoryName(projectPath)!;
|
|
558
|
+
var args = new[]
|
|
559
|
+
{
|
|
560
|
+
"msbuild",
|
|
561
|
+
projectPath,
|
|
562
|
+
"-getProperty:TargetFrameworks"
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(args, projectDirectory);
|
|
566
|
+
if (exitCode != 0)
|
|
567
|
+
{
|
|
568
|
+
logger.Warn($"Unable to determine target frameworks for project [{projectPath}]:\nSTDOUT:\n{stdOut}\nSTDERR:\n{stdErr}\n");
|
|
569
|
+
return [];
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
var tfms = Regex.Replace(stdOut, "@[\r\n\t ]", "")
|
|
573
|
+
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
|
574
|
+
.OrderBy(t => t)
|
|
575
|
+
.ToImmutableArray();
|
|
576
|
+
return tfms;
|
|
577
|
+
}
|
|
578
|
+
|
|
548
579
|
internal static string? GetMissingFile(string output)
|
|
549
580
|
{
|
|
550
581
|
var missingFilePatterns = new[]
|
|
@@ -571,6 +602,7 @@ internal static partial class MSBuildHelper
|
|
|
571
602
|
ThrowOnTimeout(output);
|
|
572
603
|
ThrowOnBadResponse(output);
|
|
573
604
|
ThrowOnUnparseableFile(output);
|
|
605
|
+
ThrowOnMultipleProjectsForPackagesConfig(output);
|
|
574
606
|
}
|
|
575
607
|
|
|
576
608
|
private static void ThrowOnUnauthenticatedFeed(string stdout)
|
|
@@ -704,6 +736,14 @@ internal static partial class MSBuildHelper
|
|
|
704
736
|
}
|
|
705
737
|
}
|
|
706
738
|
|
|
739
|
+
private static void ThrowOnMultipleProjectsForPackagesConfig(string output)
|
|
740
|
+
{
|
|
741
|
+
if (output.Contains("Found multiple project files for "))
|
|
742
|
+
{
|
|
743
|
+
throw new Exception("Multiple project files found for single packages.config");
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
707
747
|
internal static bool TryGetGlobalJsonPath(string repoRootPath, string workspacePath, [NotNullWhen(returnValue: true)] out string? globalJsonPath)
|
|
708
748
|
{
|
|
709
749
|
globalJsonPath = PathHelper.GetFileInDirectoryOrParent(workspacePath, repoRootPath, "global.json", caseSensitive: false);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
using System.Collections.Immutable;
|
|
1
2
|
using System.Runtime.InteropServices;
|
|
3
|
+
using System.Text;
|
|
2
4
|
using System.Text.RegularExpressions;
|
|
3
5
|
|
|
4
6
|
namespace NuGetUpdater.Core;
|
|
@@ -248,4 +250,95 @@ internal static class PathHelper
|
|
|
248
250
|
|
|
249
251
|
return candidateFilePath.StartsWith(directoryPath);
|
|
250
252
|
}
|
|
253
|
+
|
|
254
|
+
public static ImmutableArray<string> GetMatchingDirectoriesUnder(string rootDirectory, string searchPattern, bool caseSensitive)
|
|
255
|
+
{
|
|
256
|
+
// translate pattern to regex
|
|
257
|
+
searchPattern = searchPattern.Replace("\\", "/"); // unix-style paths make things easier
|
|
258
|
+
searchPattern = searchPattern.TrimStart('/'); // pattern shouldn't be rooted
|
|
259
|
+
if (searchPattern == string.Empty)
|
|
260
|
+
{
|
|
261
|
+
searchPattern = "/"; // special case repo root
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
var pb = new StringBuilder();
|
|
265
|
+
pb.Append('^');
|
|
266
|
+
var appendAnchor = true;
|
|
267
|
+
for (int i = 0; i < searchPattern.Length; i++)
|
|
268
|
+
{
|
|
269
|
+
// special case recursive wildcard
|
|
270
|
+
if (searchPattern[i..] == "/**/*")
|
|
271
|
+
{
|
|
272
|
+
pb.Append("($|/.*$)"); // capture just this directory and every subdirectory
|
|
273
|
+
appendAnchor = false;
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
var c = searchPattern[i];
|
|
278
|
+
switch (c)
|
|
279
|
+
{
|
|
280
|
+
case '*':
|
|
281
|
+
// could be single level or multi-level
|
|
282
|
+
var isRecursiveMatch = i < searchPattern.Length - 2
|
|
283
|
+
&& searchPattern[i + 1] == '*'
|
|
284
|
+
&& searchPattern[i + 2] == '/';
|
|
285
|
+
if (isRecursiveMatch)
|
|
286
|
+
{
|
|
287
|
+
// match anything
|
|
288
|
+
pb.Append(".*");
|
|
289
|
+
i += 2; // consume the extra characters
|
|
290
|
+
}
|
|
291
|
+
else
|
|
292
|
+
{
|
|
293
|
+
// only match up to a directory separator
|
|
294
|
+
pb.Append("[^/]*");
|
|
295
|
+
}
|
|
296
|
+
break;
|
|
297
|
+
case '?':
|
|
298
|
+
pb.Append(".");
|
|
299
|
+
break;
|
|
300
|
+
case '/':
|
|
301
|
+
pb.Append("/");
|
|
302
|
+
break;
|
|
303
|
+
default:
|
|
304
|
+
if ("+()^$.{}[]|\\".Contains(c))
|
|
305
|
+
{
|
|
306
|
+
pb.Append('\\');
|
|
307
|
+
}
|
|
308
|
+
pb.Append(c);
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (appendAnchor)
|
|
314
|
+
{
|
|
315
|
+
pb.Append('$');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
var pattern = new Regex(pb.ToString(), caseSensitive ? RegexOptions.IgnoreCase : RegexOptions.None);
|
|
319
|
+
|
|
320
|
+
// find all directories
|
|
321
|
+
var allDirectories = Directory.EnumerateDirectories(rootDirectory, "*", SearchOption.AllDirectories)
|
|
322
|
+
.Select(d => Path.GetRelativePath(rootDirectory, d).NormalizePathToUnix())
|
|
323
|
+
.ToImmutableArray();
|
|
324
|
+
|
|
325
|
+
// filter
|
|
326
|
+
var matchingDirectories = allDirectories.Where(pattern.IsMatch)
|
|
327
|
+
.OrderBy(d => d, caseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase)
|
|
328
|
+
.Select(d => d.EnsurePrefix("/")) // paths must appear rooted from here on out
|
|
329
|
+
.ToImmutableArray();
|
|
330
|
+
|
|
331
|
+
// special case some well-known directories that are hard to generate patterns for
|
|
332
|
+
switch (searchPattern)
|
|
333
|
+
{
|
|
334
|
+
case "/":
|
|
335
|
+
case ".":
|
|
336
|
+
case "/.":
|
|
337
|
+
case "**/*":
|
|
338
|
+
matchingDirectories = [.. matchingDirectories.Prepend("/")];
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return matchingDirectories;
|
|
343
|
+
}
|
|
251
344
|
}
|
data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs
CHANGED
|
@@ -61,13 +61,10 @@ public partial class DiscoveryWorkerTests
|
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
[
|
|
65
|
-
|
|
66
|
-
[InlineData(false)]
|
|
67
|
-
public async Task DiscoveryIsMergedWithPackageReferences(bool useSingleRestore)
|
|
64
|
+
[Fact]
|
|
65
|
+
public async Task DiscoveryIsMergedWithPackageReferences()
|
|
68
66
|
{
|
|
69
67
|
await TestDiscoveryAsync(
|
|
70
|
-
experimentsManager: new ExperimentsManager() { UseSingleRestore = useSingleRestore },
|
|
71
68
|
packages:
|
|
72
69
|
[
|
|
73
70
|
MockNuGetPackage.CreateSimplePackage("Package.A", "1.0.0", "net46"),
|
data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs
CHANGED
|
@@ -626,7 +626,7 @@ public partial class DiscoveryWorkerTests
|
|
|
626
626
|
("src/project.csproj", """
|
|
627
627
|
<Project Sdk="Microsoft.NET.Sdk">
|
|
628
628
|
<PropertyGroup>
|
|
629
|
-
<TargetFrameworks>net8.0-
|
|
629
|
+
<TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst;net8.0-macos;net8.0-windows</TargetFrameworks>
|
|
630
630
|
</PropertyGroup>
|
|
631
631
|
<ItemGroup>
|
|
632
632
|
<PackageReference Include="Some.Package" Version="1.2.3" />
|
|
@@ -645,7 +645,7 @@ public partial class DiscoveryWorkerTests
|
|
|
645
645
|
new("Some.Package", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net8.0-android", "net8.0-ios", "net8.0-maccatalyst", "net8.0-macos", "net8.0-windows"], IsDirect: true),
|
|
646
646
|
],
|
|
647
647
|
Properties = [
|
|
648
|
-
new("TargetFrameworks", "net8.0-
|
|
648
|
+
new("TargetFrameworks", "net8.0-android;net8.0-ios;net8.0-maccatalyst;net8.0-macos;net8.0-windows", @"src/project.csproj"),
|
|
649
649
|
],
|
|
650
650
|
TargetFrameworks = ["net8.0-android", "net8.0-ios", "net8.0-maccatalyst", "net8.0-macos", "net8.0-windows"],
|
|
651
651
|
ReferencedProjectPaths = [],
|
|
@@ -737,7 +737,7 @@ public partial class DiscoveryWorkerTests
|
|
|
737
737
|
|
|
738
738
|
// The SDK package handling is detected in a very specific circumstance; an assembly being removed from the
|
|
739
739
|
// `@(References)` item group in the `_HandlePackageFileConflicts` target. Since we don't want to involve
|
|
740
|
-
// the real SDK, we fake some required targets.
|
|
740
|
+
// the real SDK, we fake some required targets in the same shape as the real SDK.
|
|
741
741
|
await TestDiscoveryAsync(
|
|
742
742
|
packages: [],
|
|
743
743
|
workspacePath: "",
|
|
@@ -764,6 +764,14 @@ public partial class DiscoveryWorkerTests
|
|
|
764
764
|
<Reference Include="@(RuntimeCopyLocalItems)" />
|
|
765
765
|
</ItemGroup>
|
|
766
766
|
|
|
767
|
+
<Target Name="ResolveProjectReferences">
|
|
768
|
+
<!-- this target needs to exist for discovery to work -->
|
|
769
|
+
</Target>
|
|
770
|
+
|
|
771
|
+
<Target Name="Restore">
|
|
772
|
+
<!-- this target needs to exist for discovery to work -->
|
|
773
|
+
</Target>
|
|
774
|
+
|
|
767
775
|
<Target Name="_HandlePackageFileConflicts">
|
|
768
776
|
<!-- this target needs to exist for discovery to work -->
|
|
769
777
|
<ItemGroup>
|
|
@@ -775,21 +783,25 @@ public partial class DiscoveryWorkerTests
|
|
|
775
783
|
</ItemGroup>
|
|
776
784
|
</Target>
|
|
777
785
|
|
|
778
|
-
<Target Name="
|
|
786
|
+
<Target Name="ResolvePackageAssets">
|
|
779
787
|
<!-- this target needs to exist for discovery to work -->
|
|
780
788
|
</Target>
|
|
781
789
|
|
|
782
|
-
<Target Name="
|
|
790
|
+
<Target Name="ResolveFrameworkReferences" DependsOnTargets="ResolvePackageAssets">
|
|
791
|
+
<!-- this target needs to exist for discovery to work -->
|
|
792
|
+
</Target>
|
|
793
|
+
|
|
794
|
+
<Target Name="ResolveRuntimePackAssets" DependsOnTargets="ResolveFrameworkReferences">
|
|
795
|
+
<!-- this target needs to exist for discovery to work -->
|
|
796
|
+
</Target>
|
|
797
|
+
|
|
798
|
+
<Target Name="GenerateBuildDependencyFile" DependsOnTargets="_HandlePackageFileConflicts;ResolveRuntimePackAssets">
|
|
783
799
|
<!-- this target needs to exist for discovery to work -->
|
|
784
800
|
<ItemGroup>
|
|
785
801
|
<!-- this removal is what removes the regular package reference from the project -->
|
|
786
802
|
<RuntimeCopyLocalItems Remove="TestOnlyAssembly.dll" />
|
|
787
803
|
</ItemGroup>
|
|
788
804
|
</Target>
|
|
789
|
-
|
|
790
|
-
<Target Name="ResolvePackageAssets">
|
|
791
|
-
<!-- this target needs to exist for discovery to work -->
|
|
792
|
-
</Target>
|
|
793
805
|
</Project>
|
|
794
806
|
""")
|
|
795
807
|
],
|