dependabot-nuget 0.286.0 → 0.287.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +24 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +15 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +9 -38
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +8 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/ProjectBuildFile.cs +15 -8
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +15 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +5 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +49 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +302 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +269 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +250 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +40 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/PathHelperTests.cs +14 -0
- data/helpers/lib/NuGetUpdater/global.json +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3bb2d903f08322511a7917fba47df7b66208dbbaca42e52d30a1954f9ef3eaa2
|
4
|
+
data.tar.gz: f19cfed3ad2939c93812727546b53ecec603c712641a6c1d0581469cce72d584
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3fdc15bd985678106cf45f57c6af6dd4be57858f54b50abea6f4521a8aed3ab66b7ca67cb54f9e73dabe536d8c012619bbf049662207211bc92cbb5e938c321
|
7
|
+
data.tar.gz: 3542f489f10b67fe78b3bd55703cc420a58279bf5fb131da4a99be0d99a20fcd7430b124c4b49100929b74f39178b3c7e108e7bb0170baef5f5a91a16dfbd63f
|
@@ -50,7 +50,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
|
|
50
50
|
when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
|
51
51
|
{
|
52
52
|
var localPath = PathHelper.JoinPath(repoRoot, discovery.Path);
|
53
|
-
var nugetContext = new NuGetContext(localPath);
|
53
|
+
using var nugetContext = new NuGetContext(localPath);
|
54
54
|
analysisResult = new AnalysisResult
|
55
55
|
{
|
56
56
|
ErrorType = ErrorType.AuthenticationFailure,
|
@@ -24,11 +24,16 @@ internal static class CompatibilityChecker
|
|
24
24
|
ILogger logger,
|
25
25
|
CancellationToken cancellationToken)
|
26
26
|
{
|
27
|
-
var
|
27
|
+
var packageInfo = await GetPackageInfoAsync(
|
28
28
|
package,
|
29
29
|
nugetContext,
|
30
30
|
cancellationToken);
|
31
|
+
if (packageInfo is null)
|
32
|
+
{
|
33
|
+
return false;
|
34
|
+
}
|
31
35
|
|
36
|
+
var (isDevDependency, packageFrameworks) = packageInfo.GetValueOrDefault();
|
32
37
|
return PerformCheck(package, projectFrameworks, isDevDependency, packageFrameworks, logger);
|
33
38
|
}
|
34
39
|
|
@@ -70,7 +75,7 @@ internal static class CompatibilityChecker
|
|
70
75
|
return true;
|
71
76
|
}
|
72
77
|
|
73
|
-
internal static async Task<
|
78
|
+
internal static async Task<PackageReaders?> GetPackageReadersAsync(
|
74
79
|
PackageIdentity package,
|
75
80
|
NuGetContext nugetContext,
|
76
81
|
CancellationToken cancellationToken)
|
@@ -79,7 +84,21 @@ internal static class CompatibilityChecker
|
|
79
84
|
var readers = File.Exists(tempPackagePath)
|
80
85
|
? ReadPackage(tempPackagePath)
|
81
86
|
: await DownloadPackageAsync(package, nugetContext, cancellationToken);
|
87
|
+
return readers;
|
88
|
+
}
|
89
|
+
|
90
|
+
internal static async Task<PackageInfo?> GetPackageInfoAsync(
|
91
|
+
PackageIdentity package,
|
92
|
+
NuGetContext nugetContext,
|
93
|
+
CancellationToken cancellationToken)
|
94
|
+
{
|
95
|
+
var readersOption = await GetPackageReadersAsync(package, nugetContext, cancellationToken);
|
96
|
+
if (readersOption is null)
|
97
|
+
{
|
98
|
+
return null;
|
99
|
+
}
|
82
100
|
|
101
|
+
var readers = readersOption.GetValueOrDefault();
|
83
102
|
var nuspecStream = await readers.CoreReader.GetNuspecAsync(cancellationToken);
|
84
103
|
var reader = new NuspecReader(nuspecStream);
|
85
104
|
|
@@ -127,7 +146,7 @@ internal static class CompatibilityChecker
|
|
127
146
|
return (archiveReader, archiveReader);
|
128
147
|
}
|
129
148
|
|
130
|
-
internal static async Task<PackageReaders
|
149
|
+
internal static async Task<PackageReaders?> DownloadPackageAsync(
|
131
150
|
PackageIdentity package,
|
132
151
|
NuGetContext context,
|
133
152
|
CancellationToken cancellationToken)
|
@@ -179,13 +198,13 @@ internal static class CompatibilityChecker
|
|
179
198
|
var isDownloaded = await downloader.CopyNupkgFileToAsync(tempPackagePath, cancellationToken);
|
180
199
|
if (!isDownloaded)
|
181
200
|
{
|
182
|
-
|
201
|
+
continue;
|
183
202
|
}
|
184
203
|
|
185
204
|
return (downloader.CoreReader, downloader.ContentReader);
|
186
205
|
}
|
187
206
|
|
188
|
-
|
207
|
+
return null;
|
189
208
|
}
|
190
209
|
|
191
210
|
internal static string GetTempPackagePath(PackageIdentity package, NuGetContext context)
|
@@ -142,11 +142,22 @@ internal record NuGetContext : IDisposable
|
|
142
142
|
}
|
143
143
|
|
144
144
|
var metadataResource = await sourceRepository.GetResourceAsync<PackageMetadataResource>(cancellationToken);
|
145
|
-
|
146
|
-
var url = metadata.ProjectUrl ?? metadata.LicenseUrl;
|
147
|
-
if (url is not null)
|
145
|
+
if (metadataResource is not null)
|
148
146
|
{
|
149
|
-
|
147
|
+
try
|
148
|
+
{
|
149
|
+
var metadata = await metadataResource.GetMetadataAsync(packageIdentity, SourceCacheContext, Logger, cancellationToken);
|
150
|
+
var url = metadata.ProjectUrl ?? metadata.LicenseUrl;
|
151
|
+
if (url is not null)
|
152
|
+
{
|
153
|
+
return url.ToString();
|
154
|
+
}
|
155
|
+
}
|
156
|
+
catch (ArgumentException)
|
157
|
+
{
|
158
|
+
// there was an issue deserializing the package metadata; this doesn't necessarily mean the package
|
159
|
+
// is unavailable, just that we can't return a URL
|
160
|
+
}
|
150
161
|
}
|
151
162
|
}
|
152
163
|
|
@@ -151,46 +151,17 @@ internal static class VersionFinder
|
|
151
151
|
ILogger logger,
|
152
152
|
CancellationToken cancellationToken)
|
153
153
|
{
|
154
|
-
|
155
|
-
|
156
|
-
var
|
157
|
-
|
158
|
-
var sources = packageSources.Count == 0
|
159
|
-
? nugetContext.PackageSources
|
160
|
-
: nugetContext.PackageSources
|
161
|
-
.Where(p => packageSources.Contains(p.Name))
|
162
|
-
.ToImmutableArray();
|
163
|
-
|
164
|
-
foreach (var source in sources)
|
154
|
+
// if it can be downloaded, it exists
|
155
|
+
var downloader = await CompatibilityChecker.DownloadPackageAsync(new PackageIdentity(packageId, version), nugetContext, cancellationToken);
|
156
|
+
var packageAndVersionExists = downloader is not null;
|
157
|
+
if (packageAndVersionExists)
|
165
158
|
{
|
166
|
-
|
167
|
-
var
|
168
|
-
|
169
|
-
|
170
|
-
logger.Log($"Failed to get MetadataResource for [{source.Source}]");
|
171
|
-
continue;
|
172
|
-
}
|
173
|
-
|
174
|
-
try
|
175
|
-
{
|
176
|
-
// a non-compliant v2 API returning 404 can cause this to throw
|
177
|
-
var existsInFeed = await feed.Exists(
|
178
|
-
new PackageIdentity(packageId, version),
|
179
|
-
includeUnlisted: false,
|
180
|
-
nugetContext.SourceCacheContext,
|
181
|
-
NullLogger.Instance,
|
182
|
-
cancellationToken);
|
183
|
-
if (existsInFeed)
|
184
|
-
{
|
185
|
-
return true;
|
186
|
-
}
|
187
|
-
}
|
188
|
-
catch (FatalProtocolException)
|
189
|
-
{
|
190
|
-
// if anything goes wrong here, the package source obviously doesn't contain the requested package
|
191
|
-
}
|
159
|
+
// release the handles
|
160
|
+
var readers = downloader.GetValueOrDefault();
|
161
|
+
(readers.CoreReader as IDisposable)?.Dispose();
|
162
|
+
(readers.ContentReader as IDisposable)?.Dispose();
|
192
163
|
}
|
193
164
|
|
194
|
-
return
|
165
|
+
return packageAndVersionExists;
|
195
166
|
}
|
196
167
|
}
|
@@ -275,22 +275,24 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
275
275
|
foreach (var projectPath in projectPaths)
|
276
276
|
{
|
277
277
|
// If there is some MSBuild logic that needs to run to fully resolve the path skip the project
|
278
|
-
|
278
|
+
// Ensure file existence is checked case-insensitively
|
279
|
+
var actualProjectPath = PathHelper.ResolveCaseInsensitivePathInsideRepoRoot(projectPath, repoRootPath);
|
280
|
+
if (actualProjectPath == null)
|
279
281
|
{
|
280
282
|
continue;
|
281
283
|
}
|
282
284
|
|
283
|
-
if (_processedProjectPaths.Contains(
|
285
|
+
if (_processedProjectPaths.Contains(actualProjectPath))
|
284
286
|
{
|
285
287
|
continue;
|
286
288
|
}
|
287
|
-
_processedProjectPaths.Add(
|
289
|
+
_processedProjectPaths.Add(actualProjectPath);
|
288
290
|
|
289
|
-
var relativeProjectPath = Path.GetRelativePath(workspacePath,
|
291
|
+
var relativeProjectPath = Path.GetRelativePath(workspacePath, actualProjectPath);
|
290
292
|
var packagesConfigDependencies = PackagesConfigDiscovery.Discover(workspacePath, projectPath, _logger)
|
291
293
|
?.Dependencies;
|
292
294
|
|
293
|
-
var projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath,
|
295
|
+
var projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath, actualProjectPath, _logger);
|
294
296
|
|
295
297
|
// Determine if there were unrestored MSBuildSdks
|
296
298
|
var msbuildSdks = projectResults.SelectMany(p => p.Dependencies.Where(d => d.Type == DependencyType.MSBuildSdk)).ToImmutableArray();
|
@@ -299,7 +301,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
299
301
|
// If new SDKs were restored, then we need to rerun SdkProjectDiscovery.
|
300
302
|
if (await TryRestoreMSBuildSdksAsync(repoRootPath, workspacePath, msbuildSdks, _logger))
|
301
303
|
{
|
302
|
-
projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath,
|
304
|
+
projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath, actualProjectPath, _logger);
|
303
305
|
}
|
304
306
|
}
|
305
307
|
|
@@ -43,7 +43,7 @@ internal sealed class ProjectBuildFile : XmlBuildFile
|
|
43
43
|
{
|
44
44
|
var sdkDependencies = GetSdkDependencies();
|
45
45
|
var packageDependencies = PackageItemNodes
|
46
|
-
.
|
46
|
+
.SelectMany(e => GetPackageDependencies(e) ?? Enumerable.Empty<Dependency>())
|
47
47
|
.OfType<Dependency>();
|
48
48
|
return sdkDependencies.Concat(packageDependencies);
|
49
49
|
}
|
@@ -89,8 +89,9 @@ internal sealed class ProjectBuildFile : XmlBuildFile
|
|
89
89
|
: new Dependency(name, version, DependencyType.MSBuildSdk);
|
90
90
|
}
|
91
91
|
|
92
|
-
private static Dependency
|
92
|
+
private static IEnumerable<Dependency>? GetPackageDependencies(IXmlElementSyntax element)
|
93
93
|
{
|
94
|
+
List<Dependency> dependencies = [];
|
94
95
|
var isUpdate = false;
|
95
96
|
|
96
97
|
var name = element.GetAttributeOrSubElementValue("Include", StringComparison.OrdinalIgnoreCase)?.Trim();
|
@@ -113,12 +114,18 @@ internal sealed class ProjectBuildFile : XmlBuildFile
|
|
113
114
|
isVersionOverride = version is not null;
|
114
115
|
}
|
115
116
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
dependencies.AddRange(
|
118
|
+
name.Split(';', StringSplitOptions.RemoveEmptyEntries)
|
119
|
+
.Select(dep => new Dependency(
|
120
|
+
Name: dep.Trim(),
|
121
|
+
Version: string.IsNullOrEmpty(version) ? null : version,
|
122
|
+
Type: GetDependencyType(element.Name),
|
123
|
+
IsUpdate: isUpdate,
|
124
|
+
IsOverride: isVersionOverride))
|
125
|
+
);
|
126
|
+
|
127
|
+
|
128
|
+
return dependencies;
|
122
129
|
}
|
123
130
|
|
124
131
|
private static DependencyType GetDependencyType(string name)
|
@@ -674,11 +674,21 @@ internal static class PackageReferenceUpdater
|
|
674
674
|
ProjectBuildFile buildFile,
|
675
675
|
string packageName)
|
676
676
|
=> buildFile.PackageItemNodes.Where(e =>
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
677
|
+
{
|
678
|
+
// Attempt to get "Include" or "Update" attribute values
|
679
|
+
var includeOrUpdateValue = e.GetAttributeOrSubElementValue("Include", StringComparison.OrdinalIgnoreCase)
|
680
|
+
?? e.GetAttributeOrSubElementValue("Update", StringComparison.OrdinalIgnoreCase);
|
681
|
+
// Trim and split if there's a valid value
|
682
|
+
var packageNames = includeOrUpdateValue?
|
683
|
+
.Trim()
|
684
|
+
.Split(';', StringSplitOptions.RemoveEmptyEntries)
|
685
|
+
.Select(t => t.Trim())
|
686
|
+
.Where(t => t.Equals(packageName.Trim(), StringComparison.OrdinalIgnoreCase));
|
687
|
+
// Check if there's a matching package name and a non-null version attribute
|
688
|
+
return packageNames?.Any() == true &&
|
689
|
+
(e.GetAttributeOrSubElementValue("Version", StringComparison.OrdinalIgnoreCase)
|
690
|
+
?? e.GetAttributeOrSubElementValue("VersionOverride", StringComparison.OrdinalIgnoreCase)) is not null;
|
691
|
+
});
|
682
692
|
|
683
693
|
private static async Task<bool> AreDependenciesCoherentAsync(string repoRootPath, string projectPath, string dependencyName, ILogger logger, ImmutableArray<ProjectBuildFile> buildFiles, string[] tfms)
|
684
694
|
{
|
@@ -261,7 +261,11 @@ internal static partial class MSBuildHelper
|
|
261
261
|
? evaluationResult.EvaluatedValue.TrimStart('[', '(').TrimEnd(']', ')')
|
262
262
|
: evaluationResult.EvaluatedValue;
|
263
263
|
|
264
|
-
|
264
|
+
// If at this point we have a semicolon in the name then split it and yield multiple dependencies.
|
265
|
+
foreach (var splitName in name.Split(';', StringSplitOptions.RemoveEmptyEntries))
|
266
|
+
{
|
267
|
+
yield return new Dependency(splitName.Trim(), packageVersion, dependencyType, EvaluationResult: evaluationResult, IsUpdate: isUpdate);
|
268
|
+
}
|
265
269
|
}
|
266
270
|
}
|
267
271
|
|
@@ -87,6 +87,55 @@ internal static class PathHelper
|
|
87
87
|
return candidatePaths.ToArray();
|
88
88
|
}
|
89
89
|
|
90
|
+
/// <summary>
|
91
|
+
/// Resolves the case of the file path in a case-insensitive manner. Returns null if the file path is not found. file path must be a full path inside the repoRootPath.
|
92
|
+
/// </summary>
|
93
|
+
/// <param name="filePath">The file path to resolve.</param>
|
94
|
+
/// <param name="repoRootPath">The root path of the repository.</param>
|
95
|
+
public static string? ResolveCaseInsensitivePathInsideRepoRoot(string filePath, string repoRootPath)
|
96
|
+
{
|
97
|
+
if (string.IsNullOrEmpty(filePath) || string.IsNullOrEmpty(repoRootPath))
|
98
|
+
{
|
99
|
+
return null; // Invalid input
|
100
|
+
}
|
101
|
+
|
102
|
+
// Normalize paths
|
103
|
+
var normalizedFilePath = filePath.FullyNormalizedRootedPath();
|
104
|
+
var normalizedRepoRoot = repoRootPath.FullyNormalizedRootedPath();
|
105
|
+
|
106
|
+
// Ensure the file path starts with the repo root path
|
107
|
+
if (!normalizedFilePath.StartsWith(normalizedRepoRoot + "/", StringComparison.OrdinalIgnoreCase))
|
108
|
+
{
|
109
|
+
return null; // filePath is outside of repoRootPath
|
110
|
+
}
|
111
|
+
|
112
|
+
// Start resolving from the root path
|
113
|
+
var currentPath = normalizedRepoRoot;
|
114
|
+
var relativePath = normalizedFilePath.Substring(normalizedRepoRoot.Length).TrimStart('/');
|
115
|
+
|
116
|
+
foreach (var part in relativePath.Split('/'))
|
117
|
+
{
|
118
|
+
if (string.IsNullOrEmpty(part))
|
119
|
+
{
|
120
|
+
continue;
|
121
|
+
}
|
122
|
+
|
123
|
+
// Enumerate the current directory to find a case-insensitive match
|
124
|
+
var nextPath = Directory
|
125
|
+
.EnumerateFileSystemEntries(currentPath)
|
126
|
+
.FirstOrDefault(entry => string.Equals(Path.GetFileName(entry), part, StringComparison.OrdinalIgnoreCase));
|
127
|
+
|
128
|
+
if (nextPath == null)
|
129
|
+
{
|
130
|
+
return null; // Part of the path does not exist
|
131
|
+
}
|
132
|
+
|
133
|
+
currentPath = nextPath;
|
134
|
+
}
|
135
|
+
|
136
|
+
return currentPath; // Fully resolved path with correct casing
|
137
|
+
}
|
138
|
+
|
90
139
|
/// <summary>
|
91
140
|
/// Check in every directory from <paramref name="initialPath"/> up to <paramref name="rootPath"/> for the file specified in <paramref name="fileName"/>.
|
92
141
|
/// </summary>
|