dependabot-nuget 0.300.0 → 0.301.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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs +1 -0
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +2 -0
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/ClosePullRequest.cs +1 -1
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/CommitOptions.cs +5 -1
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/CreatePullRequest.cs +1 -1
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/GroupPullRequest.cs +1 -1
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +36 -1
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +1 -1
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/MessageBase.cs +5 -0
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PullRequest.cs +2 -5
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PullRequestDependency.cs +11 -0
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/UpdatePullRequest.cs +1 -1
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/CommitOptions_IncludeScopeConverter.cs +29 -0
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/HttpApiHandler.cs +5 -0
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/IApiHandler.cs +1 -0
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestConverter.cs +35 -0
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestTextGenerator.cs +44 -0
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +205 -49
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +76 -1
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +1 -1
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestMessageTests.cs +252 -0
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestTextTests.cs +136 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +145 -22
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +15 -10
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/TestApiHandler.cs +6 -0
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/{UpdateAllowedTests.cs → UpdatePermittedAndMessageTests.cs} +110 -6
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestHttpServer.cs +105 -0
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +75 -0
  30. metadata +13 -6
@@ -1,9 +1,7 @@
1
1
  using System.Collections.Immutable;
2
- using System.Net;
3
2
  using System.Text;
4
3
  using System.Text.Json;
5
4
  using System.Text.Json.Serialization;
6
- using System.Text.RegularExpressions;
7
5
 
8
6
  using Microsoft.Extensions.FileSystemGlobbing;
9
7
 
@@ -31,7 +29,7 @@ public class RunWorker
31
29
  {
32
30
  PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower,
33
31
  WriteIndented = true,
34
- Converters = { new JsonStringEnumConverter(), new RequirementConverter(), new VersionConverter() },
32
+ Converters = { new JsonStringEnumConverter(), new PullRequestConverter(), new RequirementConverter(), new VersionConverter() },
35
33
  };
36
34
 
37
35
  public RunWorker(string jobId, IApiHandler apiHandler, IDiscoveryWorker discoverWorker, IAnalyzeWorker analyzeWorker, IUpdaterWorker updateWorker, ILogger logger)
@@ -160,39 +158,61 @@ public class RunWorker
160
158
  }
161
159
 
162
160
  // do update
163
- var updateOperations = GetUpdateOperations(discoveryResult).ToArray();
164
- var allowedUpdateOperations = updateOperations.Where(u => IsUpdateAllowed(job, u.Dependency)).ToArray();
165
-
166
- // requested update isn't listed => SecurityUpdateNotNeeded
167
- var expectedSecurityUpdateDependencyNames = job.SecurityAdvisories
161
+ var existingPullRequests = job.GetAllExistingPullRequests();
162
+ var unhandledPullRequestDependenciesSet = existingPullRequests
163
+ .Select(pr => pr.Item2.Select(d => d.DependencyName).ToHashSet(StringComparer.OrdinalIgnoreCase))
164
+ .ToHashSet();
165
+ var remainingSecurityIssues = job.SecurityAdvisories
168
166
  .Select(s => s.DependencyName)
169
167
  .ToHashSet(StringComparer.OrdinalIgnoreCase);
170
- var actualUpdateDependencyNames = allowedUpdateOperations
171
- .Select(u => u.Dependency.Name)
172
- .ToHashSet(StringComparer.OrdinalIgnoreCase);
173
- var expectedDependencyUpdateMissingInActual = expectedSecurityUpdateDependencyNames
174
- .Except(actualUpdateDependencyNames, StringComparer.OrdinalIgnoreCase)
175
- .OrderBy(d => d, StringComparer.OrdinalIgnoreCase)
176
- .ToArray();
177
-
178
- foreach (var missingSecurityUpdate in expectedDependencyUpdateMissingInActual)
179
- {
180
- await _apiHandler.RecordUpdateJobError(new SecurityUpdateNotNeeded(missingSecurityUpdate));
181
- }
168
+ var updateOperations = GetUpdateOperations(discoveryResult).ToArray();
182
169
 
