dependabot-nuget 0.264.0 → 0.266.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.Cli/Commands/UpdateCommand.cs +6 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalysisResult.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +73 -77
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +21 -8
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +24 -8
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +33 -16
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +44 -25
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +8 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/ProjectBuildFile.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/NativeResult.cs +8 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +18 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdateOperationResult.cs +5 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +62 -22
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +19 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +6 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +448 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/CompatibilityCheckerTests.cs +23 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +2 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +148 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestHttpServer.cs +81 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +27 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +32 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +87 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +88 -0
- data/lib/dependabot/nuget/analysis/dependency_analysis.rb +3 -0
- data/lib/dependabot/nuget/file_fetcher.rb +1 -1
- data/lib/dependabot/nuget/metadata_finder.rb +160 -2
- data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +3 -0
- data/lib/dependabot/nuget/native_helpers.rb +34 -3
- data/lib/dependabot/nuget/native_update_checker/native_update_checker.rb +1 -0
- data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +3 -0
- metadata +11 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4669e522f1ce196d5657096bdf738e6ab353c5a697ea1b0acb1f0c87f9815a44
|
4
|
+
data.tar.gz: 33657445578fcd52b0370490b3c1f4b2fe165ad9f00e22d831d6a216b89458f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ca40a2a42e55b376edc0694253f81a54eb30d75748c3a5572e3a754b64aab96fe86b34f753d0f4566bdf66816da3318aed0eba31fc195581cb2072f89c0d8cb
|
7
|
+
data.tar.gz: 115640e60d1b2a59edb5b6956c9e8d3c35105dafa6ce00d60aa5de52561da96670606af7862d1a24ab1f24bc4fd91651b4856eeb4b7fc545ca230cc72a529493
|
@@ -1,6 +1,4 @@
|
|
1
|
-
using System;
|
2
1
|
using System.CommandLine;
|
3
|
-
using System.IO;
|
4
2
|
|
5
3
|
using NuGetUpdater.Core;
|
6
4
|
|
@@ -15,6 +13,7 @@ internal static class UpdateCommand
|
|
15
13
|
internal static readonly Option<string> PreviousVersionOption = new("--previous-version") { IsRequired = true };
|
16
14
|
internal static readonly Option<bool> IsTransitiveOption = new("--transitive", getDefaultValue: () => false);
|
17
15
|
internal static readonly Option<bool> VerboseOption = new("--verbose", getDefaultValue: () => false);
|
16
|
+
internal static readonly Option<string?> ResultOutputPathOption = new("--result-output-path", getDefaultValue: () => null);
|
18
17
|
|
19
18
|
internal static Command GetCommand(Action<int> setExitCode)
|
20
19
|
{
|
@@ -26,17 +25,18 @@ internal static class UpdateCommand
|
|
26
25
|
NewVersionOption,
|
27
26
|
PreviousVersionOption,
|
28
27
|
IsTransitiveOption,
|
29
|
-
VerboseOption
|
28
|
+
VerboseOption,
|
29
|
+
ResultOutputPathOption
|
30
30
|
};
|
31
31
|
|
32
32
|
command.TreatUnmatchedTokensAsErrors = true;
|
33
33
|
|
34
|
-
command.SetHandler(async (repoRoot, solutionOrProjectFile, dependencyName, newVersion, previousVersion, isTransitive, verbose) =>
|
34
|
+
command.SetHandler(async (repoRoot, solutionOrProjectFile, dependencyName, newVersion, previousVersion, isTransitive, verbose, resultOutputPath) =>
|
35
35
|
{
|
36
36
|
var worker = new UpdaterWorker(new Logger(verbose));
|
37
|
-
await worker.RunAsync(repoRoot.FullName, solutionOrProjectFile.FullName, dependencyName, previousVersion, newVersion, isTransitive);
|
37
|
+
await worker.RunAsync(repoRoot.FullName, solutionOrProjectFile.FullName, dependencyName, previousVersion, newVersion, isTransitive, resultOutputPath);
|
38
38
|
setExitCode(0);
|
39
|
-
}, RepoRootOption, SolutionOrProjectFileOption, DependencyNameOption, NewVersionOption, PreviousVersionOption, IsTransitiveOption, VerboseOption);
|
39
|
+
}, RepoRootOption, SolutionOrProjectFileOption, DependencyNameOption, NewVersionOption, PreviousVersionOption, IsTransitiveOption, VerboseOption, ResultOutputPathOption);
|
40
40
|
|
41
41
|
return command;
|
42
42
|
}
|
@@ -1,8 +1,8 @@
|
|
1
1
|
using System.Collections.Immutable;
|
2
|
+
using System.Net;
|
2
3
|
using System.Text.Json;
|
3
4
|
using System.Text.Json.Serialization;
|
4
5
|
|
5
|
-
using NuGet.Configuration;
|
6
6
|
using NuGet.Frameworks;
|
7
7
|
using NuGet.Versioning;
|
8
8
|
|
@@ -57,70 +57,87 @@ public partial class AnalyzeWorker
|
|
57
57
|
ImmutableArray<Dependency> updatedDependencies = [];
|
58
58
|
|
59
59
|
bool isUpdateNecessary = IsUpdateNecessary(dependencyInfo, projectsWithDependency);
|
60
|
-
|
60
|
+
using var nugetContext = new NuGetContext(startingDirectory);
|
61
|
+
AnalysisResult result;
|
62
|
+
try
|
61
63
|
{
|
62
|
-
|
63
|
-
if (!Directory.Exists(nugetContext.TempPackageDirectory))
|
64
|
+
if (isUpdateNecessary)
|
64
65
|
{
|
65
|
-
Directory.
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
var multiDependencies = DetermineMultiDependencyDetails(
|
70
|
-
discovery,
|
71
|
-
dependencyInfo.Name,
|
72
|
-
propertyBasedDependencies);
|
73
|
-
|
74
|
-
usesMultiDependencyProperty = multiDependencies.Any(md => md.DependencyNames.Count > 1);
|
75
|
-
var dependenciesToUpdate = usesMultiDependencyProperty
|
76
|
-
? multiDependencies
|
77
|
-
.SelectMany(md => md.DependencyNames)
|
78
|
-
.ToImmutableHashSet(StringComparer.OrdinalIgnoreCase)
|
79
|
-
: [dependencyInfo.Name];
|
80
|
-
var applicableTargetFrameworks = usesMultiDependencyProperty
|
81
|
-
? multiDependencies
|
82
|
-
.SelectMany(md => md.TargetFrameworks)
|
83
|
-
.ToImmutableHashSet(StringComparer.OrdinalIgnoreCase)
|
84
|
-
.Select(NuGetFramework.Parse)
|
85
|
-
.ToImmutableArray()
|
86
|
-
: projectFrameworks;
|
87
|
-
|
88
|
-
_logger.Log($" Finding updated version.");
|
89
|
-
updatedVersion = await FindUpdatedVersionAsync(
|
90
|
-
startingDirectory,
|
91
|
-
dependencyInfo,
|
92
|
-
dependenciesToUpdate,
|
93
|
-
applicableTargetFrameworks,
|
94
|
-
nugetContext,
|
95
|
-
_logger,
|
96
|
-
CancellationToken.None);
|
66
|
+
if (!Directory.Exists(nugetContext.TempPackageDirectory))
|
67
|
+
{
|
68
|
+
Directory.CreateDirectory(nugetContext.TempPackageDirectory);
|
69
|
+
}
|
97
70
|
|
98
|
-
|
99
|
-
|
100
|
-
? await FindUpdatedDependenciesAsync(
|
101
|
-
repoRoot,
|
71
|
+
_logger.Log($" Determining multi-dependency property.");
|
72
|
+
var multiDependencies = DetermineMultiDependencyDetails(
|
102
73
|
discovery,
|
74
|
+
dependencyInfo.Name,
|
75
|
+
propertyBasedDependencies);
|
76
|
+
|
77
|
+
usesMultiDependencyProperty = multiDependencies.Any(md => md.DependencyNames.Count > 1);
|
78
|
+
var dependenciesToUpdate = usesMultiDependencyProperty
|
79
|
+
? multiDependencies
|
80
|
+
.SelectMany(md => md.DependencyNames)
|
81
|
+
.ToImmutableHashSet(StringComparer.OrdinalIgnoreCase)
|
82
|
+
: [dependencyInfo.Name];
|
83
|
+
var applicableTargetFrameworks = usesMultiDependencyProperty
|
84
|
+
? multiDependencies
|
85
|
+
.SelectMany(md => md.TargetFrameworks)
|
86
|
+
.ToImmutableHashSet(StringComparer.OrdinalIgnoreCase)
|
87
|
+
.Select(NuGetFramework.Parse)
|
88
|
+
.ToImmutableArray()
|
89
|
+
: projectFrameworks;
|
90
|
+
|
91
|
+
_logger.Log($" Finding updated version.");
|
92
|
+
updatedVersion = await FindUpdatedVersionAsync(
|
93
|
+
startingDirectory,
|
94
|
+
dependencyInfo,
|
103
95
|
dependenciesToUpdate,
|
104
|
-
|
96
|
+
applicableTargetFrameworks,
|
105
97
|
nugetContext,
|
106
98
|
_logger,
|
107
|
-
CancellationToken.None)
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
99
|
+
CancellationToken.None);
|
100
|
+
|
101
|
+
_logger.Log($" Finding updated peer dependencies.");
|
102
|
+
updatedDependencies = updatedVersion is not null
|
103
|
+
? await FindUpdatedDependenciesAsync(
|
104
|
+
repoRoot,
|
105
|
+
discovery,
|
106
|
+
dependenciesToUpdate,
|
107
|
+
updatedVersion,
|
108
|
+
nugetContext,
|
109
|
+
_logger,
|
110
|
+
CancellationToken.None)
|
111
|
+
: [];
|
112
|
+
|
113
|
+
//TODO: At this point we should add the peer dependencies to a queue where
|
114
|
+
// we will analyze them one by one to see if they themselves are part of a
|
115
|
+
// multi-dependency property. Basically looping this if-body until we have
|
116
|
+
// emptied the queue and have a complete list of updated dependencies. We
|
117
|
+
// should track the dependenciesToUpdate as they have already been analyzed.
|
118
|
+
}
|
116
119
|
|
117
|
-
|
120
|
+
result = new AnalysisResult
|
121
|
+
{
|
122
|
+
UpdatedVersion = updatedVersion?.ToNormalizedString() ?? dependencyInfo.Version,
|
123
|
+
CanUpdate = updatedVersion is not null,
|
124
|
+
VersionComesFromMultiDependencyProperty = usesMultiDependencyProperty,
|
125
|
+
UpdatedDependencies = updatedDependencies,
|
126
|
+
};
|
127
|
+
}
|
128
|
+
catch (HttpRequestException ex)
|
129
|
+
when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
|
118
130
|
{
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
131
|
+
// TODO: consolidate this error handling between AnalyzeWorker, DiscoveryWorker, and UpdateWorker
|
132
|
+
result = new AnalysisResult
|
133
|
+
{
|
134
|
+
ErrorType = ErrorType.AuthenticationFailure,
|
135
|
+
ErrorDetails = "(" + string.Join("|", nugetContext.PackageSources.Select(s => s.Source)) + ")",
|
136
|
+
UpdatedVersion = string.Empty,
|
137
|
+
CanUpdate = false,
|
138
|
+
UpdatedDependencies = [],
|
139
|
+
};
|
140
|
+
}
|
124
141
|
|
125
142
|
await WriteResultsAsync(analysisDirectory, dependencyInfo.Name, result, _logger);
|
126
143
|
|
@@ -314,27 +331,6 @@ public partial class AnalyzeWorker
|
|
314
331
|
return true;
|
315
332
|
}
|
316
333
|
|
317
|
-
internal static async Task<ImmutableDictionary<NuGetFramework, ImmutableArray<Dependency>>> GetDependenciesAsync(
|
318
|
-
string workspacePath,
|
319
|
-
string projectPath,
|
320
|
-
IEnumerable<NuGetFramework> frameworks,
|
321
|
-
Dependency package,
|
322
|
-
Logger logger)
|
323
|
-
{
|
324
|
-
var result = ImmutableDictionary.CreateBuilder<NuGetFramework, ImmutableArray<Dependency>>();
|
325
|
-
foreach (var framework in frameworks)
|
326
|
-
{
|
327
|
-
var dependencies = await MSBuildHelper.GetAllPackageDependenciesAsync(
|
328
|
-
workspacePath,
|
329
|
-
projectPath,
|
330
|
-
framework.ToString(),
|
331
|
-
[package],
|
332
|
-
logger);
|
333
|
-
result.Add(framework, [.. dependencies]);
|
334
|
-
}
|
335
|
-
return result.ToImmutable();
|
336
|
-
}
|
337
|
-
|
338
334
|
internal static async Task<ImmutableArray<Dependency>> FindUpdatedDependenciesAsync(
|
339
335
|
string repoRoot,
|
340
336
|
WorkspaceDiscoveryResult discovery,
|
@@ -54,6 +54,11 @@ internal static class CompatibilityChecker
|
|
54
54
|
|
55
55
|
var compatibilityService = new FrameworkCompatibilityService();
|
56
56
|
var compatibleFrameworks = compatibilityService.GetCompatibleFrameworks(packageFrameworks);
|
57
|
+
var packageSupportsAny = compatibleFrameworks.Any(f => f.IsAny);
|
58
|
+
if (packageSupportsAny)
|
59
|
+
{
|
60
|
+
return true;
|
61
|
+
}
|
57
62
|
|
58
63
|
var incompatibleFrameworks = projectFrameworks.Where(f => !compatibleFrameworks.Contains(f)).ToArray();
|
59
64
|
if (incompatibleFrameworks.Length > 0)
|
@@ -141,15 +146,23 @@ internal static class CompatibilityChecker
|
|
141
146
|
throw new NotSupportedException($"Failed to get FindPackageByIdResource for {source.SourceUri}");
|
142
147
|
}
|
143
148
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
149
|
+
try
|
150
|
+
{
|
151
|
+
// a non-compliant v2 API returning 404 can cause this to throw
|
152
|
+
var exists = await feed.DoesPackageExistAsync(
|
153
|
+
package.Id,
|
154
|
+
package.Version,
|
155
|
+
context.SourceCacheContext,
|
156
|
+
NullLogger.Instance,
|
157
|
+
cancellationToken);
|
158
|
+
if (!exists)
|
159
|
+
{
|
160
|
+
continue;
|
161
|
+
}
|
162
|
+
}
|
163
|
+
catch (FatalProtocolException)
|
152
164
|
{
|
165
|
+
// if anything goes wrong here, the package source obviously doesn't contain the requested package
|
153
166
|
continue;
|
154
167
|
}
|
155
168
|
|
@@ -47,6 +47,13 @@ internal record NuGetContext : IDisposable
|
|
47
47
|
|
48
48
|
private readonly Dictionary<PackageIdentity, string?> _packageInfoUrlCache = new();
|
49
49
|
|
50
|
+
public static string[] GetPackageSourceUrls(string currentDirectory)
|
51
|
+
{
|
52
|
+
using var context = new NuGetContext(currentDirectory);
|
53
|
+
var sourceUrls = context.PackageSources.Select(s => s.Source).ToArray();
|
54
|
+
return sourceUrls;
|
55
|
+
}
|
56
|
+
|
50
57
|
public async Task<string?> GetPackageInfoUrlAsync(string packageId, string packageVersion, CancellationToken cancellationToken)
|
51
58
|
{
|
52
59
|
var packageIdentity = new PackageIdentity(packageId, NuGetVersion.Parse(packageVersion));
|
@@ -86,15 +93,24 @@ internal record NuGetContext : IDisposable
|
|
86
93
|
continue;
|
87
94
|
}
|
88
95
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
+
try
|
97
|
+
{
|
98
|
+
// a non-compliant v2 API returning 404 can cause this to throw
|
99
|
+
var existsInFeed = await feed.Exists(
|
100
|
+
packageIdentity,
|
101
|
+
includeUnlisted: false,
|
102
|
+
SourceCacheContext,
|
103
|
+
NullLogger.Instance,
|
104
|
+
cancellationToken);
|
105
|
+
if (!existsInFeed)
|
106
|
+
{
|
107
|
+
message.AppendLine($" package {packageIdentity} does not exist in {source.Name}");
|
108
|
+
continue;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
catch (FatalProtocolException)
|
96
112
|
{
|
97
|
-
|
113
|
+
// if anything goes wrong here, the package source obviously doesn't contain the requested package
|
98
114
|
continue;
|
99
115
|
}
|
100
116
|
|
@@ -66,15 +66,24 @@ internal static class VersionFinder
|
|
66
66
|
continue;
|
67
67
|
}
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
69
|
+
try
|
70
|
+
{
|
71
|
+
// a non-compliant v2 API returning 404 can cause this to throw
|
72
|
+
var existsInFeed = await feed.Exists(
|
73
|
+
packageId,
|
74
|
+
includePrerelease,
|
75
|
+
includeUnlisted: false,
|
76
|
+
nugetContext.SourceCacheContext,
|
77
|
+
NullLogger.Instance,
|
78
|
+
cancellationToken);
|
79
|
+
if (!existsInFeed)
|
80
|
+
{
|
81
|
+
continue;
|
82
|
+
}
|
83
|
+
}
|
84
|
+
catch (FatalProtocolException)
|
77
85
|
{
|
86
|
+
// if anything goes wrong here, the package source obviously doesn't contain the requested package
|
78
87
|
continue;
|
79
88
|
}
|
80
89
|
|
@@ -162,15 +171,23 @@ internal static class VersionFinder
|
|
162
171
|
continue;
|
163
172
|
}
|
164
173
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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)
|
172
189
|
{
|
173
|
-
|
190
|
+
// if anything goes wrong here, the package source obviously doesn't contain the requested package
|
174
191
|
}
|
175
192
|
}
|
176
193
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
using System.Collections.Immutable;
|
2
|
+
using System.Net;
|
2
3
|
using System.Text.Json;
|
3
4
|
using System.Text.Json.Serialization;
|
4
5
|
|
@@ -6,6 +7,7 @@ using Microsoft.Build.Construction;
|
|
6
7
|
using Microsoft.Build.Definition;
|
7
8
|
using Microsoft.Build.Evaluation;
|
8
9
|
|
10
|
+
using NuGetUpdater.Core.Analyze;
|
9
11
|
using NuGetUpdater.Core.Utilities;
|
10
12
|
|
11
13
|
namespace NuGetUpdater.Core.Discover;
|
@@ -47,43 +49,60 @@ public partial class DiscoveryWorker
|
|
47
49
|
DirectoryPackagesPropsDiscoveryResult? directoryPackagesPropsDiscovery = null;
|
48
50
|
|
49
51
|
ImmutableArray<ProjectDiscoveryResult> projectResults = [];
|
52
|
+
WorkspaceDiscoveryResult result;
|
50
53
|
|
51
|
-
|
54
|
+
try
|
52
55
|
{
|
53
|
-
|
56
|
+
if (Directory.Exists(workspacePath))
|
57
|
+
{
|
58
|
+
_logger.Log($"Discovering build files in workspace [{workspacePath}].");
|
54
59
|
|
55
|
-
|
56
|
-
|
60
|
+
dotNetToolsJsonDiscovery = DotNetToolsJsonDiscovery.Discover(repoRootPath, workspacePath, _logger);
|
61
|
+
globalJsonDiscovery = GlobalJsonDiscovery.Discover(repoRootPath, workspacePath, _logger);
|
57
62
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
63
|
+
if (globalJsonDiscovery is not null)
|
64
|
+
{
|
65
|
+
await TryRestoreMSBuildSdksAsync(repoRootPath, workspacePath, globalJsonDiscovery.Dependencies, _logger);
|
66
|
+
}
|
62
67
|
|
63
|
-
|
68
|
+
// this next line should throw or something
|
69
|
+
projectResults = await RunForDirectoryAsnyc(repoRootPath, workspacePath);
|
64
70
|
|
65
|
-
|
71
|
+
directoryPackagesPropsDiscovery = DirectoryPackagesPropsDiscovery.Discover(repoRootPath, workspacePath, projectResults, _logger);
|
66
72
|
|
67
|
-
|
73
|
+
if (directoryPackagesPropsDiscovery is not null)
|
74
|
+
{
|
75
|
+
projectResults = projectResults.Remove(projectResults.First(p => p.FilePath.Equals(directoryPackagesPropsDiscovery.FilePath, StringComparison.OrdinalIgnoreCase)));
|
76
|
+
}
|
77
|
+
}
|
78
|
+
else
|
68
79
|
{
|
69
|
-
|
80
|
+
_logger.Log($"Workspace path [{workspacePath}] does not exist.");
|
70
81
|
}
|
82
|
+
|
83
|
+
result = new WorkspaceDiscoveryResult
|
84
|
+
{
|
85
|
+
Path = initialWorkspacePath,
|
86
|
+
DotNetToolsJson = dotNetToolsJsonDiscovery,
|
87
|
+
GlobalJson = globalJsonDiscovery,
|
88
|
+
DirectoryPackagesProps = directoryPackagesPropsDiscovery,
|
89
|
+
Projects = projectResults.OrderBy(p => p.FilePath).ToImmutableArray(),
|
90
|
+
};
|
71
91
|
}
|
72
|
-
|
92
|
+
catch (HttpRequestException ex)
|
93
|
+
when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
|
73
94
|
{
|
74
|
-
|
95
|
+
// TODO: consolidate this error handling between AnalyzeWorker, DiscoveryWorker, and UpdateWorker
|
96
|
+
result = new WorkspaceDiscoveryResult
|
97
|
+
{
|
98
|
+
ErrorType = ErrorType.AuthenticationFailure,
|
99
|
+
ErrorDetails = "(" + string.Join("|", NuGetContext.GetPackageSourceUrls(workspacePath)) + ")",
|
100
|
+
Path = initialWorkspacePath,
|
101
|
+
Projects = [],
|
102
|
+
};
|
75
103
|
}
|
76
104
|
|
77
|
-
|
78
|
-
{
|
79
|
-
Path = initialWorkspacePath,
|
80
|
-
DotNetToolsJson = dotNetToolsJsonDiscovery,
|
81
|
-
GlobalJson = globalJsonDiscovery,
|
82
|
-
DirectoryPackagesProps = directoryPackagesPropsDiscovery,
|
83
|
-
Projects = projectResults.OrderBy(p => p.FilePath).ToImmutableArray(),
|
84
|
-
};
|
85
|
-
|
86
|
-
await WriteResults(repoRootPath, outputPath, result);
|
105
|
+
await WriteResultsAsync(repoRootPath, outputPath, result);
|
87
106
|
|
88
107
|
_logger.Log("Discovery complete.");
|
89
108
|
|
@@ -293,7 +312,7 @@ public partial class DiscoveryWorker
|
|
293
312
|
return [.. results.Values];
|
294
313
|
}
|
295
314
|
|
296
|
-
|
315
|
+
internal static async Task WriteResultsAsync(string repoRootPath, string outputPath, WorkspaceDiscoveryResult result)
|
297
316
|
{
|
298
317
|
var resultPath = Path.IsPathRooted(outputPath)
|
299
318
|
? outputPath
|
@@ -2,7 +2,7 @@ using System.Collections.Immutable;
|
|
2
2
|
|
3
3
|
namespace NuGetUpdater.Core.Discover;
|
4
4
|
|
5
|
-
public sealed record WorkspaceDiscoveryResult
|
5
|
+
public sealed record WorkspaceDiscoveryResult : NativeResult
|
6
6
|
{
|
7
7
|
public required string Path { get; init; }
|
8
8
|
public bool IsSuccess { get; init; } = true;
|
@@ -93,11 +93,11 @@ internal sealed class ProjectBuildFile : XmlBuildFile
|
|
93
93
|
{
|
94
94
|
var isUpdate = false;
|
95
95
|
|
96
|
-
var name = element.GetAttributeOrSubElementValue("Include", StringComparison.OrdinalIgnoreCase);
|
96
|
+
var name = element.GetAttributeOrSubElementValue("Include", StringComparison.OrdinalIgnoreCase)?.Trim();
|
97
97
|
if (name is null)
|
98
98
|
{
|
99
99
|
isUpdate = true;
|
100
|
-
name = element.GetAttributeOrSubElementValue("Update", StringComparison.OrdinalIgnoreCase);
|
100
|
+
name = element.GetAttributeOrSubElementValue("Update", StringComparison.OrdinalIgnoreCase)?.Trim();
|
101
101
|
}
|
102
102
|
|
103
103
|
if (name is null || name.StartsWith("@("))
|
@@ -1,3 +1,4 @@
|
|
1
|
+
using System.Diagnostics;
|
1
2
|
using System.Text;
|
2
3
|
using System.Xml.Linq;
|
3
4
|
using System.Xml.XPath;
|
@@ -102,9 +103,9 @@ internal static class PackagesConfigUpdater
|
|
102
103
|
Console.SetError(writer);
|
103
104
|
|
104
105
|
var currentDir = Environment.CurrentDirectory;
|
106
|
+
var existingSpawnedProcesses = GetLikelyNuGetSpawnedProcesses();
|
105
107
|
try
|
106
108
|
{
|
107
|
-
|
108
109
|
Environment.CurrentDirectory = projectDirectory;
|
109
110
|
var retryingAfterRestore = false;
|
110
111
|
|
@@ -144,6 +145,7 @@ internal static class PackagesConfigUpdater
|
|
144
145
|
goto doRestore;
|
145
146
|
}
|
146
147
|
|
148
|
+
MSBuildHelper.ThrowOnUnauthenticatedFeed(fullOutput);
|
147
149
|
throw new Exception(fullOutput);
|
148
150
|
}
|
149
151
|
}
|
@@ -157,9 +159,24 @@ internal static class PackagesConfigUpdater
|
|
157
159
|
Environment.CurrentDirectory = currentDir;
|
158
160
|
Console.SetOut(originalOut);
|
159
161
|
Console.SetError(originalError);
|
162
|
+
|
163
|
+
// NuGet.exe can spawn processes that hold on to the temporary directory, so we need to kill them
|
164
|
+
var currentSpawnedProcesses = GetLikelyNuGetSpawnedProcesses();
|
165
|
+
var deltaSpawnedProcesses = currentSpawnedProcesses.Except(existingSpawnedProcesses).ToArray();
|
166
|
+
foreach (var credProvider in deltaSpawnedProcesses)
|
167
|
+
{
|
168
|
+
logger.Log($"Ending spawned credential provider process");
|
169
|
+
credProvider.Kill();
|
170
|
+
}
|
160
171
|
}
|
161
172
|
}
|
162
173
|
|
174
|
+
private static Process[] GetLikelyNuGetSpawnedProcesses()
|
175
|
+
{
|
176
|
+
var processes = Process.GetProcesses().Where(p => p.ProcessName.StartsWith("CredentialProvider", StringComparison.OrdinalIgnoreCase) == true).ToArray();
|
177
|
+
return processes;
|
178
|
+
}
|
179
|
+
|
163
180
|
internal static string? GetPathToPackagesDirectory(ProjectBuildFile projectBuildFile, string dependencyName, string dependencyVersion, string packagesConfigPath)
|
164
181
|
{
|
165
182
|
// the packages directory can be found from the hint path of the matching dependency, e.g., when given "Newtonsoft.Json", "7.0.1", and a project like this:
|
@@ -228,6 +228,7 @@ internal static class SdkPackageUpdater
|
|
228
228
|
|
229
229
|
// see https://learn.microsoft.com/nuget/consume-packages/install-use-packages-dotnet-cli
|
230
230
|
var (exitCode, stdout, stderr) = await ProcessEx.RunAsync("dotnet", $"add {projectPath} package {dependencyName} --version {newDependencyVersion}", workingDirectory: Path.GetDirectoryName(projectPath));
|
231
|
+
MSBuildHelper.ThrowOnUnauthenticatedFeed(stdout);
|
231
232
|
if (exitCode != 0)
|
232
233
|
{
|
233
234
|
logger.Log($" Transitive dependency [{dependencyName}/{newDependencyVersion}] was not added.\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}");
|
@@ -594,7 +595,7 @@ internal static class SdkPackageUpdater
|
|
594
595
|
string packageName)
|
595
596
|
=> buildFile.PackageItemNodes.Where(e =>
|
596
597
|
string.Equals(
|
597
|
-
e.GetAttributeOrSubElementValue("Include", StringComparison.OrdinalIgnoreCase) ?? e.GetAttributeOrSubElementValue("Update", StringComparison.OrdinalIgnoreCase),
|
598
|
+
(e.GetAttributeOrSubElementValue("Include", StringComparison.OrdinalIgnoreCase) ?? e.GetAttributeOrSubElementValue("Update", StringComparison.OrdinalIgnoreCase))?.Trim(),
|
598
599
|
packageName,
|
599
600
|
StringComparison.OrdinalIgnoreCase) &&
|
600
601
|
(e.GetAttributeOrSubElementValue("Version", StringComparison.OrdinalIgnoreCase) ?? e.GetAttributeOrSubElementValue("VersionOverride", StringComparison.OrdinalIgnoreCase)) is not null);
|