dependabot-nuget 0.292.0 → 0.294.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/.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)
|