183
- foreach (var updateOperation in allowedUpdateOperations)
170
+ foreach (var updateOperation in updateOperations)
184
171
  {
185
172
  var dependency = updateOperation.Dependency;
186
- _logger.Info($"Updating [{dependency.Name}] in [{updateOperation.FilePath}]");
173
+ var (isAllowed, message) = UpdatePermittedAndMessage(job, updateOperation.Dependency);
174
+ if (message is SecurityUpdateNotNeeded sec)
175
+ {
176
+ // flag this update operation as having been handled
177
+ remainingSecurityIssues.RemoveWhere(r => r.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase));
178
+
179
+ // we only want to send this message if we're in the only update operation for this dependency, otherwise it's ambiguous
180
+ var updateOperationsWithSameName = updateOperations.Where(u => u.Dependency.Name.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase))
181
+ .ToArray();
182
+ if (updateOperationsWithSameName.Length > 1)
183
+ {
184
+ // suppress the message
185
+ message = null;
186
+ }
187
+ }
188
+
189
+ await SendApiMessage(message);
190
+ if (!isAllowed)
191
+ {
192
+ continue;
193
+ }
194
+
195
+ _logger.Info($"Updating [{dependency.Name}] in [{updateOperation.ProjectPath}]");
187
196
 
188
197
  var dependencyInfo = GetDependencyInfo(job, dependency);
189
198
  var analysisResult = await _analyzeWorker.RunAsync(repoContentsPath.FullName, discoveryResult, dependencyInfo);
190
199
  // TODO: log analysisResult
191
200
  if (analysisResult.CanUpdate)
192
201
  {
202
+ if (!job.UpdatingAPullRequest)
203
+ {
204
+ var existingPullRequest = job.GetExistingPullRequestForDependency(analysisResult.UpdatedDependencies.First(d => d.Name.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase)));
205
+ if (existingPullRequest is not null)
206
+ {
207
+ await SendApiMessage(new PullRequestExistsForLatestVersion(dependency.Name, analysisResult.UpdatedVersion));
208
+ unhandledPullRequestDependenciesSet.RemoveWhere(handled => handled.Count == 1 && handled.Contains(dependency.Name));
209
+ continue;
210
+ }
211
+ }
212
+
193
213
  // TODO: this is inefficient, but not likely causing a bottleneck
194
214
  var previousDependency = discoveredUpdatedDependencies.Dependencies
195
- .Single(d => d.Name == dependency.Name && d.Requirements.Single().File == updateOperation.FilePath);
215
+ .Single(d => d.Name == dependency.Name && d.Requirements.Single().File == updateOperation.ProjectPath);
196
216
  var updatedDependency = new ReportedDependency()
