dependabot-nuget 0.398.0 → 0.400.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/Directory.Packages.props +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +48 -11
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +31 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/PackageVersionsCache.cs +91 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +8 -25
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Condition.cs +17 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyGroup.cs +37 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +66 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestTextGenerator.cs +44 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/GroupUpdateAllVersionsHandler.cs +177 -36
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandler.cs +35 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +107 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/VersionFinderTests.cs +406 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +269 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestTextTests.cs +32 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +33 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandlerTests.cs +11 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/GroupUpdateAllVersionsHandlerTests.cs +404 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandlerTests.cs +242 -0
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a29d38c1ed416c5fc9c810f3815f241789054754ff92ac4982bf65e9ef221488
|
|
4
|
+
data.tar.gz: 75c1ce1d121fc582d1ad2edbd1e3a35bb79e6955501984585643e455a85e4934
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 525d56946331f53dabd8705aa5a903b2489b89e2ebf40a5cc3b514dbf4c28d93633e09a46330d8d0b0509e7feb2439a988a408dd4f01e5ce71cf4b4c6a7cbb41
|
|
7
|
+
data.tar.gz: 2bdbf0b8a2c5302646e50fa666a14b91567dfecc96713472a419f15407c1c7a7628470adec534c50edf342ac4f3356f90840bf1d8c65526f24660d6b005fd9c1
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="5.9.0" />
|
|
18
18
|
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
|
|
19
19
|
<PackageVersion Include="Microsoft.Extensions.FileProviders.Abstractions" Version="10.0.12" />
|
|
20
|
-
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="10.0.
|
|
20
|
+
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="10.0.12" />
|
|
21
21
|
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.12" />
|
|
22
22
|
<PackageVersion Include="Microsoft.NET.StringTools" Version="$(MSBuildPackageVersion)" />
|
|
23
|
-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.
|
|
23
|
+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.10.1" />
|
|
24
24
|
<PackageVersion Include="Microsoft.VisualStudio.Setup.Configuration.Interop" Version="3.14.2075" />
|
|
25
25
|
<PackageVersion Include="Microsoft.VisualStudio.SolutionPersistence" Version="1.0.52" />
|
|
26
26
|
<PackageVersion Include="Microsoft.Web.Xdt" Version="3.2.11" />
|
|
@@ -20,6 +20,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
20
20
|
private readonly string _jobId;
|
|
21
21
|
private readonly ExperimentsManager _experimentsManager;
|
|
22
22
|
private readonly ILogger _logger;
|
|
23
|
+
private readonly PackageVersionsCache _packageVersionsCache = new();
|
|
23
24
|
|
|
24
25
|
internal static readonly JsonSerializerOptions SerializerOptions = new()
|
|
25
26
|
{
|
|
@@ -96,7 +97,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
96
97
|
|
|
97
98
|
bool isProjectUpdateNecessary = IsUpdateNecessary(dependencyInfo, projectsWithDependency);
|
|
98
99
|
var isUpdateNecessary = isProjectUpdateNecessary || dotnetToolsHasDependency || globalJsonHasDependency;
|
|
99
|
-
using var nugetContext = new NuGetContext(startingDirectory);
|
|
100
|
+
using var nugetContext = new NuGetContext(startingDirectory, packageVersionsCache: _packageVersionsCache);
|
|
100
101
|
AnalysisResult analysisResult;
|
|
101
102
|
if (isUpdateNecessary)
|
|
102
103
|
{
|
|
@@ -120,6 +121,34 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
120
121
|
.ToImmutableArray()
|
|
121
122
|
: projectFrameworks;
|
|
122
123
|
|
|
124
|
+
ImmutableArray<Dependency> candidateUpdatedDependencies = [];
|
|
125
|
+
Func<NuGetVersion, Task<bool>>? candidateValidator = null;
|
|
126
|
+
if (isProjectUpdateNecessary)
|
|
127
|
+
{
|
|
128
|
+
candidateValidator = async candidateVersion =>
|
|
129
|
+
{
|
|
130
|
+
try
|
|
131
|
+
{
|
|
132
|
+
candidateUpdatedDependencies = await FindUpdatedDependenciesAsync(
|
|
133
|
+
repoRoot,
|
|
134
|
+
discovery,
|
|
135
|
+
dependenciesToUpdate,
|
|
136
|
+
candidateVersion,
|
|
137
|
+
nugetContext,
|
|
138
|
+
_logger,
|
|
139
|
+
CancellationToken.None);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch (DependencyNotFoundException ex)
|
|
143
|
+
{
|
|
144
|
+
_logger.Info(
|
|
145
|
+
$" Rejecting version {candidateVersion.ToNormalizedString()} because dependencies could not be found: " +
|
|
146
|
+
$"{string.Join(", ", ex.Dependencies)}");
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
123
152
|
_logger.Info($" Finding updated version.");
|
|
124
153
|
updatedVersion = await FindUpdatedVersionAsync(
|
|
125
154
|
startingDirectory,
|
|
@@ -128,6 +157,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
128
157
|
applicableTargetFrameworks,
|
|
129
158
|
nugetContext,
|
|
130
159
|
_logger,
|
|
160
|
+
candidateValidator,
|
|
131
161
|
CancellationToken.None);
|
|
132
162
|
|
|
133
163
|
_logger.Info($" Finding updated peer dependencies.");
|
|
@@ -137,14 +167,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
137
167
|
}
|
|
138
168
|
else if (isProjectUpdateNecessary)
|
|
139
169
|
{
|
|
140
|
-
updatedDependencies =
|
|
141
|
-
repoRoot,
|
|
142
|
-
discovery,
|
|
143
|
-
dependenciesToUpdate,
|
|
144
|
-
updatedVersion,
|
|
145
|
-
nugetContext,
|
|
146
|
-
_logger,
|
|
147
|
-
CancellationToken.None);
|
|
170
|
+
updatedDependencies = candidateUpdatedDependencies;
|
|
148
171
|
}
|
|
149
172
|
else if (dotnetToolsHasDependency)
|
|
150
173
|
{
|
|
@@ -232,6 +255,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
232
255
|
ImmutableArray<NuGetFramework> projectFrameworks,
|
|
233
256
|
NuGetContext nugetContext,
|
|
234
257
|
ILogger logger,
|
|
258
|
+
Func<NuGetVersion, Task<bool>>? candidateValidator,
|
|
235
259
|
CancellationToken cancellationToken)
|
|
236
260
|
{
|
|
237
261
|
var versionResult = await VersionFinder.GetVersionsAsync(
|
|
@@ -250,6 +274,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
250
274
|
findLowestVersion: dependencyInfo.IsVulnerable,
|
|
251
275
|
nugetContext,
|
|
252
276
|
logger,
|
|
277
|
+
candidateValidator,
|
|
253
278
|
cancellationToken);
|
|
254
279
|
}
|
|
255
280
|
|
|
@@ -261,6 +286,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
261
286
|
bool findLowestVersion,
|
|
262
287
|
NuGetContext nugetContext,
|
|
263
288
|
ILogger logger,
|
|
289
|
+
Func<NuGetVersion, Task<bool>>? candidateValidator,
|
|
264
290
|
CancellationToken cancellationToken)
|
|
265
291
|
{
|
|
266
292
|
var versions = versionResult.GetVersions();
|
|
@@ -282,6 +308,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
282
308
|
projectFrameworks,
|
|
283
309
|
nugetContext,
|
|
284
310
|
logger,
|
|
311
|
+
candidateValidator,
|
|
285
312
|
cancellationToken);
|
|
286
313
|
}
|
|
287
314
|
|
|
@@ -293,6 +320,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
293
320
|
ImmutableArray<NuGetFramework> projectFrameworks,
|
|
294
321
|
NuGetContext nugetContext,
|
|
295
322
|
ILogger logger,
|
|
323
|
+
Func<NuGetVersion, Task<bool>>? candidateValidator,
|
|
296
324
|
CancellationToken cancellationToken)
|
|
297
325
|
{
|
|
298
326
|
if (NuGetVersion.TryParse(versionString, out var currentVersion))
|
|
@@ -308,7 +336,15 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
308
336
|
if (!isCompatible)
|
|
309
337
|
{
|
|
310
338
|
// If the current package is incompatible, then don't check for compatibility.
|
|
311
|
-
|
|
339
|
+
foreach (var version in orderedVersions)
|
|
340
|
+
{
|
|
341
|
+
if (candidateValidator is null || await candidateValidator(version))
|
|
342
|
+
{
|
|
343
|
+
return version;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return null;
|
|
312
348
|
}
|
|
313
349
|
}
|
|
314
350
|
|
|
@@ -328,7 +364,8 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
|
328
364
|
logger,
|
|
329
365
|
cancellationToken);
|
|
330
366
|
|
|
331
|
-
if (isCompatible
|
|
367
|
+
if (isCompatible &&
|
|
368
|
+
(candidateValidator is null || await candidateValidator(version)))
|
|
332
369
|
{
|
|
333
370
|
return version;
|
|
334
371
|
}
|
|
@@ -21,11 +21,13 @@ internal record NuGetContext : IDisposable
|
|
|
21
21
|
public ImmutableArray<PackageSource> PackageSources { get; }
|
|
22
22
|
public NuGet.Common.ILogger Logger { get; }
|
|
23
23
|
private readonly Func<PackageSource, SourceRepository> _sourceRepositoryFactory;
|
|
24
|
+
private readonly PackageVersionsCache _packageVersionsCache;
|
|
24
25
|
|
|
25
26
|
public NuGetContext(
|
|
26
27
|
string? currentDirectory = null,
|
|
27
28
|
NuGet.Common.ILogger? logger = null,
|
|
28
|
-
Func<PackageSource, SourceRepository>? sourceRepositoryFactory = null
|
|
29
|
+
Func<PackageSource, SourceRepository>? sourceRepositoryFactory = null,
|
|
30
|
+
PackageVersionsCache? packageVersionsCache = null)
|
|
29
31
|
{
|
|
30
32
|
SourceCacheContext = new SourceCacheContext();
|
|
31
33
|
PackageDownloadContext = new PackageDownloadContext(SourceCacheContext);
|
|
@@ -41,6 +43,7 @@ internal record NuGetContext : IDisposable
|
|
|
41
43
|
.ToImmutableArray();
|
|
42
44
|
Logger = logger ?? NullLogger.Instance;
|
|
43
45
|
_sourceRepositoryFactory = sourceRepositoryFactory ?? Repository.Factory.GetCoreV3;
|
|
46
|
+
_packageVersionsCache = packageVersionsCache ?? new PackageVersionsCache();
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
public void Dispose()
|
|
@@ -71,6 +74,32 @@ internal record NuGetContext : IDisposable
|
|
|
71
74
|
return infoUrl;
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
internal SourceRepository GetSourceRepository(PackageSource source) => _sourceRepositoryFactory(source);
|
|
78
|
+
|
|
79
|
+
internal Task<PackageVersions> GetPackageVersionsAsync(
|
|
80
|
+
PackageSource source,
|
|
81
|
+
string packageId,
|
|
82
|
+
bool includePrerelease,
|
|
83
|
+
bool includeUnlisted,
|
|
84
|
+
MetadataResource metadataResource,
|
|
85
|
+
CancellationToken cancellationToken)
|
|
86
|
+
{
|
|
87
|
+
return _packageVersionsCache.GetVersionsAsync(
|
|
88
|
+
CurrentDirectory,
|
|
89
|
+
source,
|
|
90
|
+
packageId,
|
|
91
|
+
includePrerelease,
|
|
92
|
+
includeUnlisted,
|
|
93
|
+
token => metadataResource.GetVersions(
|
|
94
|
+
packageId,
|
|
95
|
+
includePrerelease,
|
|
96
|
+
includeUnlisted,
|
|
97
|
+
SourceCacheContext,
|
|
98
|
+
NullLogger.Instance,
|
|
99
|
+
token),
|
|
100
|
+
cancellationToken);
|
|
101
|
+
}
|
|
102
|
+
|
|
74
103
|
private async Task<string?> FindPackageInfoUrlAsync(PackageIdentity packageIdentity, CancellationToken cancellationToken)
|
|
75
104
|
{
|
|
76
105
|
var globalPackagesFolder = SettingsUtility.GetGlobalPackagesFolder(Settings);
|
|
@@ -88,7 +117,7 @@ internal record NuGetContext : IDisposable
|
|
|
88
117
|
foreach (var source in sources)
|
|
89
118
|
{
|
|
90
119
|
message.AppendLine($" checking {source.Name}");
|
|
91
|
-
var sourceRepository =
|
|
120
|
+
var sourceRepository = GetSourceRepository(source);
|
|
92
121
|
var feed = await sourceRepository.GetResourceAsync<MetadataResource>(cancellationToken);
|
|
93
122
|
if (feed is null)
|
|
94
123
|
{
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
using NuGet.Configuration;
|
|
2
|
+
using NuGet.Versioning;
|
|
3
|
+
|
|
4
|
+
namespace NuGetUpdater.Core.Analyze;
|
|
5
|
+
|
|
6
|
+
internal sealed class PackageVersionsCache
|
|
7
|
+
{
|
|
8
|
+
private readonly Dictionary<CacheKey, Task<PackageVersions>> _cache = [];
|
|
9
|
+
private readonly object _cacheLock = new();
|
|
10
|
+
|
|
11
|
+
public async Task<PackageVersions> GetVersionsAsync(
|
|
12
|
+
string currentDirectory,
|
|
13
|
+
PackageSource source,
|
|
14
|
+
string packageId,
|
|
15
|
+
bool includePrerelease,
|
|
16
|
+
bool includeUnlisted,
|
|
17
|
+
Func<CancellationToken, Task<IEnumerable<NuGetVersion>>> getVersionsAsync,
|
|
18
|
+
CancellationToken cancellationToken)
|
|
19
|
+
{
|
|
20
|
+
cancellationToken.ThrowIfCancellationRequested();
|
|
21
|
+
|
|
22
|
+
var key = new CacheKey(
|
|
23
|
+
Path.TrimEndingDirectorySeparator(Path.GetFullPath(currentDirectory)),
|
|
24
|
+
source.Name,
|
|
25
|
+
source.Source,
|
|
26
|
+
packageId.ToLowerInvariant(),
|
|
27
|
+
includePrerelease,
|
|
28
|
+
includeUnlisted);
|
|
29
|
+
|
|
30
|
+
Task<PackageVersions> versionsTask;
|
|
31
|
+
var createdLoad = false;
|
|
32
|
+
lock (_cacheLock)
|
|
33
|
+
{
|
|
34
|
+
if (_cache.TryGetValue(key, out var cachedTask))
|
|
35
|
+
{
|
|
36
|
+
versionsTask = cachedTask;
|
|
37
|
+
}
|
|
38
|
+
else
|
|
39
|
+
{
|
|
40
|
+
versionsTask = LoadVersionsAsync(getVersionsAsync, cancellationToken);
|
|
41
|
+
_cache.Add(key, versionsTask);
|
|
42
|
+
createdLoad = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try
|
|
47
|
+
{
|
|
48
|
+
return await versionsTask.WaitAsync(cancellationToken);
|
|
49
|
+
}
|
|
50
|
+
catch
|
|
51
|
+
{
|
|
52
|
+
if (!versionsTask.IsCompletedSuccessfully &&
|
|
53
|
+
(createdLoad || versionsTask.IsCanceled || versionsTask.IsFaulted))
|
|
54
|
+
{
|
|
55
|
+
lock (_cacheLock)
|
|
56
|
+
{
|
|
57
|
+
if (_cache.TryGetValue(key, out var cachedTask) && ReferenceEquals(cachedTask, versionsTask))
|
|
58
|
+
{
|
|
59
|
+
_cache.Remove(key);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
throw;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private static async Task<PackageVersions> LoadVersionsAsync(
|
|
69
|
+
Func<CancellationToken, Task<IEnumerable<NuGetVersion>>> getVersionsAsync,
|
|
70
|
+
CancellationToken cancellationToken)
|
|
71
|
+
{
|
|
72
|
+
var versions = await getVersionsAsync(cancellationToken);
|
|
73
|
+
return new PackageVersions(versions.ToHashSet());
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private sealed record CacheKey(
|
|
77
|
+
string CurrentDirectory,
|
|
78
|
+
string SourceName,
|
|
79
|
+
string SourceUrl,
|
|
80
|
+
string PackageId,
|
|
81
|
+
bool IncludePrerelease,
|
|
82
|
+
bool IncludeUnlisted);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
internal sealed class PackageVersions(HashSet<NuGetVersion> items)
|
|
86
|
+
{
|
|
87
|
+
public int Count => items.Count;
|
|
88
|
+
public IEnumerable<NuGetVersion> Items => items;
|
|
89
|
+
|
|
90
|
+
public bool Contains(NuGetVersion version) => items.Contains(version);
|
|
91
|
+
}
|
|
@@ -6,7 +6,6 @@ using NuGet.Common;
|
|
|
6
6
|
using NuGet.Configuration;
|
|
7
7
|
using NuGet.Frameworks;
|
|
8
8
|
using NuGet.Packaging.Core;
|
|
9
|
-
using NuGet.Protocol;
|
|
10
9
|
using NuGet.Protocol.Core.Types;
|
|
11
10
|
using NuGet.Versioning;
|
|
12
11
|
|
|
@@ -94,25 +93,18 @@ internal static class VersionFinder
|
|
|
94
93
|
|
|
95
94
|
foreach (var source in sources)
|
|
96
95
|
{
|
|
97
|
-
MetadataResource? feed = null;
|
|
98
96
|
PackageMetadataResource? metadataResource = null;
|
|
97
|
+
PackageVersions feedVersions;
|
|
99
98
|
try
|
|
100
99
|
{
|
|
101
|
-
var sourceRepository =
|
|
102
|
-
feed = await sourceRepository.GetResourceAsync<MetadataResource>();
|
|
100
|
+
var sourceRepository = nugetContext.GetSourceRepository(source);
|
|
101
|
+
var feed = await sourceRepository.GetResourceAsync<MetadataResource>();
|
|
103
102
|
if (feed is null)
|
|
104
103
|
{
|
|
105
104
|
logger.Warn($"Failed to get {nameof(MetadataResource)} for [{source.Source}]");
|
|
106
105
|
continue;
|
|
107
106
|
}
|
|
108
107
|
|
|
109
|
-
var packageFinder = await sourceRepository.GetResourceAsync<FindPackageByIdResource>();
|
|
110
|
-
if (packageFinder is null)
|
|
111
|
-
{
|
|
112
|
-
logger.Warn($"Failed to get {nameof(FindPackageByIdResource)} for [{source.Source}]");
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
108
|
if (dependencyInfo.Cooldown is not null)
|
|
117
109
|
{
|
|
118
110
|
metadataResource = await sourceRepository.GetResourceAsync<PackageMetadataResource>();
|
|
@@ -123,15 +115,14 @@ internal static class VersionFinder
|
|
|
123
115
|
}
|
|
124
116
|
}
|
|
125
117
|
|
|
126
|
-
|
|
127
|
-
|
|
118
|
+
feedVersions = await nugetContext.GetPackageVersionsAsync(
|
|
119
|
+
source,
|
|
128
120
|
dependencyInfo.Name,
|
|
129
121
|
includePrerelease,
|
|
130
122
|
includeUnlisted: false,
|
|
131
|
-
|
|
132
|
-
NullLogger.Instance,
|
|
123
|
+
feed,
|
|
133
124
|
cancellationToken);
|
|
134
|
-
if (
|
|
125
|
+
if (feedVersions.Count == 0)
|
|
135
126
|
{
|
|
136
127
|
continue;
|
|
137
128
|
}
|
|
@@ -152,20 +143,12 @@ internal static class VersionFinder
|
|
|
152
143
|
throw new BadResponseException(ex.Message, source.Source);
|
|
153
144
|
}
|
|
154
145
|
|
|
155
|
-
var feedVersions = (await feed.GetVersions(
|
|
156
|
-
dependencyInfo.Name,
|
|
157
|
-
includePrerelease,
|
|
158
|
-
includeUnlisted: false,
|
|
159
|
-
nugetContext.SourceCacheContext,
|
|
160
|
-
NullLogger.Instance,
|
|
161
|
-
CancellationToken.None)).ToHashSet();
|
|
162
|
-
|
|
163
146
|
if (feedVersions.Contains(currentVersion))
|
|
164
147
|
{
|
|
165
148
|
result.AddCurrentVersionSource(source);
|
|
166
149
|
}
|
|
167
150
|
|
|
168
|
-
var versions = feedVersions.Where(versionFilter).ToArray();
|
|
151
|
+
var versions = feedVersions.Items.Where(versionFilter).ToArray();
|
|
169
152
|
foreach (var version in versions)
|
|
170
153
|
{
|
|
171
154
|
var packageIdentity = new PackageIdentity(dependencyInfo.Name, version);
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
using System.Text.Json.Serialization;
|
|
2
2
|
|
|
3
|
+
using NuGet.Versioning;
|
|
4
|
+
|
|
3
5
|
using NuGetUpdater.Core.Analyze;
|
|
4
6
|
|
|
5
7
|
namespace NuGetUpdater.Core.Run.ApiModel;
|
|
6
8
|
|
|
7
9
|
public sealed record Condition
|
|
8
10
|
{
|
|
11
|
+
private static readonly NuGetVersion MinimumVersion = NuGetVersion.Parse("0");
|
|
12
|
+
|
|
9
13
|
[JsonPropertyName("dependency-name")]
|
|
10
14
|
public required string DependencyName { get; init; }
|
|
11
15
|
[JsonPropertyName("source")]
|
|
@@ -16,6 +20,19 @@ public sealed record Condition
|
|
|
16
20
|
public DateTime? UpdatedAt { get; init; } = null;
|
|
17
21
|
[JsonPropertyName("version-requirement")]
|
|
18
22
|
public Requirement? VersionRequirement { get; init; } = null;
|
|
23
|
+
|
|
24
|
+
internal bool IsUnconditionalIgnore()
|
|
25
|
+
{
|
|
26
|
+
if ((UpdateTypes ?? []).Length > 0)
|
|
27
|
+
{
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Name-only ignore conditions are serialized by the service with a >= 0 requirement.
|
|
32
|
+
return VersionRequirement is null ||
|
|
33
|
+
VersionRequirement is IndividualRequirement { Operator: ">=", Version: var version } &&
|
|
34
|
+
version == MinimumVersion;
|
|
35
|
+
}
|
|
19
36
|
}
|
|
20
37
|
|
|
21
38
|
public enum ConditionUpdateType
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
using System.Collections.Immutable;
|
|
2
2
|
using System.IO.Enumeration;
|
|
3
3
|
using System.Text.Json;
|
|
4
|
+
using System.Text.Json.Serialization;
|
|
4
5
|
|
|
5
6
|
using NuGet.Versioning;
|
|
6
7
|
|
|
@@ -19,6 +20,42 @@ public record DependencyGroup
|
|
|
19
20
|
public Dictionary<string, object> Rules { get; init; } = new();
|
|
20
21
|
|
|
21
22
|
public GroupMatcher GetGroupMatcher() => GroupMatcher.FromRules(Rules);
|
|
23
|
+
|
|
24
|
+
public bool IsGroupedByDependencyName =>
|
|
25
|
+
GetString(Rules, "group-by")?.Equals("dependency-name", StringComparison.Ordinal) == true;
|
|
26
|
+
|
|
27
|
+
[JsonIgnore]
|
|
28
|
+
public string? DependencyNameGroupTarget { get; init; }
|
|
29
|
+
|
|
30
|
+
public DependencyGroup CreateDependencyNameSubgroup(string dependencyName, string? subgroupName = null)
|
|
31
|
+
{
|
|
32
|
+
var matchesParent = GetGroupMatcher().IsMatch(dependencyName);
|
|
33
|
+
var subgroupRules = new Dictionary<string, object>(Rules)
|
|
34
|
+
{
|
|
35
|
+
["patterns"] = matchesParent ? new[] { dependencyName } : Array.Empty<string>(),
|
|
36
|
+
};
|
|
37
|
+
return this with
|
|
38
|
+
{
|
|
39
|
+
Name = subgroupName ?? $"{Name}/{dependencyName}",
|
|
40
|
+
Rules = subgroupRules,
|
|
41
|
+
DependencyNameGroupTarget = dependencyName,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private static string? GetString(Dictionary<string, object> rules, string propertyName)
|
|
46
|
+
{
|
|
47
|
+
if (!rules.TryGetValue(propertyName, out var propertyObject))
|
|
48
|
+
{
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return propertyObject switch
|
|
53
|
+
{
|
|
54
|
+
string value => value,
|
|
55
|
+
JsonElement { ValueKind: JsonValueKind.String } element => element.GetString(),
|
|
56
|
+
_ => null,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
22
59
|
}
|
|
23
60
|
|
|
24
61
|
public enum GroupUpdateType
|
|
@@ -102,7 +102,65 @@ public sealed record Job
|
|
|
102
102
|
return existingPullRequests;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
public
|
|
105
|
+
public DependencyGroup? ResolveDependencyGroupToRefresh()
|
|
106
|
+
{
|
|
107
|
+
if (DependencyGroupToRefresh is null)
|
|
108
|
+
{
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
var exactGroup = FindConfiguredDependencyGroup(DependencyGroupToRefresh);
|
|
113
|
+
if (exactGroup is not null)
|
|
114
|
+
{
|
|
115
|
+
return exactGroup.IsGroupedByDependencyName ? null : exactGroup;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
var dynamicParent = DependencyGroups
|
|
119
|
+
.Where(g => g.IsGroupedByDependencyName)
|
|
120
|
+
.Where(g => DependencyGroupToRefresh.StartsWith($"{g.Name}/", StringComparison.OrdinalIgnoreCase))
|
|
121
|
+
.OrderByDescending(g => g.Name.Length)
|
|
122
|
+
.FirstOrDefault();
|
|
123
|
+
if (dynamicParent is null)
|
|
124
|
+
{
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
var dependencyName = DependencyGroupToRefresh[(dynamicParent.Name.Length + 1)..];
|
|
129
|
+
if (dependencyName.Length == 0 ||
|
|
130
|
+
(Dependencies.Length > 0 && !Dependencies.Contains(dependencyName, StringComparer.OrdinalIgnoreCase)))
|
|
131
|
+
{
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return dynamicParent.CreateDependencyNameSubgroup(dependencyName, DependencyGroupToRefresh);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public DependencyGroup? FindConfiguredDependencyGroup(string name)
|
|
139
|
+
{
|
|
140
|
+
return DependencyGroups.FirstOrDefault(g => g.Name == name) ??
|
|
141
|
+
DependencyGroups.FirstOrDefault(g => g.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public Tuple<string?, ImmutableArray<PullRequestDependency>>? GetExistingPullRequestForDependencies(
|
|
145
|
+
IEnumerable<ReportedDependencyWithDirectory> dependencies,
|
|
146
|
+
bool considerVersions)
|
|
147
|
+
{
|
|
148
|
+
return GetExistingPullRequestForDependencies(dependencies, considerVersions, dependencyGroupName: null, matchGroupName: false);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public Tuple<string?, ImmutableArray<PullRequestDependency>>? GetExistingGroupPullRequestForDependencies(
|
|
152
|
+
IEnumerable<ReportedDependencyWithDirectory> dependencies,
|
|
153
|
+
bool considerVersions,
|
|
154
|
+
string dependencyGroupName)
|
|
155
|
+
{
|
|
156
|
+
return GetExistingPullRequestForDependencies(dependencies, considerVersions, dependencyGroupName, matchGroupName: true);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private Tuple<string?, ImmutableArray<PullRequestDependency>>? GetExistingPullRequestForDependencies(
|
|
160
|
+
IEnumerable<ReportedDependencyWithDirectory> dependencies,
|
|
161
|
+
bool considerVersions,
|
|
162
|
+
string? dependencyGroupName,
|
|
163
|
+
bool matchGroupName)
|
|
106
164
|
{
|
|
107
165
|
var desiredDependencies = dependencies.ToArray();
|
|
108
166
|
if (desiredDependencies.Any(d => d.Version is null))
|
|
@@ -128,6 +186,12 @@ public sealed record Job
|
|
|
128
186
|
var existingPullRequest = existingPullRequests
|
|
129
187
|
.FirstOrDefault(pr =>
|
|
130
188
|
{
|
|
189
|
+
if (matchGroupName &&
|
|
190
|
+
!string.Equals(pr.Item1, dependencyGroupName, StringComparison.OrdinalIgnoreCase))
|
|
191
|
+
{
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
|
|
131
195
|
return desiredDependencies.All(desired => pr.Item2.Any(existing => DependenciesMatch(desired, existing))) &&
|
|
132
196
|
pr.Item2.All(existing => desiredDependencies.Any(desired => DependenciesMatch(desired, existing)));
|
|
133
197
|
});
|
|
@@ -137,7 +201,7 @@ public sealed record Job
|
|
|
137
201
|
public bool IsDependencyIgnoredByNameOnly(string dependencyName)
|
|
138
202
|
{
|
|
139
203
|
var packageNamesToIgnore = IgnoreConditions
|
|
140
|
-
.Where(c =>
|
|
204
|
+
.Where(c => c.IsUnconditionalIgnore())
|
|
141
205
|
.Select(c => c.DependencyName)
|
|
142
206
|
.ToArray();
|
|
143
207
|
var isIgnored = packageNamesToIgnore
|
|
@@ -14,9 +14,19 @@ public class PullRequestTextGenerator
|
|
|
14
14
|
{
|
|
15
15
|
private const int MaxTitleLength = 70;
|
|
16
16
|
|
|
17
|
-
public static string GetPullRequestTitle(
|
|
17
|
+
public static string GetPullRequestTitle(
|
|
18
|
+
Job job,
|
|
19
|
+
ImmutableArray<UpdateOperationBase> updateOperationsPerformed,
|
|
20
|
+
string? dependencyGroupName,
|
|
21
|
+
string? dependencyNameGroupTarget = null,
|
|
22
|
+
IEnumerable<string>? updatedDirectories = null)
|
|
18
23
|
{
|
|
19
|
-
var shortTitle = GetPullRequestShortTitle(
|
|
24
|
+
var shortTitle = GetPullRequestShortTitle(
|
|
25
|
+
job,
|
|
26
|
+
updateOperationsPerformed,
|
|
27
|
+
dependencyGroupName,
|
|
28
|
+
dependencyNameGroupTarget,
|
|
29
|
+
updatedDirectories);
|
|
20
30
|
var titlePrefix = GetPullRequestTitlePrefix(job);
|
|
21
31
|
var fullTitle = $"{titlePrefix}{shortTitle}";
|
|
22
32
|
return fullTitle;
|
|
@@ -43,14 +53,31 @@ public class PullRequestTextGenerator
|
|
|
43
53
|
return prefix;
|
|
44
54
|
}
|
|
45
55
|
|
|
46
|
-
private static string GetPullRequestShortTitle(
|
|
56
|
+
private static string GetPullRequestShortTitle(
|
|
57
|
+
Job job,
|
|
58
|
+
ImmutableArray<UpdateOperationBase> updateOperationsPerformed,
|
|
59
|
+
string? dependencyGroupName,
|
|
60
|
+
string? dependencyNameGroupTarget,
|
|
61
|
+
IEnumerable<string>? updatedDirectories)
|
|
47
62
|
{
|
|
48
63
|
string title;
|
|
49
64
|
var dependencySets = GetDependencySets(updateOperationsPerformed);
|
|
50
|
-
if (dependencyGroupName is not null)
|
|
65
|
+
if (dependencyGroupName is not null && dependencyNameGroupTarget is null)
|
|
51
66
|
{
|
|
52
67
|
title = $"Bump the {dependencyGroupName} group with {dependencySets.Length} update{(dependencySets.Length > 1 ? "s" : "")}";
|
|
53
68
|
}
|
|
69
|
+
else if (dependencyNameGroupTarget is not null)
|
|
70
|
+
{
|
|
71
|
+
var directories = (updatedDirectories ?? [])
|
|
72
|
+
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
73
|
+
.ToArray();
|
|
74
|
+
title = directories.Length switch
|
|
75
|
+
{
|
|
76
|
+
> 1 => $"Bump {dependencyNameGroupTarget} across {directories.Length} directories",
|
|
77
|
+
1 when directories[0] != "/" => $"Bump {dependencyNameGroupTarget} in {directories[0]}",
|
|
78
|
+
_ => $"Bump {dependencyNameGroupTarget}",
|
|
79
|
+
};
|
|
80
|
+
}
|
|
54
81
|
else
|
|
55
82
|
{
|
|
56
83
|
if (dependencySets.Length == 1)
|
|
@@ -73,13 +100,23 @@ public class PullRequestTextGenerator
|
|
|
73
100
|
return title;
|
|
74
101
|
}
|
|
75
102
|
|
|
76
|
-
public static string GetPullRequestCommitMessage(
|
|
103
|
+
public static string GetPullRequestCommitMessage(
|
|
104
|
+
Job job,
|
|
105
|
+
ImmutableArray<UpdateOperationBase> updateOperationsPerformed,
|
|
106
|
+
string? dependencyGroupName,
|
|
107
|
+
string? dependencyNameGroupTarget = null,
|
|
108
|
+
IEnumerable<string>? updatedDirectories = null)
|
|
77
109
|
{
|
|
78
110
|
var sb = new StringBuilder();
|
|
79
|
-
sb.AppendLine(GetPullRequestTitle(
|
|
111
|
+
sb.AppendLine(GetPullRequestTitle(
|
|
112
|
+
job,
|
|
113
|
+
updateOperationsPerformed,
|
|
114
|
+
dependencyGroupName,
|
|
115
|
+
dependencyNameGroupTarget,
|
|
116
|
+
updatedDirectories));
|
|
80
117
|
var dependencySets = GetDependencySets(updateOperationsPerformed);
|
|
81
118
|
if (dependencySets.Length > 1 ||
|
|
82
|
-
dependencyGroupName is not null)
|
|
119
|
+
(dependencyGroupName is not null && dependencyNameGroupTarget is null))
|
|
83
120
|
{
|
|
84
121
|
// multiple updates performed, enumerate them
|
|
85
122
|
sb.AppendLine();
|