dependabot-nuget 0.242.1 → 0.244.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/.editorconfig +37 -28
- data/helpers/lib/NuGetUpdater/.gitignore +1 -0
- data/helpers/lib/NuGetUpdater/NuGetProjects/NuGet.CommandLine/AssemblyMetadataExtractor.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Program.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +178 -176
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/JsonBuildFile.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/PackagesConfigBuildFile.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/ProjectBuildFile.cs +5 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/CompatabilityChecker.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/FrameworkCompatibilityService.cs +10 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/SupportedFrameworks.cs +16 -12
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +18 -17
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectResolver.cs +7 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/DotNetToolsJsonUpdater.cs +13 -20
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/GlobalJsonUpdater.cs +9 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +32 -16
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +44 -24
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +32 -13
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/WebApplicationTargetsConditionPatcher.cs +47 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/XmlFilePreAndPostProcessor.cs +55 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/JsonHelper.cs +12 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +78 -54
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +16 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProcessExtensions.cs +6 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/XmlExtensions.cs +11 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Files/ProjectBuildFileTests.cs +18 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/FrameworkChecker/CompatibilityCheckerFacts.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/FrameworkChecker/FrameworkCompatibilityServiceFacts.cs +7 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/FrameworkChecker/SupportedFrameworkFacts.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackagesConfigUpdaterTests.cs +9 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorker.DirsProj.cs +228 -75
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +22 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DotNetTools.cs +140 -104
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs +25 -25
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +8 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +198 -22
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +401 -399
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/JsonHelperTests.cs +17 -15
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +114 -45
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/SdkPackageUpdaterTests.cs +103 -87
- data/lib/dependabot/nuget/file_parser/project_file_parser.rb +109 -39
- data/lib/dependabot/nuget/file_parser.rb +23 -4
- data/lib/dependabot/nuget/file_updater.rb +44 -7
- data/lib/dependabot/nuget/native_helpers.rb +27 -8
- data/lib/dependabot/nuget/nuget_client.rb +66 -23
- data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +7 -3
- data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +63 -59
- data/lib/dependabot/nuget/update_checker/dependency_finder.rb +7 -5
- data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +1 -1
- data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +22 -17
- data/lib/dependabot/nuget/update_checker/property_updater.rb +7 -4
- data/lib/dependabot/nuget/update_checker/repository_finder.rb +292 -270
- data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +11 -13
- data/lib/dependabot/nuget/update_checker/tfm_finder.rb +82 -82
- data/lib/dependabot/nuget/update_checker/version_finder.rb +9 -5
- data/lib/dependabot/nuget/update_checker.rb +6 -3
- data/lib/dependabot/nuget/version.rb +18 -7
- data/lib/dependabot/nuget.rb +0 -2
- metadata +7 -5
@@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
|
5
5
|
|
6
6
|
namespace NuGetUpdater.Core;
|
7
7
|
|
8
|
-
public
|
8
|
+
public class UpdaterWorker
|
9
9
|
{
|
10
10
|
private readonly Logger _logger;
|
11
11
|
private readonly HashSet<string> _processedGlobalJsonPaths = new(StringComparer.OrdinalIgnoreCase);
|
@@ -15,33 +15,33 @@ public partial class UpdaterWorker
|
|
15
15
|
_logger = logger;
|
16
16
|
}
|
17
17
|
|
18
|
-
public async Task RunAsync(string repoRootPath, string
|
18
|
+
public async Task RunAsync(string repoRootPath, string workspacePath, string dependencyName, string previousDependencyVersion, string newDependencyVersion, bool isTransitive)
|
19
19
|
{
|
20
20
|
MSBuildHelper.RegisterMSBuild();
|
21
21
|
|
22
|
-
if (!Path.IsPathRooted(
|
22
|
+
if (!Path.IsPathRooted(workspacePath) || !File.Exists(workspacePath))
|
23
23
|
{
|
24
|
-
|
24
|
+
workspacePath = Path.GetFullPath(Path.Join(repoRootPath, workspacePath));
|
25
25
|
}
|
26
26
|
|
27
27
|
if (!isTransitive)
|
28
28
|
{
|
29
|
-
await DotNetToolsJsonUpdater.UpdateDependencyAsync(repoRootPath, dependencyName, previousDependencyVersion, newDependencyVersion, _logger);
|
29
|
+
await DotNetToolsJsonUpdater.UpdateDependencyAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, _logger);
|
30
30
|
}
|
31
31
|
|
32
|
-
var extension = Path.GetExtension(
|
32
|
+
var extension = Path.GetExtension(workspacePath).ToLowerInvariant();
|
33
33
|
switch (extension)
|
34
34
|
{
|
35
35
|
case ".sln":
|
36
|
-
await RunForSolutionAsync(repoRootPath,
|
36
|
+
await RunForSolutionAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive);
|
37
37
|
break;
|
38
38
|
case ".proj":
|
39
|
-
await RunForProjFileAsync(repoRootPath,
|
39
|
+
await RunForProjFileAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive);
|
40
40
|
break;
|
41
41
|
case ".csproj":
|
42
42
|
case ".fsproj":
|
43
43
|
case ".vbproj":
|
44
|
-
await RunForProjectAsync(repoRootPath,
|
44
|
+
await RunForProjectAsync(repoRootPath, workspacePath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive);
|
45
45
|
break;
|
46
46
|
default:
|
47
47
|
_logger.Log($"File extension [{extension}] is not supported.");
|
@@ -51,7 +51,13 @@ public partial class UpdaterWorker
|
|
51
51
|
_processedGlobalJsonPaths.Clear();
|
52
52
|
}
|
53
53
|
|
54
|
-
private async Task RunForSolutionAsync(
|
54
|
+
private async Task RunForSolutionAsync(
|
55
|
+
string repoRootPath,
|
56
|
+
string solutionPath,
|
57
|
+
string dependencyName,
|
58
|
+
string previousDependencyVersion,
|
59
|
+
string newDependencyVersion,
|
60
|
+
bool isTransitive)
|
55
61
|
{
|
56
62
|
_logger.Log($"Running for solution [{Path.GetRelativePath(repoRootPath, solutionPath)}]");
|
57
63
|
var projectPaths = MSBuildHelper.GetProjectPathsFromSolution(solutionPath);
|
@@ -61,7 +67,13 @@ public partial class UpdaterWorker
|
|
61
67
|
}
|
62
68
|
}
|
63
69
|
|
64
|
-
private async Task RunForProjFileAsync(
|
70
|
+
private async Task RunForProjFileAsync(
|
71
|
+
string repoRootPath,
|
72
|
+
string projFilePath,
|
73
|
+
string dependencyName,
|
74
|
+
string previousDependencyVersion,
|
75
|
+
string newDependencyVersion,
|
76
|
+
bool isTransitive)
|
65
77
|
{
|
66
78
|
_logger.Log($"Running for proj file [{Path.GetRelativePath(repoRootPath, projFilePath)}]");
|
67
79
|
if (!File.Exists(projFilePath))
|
@@ -69,6 +81,7 @@ public partial class UpdaterWorker
|
|
69
81
|
_logger.Log($"File [{projFilePath}] does not exist.");
|
70
82
|
return;
|
71
83
|
}
|
84
|
+
|
72
85
|
var projectFilePaths = MSBuildHelper.GetProjectPathsFromProject(projFilePath);
|
73
86
|
foreach (var projectFullPath in projectFilePaths)
|
74
87
|
{
|
@@ -80,12 +93,18 @@ public partial class UpdaterWorker
|
|
80
93
|
}
|
81
94
|
}
|
82
95
|
|
83
|
-
private async Task RunForProjectAsync(
|
96
|
+
private async Task RunForProjectAsync(
|
97
|
+
string repoRootPath,
|
98
|
+
string projectPath,
|
99
|
+
string dependencyName,
|
100
|
+
string previousDependencyVersion,
|
101
|
+
string newDependencyVersion,
|
102
|
+
bool isTransitive)
|
84
103
|
{
|
85
104
|
_logger.Log($"Running for project [{projectPath}]");
|
86
105
|
|
87
106
|
if (!isTransitive
|
88
|
-
&& MSBuildHelper.GetGlobalJsonPath(repoRootPath, projectPath) is
|
107
|
+
&& MSBuildHelper.GetGlobalJsonPath(repoRootPath, projectPath) is { } globalJsonPath
|
89
108
|
&& !_processedGlobalJsonPaths.Contains(globalJsonPath))
|
90
109
|
{
|
91
110
|
_processedGlobalJsonPaths.Add(globalJsonPath);
|
data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/WebApplicationTargetsConditionPatcher.cs
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
using System;
|
2
|
+
using System.IO;
|
3
|
+
using System.Linq;
|
4
|
+
|
5
|
+
using Microsoft.Language.Xml;
|
6
|
+
|
7
|
+
namespace NuGetUpdater.Core.Updater
|
8
|
+
{
|
9
|
+
internal class WebApplicationTargetsConditionPatcher : IDisposable
|
10
|
+
{
|
11
|
+
private string? _capturedCondition;
|
12
|
+
private readonly XmlFilePreAndPostProcessor _processor;
|
13
|
+
|
14
|
+
public WebApplicationTargetsConditionPatcher(string projectFilePath)
|
15
|
+
{
|
16
|
+
_processor = new XmlFilePreAndPostProcessor(
|
17
|
+
getContent: () => File.ReadAllText(projectFilePath),
|
18
|
+
setContent: s => File.WriteAllText(projectFilePath, s),
|
19
|
+
nodeFinder: doc => doc.Descendants()
|
20
|
+
.FirstOrDefault(e => e.Name == "Import" && e.GetAttributeValue("Project") == @"$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets")
|
21
|
+
as XmlNodeSyntax,
|
22
|
+
preProcessor: n =>
|
23
|
+
{
|
24
|
+
var element = (IXmlElementSyntax)n;
|
25
|
+
_capturedCondition = element.GetAttributeValue("Condition");
|
26
|
+
return (XmlNodeSyntax)element.RemoveAttributeByName("Condition").WithAttribute("Condition", "false");
|
27
|
+
},
|
28
|
+
postProcessor: n =>
|
29
|
+
{
|
30
|
+
var element = (IXmlElementSyntax)n;
|
31
|
+
var newElement = element.RemoveAttributeByName("Condition");
|
32
|
+
if (_capturedCondition is not null)
|
33
|
+
{
|
34
|
+
newElement = newElement.WithAttribute("Condition", _capturedCondition);
|
35
|
+
}
|
36
|
+
|
37
|
+
return (XmlNodeSyntax)newElement;
|
38
|
+
}
|
39
|
+
);
|
40
|
+
}
|
41
|
+
|
42
|
+
public void Dispose()
|
43
|
+
{
|
44
|
+
_processor.Dispose();
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
using System;
|
2
|
+
|
3
|
+
using Microsoft.Language.Xml;
|
4
|
+
|
5
|
+
namespace NuGetUpdater.Core.Updater
|
6
|
+
{
|
7
|
+
internal class XmlFilePreAndPostProcessor : IDisposable
|
8
|
+
{
|
9
|
+
public Func<string> GetContent { get; }
|
10
|
+
public Action<string> SetContent { get; }
|
11
|
+
public Func<XmlDocumentSyntax, XmlNodeSyntax?> NodeFinder { get; }
|
12
|
+
public Func<XmlNodeSyntax, XmlNodeSyntax> PreProcessor { get; }
|
13
|
+
public Func<XmlNodeSyntax, XmlNodeSyntax> PostProcessor { get; }
|
14
|
+
|
15
|
+
public XmlFilePreAndPostProcessor(Func<string> getContent, Action<string> setContent, Func<XmlDocumentSyntax, XmlNodeSyntax?> nodeFinder, Func<XmlNodeSyntax, XmlNodeSyntax> preProcessor, Func<XmlNodeSyntax, XmlNodeSyntax> postProcessor)
|
16
|
+
{
|
17
|
+
GetContent = getContent;
|
18
|
+
SetContent = setContent;
|
19
|
+
NodeFinder = nodeFinder;
|
20
|
+
PreProcessor = preProcessor;
|
21
|
+
PostProcessor = postProcessor;
|
22
|
+
PreProcess();
|
23
|
+
}
|
24
|
+
|
25
|
+
public void Dispose()
|
26
|
+
{
|
27
|
+
PostProcess();
|
28
|
+
}
|
29
|
+
|
30
|
+
private void PreProcess() => RunProcessor(PreProcessor);
|
31
|
+
|
32
|
+
private void PostProcess() => RunProcessor(PostProcessor);
|
33
|
+
|
34
|
+
private void RunProcessor(Func<XmlNodeSyntax, XmlNodeSyntax> processor)
|
35
|
+
{
|
36
|
+
var content = GetContent();
|
37
|
+
var xml = Parser.ParseText(content);
|
38
|
+
if (xml is null)
|
39
|
+
{
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
|
43
|
+
var node = NodeFinder(xml);
|
44
|
+
if (node is null)
|
45
|
+
{
|
46
|
+
return;
|
47
|
+
}
|
48
|
+
|
49
|
+
var replacementElement = processor(node);
|
50
|
+
var replacementXml = xml.ReplaceNode(node, replacementElement);
|
51
|
+
var replacementString = replacementXml.ToFullString();
|
52
|
+
SetContent(replacementString);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
@@ -4,6 +4,7 @@ using System.IO;
|
|
4
4
|
using System.Linq;
|
5
5
|
using System.Runtime.InteropServices;
|
6
6
|
using System.Text;
|
7
|
+
using System.Text.Encodings.Web;
|
7
8
|
using System.Text.Json;
|
8
9
|
using System.Text.Json.Nodes;
|
9
10
|
|
@@ -11,7 +12,7 @@ namespace NuGetUpdater.Core.Utilities
|
|
11
12
|
{
|
12
13
|
internal static class JsonHelper
|
13
14
|
{
|
14
|
-
public static JsonDocumentOptions DocumentOptions { get; } = new JsonDocumentOptions
|
15
|
+
public static JsonDocumentOptions DocumentOptions { get; } = new JsonDocumentOptions
|
15
16
|
{
|
16
17
|
CommentHandling = JsonCommentHandling.Skip,
|
17
18
|
};
|
@@ -24,16 +25,16 @@ namespace NuGetUpdater.Core.Utilities
|
|
24
25
|
|
25
26
|
public static string UpdateJsonProperty(string json, string[] propertyPath, string newValue, StringComparison comparisonType = StringComparison.Ordinal)
|
26
27
|
{
|
27
|
-
var readerOptions = new JsonReaderOptions
|
28
|
+
var readerOptions = new JsonReaderOptions
|
28
29
|
{
|
29
30
|
CommentHandling = JsonCommentHandling.Allow,
|
30
31
|
};
|
31
32
|
var bytes = Encoding.UTF8.GetBytes(json);
|
32
33
|
var reader = new Utf8JsonReader(bytes, readerOptions);
|
33
34
|
using var ms = new MemoryStream();
|
34
|
-
var writerOptions = new JsonWriterOptions
|
35
|
+
var writerOptions = new JsonWriterOptions
|
35
36
|
{
|
36
|
-
Encoder =
|
37
|
+
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
37
38
|
Indented = true,
|
38
39
|
};
|
39
40
|
var writer = new Utf8JsonWriter(ms, writerOptions);
|
@@ -70,6 +71,7 @@ namespace NuGetUpdater.Core.Utilities
|
|
70
71
|
// let the default block comment writer handle it
|
71
72
|
writer.WriteCommentValue(reader.GetComment());
|
72
73
|
}
|
74
|
+
|
73
75
|
break;
|
74
76
|
case JsonTokenType.EndArray:
|
75
77
|
writer.WriteEndArray();
|
@@ -126,7 +128,7 @@ namespace NuGetUpdater.Core.Utilities
|
|
126
128
|
{
|
127
129
|
currentPath.RemoveAt(currentPath.Count - 1);
|
128
130
|
}
|
129
|
-
|
131
|
+
|
130
132
|
currentPath[pathDepth] = pathValue;
|
131
133
|
if (IsPathMatch(currentPath, propertyPath, comparisonType))
|
132
134
|
{
|
@@ -187,18 +189,19 @@ namespace NuGetUpdater.Core.Utilities
|
|
187
189
|
// quit at newline, modulo some special cases
|
188
190
|
if (c == '\n')
|
189
191
|
{
|
190
|
-
// check for
|
192
|
+
// check for preceding CR
|
191
193
|
if (IsPreceedingCharacterEqual(originalJson, prefixStart, '\r'))
|
192
194
|
{
|
193
195
|
prefixStart--;
|
194
196
|
}
|
195
197
|
}
|
196
198
|
|
197
|
-
// check for
|
199
|
+
// check for preceding comma
|
198
200
|
if (IsPreceedingCharacterEqual(originalJson, prefixStart, ','))
|
199
201
|
{
|
200
202
|
prefixStart--;
|
201
203
|
}
|
204
|
+
|
202
205
|
goto done;
|
203
206
|
default:
|
204
207
|
// found regular character; move forward one and quit
|
@@ -215,8 +218,8 @@ namespace NuGetUpdater.Core.Utilities
|
|
215
218
|
private static bool IsPreceedingCharacterEqual(string originalText, int currentIndex, char expectedCharacter)
|
216
219
|
{
|
217
220
|
return currentIndex > 0
|
218
|
-
|
219
|
-
|
221
|
+
&& currentIndex < originalText.Length
|
222
|
+
&& originalText[currentIndex - 1] == expectedCharacter;
|
220
223
|
}
|
221
224
|
}
|
222
225
|
}
|
@@ -15,6 +15,7 @@ using Microsoft.Build.Definition;
|
|
15
15
|
using Microsoft.Build.Evaluation;
|
16
16
|
using Microsoft.Build.Exceptions;
|
17
17
|
using Microsoft.Build.Locator;
|
18
|
+
using Microsoft.Extensions.FileSystemGlobbing;
|
18
19
|
|
19
20
|
using NuGetUpdater.Core.Utilities;
|
20
21
|
|
@@ -101,6 +102,7 @@ internal static partial class MSBuildHelper
|
|
101
102
|
{
|
102
103
|
var projectStack = new Stack<(string folderPath, ProjectRootElement)>();
|
103
104
|
var projectRootElement = ProjectRootElement.Open(projFilePath);
|
105
|
+
var processedProjectFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
104
106
|
|
105
107
|
projectStack.Push((Path.GetFullPath(Path.GetDirectoryName(projFilePath)!), projectRootElement));
|
106
108
|
|
@@ -114,27 +116,42 @@ internal static partial class MSBuildHelper
|
|
114
116
|
continue;
|
115
117
|
}
|
116
118
|
|
117
|
-
|
119
|
+
Matcher matcher = new Matcher();
|
120
|
+
matcher.AddInclude(PathHelper.NormalizePathToUnix(projectReference.Include));
|
118
121
|
|
119
|
-
|
120
|
-
|
122
|
+
string searchDirectory = PathHelper.NormalizePathToUnix(folderPath);
|
123
|
+
|
124
|
+
IEnumerable<string> files = matcher.GetResultsInFullPath(searchDirectory);
|
125
|
+
|
126
|
+
foreach (var file in files)
|
121
127
|
{
|
122
|
-
//
|
123
|
-
if (
|
128
|
+
// Check that we haven't already processed this file
|
129
|
+
if (processedProjectFiles.Contains(file))
|
124
130
|
{
|
125
|
-
|
126
|
-
|
131
|
+
continue;
|
132
|
+
}
|
133
|
+
|
134
|
+
var projectExtension = Path.GetExtension(file).ToLowerInvariant();
|
135
|
+
if (projectExtension == ".proj")
|
136
|
+
{
|
137
|
+
// If there is some MSBuild logic that needs to run to fully resolve the path skip the project
|
138
|
+
if (File.Exists(file))
|
139
|
+
{
|
140
|
+
var additionalProjectRootElement = ProjectRootElement.Open(file);
|
141
|
+
projectStack.Push((Path.GetFullPath(Path.GetDirectoryName(file)!), additionalProjectRootElement));
|
142
|
+
processedProjectFiles.Add(file);
|
143
|
+
}
|
144
|
+
}
|
145
|
+
else if (projectExtension == ".csproj" || projectExtension == ".vbproj" || projectExtension == ".fsproj")
|
146
|
+
{
|
147
|
+
yield return file;
|
127
148
|
}
|
128
|
-
}
|
129
|
-
else if (projectExtension == ".csproj" || projectExtension == ".vbproj" || projectExtension == ".fsproj")
|
130
|
-
{
|
131
|
-
yield return projectPath;
|
132
149
|
}
|
133
150
|
}
|
134
151
|
}
|
135
152
|
}
|
136
153
|
|
137
|
-
public static IEnumerable<Dependency>
|
154
|
+
public static IEnumerable<Dependency> GetTopLevelPackageDependencyInfos(ImmutableArray<ProjectBuildFile> buildFiles)
|
138
155
|
{
|
139
156
|
Dictionary<string, (string, bool)> packageInfo = new(StringComparer.OrdinalIgnoreCase);
|
140
157
|
Dictionary<string, string> packageVersionInfo = new(StringComparer.OrdinalIgnoreCase);
|
@@ -145,11 +162,11 @@ internal static partial class MSBuildHelper
|
|
145
162
|
var projectRoot = CreateProjectRootElement(buildFile);
|
146
163
|
|
147
164
|
foreach (var packageItem in projectRoot.Items
|
148
|
-
|
165
|
+
.Where(i => (i.ItemType == "PackageReference" || i.ItemType == "GlobalPackageReference")))
|
149
166
|
{
|
150
167
|
var versionSpecification = packageItem.Metadata.FirstOrDefault(m => m.Name.Equals("Version", StringComparison.OrdinalIgnoreCase))?.Value
|
151
|
-
|
152
|
-
|
168
|
+
?? packageItem.Metadata.FirstOrDefault(m => m.Name.Equals("VersionOverride", StringComparison.OrdinalIgnoreCase))?.Value
|
169
|
+
?? string.Empty;
|
153
170
|
foreach (var attributeValue in new[] { packageItem.Include, packageItem.Update })
|
154
171
|
{
|
155
172
|
if (!string.IsNullOrWhiteSpace(attributeValue))
|
@@ -175,10 +192,10 @@ internal static partial class MSBuildHelper
|
|
175
192
|
}
|
176
193
|
|
177
194
|
foreach (var packageItem in projectRoot.Items
|
178
|
-
|
195
|
+
.Where(i => i.ItemType == "PackageVersion" && !string.IsNullOrEmpty(i.Include)))
|
179
196
|
{
|
180
197
|
packageVersionInfo[packageItem.Include] = packageItem.Metadata.FirstOrDefault(m => m.Name.Equals("Version", StringComparison.OrdinalIgnoreCase))?.Value
|
181
|
-
|
198
|
+
?? string.Empty;
|
182
199
|
}
|
183
200
|
|
184
201
|
foreach (var property in projectRoot.Properties)
|
@@ -187,7 +204,8 @@ internal static partial class MSBuildHelper
|
|
187
204
|
// going to be used, and even then we might not be able to update it. As a best guess, we'll simply
|
188
205
|
// skip any property that has a condition _or_ where the condition is checking for an empty string.
|
189
206
|
var hasEmptyCondition = string.IsNullOrEmpty(property.Condition);
|
190
|
-
var conditionIsCheckingForEmptyString = string.Equals(property.Condition, $"$({property.Name}) == ''", StringComparison.OrdinalIgnoreCase)
|
207
|
+
var conditionIsCheckingForEmptyString = string.Equals(property.Condition, $"$({property.Name}) == ''", StringComparison.OrdinalIgnoreCase) ||
|
208
|
+
string.Equals(property.Condition, $"'$({property.Name})' == ''", StringComparison.OrdinalIgnoreCase);
|
191
209
|
if (hasEmptyCondition || conditionIsCheckingForEmptyString)
|
192
210
|
{
|
193
211
|
propertyInfo[property.Name] = property.Value;
|
@@ -285,7 +303,12 @@ internal static partial class MSBuildHelper
|
|
285
303
|
return projectRoot;
|
286
304
|
}
|
287
305
|
|
288
|
-
private static async Task<string> CreateTempProjectAsync(
|
306
|
+
private static async Task<string> CreateTempProjectAsync(
|
307
|
+
DirectoryInfo tempDir,
|
308
|
+
string repoRoot,
|
309
|
+
string projectPath,
|
310
|
+
string targetFramework,
|
311
|
+
IReadOnlyCollection<Dependency> packages)
|
289
312
|
{
|
290
313
|
var projectDirectory = Path.GetDirectoryName(projectPath);
|
291
314
|
projectDirectory ??= repoRoot;
|
@@ -299,39 +322,40 @@ internal static partial class MSBuildHelper
|
|
299
322
|
var packageReferences = string.Join(
|
300
323
|
Environment.NewLine,
|
301
324
|
packages
|
302
|
-
|
325
|
+
// empty `Version` attributes will cause the temporary project to not build
|
326
|
+
.Where(p => !string.IsNullOrWhiteSpace(p.Version))
|
303
327
|
// If all PackageReferences for a package are update-only mark it as such, otherwise it can cause package incoherence errors which do not exist in the repo.
|
304
328
|
.Select(static p => $"<PackageReference {(p.IsUpdate ? "Update" : "Include")}=\"{p.Name}\" Version=\"[{p.Version}]\" />"));
|
305
329
|
|
306
330
|
var projectContents = $"""
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
331
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
332
|
+
<PropertyGroup>
|
333
|
+
<TargetFramework>{targetFramework}</TargetFramework>
|
334
|
+
<GenerateDependencyFile>true</GenerateDependencyFile>
|
335
|
+
<RunAnalyzers>false</RunAnalyzers>
|
336
|
+
</PropertyGroup>
|
337
|
+
<ItemGroup>
|
338
|
+
{packageReferences}
|
339
|
+
</ItemGroup>
|
340
|
+
<Target Name="_CollectDependencies" DependsOnTargets="GenerateBuildDependencyFile">
|
341
|
+
<ItemGroup>
|
342
|
+
<_NuGetPackageData Include="@(NativeCopyLocalItems)" />
|
343
|
+
<_NuGetPackageData Include="@(ResourceCopyLocalItems)" />
|
344
|
+
<_NuGetPackageData Include="@(RuntimeCopyLocalItems)" />
|
345
|
+
<_NuGetPackageData Include="@(ResolvedAnalyzers)" />
|
346
|
+
<_NuGetPackageData Include="@(_PackageDependenciesDesignTime)">
|
347
|
+
<NuGetPackageId>%(_PackageDependenciesDesignTime.Name)</NuGetPackageId>
|
348
|
+
<NuGetPackageVersion>%(_PackageDependenciesDesignTime.Version)</NuGetPackageVersion>
|
349
|
+
</_NuGetPackageData>
|
350
|
+
</ItemGroup>
|
351
|
+
</Target>
|
352
|
+
<Target Name="_ReportDependencies" DependsOnTargets="_CollectDependencies">
|
353
|
+
<Message Text="NuGetData::Package=%(_NuGetPackageData.NuGetPackageId), Version=%(_NuGetPackageData.NuGetPackageVersion)"
|
354
|
+
Condition="'%(_NuGetPackageData.NuGetPackageId)' != '' AND '%(_NuGetPackageData.NuGetPackageVersion)' != ''"
|
355
|
+
Importance="High" />
|
356
|
+
</Target>
|
357
|
+
</Project>
|
358
|
+
""";
|
335
359
|
var tempProjectPath = Path.Combine(tempDir.FullName, "Project.csproj");
|
336
360
|
await File.WriteAllTextAsync(tempProjectPath, projectContents);
|
337
361
|
|
@@ -344,7 +368,7 @@ internal static partial class MSBuildHelper
|
|
344
368
|
}
|
345
369
|
|
346
370
|
internal static async Task<Dependency[]> GetAllPackageDependenciesAsync(
|
347
|
-
string repoRoot, string projectPath, string targetFramework, Dependency
|
371
|
+
string repoRoot, string projectPath, string targetFramework, IReadOnlyCollection<Dependency> packages, Logger? logger = null)
|
348
372
|
{
|
349
373
|
var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-resolution_");
|
350
374
|
try
|
@@ -368,7 +392,7 @@ internal static partial class MSBuildHelper
|
|
368
392
|
else
|
369
393
|
{
|
370
394
|
logger?.Log($"dotnet build in {nameof(GetAllPackageDependenciesAsync)} failed. STDOUT: {stdout} STDERR: {stderr}");
|
371
|
-
return
|
395
|
+
return [];
|
372
396
|
}
|
373
397
|
}
|
374
398
|
finally
|
@@ -390,7 +414,7 @@ internal static partial class MSBuildHelper
|
|
390
414
|
|
391
415
|
internal static async Task<ImmutableArray<ProjectBuildFile>> LoadBuildFiles(string repoRootPath, string projectPath)
|
392
416
|
{
|
393
|
-
var buildFileList = new List<string>
|
417
|
+
var buildFileList = new List<string>
|
394
418
|
{
|
395
419
|
projectPath.NormalizePathToUnix() // always include the starting project
|
396
420
|
};
|
@@ -409,12 +433,12 @@ internal static partial class MSBuildHelper
|
|
409
433
|
// create a safe version with only certain top-level keys
|
410
434
|
var globalJsonContent = await File.ReadAllTextAsync(safeGlobalJsonName);
|
411
435
|
var json = JsonHelper.ParseNode(globalJsonContent);
|
412
|
-
var sdks = json["msbuild-sdks"];
|
436
|
+
var sdks = json?["msbuild-sdks"];
|
413
437
|
if (sdks is not null)
|
414
438
|
{
|
415
439
|
var newObject = new Dictionary<string, object>()
|
416
440
|
{
|
417
|
-
|
441
|
+
["msbuild-sdks"] = sdks,
|
418
442
|
};
|
419
443
|
var newContent = JsonSerializer.Serialize(newObject);
|
420
444
|
await File.WriteAllTextAsync(globalJsonPath, newContent);
|
@@ -426,7 +450,7 @@ internal static partial class MSBuildHelper
|
|
426
450
|
// load the project even if it imports a file that doesn't exist (e.g. a file that's generated at restore
|
427
451
|
// or build time).
|
428
452
|
using var projectCollection = new ProjectCollection(); // do this in a one-off instance and don't pollute the global collection
|
429
|
-
var project = Project.FromFile(projectPath, new ProjectOptions
|
453
|
+
var project = Project.FromFile(projectPath, new ProjectOptions
|
430
454
|
{
|
431
455
|
LoadSettings = ProjectLoadSettings.IgnoreMissingImports,
|
432
456
|
ProjectCollection = projectCollection,
|
@@ -10,6 +10,7 @@ internal static class PathHelper
|
|
10
10
|
{
|
11
11
|
MatchCasing = MatchCasing.CaseInsensitive,
|
12
12
|
};
|
13
|
+
|
13
14
|
private static readonly EnumerationOptions _caseSensitiveEnumerationOptions = new()
|
14
15
|
{
|
15
16
|
MatchCasing = MatchCasing.CaseSensitive,
|
@@ -39,6 +40,11 @@ internal static class PathHelper
|
|
39
40
|
/// <returns>The path of the found file or null.</returns>
|
40
41
|
public static string? GetFileInDirectoryOrParent(string initialPath, string rootPath, string fileName, bool caseSensitive = true)
|
41
42
|
{
|
43
|
+
if (File.Exists(initialPath))
|
44
|
+
{
|
45
|
+
initialPath = Path.GetDirectoryName(initialPath)!;
|
46
|
+
}
|
47
|
+
|
42
48
|
var candidatePaths = new List<string>();
|
43
49
|
var rootDirectory = new DirectoryInfo(rootPath);
|
44
50
|
var candidateDirectory = new DirectoryInfo(initialPath);
|
@@ -56,11 +62,18 @@ internal static class PathHelper
|
|
56
62
|
|
57
63
|
foreach (var candidatePath in candidatePaths)
|
58
64
|
{
|
59
|
-
|
65
|
+
try
|
66
|
+
{
|
67
|
+
var files = Directory.EnumerateFiles(candidatePath, fileName, caseSensitive ? _caseSensitiveEnumerationOptions : _caseInsensitiveEnumerationOptions);
|
60
68
|
|
61
|
-
|
69
|
+
if (files.Any())
|
70
|
+
{
|
71
|
+
return files.First();
|
72
|
+
}
|
73
|
+
}
|
74
|
+
catch (DirectoryNotFoundException)
|
62
75
|
{
|
63
|
-
|
76
|
+
// When searching for a file in a directory that doesn't exist, Directory.EnumerateFiles throws a DirectoryNotFoundException.
|
64
77
|
}
|
65
78
|
}
|
66
79
|
|
@@ -45,14 +45,14 @@ public static class ProcessEx
|
|
45
45
|
// than enter right back into the Process type and start a wait which isn't guaranteed to be safe.
|
46
46
|
Task.Run(() =>
|
47
47
|
{
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
redirectInitiated.Wait();
|
49
|
+
redirectInitiated.Dispose();
|
50
|
+
redirectInitiated = null;
|
51
51
|
|
52
|
-
|
52
|
+
process.WaitForExit();
|
53
53
|
|
54
|
-
|
55
|
-
|
54
|
+
tcs.TrySetResult((process.ExitCode, stdout.ToString(), stderr.ToString()));
|
55
|
+
process.Dispose();
|
56
56
|
});
|
57
57
|
};
|
58
58
|
|
@@ -30,6 +30,17 @@ public static class XmlExtensions
|
|
30
30
|
return element.Attributes.FirstOrDefault(a => a.Name.Equals(name, comparisonType));
|
31
31
|
}
|
32
32
|
|
33
|
+
public static IXmlElementSyntax RemoveAttributeByName(this IXmlElementSyntax element, string attributeName, StringComparison comparisonType = StringComparison.Ordinal)
|
34
|
+
{
|
35
|
+
var attribute = element.GetAttribute(attributeName, comparisonType);
|
36
|
+
if (attribute is null)
|
37
|
+
{
|
38
|
+
return element;
|
39
|
+
}
|
40
|
+
|
41
|
+
return element.RemoveAttribute(attribute);
|
42
|
+
}
|
43
|
+
|
33
44
|
public static string GetAttributeValue(this IXmlElementSyntax element, string name, StringComparison comparisonType)
|
34
45
|
{
|
35
46
|
return element.Attributes.First(a => a.Name.Equals(name, comparisonType)).Value;
|