197
217
  {
198
218
  Name = dependency.Name,
@@ -201,7 +221,7 @@ public class RunWorker
201
221
  [
202
222
  new ReportedRequirement()
203
223
  {
204
- File = updateOperation.FilePath,
224
+ File = updateOperation.ProjectPath,
205
225
  Requirement = analysisResult.UpdatedVersion,
206
226
  Groups = previousDependency.Requirements.Single().Groups,
207
227
  Source = new RequirementSource()
@@ -214,7 +234,7 @@ public class RunWorker
214
234
  PreviousRequirements = previousDependency.Requirements,
215
235
  };
216
236
 
217
- var updateResult = await _updaterWorker.RunAsync(repoContentsPath.FullName, updateOperation.FilePath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, isTransitive: dependency.IsTransitive);
237
+ var updateResult = await _updaterWorker.RunAsync(repoContentsPath.FullName, updateOperation.ProjectPath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, isTransitive: dependency.IsTransitive);
218
238
  // TODO: need to report if anything was actually updated
219
239
  if (updateResult.Error is null)
220
240
  {
@@ -262,27 +282,39 @@ public class RunWorker
262
282
  await AddUpdatedFileIfDifferentAsync(discoveryResult.Path, nonProjectFile);
263
283
  }
264
284
 
265
- if (updatedDependencyFiles.Count > 0)
285
+ var updatedDependencyFileList = updatedDependencyFiles
286
+ .OrderBy(kvp => kvp.Key)
287
+ .Select(kvp => kvp.Value)
288
+ .ToArray();
289
+
290
+ var resultMessage = GetPullRequestApiMessage(job, updatedDependencyFileList, actualUpdatedDependencies.ToArray(), baseCommitSha);
291
+ switch (resultMessage)
266
292
  {
267
- var updatedDependencyFileList = updatedDependencyFiles
268
- .OrderBy(kvp => kvp.Key)
269
- .Select(kvp => kvp.Value)
270
- .ToArray();
271
- var createPullRequest = new CreatePullRequest()
272
- {
273
- Dependencies = actualUpdatedDependencies.ToArray(),
274
- UpdatedDependencyFiles = updatedDependencyFileList,
275
- BaseCommitSha = baseCommitSha,
276
- CommitMessage = "TODO: message",
277
- PrTitle = "TODO: title",
278
- PrBody = "TODO: body",
279
- };
280
- await _apiHandler.CreatePullRequest(createPullRequest);
281
- // TODO: log updated dependencies to console
293
+ case ClosePullRequest close:
294
+ var closePrDependencies = close.DependencyNames.ToHashSet(StringComparer.OrdinalIgnoreCase);
295
+ remainingSecurityIssues.RemoveWhere(closePrDependencies.Contains);
296
+ if (!unhandledPullRequestDependenciesSet.Remove(closePrDependencies))
297
+ {
298
+ // this PR was handled earlier, we don't want to now close it; suppress the message
299
+ resultMessage = null;
300
+ }
301
+ break;
302
+ case CreatePullRequest create:
303
+ var createPrDependencies = create.Dependencies.Select(d => d.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
304
+ remainingSecurityIssues.RemoveWhere(createPrDependencies.Contains);
305
+ break;
306
+ case UpdatePullRequest update:
307
+ var updatePrDependencies = update.DependencyNames.ToHashSet(StringComparer.OrdinalIgnoreCase);
308
+ remainingSecurityIssues.RemoveWhere(updatePrDependencies.Contains);
309
+ break;
282
310
  }
283
- else
311
+
312
+ await SendApiMessage(resultMessage);
313
+
314
+ // for each security advisory that _didn't_ result in a pr, report it
315
+ foreach (var depName in remainingSecurityIssues)
284
316
  {
285
- // TODO: log or throw if nothing was updated, but was expected to be
317
+ await SendApiMessage(new SecurityUpdateNotNeeded(depName));
286
318
  }
287
319
 
288
320
  var result = new RunResult()
@@ -302,7 +334,104 @@ public class RunWorker
302
334
  return result;
303
335
  }
304
336
 
305
- internal static IEnumerable<(string FilePath, Dependency Dependency)> GetUpdateOperations(WorkspaceDiscoveryResult discovery)
337
+ private async Task SendApiMessage(MessageBase? message)
338
+ {
339
+ switch (message)
340
+ {
341
+ case null:
342
+ break;
343
+ case JobErrorBase error:
344
+ await _apiHandler.RecordUpdateJobError(error);
345
+ break;
346
+ case CreatePullRequest create:
347
+ await _apiHandler.CreatePullRequest(create);
348
+ break;
349
+ case ClosePullRequest close:
350
+ await _apiHandler.ClosePullRequest(close);
351
+ break;
352
+ case UpdatePullRequest update:
353
+ await _apiHandler.UpdatePullRequest(update);
354
+ break;
355
+ default:
356
+ throw new NotSupportedException($"unsupported api message: {message.GetType().Name}");
357
+ }
358
+ }
359
+
360
+ internal static MessageBase? GetPullRequestApiMessage(Job job, DependencyFile[] updatedFiles, ReportedDependency[] updatedDependencies, string baseCommitSha)
361
+ {
362
+ updatedDependencies = updatedDependencies.OrderBy(d => d.Name, StringComparer.OrdinalIgnoreCase).ToArray();
363
+ var updatedDependenciesSet = updatedDependencies.Select(d => d.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
364
+
365
+ // all pull request dependencies with optional group name
366
+ var existingPullRequests = job.GetAllExistingPullRequests();
367
+ var existingPullRequest = existingPullRequests.FirstOrDefault(pr => pr.Item2.Select(d => d.DependencyName).All(updatedDependenciesSet.Contains));
368
+ if (existingPullRequest is null && updatedFiles.Length == 0)
369
+ {
370
+ // it's possible that we were asked to update a specific package, but it's no longer there; in that case find _that_ specific PR
371
+ var requestedUpdates = (job.Dependencies ?? []).ToHashSet(StringComparer.OrdinalIgnoreCase);
372
+ existingPullRequest = existingPullRequests.FirstOrDefault(pr => pr.Item2.Select(d => d.DependencyName).All(requestedUpdates.Contains));
373
+ }
374
+
375
+ var expectedSecurityUpdateDependencyNames = job.SecurityAdvisories.Select(sa => sa.DependencyName).ToHashSet(StringComparer.OrdinalIgnoreCase);
376
+ var isExpectedSecurityUpdate = updatedDependenciesSet.All(expectedSecurityUpdateDependencyNames.Contains);
377
+
378
+ if (existingPullRequest is { })
379
+ {
380
+ if (job.UpdatingAPullRequest)
381
+ {
382
+ return new UpdatePullRequest()
383
+ {
384
+ DependencyGroup = existingPullRequest.Item1,
385
+ DependencyNames = updatedDependencies.Select(d => d.Name).ToImmutableArray(),
386
+ UpdatedDependencyFiles = updatedFiles,
387
+ BaseCommitSha = baseCommitSha,
388
+ CommitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, updatedDependencies, updatedFiles, existingPullRequest.Item1),
389
+ PrTitle = PullRequestTextGenerator.GetPullRequestTitle(job, updatedDependencies, updatedFiles, existingPullRequest.Item1),
390
+ PrBody = PullRequestTextGenerator.GetPullRequestBody(job, updatedDependencies, updatedFiles, existingPullRequest.Item1),
391
+ };
392
+ }
393
+ else
394
+ {
395
+ if (updatedDependenciesSet.Count == 0)
396
+ {
397
+ // nothing found, close current
398
+ return new ClosePullRequest()
399
+ {
400
+ DependencyNames = [.. existingPullRequest.Item2.Select(d => d.DependencyName)],
401
+ Reason = "dependency_removed",
402
+ };
403
+ }
404
+ else
405
+ {
406
+ // found but no longer required
407
+ return new ClosePullRequest()
408
+ {
409
+ DependencyNames = [.. updatedDependenciesSet],
410
+ Reason = "up_to_date",
411
+ };
412
+ }
413
+ }
414
+ }
415
+ else
416
+ {
417
+ if (updatedDependencies.Any())
418
+ {
419
+ return new CreatePullRequest()
420
+ {
421
+ Dependencies = updatedDependencies,
422
+ UpdatedDependencyFiles = updatedFiles,
423
+ BaseCommitSha = baseCommitSha,
424
+ CommitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, updatedDependencies, updatedFiles),
425
+ PrTitle = PullRequestTextGenerator.GetPullRequestTitle(job, updatedDependencies, updatedFiles),
426
+ PrBody = PullRequestTextGenerator.GetPullRequestBody(job, updatedDependencies, updatedFiles),
427
+ };
428
+ }
429
+ }
430
+
431
+ return null;
432
+ }
433
+
434
+ internal static IEnumerable<(string ProjectPath, Dependency Dependency)> GetUpdateOperations(WorkspaceDiscoveryResult discovery)
306
435
  {
307
436
  // discovery is grouped by project/file then dependency, but we want to pivot and return a list of update operations sorted by dependency name then file path
308
437
 
@@ -364,25 +493,26 @@ public class RunWorker
364
493
  return increment;
365
494
  }
366
495
 
367
- internal static bool IsUpdateAllowed(Job job, Dependency dependency)
496
+ internal static (bool, MessageBase?) UpdatePermittedAndMessage(Job job, Dependency dependency)
368
497
  {
369
498
  if (dependency.Name.Equals("Microsoft.NET.Sdk", StringComparison.OrdinalIgnoreCase))
370
499
  {
371
500
  // this can't be updated
372
501
  // TODO: pull this out of discovery?
373
- return false;
502
+ return (false, null);
374
503
  }
375
504
 
376
505
  if (dependency.Version is null)
377
506
  {
378
507
  // if we don't know the version, there's nothing we can do
379
508
  // TODO: pull this out of discovery?
380
- return false;
509
+ return (false, null);
381
510
  }
382
511
 
383
512
  var version = NuGetVersion.Parse(dependency.Version);
384
513
  var dependencyInfo = GetDependencyInfo(job, dependency);
385
514
  var isVulnerable = dependencyInfo.Vulnerabilities.Any(v => v.IsVulnerable(version));
515
+ MessageBase? message = null;
386
516
  var allowed = job.AllowedUpdates.Any(allowedUpdate =>
387
517
  {
388
518
  // check name restriction, if any
@@ -400,7 +530,33 @@ public class RunWorker
400
530
  var isSecurityUpdate = allowedUpdate.UpdateType == UpdateType.Security || job.SecurityUpdatesOnly;
401
531
  if (isSecurityUpdate)
402
532
  {
403
- // only update if it's vulnerable
533
+ if (isVulnerable)
534
+ {
535
+ // try to match to existing PR
536
+ var dependencyVersion = NuGetVersion.Parse(dependency.Version);
537
+ var existingPullRequests = job.GetAllExistingPullRequests()
538
+ .Where(pr => pr.Item2.Any(d => d.DependencyName.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase) && d.DependencyVersion >= dependencyVersion))
539
+ .ToArray();
540
+ if (existingPullRequests.Length > 0)
541
+ {
542
+ var existingPrVersion = existingPullRequests[0].Item2.First(d => d.DependencyName.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase)).DependencyVersion;
543
+ message = new PullRequestExistsForLatestVersion(dependency.Name, existingPrVersion.ToString());
544
+ return false;
545
+ }
546
+ }
547
+ else
548
+ {
549
+ // not vulnerable => no longer needed
550
+ var specificJobDependencies = job.SecurityAdvisories
551
+ .Select(a => a.DependencyName)
552
+ .Concat(job.Dependencies ?? [])
553
+ .ToHashSet(StringComparer.OrdinalIgnoreCase);
554
+ if (specificJobDependencies.Contains(dependency.Name))
555
+ {
556
+ message = new SecurityUpdateNotNeeded(dependency.Name);
557
+ }
558
+ }
559
+
404
560
  return isVulnerable;
405
561
  }
406
562
  else
@@ -417,7 +573,7 @@ public class RunWorker
417
573
  }
418
574
  });
