dependabot-nuget 0.323.0 → 0.325.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/NuGetUpdater.Cli/Program.cs +0 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +1 -31
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyFinder.cs +0 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyInfo.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +64 -10
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Clone/CloneWorker.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencySolver/MSBuildDependencySolver.cs +10 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscovery.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +31 -41
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +3 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Cooldown.cs +83 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ModifiedFilesTracker.cs +9 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestBodyGenerator/DetailedPullRequestBodyGenerator.cs +6 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +8 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/GroupUpdateAllVersionsHandler.cs +79 -67
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandler.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshSecurityUpdatePullRequestHandler.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshVersionUpdatePullRequestHandler.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/FileWriterWorker.cs +10 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/XmlFileWriter.cs +245 -125
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +4 -11
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +4 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/DependencyConflictResolver.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +14 -31
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +3 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProcessExtensions.cs +12 -13
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/XmlExtensions.cs +3 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +78 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/VersionFinderTests.cs +126 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Clone/CloneWorkerTests.cs +14 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/DependencySolver/MSBuildDependencySolverTests.cs +1 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +1 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +0 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +2 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +1 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/ApiModel/CooldownTests.cs +99 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +168 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestBodyGenerator/DetailedPullRequestBodyGeneratorTests.cs +71 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +71 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/GroupUpdateAllVersionsHandlerTests.cs +70 -39
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/FileWriterWorkerTests.cs +43 -30
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/XmlFileWriterTests.cs +76 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackageReferenceUpdaterTests.cs +0 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +11 -27
- data/lib/dependabot/nuget.rb +3 -11
- metadata +8 -54
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +0 -49
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs +0 -60
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/FrameworkCheckCommand.cs +0 -35
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs +0 -58
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +0 -380
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +0 -557
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.FrameworkCheck.cs +0 -37
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +0 -226
- data/lib/dependabot/nuget/analysis/analysis_json_reader.rb +0 -65
- data/lib/dependabot/nuget/analysis/dependency_analysis.rb +0 -66
- data/lib/dependabot/nuget/cache_manager.rb +0 -29
- data/lib/dependabot/nuget/discovery/dependency_details.rb +0 -102
- data/lib/dependabot/nuget/discovery/dependency_file_discovery.rb +0 -122
- data/lib/dependabot/nuget/discovery/discovery_json_reader.rb +0 -266
- data/lib/dependabot/nuget/discovery/evaluation_details.rb +0 -63
- data/lib/dependabot/nuget/discovery/project_discovery.rb +0 -104
- data/lib/dependabot/nuget/discovery/property_details.rb +0 -43
- data/lib/dependabot/nuget/discovery/workspace_discovery.rb +0 -61
- data/lib/dependabot/nuget/file_fetcher.rb +0 -46
- data/lib/dependabot/nuget/file_parser.rb +0 -153
- data/lib/dependabot/nuget/file_updater.rb +0 -256
- data/lib/dependabot/nuget/language.rb +0 -98
- data/lib/dependabot/nuget/metadata_finder.rb +0 -197
- data/lib/dependabot/nuget/native_helpers.rb +0 -364
- data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +0 -88
- data/lib/dependabot/nuget/package_manager.rb +0 -51
- data/lib/dependabot/nuget/update_checker/requirements_updater.rb +0 -105
- data/lib/dependabot/nuget/update_checker.rb +0 -210
@@ -1,7 +1,7 @@
|
|
1
1
|
using System.Collections.Immutable;
|
2
2
|
using System.Text.RegularExpressions;
|
3
|
-
|
4
|
-
using
|
3
|
+
|
4
|
+
using Microsoft.Language.Xml;
|
5
5
|
|
6
6
|
using NuGet.Versioning;
|
7
7
|
|
@@ -25,7 +25,7 @@ public class XmlFileWriter : IFileWriter
|
|
25
25
|
private readonly ILogger _logger;
|
26
26
|
|
27
27
|
// these file extensions are valid project entrypoints; everything else is ignored
|
28
|
-
|
28
|
+
internal static readonly HashSet<string> SupportedProjectFileExtensions = new(StringComparer.OrdinalIgnoreCase)
|
29
29
|
{
|
30
30
|
".csproj",
|
31
31
|
".vbproj",
|
@@ -33,7 +33,7 @@ public class XmlFileWriter : IFileWriter
|
|
33
33
|
};
|
34
34
|
|
35
35
|
// these file extensions are valid additional files and can be updated; everything else is ignored
|
36
|
-
|
36
|
+
internal static readonly HashSet<string> SupportedAdditionalFileExtensions = new(StringComparer.OrdinalIgnoreCase)
|
37
37
|
{
|
38
38
|
".props",
|
39
39
|
".targets",
|
@@ -71,8 +71,7 @@ public class XmlFileWriter : IFileWriter
|
|
71
71
|
.Where(path => SupportedProjectFileExtensions.Contains(Path.GetExtension(path)) || SupportedAdditionalFileExtensions.Contains(Path.GetExtension(path)))
|
72
72
|
.Select(async path =>
|
73
73
|
{
|
74
|
-
var
|
75
|
-
var document = XDocument.Parse(content, LoadOptions.PreserveWhitespace);
|
74
|
+
var document = await ReadFileContentsAsync(repoContentsPath, path);
|
76
75
|
return KeyValuePair.Create(path, document);
|
77
76
|
})
|
78
77
|
.ToArray();
|
@@ -102,17 +101,46 @@ public class XmlFileWriter : IFileWriter
|
|
102
101
|
string? currentVersionString = null;
|
103
102
|
Action<string>? updateVersionLocation = null;
|
104
103
|
|
105
|
-
var
|
106
|
-
.SelectMany(
|
107
|
-
|
104
|
+
var packageReferenceElementsAndPaths = filesAndContents
|
105
|
+
.SelectMany(kvp =>
|
106
|
+
{
|
107
|
+
var path = kvp.Key;
|
108
|
+
var doc = kvp.Value;
|
109
|
+
var elements = doc.Descendants().Where(e => e.Name == PackageReferenceElementName || e.Name == GlobalPackageReferenceElementName);
|
110
|
+
var pair = elements.Select(element => KeyValuePair.Create(element, path));
|
111
|
+
return pair;
|
112
|
+
})
|
113
|
+
.Where(pair =>
|
108
114
|
{
|
109
|
-
var
|
115
|
+
var element = pair.Key;
|
116
|
+
var attributeValue = element.GetAttributeValue(IncludeAttributeName) ?? element.GetAttributeValue(UpdateAttributeName) ?? string.Empty;
|
110
117
|
var packageNames = attributeValue.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
111
118
|
return packageNames.Any(name => name.Equals(requiredPackageVersion.Name, StringComparison.OrdinalIgnoreCase));
|
112
119
|
})
|
113
120
|
.ToArray();
|
114
121
|
|
115
|
-
|
122
|
+
SyntaxNode ReplaceNode(string filePath, SyntaxNode original, SyntaxNode replacement)
|
123
|
+
{
|
124
|
+
var doc = filesAndContents[filePath];
|
125
|
+
|
126
|
+
#if DEBUG
|
127
|
+
if (!doc.DescendantNodes().OfType<XmlNodeSyntax>().Any(n => n == original))
|
128
|
+
{
|
129
|
+
throw new NotSupportedException("original node was not found");
|
130
|
+
}
|
131
|
+
#endif
|
132
|
+
|
133
|
+
var updatedDoc = doc.ReplaceNode(original, replacement);
|
134
|
+
#if DEBUG
|
135
|
+
var docFullString = doc.ToFullString();
|
136
|
+
var updatedDocFullString = updatedDoc.ToFullString();
|
137
|
+
#endif
|
138
|
+
filesAndContents[filePath] = updatedDoc;
|
139
|
+
var newlyAddedNode = updatedDoc.DescendantNodes().OfType<XmlNodeSyntax>().First(d => d.FullSpan.Start == original.FullSpan.Start);
|
140
|
+
return newlyAddedNode;
|
141
|
+
}
|
142
|
+
|
143
|
+
if (packageReferenceElementsAndPaths.Length == 0)
|
116
144
|
{
|
117
145
|
// no matching `<PackageReference>` elements found; pin it as a transitive dependency
|
118
146
|
updatesPerformed[requiredPackageVersion.Name] = true; // all cases below add the dependency
|
@@ -120,51 +148,112 @@ public class XmlFileWriter : IFileWriter
|
|
120
148
|
// find last `<ItemGroup>` in the project...
|
121
149
|
Action addItemGroup = () => { }; // adding an ItemGroup to the project isn't always necessary, but it's much easier to prepare for it here
|
122
150
|
var projectDocument = filesAndContents[projectRelativePath];
|
123
|
-
var lastItemGroup = projectDocument.
|
124
|
-
.LastOrDefault(e => e.Name.
|
151
|
+
var lastItemGroup = projectDocument.RootSyntax.Elements
|
152
|
+
.LastOrDefault(e => e.Name.Equals(ItemGroupElementName, StringComparison.OrdinalIgnoreCase));
|
125
153
|
if (lastItemGroup is null)
|
126
154
|
{
|
127
155
|
_logger.Info($"No `<{ItemGroupElementName}>` element found in project; adding one.");
|
128
|
-
lastItemGroup =
|
129
|
-
|
156
|
+
lastItemGroup = XmlExtensions.CreateOpenCloseXmlElementSyntax(ItemGroupElementName,
|
157
|
+
new SyntaxList<SyntaxNode>([SyntaxFactory.EndOfLineTrivia("\n"), SyntaxFactory.WhitespaceTrivia(" ")]),
|
158
|
+
insertIntermediateNewline: false);
|
159
|
+
addItemGroup = () =>
|
160
|
+
{
|
161
|
+
// add the new element
|
162
|
+
var updatedRootSyntax = projectDocument.RootSyntax.AddChild(lastItemGroup);
|
163
|
+
var updatedProjectDocument = projectDocument.ReplaceNode(projectDocument.RootSyntax.AsNode, updatedRootSyntax.AsNode);
|
164
|
+
|
165
|
+
// reset well-known variables
|
166
|
+
projectDocument = updatedProjectDocument;
|
167
|
+
filesAndContents[projectRelativePath] = updatedProjectDocument;
|
168
|
+
lastItemGroup = updatedProjectDocument.RootSyntax.Elements.Last(e => e.Name.Equals(ItemGroupElementName, StringComparison.OrdinalIgnoreCase));
|
169
|
+
};
|
130
170
|
}
|
131
171
|
|
132
172
|
// ...find where the new item should go...
|
133
|
-
var
|
134
|
-
.Where(e => e.Name.LocalName.Equals(PackageReferenceElementName, StringComparison.OrdinalIgnoreCase))
|
135
|
-
.TakeWhile(e => (e.Attribute(IncludeAttributeName)?.Value ?? e.Attribute(UpdateAttributeName)?.Value ?? string.Empty).CompareTo(requiredPackageVersion.Name) < 0)
|
136
|
-
.ToArray();
|
173
|
+
var elementsBeforeNew = GetOrderedElementsBeforeSpecified(lastItemGroup, PackageReferenceElementName, [IncludeAttributeName, UpdateAttributeName], requiredPackageVersion.Name);
|
137
174
|
|
138
175
|
// ...prepare a new `<PackageReference>` element...
|
139
|
-
var newElement = new
|
140
|
-
|
141
|
-
new XAttribute(IncludeAttributeName, requiredPackageVersion.Name));
|
176
|
+
var newElement = XmlExtensions.CreateSingleLineXmlElementSyntax(PackageReferenceElementName, leadingTrivia: new SyntaxList<SyntaxNode>())
|
177
|
+
.WithAttribute(IncludeAttributeName, requiredPackageVersion.Name);
|
142
178
|
|
143
179
|
// ...add the `<PackageReference>` element if and where appropriate...
|
144
180
|
if (addPackageReferenceElementForPinnedPackages)
|
145
181
|
{
|
146
182
|
addItemGroup();
|
147
|
-
var
|
148
|
-
if (
|
183
|
+
var lastPriorElement = elementsBeforeNew.LastOrDefault();
|
184
|
+
if (lastPriorElement is not null)
|
149
185
|
{
|
150
|
-
|
186
|
+
// find line number of last prior element
|
187
|
+
// find the offset of the first token on each newline
|
188
|
+
var firstOffsetForLine = new List<int>();
|
189
|
+
foreach (var tr in filesAndContents[projectRelativePath].DescendantTrivia(descendIntoChildren: _ => true, descendIntoTrivia: true))
|
190
|
+
{
|
191
|
+
if (tr.Kind == SyntaxKind.EndOfLineTrivia)
|
192
|
+
{
|
193
|
+
firstOffsetForLine.Add(tr.SpanStart);
|
194
|
+
}
|
195
|
+
|
196
|
+
if (tr.SpanStart >= lastPriorElement.SpanStart)
|
197
|
+
{
|
198
|
+
break;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
var lastPriorElementLineNumber = firstOffsetForLine.Count(o => o < lastPriorElement.SpanStart);
|
203
|
+
var lastElementAtStartOfLine = lastPriorElement.Parent.ChildNodes
|
204
|
+
.First(n => firstOffsetForLine.Count(o => o < n.SpanStart) >= lastPriorElementLineNumber);
|
205
|
+
var trivia = lastElementAtStartOfLine.GetLeadingTrivia().ToList();
|
206
|
+
var priorEolIndex = trivia.FindLastIndex(t => t.Kind == SyntaxKind.EndOfLineTrivia);
|
207
|
+
var indentTrivia = trivia
|
208
|
+
.Skip(priorEolIndex + 1)
|
209
|
+
.Select(t => SyntaxFactory.WhitespaceTrivia(t.ToFullString()))
|
210
|
+
.ToArray();
|
211
|
+
var newTrivia = new SyntaxTriviaList([SyntaxFactory.EndOfLineTrivia("\n"), .. indentTrivia]);
|
212
|
+
newElement = (IXmlElementSyntax)newElement.AsNode.WithLeadingTrivia(newTrivia);
|
213
|
+
var replacementParent = lastPriorElement.Parent.InsertNodesAfter(lastPriorElement, [newElement.AsNode]);
|
214
|
+
var actualReplacementParent = ReplaceNode(projectRelativePath, lastPriorElement.Parent, replacementParent);
|
215
|
+
var insertionIndex = elementsBeforeNew.Length;
|
216
|
+
var actualNewElement = ((IXmlElementSyntax)actualReplacementParent).Content[insertionIndex];
|
217
|
+
newElement = (IXmlElementSyntax)actualNewElement;
|
151
218
|
}
|
152
219
|
else
|
153
220
|
{
|
154
221
|
// no prior package references; add to the front
|
155
|
-
var
|
156
|
-
|
222
|
+
var itemGroupTrivia = lastItemGroup.AsNode.GetLeadingTrivia().ToList();
|
223
|
+
var priorEolIndex = itemGroupTrivia.FindLastIndex(t => t.Kind == SyntaxKind.EndOfLineTrivia);
|
224
|
+
var indentTrivia = itemGroupTrivia
|
225
|
+
.Skip(priorEolIndex + 1)
|
226
|
+
.Select(t => SyntaxFactory.WhitespaceTrivia(t.ToFullString()))
|
227
|
+
.ToArray();
|
228
|
+
var newTrivia = new SyntaxTriviaList([SyntaxFactory.EndOfLineTrivia("\n"), SyntaxFactory.WhitespaceTrivia(" "), .. indentTrivia]);
|
229
|
+
newElement = (IXmlElementSyntax)newElement.AsNode.WithLeadingTrivia(newTrivia);
|
230
|
+
var updatedItemGroup = (IXmlElementSyntax)ReplaceNode(
|
231
|
+
projectRelativePath,
|
232
|
+
lastItemGroup.AsNode,
|
233
|
+
lastItemGroup.InsertChild(newElement, 0).AsNode
|
234
|
+
);
|
235
|
+
newElement = (IXmlElementSyntax)updatedItemGroup.Content[0];
|
157
236
|
}
|
158
237
|
}
|
159
238
|
|
160
239
|
// ...find the best place to add the version...
|
161
|
-
var
|
162
|
-
.SelectMany(
|
163
|
-
|
164
|
-
|
240
|
+
var matchingPackageVersionElementsAndPaths = filesAndContents
|
241
|
+
.SelectMany(kvp =>
|
242
|
+
{
|
243
|
+
var path = kvp.Key;
|
244
|
+
var doc = kvp.Value;
|
245
|
+
var packageVersionElements = doc.Descendants()
|
246
|
+
.Where(e => e.Name.Equals(PackageVersionElementName, StringComparison.OrdinalIgnoreCase))
|
247
|
+
.Where(element => (element.GetAttributeValue(IncludeAttributeName) ?? string.Empty).Trim().Equals(requiredPackageVersion.Name, StringComparison.OrdinalIgnoreCase))
|
248
|
+
.ToArray();
|
249
|
+
return packageVersionElements.Select(element => KeyValuePair.Create(element, path));
|
250
|
+
})
|
251
|
+
.ToArray();
|
252
|
+
if (matchingPackageVersionElementsAndPaths.Length > 0)
|
165
253
|
{
|
166
254
|
// found matching `<PackageVersion>` element; if `Version` attribute is appropriate we're done, otherwise set `VersionOverride` attribute on new element
|
167
|
-
var
|
255
|
+
var (matchingPackageVersionElement, filePath) = matchingPackageVersionElementsAndPaths.First();
|
256
|
+
var versionAttribute = matchingPackageVersionElement.GetAttributeCaseInsensitive(VersionMetadataName);
|
168
257
|
if (versionAttribute is not null &&
|
169
258
|
NuGetVersion.TryParse(versionAttribute.Value, out var existingVersion) &&
|
170
259
|
existingVersion == requiredVersion)
|
@@ -176,88 +265,152 @@ public class XmlFileWriter : IFileWriter
|
|
176
265
|
{
|
177
266
|
// version doesn't match; use `VersionOverride` attribute on new element
|
178
267
|
_logger.Info($"Dependency {requiredPackageVersion.Name} set to {requiredVersion}; using `{VersionOverrideMetadataName}` attribute on new element.");
|
179
|
-
newElement
|
268
|
+
newElement = (IXmlElementSyntax)ReplaceNode(
|
269
|
+
projectRelativePath,
|
270
|
+
newElement.AsNode,
|
271
|
+
newElement.WithAttribute(VersionOverrideMetadataName, requiredVersion.ToString()).AsNode
|
272
|
+
);
|
180
273
|
}
|
181
274
|
}
|
182
275
|
else
|
183
276
|
{
|
184
277
|
// no matching `<PackageVersion>` element; either add a new one, or directly set the `Version` attribute on the new element
|
185
|
-
var
|
186
|
-
.SelectMany(
|
278
|
+
var allPackageVersionElementsAndPaths = filesAndContents
|
279
|
+
.SelectMany(kvp =>
|
280
|
+
{
|
281
|
+
var path = kvp.Key;
|
282
|
+
var doc = kvp.Value;
|
283
|
+
return doc.Descendants()
|
284
|
+
.Where(e => e.Name.Equals(PackageVersionElementName, StringComparison.OrdinalIgnoreCase))
|
285
|
+
.Select(element => KeyValuePair.Create(element, path));
|
286
|
+
})
|
187
287
|
.ToArray();
|
188
|
-
if (
|
288
|
+
if (allPackageVersionElementsAndPaths.Length > 0)
|
189
289
|
{
|
190
290
|
// add a new `<PackageVersion>` element
|
191
|
-
var newVersionElement =
|
192
|
-
|
193
|
-
|
194
|
-
var
|
195
|
-
.TakeWhile(
|
196
|
-
.
|
197
|
-
if (
|
291
|
+
var newVersionElement = XmlExtensions.CreateSingleLineXmlElementSyntax(PackageVersionElementName)
|
292
|
+
.WithAttribute(IncludeAttributeName, requiredPackageVersion.Name)
|
293
|
+
.WithAttribute(VersionMetadataName, requiredVersion.ToString());
|
294
|
+
var priorPackageVersionElementsAndPaths = allPackageVersionElementsAndPaths
|
295
|
+
.TakeWhile(pair => (pair.Key.GetAttributeValue(IncludeAttributeName) ?? string.Empty).Trim().CompareTo(requiredPackageVersion.Name) < 0)
|
296
|
+
.ToArray();
|
297
|
+
if (priorPackageVersionElementsAndPaths.Length > 0)
|
198
298
|
{
|
199
299
|
_logger.Info($"Adding new `<{PackageVersionElementName}>` element for {requiredPackageVersion.Name} with version {requiredVersion}.");
|
200
|
-
|
300
|
+
var (lastPriorPackageVersionElement, filePath) = priorPackageVersionElementsAndPaths.Last();
|
301
|
+
var trivia = lastPriorPackageVersionElement.AsNode.GetLeadingTrivia().ToList();
|
302
|
+
var priorEolIndex = trivia.FindLastIndex(t => t.Kind == SyntaxKind.EndOfLineTrivia);
|
303
|
+
var indentTrivia = trivia
|
304
|
+
.Skip(priorEolIndex + 1)
|
305
|
+
.Select(t => SyntaxFactory.WhitespaceTrivia(t.ToFullString()))
|
306
|
+
.ToArray();
|
307
|
+
var newTrivia = new SyntaxTriviaList([SyntaxFactory.EndOfLineTrivia("\n"), .. indentTrivia]);
|
308
|
+
newVersionElement = (IXmlElementSyntax)newVersionElement.AsNode.WithLeadingTrivia(newTrivia).WithoutTrailingTrivia();
|
309
|
+
var insertionIndex = lastPriorPackageVersionElement.Parent.Content.IndexOf(lastPriorPackageVersionElement.AsNode) + 1;
|
310
|
+
var replacementParent = lastPriorPackageVersionElement.Parent
|
311
|
+
.InsertChild(newVersionElement, insertionIndex);
|
312
|
+
var actualReplacementParent = ReplaceNode(filePath, lastPriorPackageVersionElement.Parent.AsNode, replacementParent.AsNode);
|
313
|
+
var actualNewElement = ((IXmlElementSyntax)actualReplacementParent).Content[insertionIndex];
|
314
|
+
newVersionElement = (IXmlElementSyntax)actualNewElement;
|
201
315
|
}
|
202
316
|
else
|
203
317
|
{
|
204
318
|
// no prior package versions; add to the front of the document
|
205
319
|
_logger.Info($"Adding new `<{PackageVersionElementName}>` element for {requiredPackageVersion.Name} with version {requiredVersion} at the start of the document.");
|
206
|
-
var packageVersionGroup =
|
207
|
-
|
208
|
-
packageVersionGroup.
|
320
|
+
var (packageVersionGroup, filePath) = allPackageVersionElementsAndPaths.First();
|
321
|
+
packageVersionGroup = packageVersionGroup.Parent;
|
322
|
+
var itemGroupTrivia = packageVersionGroup.AsNode.GetLeadingTrivia().ToList();
|
323
|
+
var priorEolIndex = itemGroupTrivia.FindLastIndex(t => t.Kind == SyntaxKind.EndOfLineTrivia);
|
324
|
+
var indentTrivia = itemGroupTrivia
|
325
|
+
.Skip(priorEolIndex + 1)
|
326
|
+
.Select(t => SyntaxFactory.WhitespaceTrivia(t.ToFullString()))
|
327
|
+
.ToArray();
|
328
|
+
var newTrivia = new SyntaxTriviaList([SyntaxFactory.EndOfLineTrivia("\n"), SyntaxFactory.WhitespaceTrivia(" "), .. indentTrivia]);
|
329
|
+
newVersionElement = (IXmlElementSyntax)newVersionElement.AsNode.WithLeadingTrivia(newTrivia).WithoutTrailingTrivia();
|
330
|
+
var insertionIndex = 0;
|
331
|
+
var replacementPackageVersionGroup = packageVersionGroup
|
332
|
+
.InsertChild(newVersionElement, insertionIndex);
|
333
|
+
ReplaceNode(
|
334
|
+
filePath,
|
335
|
+
packageVersionGroup.AsNode,
|
336
|
+
replacementPackageVersionGroup.AsNode
|
337
|
+
);
|
209
338
|
}
|
210
339
|
}
|
211
340
|
else
|
212
341
|
{
|
213
342
|
// add a direct `Version` attribute
|
214
|
-
newElement.
|
343
|
+
var newElementWithVersion = newElement.WithAttribute(VersionMetadataName, requiredVersion.ToString());
|
344
|
+
newElement = (IXmlElementSyntax)ReplaceNode(projectRelativePath, newElement.AsNode, newElementWithVersion.AsNode);
|
215
345
|
}
|
216
346
|
}
|
217
347
|
}
|
218
348
|
else
|
219
349
|
{
|
220
350
|
// found matching `<PackageReference>` elements to update
|
221
|
-
foreach (var packageReferenceElement in
|
351
|
+
foreach (var (packageReferenceElement, filePath) in packageReferenceElementsAndPaths)
|
222
352
|
{
|
223
353
|
// first check for matching `Version` attribute
|
224
|
-
var versionAttribute = packageReferenceElement.
|
354
|
+
var versionAttribute = packageReferenceElement.GetAttribute(VersionMetadataName, StringComparison.OrdinalIgnoreCase);
|
225
355
|
if (versionAttribute is not null)
|
226
356
|
{
|
227
357
|
currentVersionString = versionAttribute.Value;
|
228
|
-
updateVersionLocation =
|
358
|
+
updateVersionLocation = version =>
|
359
|
+
{
|
360
|
+
var refoundVersionAttribute = filesAndContents[filePath]
|
361
|
+
.DescendantNodes()
|
362
|
+
.OfType<XmlAttributeSyntax>()
|
363
|
+
.First(a => a.FullSpan.Start == versionAttribute.FullSpan.Start);
|
364
|
+
ReplaceNode(filePath, refoundVersionAttribute, refoundVersionAttribute.WithValue(version));
|
365
|
+
};
|
229
366
|
goto doVersionUpdate;
|
230
367
|
}
|
231
368
|
|
232
369
|
// next check for `Version` child element
|
233
|
-
var versionElement = packageReferenceElement.Elements
|
370
|
+
var versionElement = packageReferenceElement.Elements.FirstOrDefault(e => e.Name.Equals(VersionMetadataName, StringComparison.OrdinalIgnoreCase));
|
234
371
|
if (versionElement is not null)
|
235
372
|
{
|
236
|
-
currentVersionString = versionElement.
|
237
|
-
updateVersionLocation =
|
373
|
+
currentVersionString = versionElement.GetContentValue();
|
374
|
+
updateVersionLocation = version =>
|
375
|
+
{
|
376
|
+
var refoundVersionElement = filesAndContents[filePath]
|
377
|
+
.DescendantNodes()
|
378
|
+
.OfType<IXmlElementSyntax>()
|
379
|
+
.First(e => e.AsNode.FullSpan.Start == versionElement.AsNode.FullSpan.Start);
|
380
|
+
ReplaceNode(filePath, refoundVersionElement.AsNode, refoundVersionElement.WithContent(version).AsNode);
|
381
|
+
};
|
238
382
|
goto doVersionUpdate;
|
239
383
|
}
|
240
384
|
|
241
385
|
// check for matching `<PackageVersion>` element
|
242
|
-
var
|
243
|
-
.SelectMany(
|
244
|
-
|
245
|
-
|
386
|
+
var packageVersionElementsAndPaths = filesAndContents
|
387
|
+
.SelectMany(kvp =>
|
388
|
+
{
|
389
|
+
var path = kvp.Key;
|
390
|
+
var doc = kvp.Value;
|
391
|
+
return doc.Descendants()
|
392
|
+
.Where(e => e.Name.Equals(PackageVersionElementName, StringComparison.OrdinalIgnoreCase))
|
393
|
+
.Where(e => (e.GetAttributeValue(IncludeAttributeName) ?? string.Empty).Trim().Equals(requiredPackageVersion.Name, StringComparison.OrdinalIgnoreCase))
|
394
|
+
.Select(element => KeyValuePair.Create(element, path));
|
395
|
+
})
|
396
|
+
.ToArray();
|
397
|
+
if (packageVersionElementsAndPaths.Length > 0)
|
246
398
|
{
|
247
|
-
var
|
399
|
+
var (packageVersionElement, packageVersionFilePath) = packageVersionElementsAndPaths.First();
|
400
|
+
var packageVersionAttribute = packageVersionElement.GetAttributeCaseInsensitive(VersionMetadataName);
|
248
401
|
if (packageVersionAttribute is not null)
|
249
402
|
{
|
250
403
|
currentVersionString = packageVersionAttribute.Value;
|
251
|
-
updateVersionLocation =
|
404
|
+
updateVersionLocation = version => ReplaceNode(packageVersionFilePath, packageVersionAttribute, packageVersionAttribute.WithValue(version));
|
252
405
|
goto doVersionUpdate;
|
253
406
|
}
|
254
407
|
else
|
255
408
|
{
|
256
|
-
var cpmVersionElement = packageVersionElement.
|
409
|
+
var cpmVersionElement = packageVersionElement.GetElements(VersionMetadataName, StringComparison.OrdinalIgnoreCase).FirstOrDefault();
|
257
410
|
if (cpmVersionElement is not null)
|
258
411
|
{
|
259
|
-
currentVersionString = cpmVersionElement.
|
260
|
-
updateVersionLocation =
|
412
|
+
currentVersionString = cpmVersionElement.GetContentValue();
|
413
|
+
updateVersionLocation = version => ReplaceNode(packageVersionFilePath, cpmVersionElement.AsNode, cpmVersionElement.WithContent(version).AsNode);
|
261
414
|
goto doVersionUpdate;
|
262
415
|
}
|
263
416
|
}
|
@@ -345,13 +498,21 @@ public class XmlFileWriter : IFileWriter
|
|
345
498
|
{
|
346
499
|
// this looks like a property; keep walking backwards with all possible elements
|
347
500
|
var propertyName = propertyMatch.Groups["PropertyName"].Value;
|
348
|
-
var
|
349
|
-
.SelectMany(
|
350
|
-
|
501
|
+
var propertyDefinitionsAndPaths = filesAndContents
|
502
|
+
.SelectMany(kvp =>
|
503
|
+
{
|
504
|
+
var path = kvp.Key;
|
505
|
+
var doc = kvp.Value;
|
506
|
+
return doc.Descendants()
|
507
|
+
.Where(e => e.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase))
|
508
|
+
.Where(e => e.Parent?.Name.Equals(PropertyGroupElementName, StringComparison.OrdinalIgnoreCase) == true)
|
509
|
+
.Select(element => KeyValuePair.Create(element, path));
|
510
|
+
})
|
351
511
|
.ToArray();
|
352
|
-
foreach (var propertyDefinition in
|
512
|
+
foreach (var (propertyDefinition, propertyFilePath) in propertyDefinitionsAndPaths)
|
353
513
|
{
|
354
|
-
|
514
|
+
var updateAction = new Action<string>(version => ReplaceNode(propertyFilePath, propertyDefinition.AsNode, propertyDefinition.WithContent(version).AsNode));
|
515
|
+
candidateUpdateLocations.Enqueue((propertyDefinition.GetContentValue(), updateAction));
|
355
516
|
}
|
356
517
|
}
|
357
518
|
}
|
@@ -377,73 +538,32 @@ public class XmlFileWriter : IFileWriter
|
|
377
538
|
return performedAllUpdates;
|
378
539
|
}
|
379
540
|
|
380
|
-
private static
|
381
|
-
{
|
382
|
-
var indentText = (element.PreviousNode as XText)?.Value;
|
383
|
-
var indent = indentText is not null
|
384
|
-
? new XText(indentText + extraIndentationToAdd)
|
385
|
-
: null;
|
386
|
-
return indent;
|
387
|
-
}
|
388
|
-
|
389
|
-
private static void AddAfterSiblingElement(XElement siblingElement, XElement newElement, string extraIndentationToAdd = "")
|
541
|
+
private static ImmutableArray<SyntaxNode> GetOrderedElementsBeforeSpecified(IXmlElementSyntax parentElement, string elementName, IEnumerable<string> attributeNamesToCheck, string attributeValue)
|
390
542
|
{
|
391
|
-
var
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
if (text.Value.Contains('\n'))
|
401
|
-
{
|
402
|
-
done = true;
|
403
|
-
}
|
404
|
-
else
|
405
|
-
{
|
406
|
-
nodeToAddAfter = nodeToAddAfter.NextNode;
|
407
|
-
}
|
408
|
-
|
409
|
-
break;
|
410
|
-
case XComment comment:
|
411
|
-
if (comment.Value.Contains('\n'))
|
412
|
-
{
|
413
|
-
done = true;
|
414
|
-
}
|
415
|
-
else
|
416
|
-
{
|
417
|
-
nodeToAddAfter = nodeToAddAfter.NextNode;
|
418
|
-
}
|
419
|
-
|
420
|
-
break;
|
421
|
-
default:
|
422
|
-
done = true;
|
423
|
-
break;
|
424
|
-
}
|
425
|
-
}
|
426
|
-
|
427
|
-
nodeToAddAfter.AddAfterSelf(indent, newElement);
|
543
|
+
var elementsBeforeNew = parentElement.Content
|
544
|
+
.TakeWhile(
|
545
|
+
e => e is XmlCommentSyntax ||
|
546
|
+
(e is IXmlElementSyntax element &&
|
547
|
+
element.Name.Equals(elementName, StringComparison.OrdinalIgnoreCase) &&
|
548
|
+
(attributeNamesToCheck.Select(attributeName => element.GetAttributeValue(attributeName)).FirstOrDefault(value => value is not null) ?? string.Empty)
|
549
|
+
.CompareTo(attributeValue) < 0))
|
550
|
+
.ToImmutableArray();
|
551
|
+
return elementsBeforeNew;
|
428
552
|
}
|
429
553
|
|
430
|
-
private static async Task<
|
554
|
+
private static async Task<XmlDocumentSyntax> ReadFileContentsAsync(DirectoryInfo repoContentsPath, string path)
|
431
555
|
{
|
432
556
|
var fullPath = Path.Join(repoContentsPath.FullName, path);
|
433
557
|
var contents = await File.ReadAllTextAsync(fullPath);
|
434
|
-
|
558
|
+
var document = Parser.ParseText(contents);
|
559
|
+
return document;
|
435
560
|
}
|
436
561
|
|
437
|
-
private static async Task WriteFileContentsAsync(DirectoryInfo repoContentsPath, string path,
|
562
|
+
private static async Task WriteFileContentsAsync(DirectoryInfo repoContentsPath, string path, XmlDocumentSyntax document)
|
438
563
|
{
|
439
564
|
var fullPath = Path.Join(repoContentsPath.FullName, path);
|
440
|
-
var
|
441
|
-
|
442
|
-
Async = true,
|
443
|
-
OmitXmlDeclaration = document.Declaration is null,
|
444
|
-
};
|
445
|
-
using var writer = XmlWriter.Create(fullPath, writerSettings);
|
446
|
-
await document.SaveAsync(writer, CancellationToken.None);
|
565
|
+
var content = document.ToFullString();
|
566
|
+
await File.WriteAllTextAsync(fullPath, content);
|
447
567
|
}
|
448
568
|
|
449
569
|
public static string CreateUpdatedVersionRangeString(VersionRange existingRange, NuGetVersion existingVersion, NuGetVersion requiredVersion)
|
@@ -1,5 +1,3 @@
|
|
1
|
-
using NuGetUpdater.Core.Updater;
|
2
|
-
|
3
1
|
namespace NuGetUpdater.Core;
|
4
2
|
|
5
3
|
internal static class LockFileUpdater
|
@@ -7,18 +5,13 @@ internal static class LockFileUpdater
|
|
7
5
|
public static async Task UpdateLockFileAsync(
|
8
6
|
string repoRootPath,
|
9
7
|
string projectPath,
|
10
|
-
ExperimentsManager experimentsManager,
|
11
8
|
ILogger logger)
|
12
9
|
{
|
13
10
|
var projectDirectory = Path.GetDirectoryName(projectPath)!;
|
14
|
-
await
|
11
|
+
var (exitCode, stdout, stderr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["restore", "--force-evaluate", "-p:EnableWindowsTargeting=true", projectPath], projectDirectory);
|
12
|
+
if (exitCode != 0)
|
15
13
|
{
|
16
|
-
|
17
|
-
|
18
|
-
{
|
19
|
-
logger.Error($" Lock file update failed.\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}");
|
20
|
-
}
|
21
|
-
return (exitCode, stdout, stderr);
|
22
|
-
}, logger, retainMSBuildSdks: true);
|
14
|
+
logger.Error($" Lock file update failed.\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}");
|
15
|
+
}
|
23
16
|
}
|
24
17
|
}
|
@@ -29,7 +29,6 @@ internal static class PackageReferenceUpdater
|
|
29
29
|
ImmutableArray<Dependency> topLevelDependencies,
|
30
30
|
ImmutableArray<Dependency> requestedUpdates,
|
31
31
|
ImmutableArray<Dependency> resolvedDependencies,
|
32
|
-
ExperimentsManager experimentsManager,
|
33
32
|
ILogger logger
|
34
33
|
)
|
35
34
|
{
|
@@ -41,7 +40,7 @@ internal static class PackageReferenceUpdater
|
|
41
40
|
.Where(d => d.Item2)
|
42
41
|
.ToDictionary(d => d.Item1, d => d.Item3!, StringComparer.OrdinalIgnoreCase);
|
43
42
|
|
44
|
-
var (packageParents, packageVersions) = await GetPackageGraphForDependencies(repoRoot, projectPath, targetFramework, resolvedDependencies,
|
43
|
+
var (packageParents, packageVersions) = await GetPackageGraphForDependencies(repoRoot, projectPath, targetFramework, resolvedDependencies, logger);
|
45
44
|
var updateOperations = new List<UpdateOperationBase>();
|
46
45
|
foreach (var (requestedDependencyName, requestedDependencyVersion) in requestedVersions)
|
47
46
|
{
|
@@ -109,7 +108,7 @@ internal static class PackageReferenceUpdater
|
|
109
108
|
return [.. updateOperations];
|
110
109
|
}
|
111
110
|
|
112
|
-
private static async Task<(Dictionary<string, HashSet<string>> PackageParents, Dictionary<string, NuGetVersion> PackageVersions)> GetPackageGraphForDependencies(string repoRoot, string projectPath, string targetFramework, ImmutableArray<Dependency> topLevelDependencies,
|
111
|
+
private static async Task<(Dictionary<string, HashSet<string>> PackageParents, Dictionary<string, NuGetVersion> PackageVersions)> GetPackageGraphForDependencies(string repoRoot, string projectPath, string targetFramework, ImmutableArray<Dependency> topLevelDependencies, ILogger logger)
|
113
112
|
{
|
114
113
|
var packageParents = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
|
115
114
|
var packageVersions = new Dictionary<string, NuGetVersion>(StringComparer.OrdinalIgnoreCase);
|
@@ -118,8 +117,8 @@ internal static class PackageReferenceUpdater
|
|
118
117
|
{
|
119
118
|
// generate project.assets.json
|
120
119
|
var parsedTargetFramework = NuGetFramework.Parse(targetFramework);
|
121
|
-
var tempProject = await MSBuildHelper.CreateTempProjectAsync(tempDir, repoRoot, projectPath, targetFramework, topLevelDependencies,
|
122
|
-
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["build", tempProject, "/t:_ReportDependencies"], tempDir.FullName
|
120
|
+
var tempProject = await MSBuildHelper.CreateTempProjectAsync(tempDir, repoRoot, projectPath, targetFramework, topLevelDependencies, logger, importDependencyTargets: false);
|
121
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetWithoutMSBuildEnvironmentVariablesAsync(["build", tempProject, "/t:_ReportDependencies"], tempDir.FullName);
|
123
122
|
var assetsJsonPath = Path.Join(tempDir.FullName, "obj", "project.assets.json");
|
124
123
|
var assetsJsonContent = await File.ReadAllTextAsync(assetsJsonPath);
|
125
124
|
|
@@ -77,7 +77,7 @@ public class UpdaterWorker : IUpdaterWorker
|
|
77
77
|
|
78
78
|
var worker = new FileWriterWorker(
|
79
79
|
new DiscoveryWorker(_jobId, _experimentsManager, _logger),
|
80
|
-
new MSBuildDependencySolver(new DirectoryInfo(repoRootPath), new FileInfo(workspacePath),
|
80
|
+
new MSBuildDependencySolver(new DirectoryInfo(repoRootPath), new FileInfo(workspacePath), _logger),
|
81
81
|
new XmlFileWriter(_logger),
|
82
82
|
_logger
|
83
83
|
);
|
@@ -460,7 +460,7 @@ public class PackageManager
|
|
460
460
|
string currentVersionString = parent.CurrentVersion;
|
461
461
|
NuGetVersion currentVersionParent = NuGetVersion.Parse(currentVersionString);
|
462
462
|
|
463
|
-
var result = await VersionFinder.
|
463
|
+
var result = await VersionFinder.GetVersionsByNameAsync([projectFramework], parent.PackageName, currentVersionParent, nugetContext, logger, CancellationToken.None);
|
464
464
|
var versions = result.GetVersions();
|
465
465
|
NuGetVersion latestVersion = versions.Where(v => !v.IsPrerelease).Max();
|
466
466
|
|
@@ -550,7 +550,7 @@ public class PackageManager
|
|
550
550
|
NuGetContext nugetContext = new NuGetContext(Path.GetDirectoryName(projectPath));
|
551
551
|
var projectFramework = NuGetFramework.Parse(targetFramework);
|
552
552
|
|
553
|
-
var result = await VersionFinder.
|
553
|
+
var result = await VersionFinder.GetVersionsByNameAsync([projectFramework], possibleParent.PackageName, CurrentVersion, nugetContext, logger, CancellationToken.None);
|
554
554
|
var versions = result.GetVersions();
|
555
555
|
|
556
556
|
// If there are no versions
|