dependabot-nuget 0.292.0 → 0.294.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/.gitignore +1 -0
- data/helpers/lib/NuGetUpdater/Directory.Packages.props +2 -1
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Correlator.cs +197 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/DotNetPackageCorrelation.csproj +12 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/PackageMapper.cs +68 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/PackageSet.cs +11 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/Release.cs +25 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/ReleasesFile.cs +9 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/RuntimePackages.cs +11 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/Sdk.cs +13 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/SemVerComparer.cs +16 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation/Model/SemVersionConverter.cs +42 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Cli/DotNetPackageCorrelation.Cli.csproj +16 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Cli/Program.cs +32 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Test/CorrelatorTests.cs +99 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Test/DotNetPackageCorrelation.Test.csproj +18 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Test/EndToEndTests.cs +30 -0
- data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Test/RuntimePackagesTests.cs +206 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +6 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs +8 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs +17 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +7 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +46 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +8 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +8 -17
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyFinder.cs +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/Extensions.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +16 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Clone/CloneWorker.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencyDiscovery.targets +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +7 -20
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/ProjectDiscoveryResult.cs +3 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +99 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/EnsureDotNetPackageCorrelation.targets +25 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +9 -22
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/PackagesConfigBuildFile.cs +5 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/MissingFileException.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/NativeResult.cs +3 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/NuGetUpdater.Core.csproj +3 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Advisory.cs +2 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyFileNotFound.cs +7 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyFileNotParseable.cs +15 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +24 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +33 -30
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/UnparseableFileException.cs +12 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +21 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +6 -30
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/DotNetPackageCorrelationManager.cs +46 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +51 -27
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +15 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +70 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +20 -12
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +108 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +16 -12
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +15 -28
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +61 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +5 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +9 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestBase.cs +24 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/ExpectedUpdateOperationResult.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +11 -15
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +14 -8
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +148 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +12 -14
- data/helpers/lib/NuGetUpdater/NuGetUpdater.sln +18 -1
- data/lib/dependabot/nuget/native_helpers.rb +41 -16
- metadata +25 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +0 -12
@@ -113,11 +113,22 @@ internal static class VersionFinder
|
|
113
113
|
? versionRange.MinVersion
|
114
114
|
: null;
|
115
115
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
116
|
+
var safeVersions = dependencyInfo.Vulnerabilities.SelectMany(v => v.SafeVersions).ToList();
|
117
|
+
return version =>
|
118
|
+
{
|
119
|
+
var versionGreaterThanCurrent = currentVersion is null || version > currentVersion;
|
120
|
+
var rangeSatisfies = versionRange.Satisfies(version);
|
121
|
+
var prereleaseTypeMatches = currentVersion is null || !currentVersion.IsPrerelease || !version.IsPrerelease || version.Version == currentVersion.Version;
|
122
|
+
var isIgnoredVersion = dependencyInfo.IgnoredVersions.Any(i => i.IsSatisfiedBy(version));
|
123
|
+
var isVulnerableVersion = dependencyInfo.Vulnerabilities.Any(v => v.IsVulnerable(version));
|
124
|
+
var isSafeVersion = !safeVersions.Any() || safeVersions.Any(s => s.IsSatisfiedBy(version));
|
125
|
+
return versionGreaterThanCurrent
|
126
|
+
&& rangeSatisfies
|
127
|
+
&& prereleaseTypeMatches
|
128
|
+
&& !isIgnoredVersion
|
129
|
+
&& !isVulnerableVersion
|
130
|
+
&& isSafeVersion;
|
131
|
+
};
|
121
132
|
}
|
122
133
|
|
123
134
|
internal static Func<NuGetVersion, bool> CreateVersionFilter(NuGetVersion currentVersion)
|
@@ -70,11 +70,12 @@ public class CloneWorker
|
|
70
70
|
catch (HttpRequestException ex)
|
71
71
|
when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
|
72
72
|
{
|
73
|
+
// this is a _very_ specific case we want to handle before the common error handling kicks in
|
73
74
|
error = new JobRepoNotFound(ex.Message);
|
74
75
|
}
|
75
76
|
catch (Exception ex)
|
76
77
|
{
|
77
|
-
error =
|
78
|
+
error = JobErrorBase.ErrorFromException(ex, _jobId, repoContentsPath);
|
78
79
|
}
|
79
80
|
|
80
81
|
if (error is not null)
|
@@ -1,9 +1,9 @@
|
|
1
1
|
<Project>
|
2
2
|
<Import Project="DependencyDiscovery.props" />
|
3
3
|
|
4
|
-
<Target Name="_DiscoverDependencies" DependsOnTargets="GenerateBuildDependencyFile;ResolvePackageAssets">
|
4
|
+
<Target Name="_DiscoverDependencies" DependsOnTargets="ResolveAssemblyReferences;GenerateBuildDependencyFile;ResolvePackageAssets">
|
5
5
|
<!--
|
6
|
-
The
|
6
|
+
The targets ResolveAssemblyReferences and GenerateBuildDependencyFile are sufficient for projects targeting .NET Standard or .NET Core.
|
7
7
|
The target ResolvePackageAssets is necessary for projects targeting .NET Framework.
|
8
8
|
-->
|
9
9
|
</Target>
|
@@ -1,5 +1,4 @@
|
|
1
1
|
using System.Collections.Immutable;
|
2
|
-
using System.Net;
|
3
2
|
using System.Text.Json;
|
4
3
|
using System.Text.Json.Serialization;
|
5
4
|
|
@@ -10,7 +9,7 @@ using Microsoft.Build.Exceptions;
|
|
10
9
|
|
11
10
|
using NuGet.Frameworks;
|
12
11
|
|
13
|
-
using NuGetUpdater.Core.
|
12
|
+
using NuGetUpdater.Core.Run.ApiModel;
|
14
13
|
using NuGetUpdater.Core.Utilities;
|
15
14
|
|
16
15
|
namespace NuGetUpdater.Core.Discover;
|
@@ -19,6 +18,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
19
18
|
{
|
20
19
|
public const string DiscoveryResultFileName = "./.dependabot/discovery.json";
|
21
20
|
|
21
|
+
private readonly string _jobId;
|
22
22
|
private readonly ExperimentsManager _experimentsManager;
|
23
23
|
private readonly ILogger _logger;
|
24
24
|
private readonly HashSet<string> _processedProjectPaths = new(StringComparer.Ordinal); private readonly HashSet<string> _restoredMSBuildSdks = new(StringComparer.OrdinalIgnoreCase);
|
@@ -29,8 +29,9 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
29
29
|
Converters = { new JsonStringEnumConverter() },
|
30
30
|
};
|
31
31
|
|
32
|
-
public DiscoveryWorker(ExperimentsManager experimentsManager, ILogger logger)
|
32
|
+
public DiscoveryWorker(string jobId, ExperimentsManager experimentsManager, ILogger logger)
|
33
33
|
{
|
34
|
+
_jobId = jobId;
|
34
35
|
_experimentsManager = experimentsManager;
|
35
36
|
_logger = logger;
|
36
37
|
}
|
@@ -48,23 +49,11 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
48
49
|
{
|
49
50
|
result = await RunAsync(repoRootPath, workspacePath);
|
50
51
|
}
|
51
|
-
catch (HttpRequestException ex)
|
52
|
-
when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
|
53
|
-
{
|
54
|
-
result = new WorkspaceDiscoveryResult
|
55
|
-
{
|
56
|
-
ErrorType = ErrorType.AuthenticationFailure,
|
57
|
-
ErrorDetails = "(" + string.Join("|", NuGetContext.GetPackageSourceUrls(PathHelper.JoinPath(repoRootPath, workspacePath))) + ")",
|
58
|
-
Path = workspacePath,
|
59
|
-
Projects = [],
|
60
|
-
};
|
61
|
-
}
|
62
52
|
catch (Exception ex)
|
63
53
|
{
|
64
54
|
result = new WorkspaceDiscoveryResult
|
65
55
|
{
|
66
|
-
|
67
|
-
ErrorDetails = ex.ToString(),
|
56
|
+
Error = JobErrorBase.ErrorFromException(ex, _jobId, PathHelper.JoinPath(repoRootPath, workspacePath)),
|
68
57
|
Path = workspacePath,
|
69
58
|
Projects = [],
|
70
59
|
};
|
@@ -123,8 +112,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
123
112
|
DotNetToolsJson = null,
|
124
113
|
GlobalJson = null,
|
125
114
|
Projects = projectResults.Where(p => p.IsSuccess).OrderBy(p => p.FilePath).ToImmutableArray(),
|
126
|
-
|
127
|
-
ErrorDetails = failedProjectResult.FilePath,
|
115
|
+
Error = failedProjectResult.Error,
|
128
116
|
IsSuccess = false,
|
129
117
|
};
|
130
118
|
|
@@ -192,8 +180,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
192
180
|
ImportedFiles = ImmutableArray<string>.Empty,
|
193
181
|
AdditionalFiles = ImmutableArray<string>.Empty,
|
194
182
|
IsSuccess = false,
|
195
|
-
|
196
|
-
ErrorDetails = "Failed to parse project file found at " + invalidProjectFile,
|
183
|
+
Error = new DependencyFileNotParseable(invalidProjectFile),
|
197
184
|
}];
|
198
185
|
}
|
199
186
|
if (projects.IsEmpty)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
using System.Collections.Immutable;
|
2
|
-
|
2
|
+
|
3
|
+
using NuGetUpdater.Core.Run.ApiModel;
|
3
4
|
|
4
5
|
namespace NuGetUpdater.Core.Discover;
|
5
6
|
|
@@ -8,8 +9,7 @@ public record ProjectDiscoveryResult : IDiscoveryResultWithDependencies
|
|
8
9
|
public required string FilePath { get; init; }
|
9
10
|
public required ImmutableArray<Dependency> Dependencies { get; init; }
|
10
11
|
public bool IsSuccess { get; init; } = true;
|
11
|
-
public
|
12
|
-
public ErrorType? ErrorType { get; init; }
|
12
|
+
public JobErrorBase? Error { get; init; } = null;
|
13
13
|
public ImmutableArray<Property> Properties { get; init; } = [];
|
14
14
|
public ImmutableArray<string> TargetFrameworks { get; init; } = [];
|
15
15
|
public ImmutableArray<string> ReferencedProjectPaths { get; init; } = [];
|
@@ -9,6 +9,8 @@ using NuGet.Versioning;
|
|
9
9
|
|
10
10
|
using NuGetUpdater.Core.Utilities;
|
11
11
|
|
12
|
+
using Semver;
|
13
|
+
|
12
14
|
using LoggerProperty = Microsoft.Build.Logging.StructuredLogger.Property;
|
13
15
|
|
14
16
|
namespace NuGetUpdater.Core.Discover;
|
@@ -72,6 +74,9 @@ internal static class SdkProjectDiscovery
|
|
72
74
|
Dictionary<string, HashSet<string>> topLevelPackagesPerProject = new(PathComparer.Instance);
|
73
75
|
// projectPath, packageNames
|
74
76
|
|
77
|
+
Dictionary<string, Dictionary<string, Dictionary<string, string>>> packagesReplacedBySdkPerProject = new(PathComparer.Instance);
|
78
|
+
// projectPath tfm packageName, packageVersion
|
79
|
+
|
75
80
|
Dictionary<string, Dictionary<string, string>> resolvedProperties = new(PathComparer.Instance);
|
76
81
|
// projectPath propertyName, propertyValue
|
77
82
|
|
@@ -164,7 +169,7 @@ internal static class SdkProjectDiscovery
|
|
164
169
|
}
|
165
170
|
break;
|
166
171
|
case NamedNode namedNode when namedNode is AddItem or RemoveItem:
|
167
|
-
ProcessResolvedPackageReference(namedNode, packagesPerProject, topLevelPackagesPerProject);
|
172
|
+
ProcessResolvedPackageReference(namedNode, packagesPerProject, topLevelPackagesPerProject, experimentsManager);
|
168
173
|
|
169
174
|
if (namedNode is AddItem addItem)
|
170
175
|
{
|
@@ -203,6 +208,70 @@ internal static class SdkProjectDiscovery
|
|
203
208
|
}
|
204
209
|
}
|
205
210
|
break;
|
211
|
+
case Target target when target.Name == "_HandlePackageFileConflicts":
|
212
|
+
// this only works if we've installed the exact SDK required
|
213
|
+
if (experimentsManager.InstallDotnetSdks)
|
214
|
+
{
|
215
|
+
var projectEvaluation = GetNearestProjectEvaluation(target);
|
216
|
+
if (projectEvaluation is null)
|
217
|
+
{
|
218
|
+
break;
|
219
|
+
}
|
220
|
+
|
221
|
+
var removedReferences = target.Children.OfType<RemoveItem>().FirstOrDefault(r => r.Name == "Reference");
|
222
|
+
var addedReferences = target.Children.OfType<AddItem>().FirstOrDefault(r => r.Name == "Reference");
|
223
|
+
if (removedReferences is null || addedReferences is null)
|
224
|
+
{
|
225
|
+
break;
|
226
|
+
}
|
227
|
+
|
228
|
+
foreach (var removedAssembly in removedReferences.Children.OfType<Item>())
|
229
|
+
{
|
230
|
+
var removedPackageName = GetChildMetadataValue(removedAssembly, "NuGetPackageId");
|
231
|
+
var removedFileName = Path.GetFileName(removedAssembly.Name);
|
232
|
+
if (removedPackageName is null || removedFileName is null)
|
233
|
+
{
|
234
|
+
continue;
|
235
|
+
}
|
236
|
+
|
237
|
+
var existingProjectPackagesByTfm = packagesPerProject.GetOrAdd(projectEvaluation.ProjectFile, () => new(PathComparer.Instance));
|
238
|
+
var existingProjectPackages = existingProjectPackagesByTfm.GetOrAdd(tfm, () => new(StringComparer.OrdinalIgnoreCase));
|
239
|
+
if (!existingProjectPackages.ContainsKey(removedPackageName))
|
240
|
+
{
|
241
|
+
continue;
|
242
|
+
}
|
243
|
+
|
244
|
+
var correspondingAddedFile = addedReferences.Children.OfType<Item>()
|
245
|
+
.FirstOrDefault(i => removedFileName.Equals(Path.GetFileName(i.Name), StringComparison.OrdinalIgnoreCase));
|
246
|
+
if (correspondingAddedFile is null)
|
247
|
+
{
|
248
|
+
continue;
|
249
|
+
}
|
250
|
+
|
251
|
+
var runtimePackageName = GetChildMetadataValue(correspondingAddedFile, "NuGetPackageId");
|
252
|
+
var runtimePackageVersion = GetChildMetadataValue(correspondingAddedFile, "NuGetPackageVersion");
|
253
|
+
if (runtimePackageName is null ||
|
254
|
+
runtimePackageVersion is null ||
|
255
|
+
!SemVersion.TryParse(runtimePackageVersion, out var parsedRuntimePackageVersion))
|
256
|
+
{
|
257
|
+
continue;
|
258
|
+
}
|
259
|
+
|
260
|
+
var packageMapper = DotNetPackageCorrelationManager.GetPackageMapper();
|
261
|
+
var replacementPackageVersion = packageMapper.GetPackageVersionThatShippedWithOtherPackage(runtimePackageName, parsedRuntimePackageVersion, removedPackageName);
|
262
|
+
if (replacementPackageVersion is null)
|
263
|
+
{
|
264
|
+
continue;
|
265
|
+
}
|
266
|
+
|
267
|
+
var packagesPerThisProject = packagesReplacedBySdkPerProject.GetOrAdd(projectEvaluation.ProjectFile, () => new(PathComparer.Instance));
|
268
|
+
var packagesPerTfm = packagesPerThisProject.GetOrAdd(tfm, () => new(StringComparer.OrdinalIgnoreCase));
|
269
|
+
packagesPerTfm[removedPackageName] = replacementPackageVersion.ToString();
|
270
|
+
var relativeProjectPath = Path.GetRelativePath(repoRootPath, projectEvaluation.ProjectFile).NormalizePathToUnix();
|
271
|
+
logger.Info($"Re-added SDK managed package [{removedPackageName}/{replacementPackageVersion}] to project [{relativeProjectPath}]");
|
272
|
+
}
|
273
|
+
}
|
274
|
+
break;
|
206
275
|
}
|
207
276
|
}, takeChildrenSnapshot: true);
|
208
277
|
}
|
@@ -228,6 +297,33 @@ internal static class SdkProjectDiscovery
|
|
228
297
|
{
|
229
298
|
// gather some project-level information
|
230
299
|
var packagesByTfm = packagesPerProject[projectPath];
|
300
|
+
if (packagesReplacedBySdkPerProject.TryGetValue(projectPath, out var packagesReplacedBySdk))
|
301
|
+
{
|
302
|
+
var consolidatedPackagesByTfm = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
|
303
|
+
|
304
|
+
// copy the first dictionary
|
305
|
+
foreach (var kvp in packagesByTfm)
|
306
|
+
{
|
307
|
+
var tfm = kvp.Key;
|
308
|
+
var packages = kvp.Value;
|
309
|
+
consolidatedPackagesByTfm[tfm] = packages;
|
310
|
+
}
|
311
|
+
|
312
|
+
// merge in the second
|
313
|
+
foreach (var kvp in packagesReplacedBySdk)
|
314
|
+
{
|
315
|
+
var tfm = kvp.Key;
|
316
|
+
var packages = kvp.Value;
|
317
|
+
var replacedPackages = consolidatedPackagesByTfm.GetOrAdd(tfm, () => new(StringComparer.OrdinalIgnoreCase));
|
318
|
+
foreach (var packagePair in packages)
|
319
|
+
{
|
320
|
+
replacedPackages[packagePair.Key] = packagePair.Value;
|
321
|
+
}
|
322
|
+
}
|
323
|
+
|
324
|
+
packagesByTfm = consolidatedPackagesByTfm;
|
325
|
+
}
|
326
|
+
|
231
327
|
var projectFullDirectory = Path.GetDirectoryName(projectPath)!;
|
232
328
|
var doc = XDocument.Load(projectPath);
|
233
329
|
var localPropertyDefinitionElements = doc.Root!.XPathSelectElements("/Project/PropertyGroup/*");
|
@@ -288,7 +384,8 @@ internal static class SdkProjectDiscovery
|
|
288
384
|
private static void ProcessResolvedPackageReference(
|
289
385
|
NamedNode node,
|
290
386
|
Dictionary<string, Dictionary<string, Dictionary<string, string>>> packagesPerProject, // projectPath -> tfm -> (packageName, packageVersion)
|
291
|
-
Dictionary<string, HashSet<string>> topLevelPackagesPerProject
|
387
|
+
Dictionary<string, HashSet<string>> topLevelPackagesPerProject,
|
388
|
+
ExperimentsManager experimentsManager
|
292
389
|
)
|
293
390
|
{
|
294
391
|
var doRemoveOperation = node is RemoveItem;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<Project>
|
2
|
+
|
3
|
+
<PropertyGroup>
|
4
|
+
<PackageCorrelationCliDirectory>$(MSBuildThisFileDirectory)..\DotNetPackageCorrelation.Cli</PackageCorrelationCliDirectory>
|
5
|
+
<DotNetCoreDirectory>$(MSBuildThisFileDirectory)..\..\dotnet-core</DotNetCoreDirectory>
|
6
|
+
<PackageCorrelationFile>$(MSBuildThisFileDirectory)dotnet-package-correlation.json</PackageCorrelationFile>
|
7
|
+
</PropertyGroup>
|
8
|
+
|
9
|
+
<ItemGroup>
|
10
|
+
<None Include="$(PackageCorrelationFile)" CopyToOutputDirectory="PreserveNewest" />
|
11
|
+
<_DotNetCoreFiles Include="$(DotNetCoreDirectory)\**\*" />
|
12
|
+
</ItemGroup>
|
13
|
+
|
14
|
+
<Target Name="BuildDotNetPackageCorrelationFile" Inputs="@(_DotNetCoreFiles)" Outputs="$(PackageCorrelationFile)" BeforeTargets="GetCopyToOutputDirectoryItems">
|
15
|
+
<Exec Command="dotnet run --core-location "$(DotNetCoreDirectory)" --output "$(PackageCorrelationFile)"" WorkingDirectory="$(PackageCorrelationCliDirectory)" />
|
16
|
+
</Target>
|
17
|
+
|
18
|
+
<Target Name="CleanDotNetPackageCorrelationFile" BeforeTargets="Clean">
|
19
|
+
<Delete Files="$(PackageCorrelationFile)" Condition="Exists('$(PackageCorrelationFile)')" />
|
20
|
+
</Target>
|
21
|
+
|
22
|
+
<Target Name="RebuildDotNetPackageCorrelationFile" BeforeTargets="Rebuild" DependsOnTargets="CleanDotNetPackageCorrelationFile">
|
23
|
+
</Target>
|
24
|
+
|
25
|
+
</Project>
|
@@ -1,6 +1,7 @@
|
|
1
1
|
using System.Text.Json;
|
2
2
|
|
3
3
|
using NuGetUpdater.Core.Run;
|
4
|
+
using NuGetUpdater.Core.Run.ApiModel;
|
4
5
|
|
5
6
|
namespace NuGetUpdater.Core;
|
6
7
|
|
@@ -30,42 +31,28 @@ public record ExperimentsManager
|
|
30
31
|
};
|
31
32
|
}
|
32
33
|
|
33
|
-
public static async Task<(ExperimentsManager ExperimentsManager,
|
34
|
+
public static async Task<(ExperimentsManager ExperimentsManager, JobErrorBase? Error)> FromJobFileAsync(string jobId, string jobFilePath)
|
34
35
|
{
|
35
36
|
var experimentsManager = new ExperimentsManager();
|
36
|
-
|
37
|
+
JobErrorBase? error = null;
|
38
|
+
var jobFileContent = string.Empty;
|
37
39
|
try
|
38
40
|
{
|
39
|
-
|
41
|
+
jobFileContent = await File.ReadAllTextAsync(jobFilePath);
|
40
42
|
var jobWrapper = RunWorker.Deserialize(jobFileContent);
|
41
43
|
experimentsManager = GetExperimentsManager(jobWrapper.Job.Experiments);
|
42
44
|
}
|
43
|
-
catch (BadRequirementException ex)
|
44
|
-
{
|
45
|
-
errorResult = new NativeResult
|
46
|
-
{
|
47
|
-
ErrorType = ErrorType.BadRequirement,
|
48
|
-
ErrorDetails = ex.Message,
|
49
|
-
};
|
50
|
-
}
|
51
45
|
catch (JsonException ex)
|
52
46
|
{
|
53
|
-
|
54
|
-
{
|
55
|
-
ErrorType = ErrorType.Unknown,
|
56
|
-
ErrorDetails = $"Error deserializing job file: {ex}: {File.ReadAllText(jobFilePath)}",
|
57
|
-
};
|
47
|
+
// this is a very specific case where we want to log the JSON contents for easier debugging
|
48
|
+
error = JobErrorBase.ErrorFromException(new NotSupportedException($"Error deserializing job file contents: {jobFileContent}", ex), jobId, Environment.CurrentDirectory); // TODO
|
58
49
|
}
|
59
50
|
catch (Exception ex)
|
60
51
|
{
|
61
|
-
|
62
|
-
{
|
63
|
-
ErrorType = ErrorType.Unknown,
|
64
|
-
ErrorDetails = ex.ToString(),
|
65
|
-
};
|
52
|
+
error = JobErrorBase.ErrorFromException(ex, jobId, Environment.CurrentDirectory); // TODO
|
66
53
|
}
|
67
54
|
|
68
|
-
return (experimentsManager,
|
55
|
+
return (experimentsManager, error);
|
69
56
|
}
|
70
57
|
|
71
58
|
private static bool IsEnabled(Dictionary<string, object>? experiments, string experimentName)
|
@@ -13,12 +13,16 @@ internal sealed class PackagesConfigBuildFile : XmlBuildFile
|
|
13
13
|
public PackagesConfigBuildFile(string basePath, string path, XmlDocumentSyntax contents)
|
14
14
|
: base(basePath, path, contents)
|
15
15
|
{
|
16
|
+
var invalidPackageElements = Packages.Where(p => p.GetAttribute("id") is null || p.GetAttribute("version") is null).ToList();
|
17
|
+
if (invalidPackageElements.Any())
|
18
|
+
{
|
19
|
+
throw new UnparseableFileException("`package` element missing `id` or `version` attributes", path);
|
20
|
+
}
|
16
21
|
}
|
17
22
|
|
18
23
|
public IEnumerable<IXmlElementSyntax> Packages => Contents.RootSyntax.GetElements("package", StringComparison.OrdinalIgnoreCase);
|
19
24
|
|
20
25
|
public IEnumerable<Dependency> GetDependencies() => Packages
|
21
|
-
.Where(p => p.GetAttribute("id") is not null && p.GetAttribute("version") is not null)
|
22
26
|
.Select(p => new Dependency(
|
23
27
|
p.GetAttributeValue("id", StringComparison.OrdinalIgnoreCase),
|
24
28
|
p.GetAttributeValue("version", StringComparison.OrdinalIgnoreCase),
|
@@ -1,8 +1,8 @@
|
|
1
|
+
using NuGetUpdater.Core.Run.ApiModel;
|
2
|
+
|
1
3
|
namespace NuGetUpdater.Core;
|
2
4
|
|
3
5
|
public record NativeResult
|
4
6
|
{
|
5
|
-
|
6
|
-
public ErrorType? ErrorType { get; init; }
|
7
|
-
public object? ErrorDetails { get; init; }
|
7
|
+
public JobErrorBase? Error { get; init; } = null;
|
8
8
|
}
|
@@ -14,6 +14,7 @@
|
|
14
14
|
</ItemGroup>
|
15
15
|
|
16
16
|
<ItemGroup>
|
17
|
+
<ProjectReference Include="..\DotNetPackageCorrelation\DotNetPackageCorrelation.csproj" />
|
17
18
|
<ProjectReference Include="..\NuGetProjects\NuGet.CommandLine\NuGet.CommandLine.csproj" />
|
18
19
|
</ItemGroup>
|
19
20
|
|
@@ -31,4 +32,6 @@
|
|
31
32
|
<InternalsVisibleTo Include="NuGetUpdater.Core.Test" />
|
32
33
|
</ItemGroup>
|
33
34
|
|
35
|
+
<Import Project="EnsureDotNetPackageCorrelation.targets" />
|
36
|
+
|
34
37
|
</Project>
|
@@ -10,4 +10,6 @@ public record Advisory
|
|
10
10
|
public ImmutableArray<Requirement>? AffectedVersions { get; init; } = null;
|
11
11
|
public ImmutableArray<Requirement>? PatchedVersions { get; init; } = null;
|
12
12
|
public ImmutableArray<Requirement>? UnaffectedVersions { get; init; } = null;
|
13
|
+
|
14
|
+
public IEnumerable<Requirement> SafeVersions => (PatchedVersions ?? []).Concat(UnaffectedVersions ?? []);
|
13
15
|
}
|
@@ -2,10 +2,14 @@ namespace NuGetUpdater.Core.Run.ApiModel;
|
|
2
2
|
|
3
3
|
public record DependencyFileNotFound : JobErrorBase
|
4
4
|
{
|
5
|
-
public DependencyFileNotFound(string
|
5
|
+
public DependencyFileNotFound(string filePath, string? message = null)
|
6
6
|
: base("dependency_file_not_found")
|
7
7
|
{
|
8
|
-
|
9
|
-
|
8
|
+
if (message is not null)
|
9
|
+
{
|
10
|
+
Details["message"] = message;
|
11
|
+
}
|
12
|
+
|
13
|
+
Details["file-path"] = filePath.NormalizePathToUnix();
|
10
14
|
}
|
11
15
|
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
namespace NuGetUpdater.Core.Run.ApiModel;
|
2
|
+
|
3
|
+
public record DependencyFileNotParseable : JobErrorBase
|
4
|
+
{
|
5
|
+
public DependencyFileNotParseable(string filePath, string? message = null)
|
6
|
+
: base("dependency_file_not_parseable")
|
7
|
+
{
|
8
|
+
if (message is not null)
|
9
|
+
{
|
10
|
+
Details["message"] = message;
|
11
|
+
}
|
12
|
+
|
13
|
+
Details["file-path"] = filePath.NormalizePathToUnix();
|
14
|
+
}
|
15
|
+
}
|
@@ -1,5 +1,10 @@
|
|
1
|
+
using System.Net;
|
1
2
|
using System.Text.Json.Serialization;
|
2
3
|
|
4
|
+
using Microsoft.Build.Exceptions;
|
5
|
+
|
6
|
+
using NuGetUpdater.Core.Analyze;
|
7
|
+
|
3
8
|
namespace NuGetUpdater.Core.Run.ApiModel;
|
4
9
|
|
5
10
|
public abstract record JobErrorBase
|
@@ -14,4 +19,23 @@ public abstract record JobErrorBase
|
|
14
19
|
|
15
20
|
[JsonPropertyName("error-details")]
|
16
21
|
public Dictionary<string, object> Details { get; init; } = new();
|
22
|
+
|
23
|
+
public static JobErrorBase ErrorFromException(Exception ex, string jobId, string currentDirectory)
|
24
|
+
{
|
25
|
+
return ex switch
|
26
|
+
{
|
27
|
+
BadRequirementException badRequirement => new BadRequirement(badRequirement.Message),
|
28
|
+
HttpRequestException httpRequest => httpRequest.StatusCode switch
|
29
|
+
{
|
30
|
+
HttpStatusCode.Unauthorized or
|
31
|
+
HttpStatusCode.Forbidden => new PrivateSourceAuthenticationFailure(NuGetContext.GetPackageSourceUrls(currentDirectory)),
|
32
|
+
_ => new UnknownError(ex, jobId),
|
33
|
+
},
|
34
|
+
InvalidProjectFileException invalidProjectFile => new DependencyFileNotParseable(invalidProjectFile.ProjectFile),
|
35
|
+
MissingFileException missingFile => new DependencyFileNotFound(missingFile.FilePath, missingFile.Message),
|
36
|
+
UnparseableFileException unparseableFile => new DependencyFileNotParseable(unparseableFile.FilePath, unparseableFile.Message),
|
37
|
+
UpdateNotPossibleException updateNotPossible => new UpdateNotPossible(updateNotPossible.Dependencies),
|
38
|
+
_ => new UnknownError(ex, jobId),
|
39
|
+
};
|
40
|
+
}
|
17
41
|
}
|
@@ -4,6 +4,8 @@ using System.Text;
|
|
4
4
|
using System.Text.Json;
|
5
5
|
using System.Text.Json.Serialization;
|
6
6
|
|
7
|
+
using NuGet.Versioning;
|
8
|
+
|
7
9
|
using NuGetUpdater.Core.Analyze;
|
8
10
|
using NuGetUpdater.Core.Discover;
|
9
11
|
using NuGetUpdater.Core.Run.ApiModel;
|
@@ -53,7 +55,7 @@ public class RunWorker
|
|
53
55
|
private async Task<RunResult> RunWithErrorHandlingAsync(Job job, DirectoryInfo repoContentsPath, string baseCommitSha)
|
54
56
|
{
|
55
57
|
JobErrorBase? error = null;
|
56
|
-
|
58
|
+
var currentDirectory = repoContentsPath.FullName; // used for error reporting below
|
57
59
|
var runResult = new RunResult()
|
58
60
|
{
|
59
61
|
Base64DependencyFiles = [],
|
@@ -69,7 +71,7 @@ public class RunWorker
|
|
69
71
|
foreach (var directory in job.GetAllDirectories())
|
70
72
|
{
|
71
73
|
var localPath = PathHelper.JoinPath(repoContentsPath.FullName, directory);
|
72
|
-
|
74
|
+
currentDirectory = localPath;
|
73
75
|
var result = await RunForDirectory(job, repoContentsPath, directory, baseCommitSha, experimentsManager);
|
74
76
|
foreach (var dependencyFile in result.Base64DependencyFiles)
|
75
77
|
{
|
@@ -84,26 +86,9 @@ public class RunWorker
|
|
84
86
|
BaseCommitSha = baseCommitSha,
|
85
87
|
};
|
86
88
|
}
|
87
|
-
catch (HttpRequestException ex)
|
88
|
-
when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
|
89
|
-
{
|
90
|
-
error = new PrivateSourceAuthenticationFailure(lastUsedPackageSourceUrls);
|
91
|
-
}
|
92
|
-
catch (BadRequirementException ex)
|
93
|
-
{
|
94
|
-
error = new BadRequirement(ex.Message);
|
95
|
-
}
|
96
|
-
catch (MissingFileException ex)
|
97
|
-
{
|
98
|
-
error = new DependencyFileNotFound("file not found", ex.FilePath);
|
99
|
-
}
|
100
|
-
catch (UpdateNotPossibleException ex)
|
101
|
-
{
|
102
|
-
error = new UpdateNotPossible(ex.Dependencies);
|
103
|
-
}
|
104
89
|
catch (Exception ex)
|
105
90
|
{
|
106
|
-
error =
|
91
|
+
error = JobErrorBase.ErrorFromException(ex, _jobId, currentDirectory);
|
107
92
|
}
|
108
93
|
|
109
94
|
if (error is not null)
|
@@ -123,6 +108,8 @@ public class RunWorker
|
|
123
108
|
_logger.Info("Discovery JSON content:");
|
124
109
|
_logger.Info(JsonSerializer.Serialize(discoveryResult, DiscoveryWorker.SerializerOptions));
|
125
110
|
|
111
|
+
// TODO: report errors
|
112
|
+
|
126
113
|
// report dependencies
|
127
114
|
var discoveredUpdatedDependencies = GetUpdatedDependencyListFromDiscovery(discoveryResult, repoContentsPath.FullName);
|
128
115
|
await _apiHandler.UpdateDependencyList(discoveredUpdatedDependencies);
|
@@ -179,15 +166,7 @@ public class RunWorker
|
|
179
166
|
continue;
|
180
167
|
}
|
181
168
|
|
182
|
-
var
|
183
|
-
var dependencyInfo = new DependencyInfo()
|
184
|
-
{
|
185
|
-
Name = dependency.Name,
|
186
|
-
Version = dependency.Version!,
|
187
|
-
IsVulnerable = false,
|
188
|
-
IgnoredVersions = ignoredVersions,
|
189
|
-
Vulnerabilities = [],
|
190
|
-
};
|
169
|
+
var dependencyInfo = GetDependencyInfo(job, dependency);
|
191
170
|
var analysisResult = await _analyzeWorker.RunAsync(repoContentsPath.FullName, discoveryResult, dependencyInfo);
|
192
171
|
// TODO: log analysisResult
|
193
172
|
if (analysisResult.CanUpdate)
|
@@ -221,7 +200,7 @@ public class RunWorker
|
|
221
200
|
var dependencyFilePath = Path.Join(discoveryResult.Path, project.FilePath).FullyNormalizedRootedPath();
|
222
201
|
var updateResult = await _updaterWorker.RunAsync(repoContentsPath.FullName, dependencyFilePath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, isTransitive: false);
|
223
202
|
// TODO: need to report if anything was actually updated
|
224
|
-
if (updateResult.
|
203
|
+
if (updateResult.Error is null)
|
225
204
|
{
|
226
205
|
if (dependencyLocation != dependencyFilePath)
|
227
206
|
{
|
@@ -329,6 +308,30 @@ public class RunWorker
|
|
329
308
|
return ignoredVersions;
|
330
309
|
}
|
331
310
|
|
311
|
+
internal static DependencyInfo GetDependencyInfo(Job job, Dependency dependency)
|
312
|
+
{
|
313
|
+
var dependencyVersion = NuGetVersion.Parse(dependency.Version!);
|
314
|
+
var securityAdvisories = job.SecurityAdvisories.Where(s => s.DependencyName.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase)).ToArray();
|
315
|
+
var isVulnerable = securityAdvisories.Any(s => (s.AffectedVersions ?? []).Any(v => v.IsSatisfiedBy(dependencyVersion)));
|
316
|
+
var ignoredVersions = GetIgnoredRequirementsForDependency(job, dependency.Name);
|
317
|
+
var vulnerabilities = securityAdvisories.Select(s => new SecurityVulnerability()
|
318
|
+
{
|
319
|
+
DependencyName = dependency.Name,
|
320
|
+
PackageManager = "nuget",
|
321
|
+
VulnerableVersions = s.AffectedVersions ?? [],
|
322
|
+
SafeVersions = s.SafeVersions.ToImmutableArray(),
|
323
|
+
}).ToImmutableArray();
|
324
|
+
var dependencyInfo = new DependencyInfo()
|
325
|
+
{
|
326
|
+
Name = dependency.Name,
|
327
|
+
Version = dependencyVersion.ToString(),
|
328
|
+
IsVulnerable = isVulnerable,
|
329
|
+
IgnoredVersions = ignoredVersions,
|
330
|
+
Vulnerabilities = vulnerabilities,
|
331
|
+
};
|
332
|
+
return dependencyInfo;
|
333
|
+
}
|
334
|
+
|
332
335
|
internal static UpdatedDependencyList GetUpdatedDependencyListFromDiscovery(WorkspaceDiscoveryResult discoveryResult, string pathToContents)
|
333
336
|
{
|
334
337
|
string GetFullRepoPath(string path)
|