419
575
 
420
- return allowed;
576
+ return (allowed, message);
421
577
  }
422
578
 
423
579
  internal static ImmutableArray<Requirement> GetIgnoredRequirementsForDependency(Job job, string dependencyName)
@@ -1,5 +1,4 @@
1
1
  using System.Collections.Immutable;
2
- using System.Runtime.InteropServices;
3
2
  using System.Text.Json;
4
3
 
5
4
  using NuGetUpdater.Core.Discover;
@@ -1434,4 +1433,80 @@ public partial class DiscoveryWorkerTests : DiscoveryWorkerTestBase
1434
1433
  }
1435
1434
  );
1436
1435
  }
1436
+
1437
+ [Fact]
1438
+ public async Task CentralPackageManagementStillWorksWithMultipleFeedsListedInConfig()
1439
+ {
1440
+ // If a repo doesn't contain a `NuGet.Config` file and `dependabot.yml` specifies a package source, a user-
1441
+ // local `NuGet.Config` file is created before the updater is run that enumerates the specified feeds as well
1442
+ // as `api.nuget.org`. If a given project is using Central Package Management a warning NU1507 will be
1443
+ // generated because of the multiple feeds listed. If that project _also_ specifies $(TreatWarningsAsErrors)
1444
+ // as true, this will cause dependency discovery to "fail". To simulate this, multiple remote NuGet sources
1445
+ // need to be listed in the `NuGet.Config` file in this test.
1446
+ using var http1 = TestHttpServer.CreateTestNuGetFeed(MockNuGetPackage.CreateSimplePackage("Package1", "1.0.0", "net9.0"));
1447
+ using var http2 = TestHttpServer.CreateTestNuGetFeed(MockNuGetPackage.CreateSimplePackage("Package2", "2.0.0", "net9.0"));
1448
+ await TestDiscoveryAsync(
1449
+ packages: [],
1450
+ experimentsManager: new ExperimentsManager() { UseDirectDiscovery = true },
1451
+ workspacePath: "/src",
1452
+ files: [
1453
+ ("src/NuGet.Config", $"""
1454
+ <configuration>
1455
+ <packageSources>
1456
+ <!-- explicitly _not_ calling "clear" because we also want the upstream sources in addition to these two remote sources -->
1457
+ <add key="source_1" value="{http1.GetPackageFeedIndex()}" allowInsecureConnections="true" />
1458
+ <add key="source_2" value="{http2.GetPackageFeedIndex()}" allowInsecureConnections="true" />
1459
+ </packageSources>
1460
+ </configuration>
1461
+ """),
1462
+ ("src/project.csproj", """
1463
+ <Project Sdk="Microsoft.NET.Sdk">
1464
+ <PropertyGroup>
1465
+ <TargetFramework>net9.0</TargetFramework>
1466
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
1467
+ <MSBuildTreatWarningsAsErrors>true</MSBuildTreatWarningsAsErrors>
1468
+ </PropertyGroup>
1469
+ <ItemGroup>
1470
+ <PackageReference Include="Package1" />
1471
+ <PackageReference Include="Package2" />
1472
+ </ItemGroup>
1473
+ </Project>
1474
+ """),
1475
+ ("src/Directory.Packages.props", """
1476
+ <Project>
1477
+ <PropertyGroup>
1478
+ <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
1479
+ </PropertyGroup>
1480
+ <ItemGroup>
1481
+ <PackageVersion Include="Package1" Version="1.0.0" />
1482
+ <PackageVersion Include="Package2" Version="2.0.0" />
1483
+ </ItemGroup>
1484
+ </Project>
1485
+ """)
1486
+ ],
1487
+ expectedResult: new()
1488
+ {
1489
+ Path = "src",
1490
+ Projects = [
1491
+ new()
1492
+ {
1493
+ FilePath = "project.csproj",
1494
+ TargetFrameworks = ["net9.0"],
1495
+ Dependencies = [
1496
+ new("Package1", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net9.0"], IsDirect: true),
1497
+ new("Package2", "2.0.0", DependencyType.PackageReference, TargetFrameworks: ["net9.0"], IsDirect: true),
1498
+ ],
1499
+ Properties = [
1500
+ new("MSBuildTreatWarningsAsErrors", "false", "src/project.csproj"), // this was specifically overridden by discovery
1501
+ new("TargetFramework", "net9.0", "src/project.csproj"),
1502
+ new("TreatWarningsAsErrors", "false", "src/project.csproj"), // this was specifically overridden by discovery
1503
+ ],
1504
+ ReferencedProjectPaths = [],
1505
+ ImportedFiles = ["Directory.Packages.props"],
1506
+ AdditionalFiles = [],
1507
+ }
1508
+ ]
1509
+ }
1510
+ );
1511
+ }
1437
1512
  }
@@ -58,7 +58,7 @@ public class MiscellaneousTests
58
58
  public void GetUpdateOperations(WorkspaceDiscoveryResult discovery, (string ProjectPath, string DependencyName)[] expectedUpdateOperations)
59
59
  {
60
60
  var updateOperations = RunWorker.GetUpdateOperations(discovery).ToArray();
61
- var actualUpdateOperations = updateOperations.Select(uo => (uo.FilePath, uo.Dependency.Name)).ToArray();
61
+ var actualUpdateOperations = updateOperations.Select(uo => (uo.ProjectPath, uo.Dependency.Name)).ToArray();
62
62
  Assert.Equal(expectedUpdateOperations, actualUpdateOperations);
63
63
  }
64
64