dependabot-nuget 0.309.0 → 0.311.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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/Directory.Packages.props +1 -1
  3. data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Test/DotNetPackageCorrelation.Test.csproj +1 -1
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Run.cs +6 -6
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/NuGetUpdater.Cli.Test.csproj +1 -1
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/ClosePullRequest.cs +13 -0
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/CreatePullRequest.cs +20 -0
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +1 -2
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +19 -0
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/MessageBase.cs +1 -0
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/UpdatePullRequest.cs +16 -0
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/HttpApiHandler.cs +12 -3
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestTextGenerator.cs +49 -13
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +31 -6
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdateOperationBase.cs +1 -2
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/DependencyConflictResolver.cs +6 -33
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +12 -1
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +3 -3
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +2 -2
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +37 -2
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/NuGetUpdater.Core.Test.csproj +1 -1
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/EndToEndTests.cs +355 -0
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MessageReportTests.cs +232 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestTextTests.cs +32 -8
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +1212 -840
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +4 -2
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestHttpServer.cs +16 -6
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateOperationBaseTests.cs +3 -3
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +1 -13
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/EOLHandlingTests.cs +227 -13
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/LoggerTests.cs +0 -1
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +382 -165
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/PathHelperTests.cs +1 -1
  34. data/helpers/lib/NuGetUpdater/global.json +1 -1
  35. metadata +11 -9
@@ -27,11 +27,8 @@ public class RunWorkerTests
27
27
  public const string TestPullRequestTitle = "test-pull-request-title";
28
28
  public const string TestPullRequestBody = "test-pull-request-body";
29
29
 
30
- [Theory]
31
- [InlineData(EOLType.CR)]
32
- [InlineData(EOLType.LF)]
33
- [InlineData(EOLType.CRLF)]
34
- public async Task UpdateSinglePackageProducedExpectedAPIMessages(EOLType EOL)
30
+ [Fact]
31
+ public async Task UpdateSinglePackageProducedExpectedAPIMessages()
35
32
  {
36
33
  await RunAsync(
37
34
  packages: [],
@@ -55,7 +52,7 @@ public class RunWorkerTests
55
52
  <PackageReference Include="Some.Package" Version="1.0.0" />
56
53
  </ItemGroup>
57
54
  </Project>
58
- """.SetEOL(EOL))
55
+ """)
59
56
  ],
60
57
  discoveryWorker: new TestDiscoveryWorker(_input =>
61
58
  {
@@ -106,7 +103,7 @@ public class RunWorkerTests
106
103
  <PackageReference Include="Some.Package" Version="1.0.1" />
107
104
  </ItemGroup>
108
105
  </Project>
109
- """.SetEOL(EOL));
106
+ """);
110
107
  return new UpdateOperationResult()
111
108
  {
112
109
  UpdateOperations = [
@@ -136,7 +133,7 @@ public class RunWorkerTests
136
133
  <PackageReference Include="Some.Package" Version="1.0.0" />
137
134
  </ItemGroup>
138
135
  </Project>
139
- """.SetEOL(EOL))),
136
+ """)),
140
137
  ContentEncoding = "base64"
141
138
  }
142
139
  ],
@@ -222,7 +219,7 @@ public class RunWorkerTests
222
219
  <PackageReference Include="Some.Package" Version="1.0.1" />
223
220
  </ItemGroup>
224
221
  </Project>
225
- """.SetEOL(EOL),
222
+ """,
226
223
  },
227
224
  ],
228
225
  BaseCommitSha = "TEST-COMMIT-SHA",
@@ -235,14 +232,11 @@ public class RunWorkerTests
235
232
  );
236
233
  }
237
234
 
238
- [Theory]
239
- [InlineData(EOLType.CR)]
240
- [InlineData(EOLType.LF)]
241
- [InlineData(EOLType.CRLF)]
242
- public async Task UpdateHandlesSemicolonsInPackageReference(EOLType EOL)
235
+ [Fact]
236
+ public async Task UpdateHandlesSemicolonsInPackageReference()
243
237
  {
244
- var repoMetadata = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package" />""".SetEOL(EOL));
245
- var repoMetadata2 = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package2" />""".SetEOL(EOL));
238
+ var repoMetadata = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package" />""");
239
+ var repoMetadata2 = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package2" />""");
246
240
  await RunAsync(
247
241
  packages:
248
242
  [
@@ -272,7 +266,7 @@ public class RunWorkerTests
272
266
  <PackageReference Include="Some.Package;Some.Package2" Version="1.0.0" />
273
267
  </ItemGroup>
274
268
  </Project>
275
- """.SetEOL(EOL))
269
+ """)
276
270
  ],
277
271
  discoveryWorker: new TestDiscoveryWorker(_input =>
278
272
  {
@@ -325,7 +319,7 @@ public class RunWorkerTests
325
319
  <PackageReference Include="Some.Package;Some.Package2" Version="1.0.1" />
326
320
  </ItemGroup>
327
321
  </Project>
328
- """.SetEOL(EOL));
322
+ """);
329
323
  return new UpdateOperationResult()
330
324
  {
331
325
  UpdateOperations = [
@@ -361,7 +355,7 @@ public class RunWorkerTests
361
355
  <PackageReference Include="Some.Package;Some.Package2" Version="1.0.0" />
362
356
  </ItemGroup>
363
357
  </Project>
364
- """.SetEOL(EOL))),
358
+ """)),
365
359
  ContentEncoding = "base64"
366
360
  }
367
361
  ],
@@ -490,7 +484,7 @@ public class RunWorkerTests
490
484
  <PackageReference Include="Some.Package;Some.Package2" Version="1.0.1" />
491
485
  </ItemGroup>
492
486
  </Project>
493
- """.SetEOL(EOL),
487
+ """,
494
488
  }
495
489
 
496
490
  ],
@@ -504,11 +498,8 @@ public class RunWorkerTests
504
498
  );
505
499
  }
506
500
 
507
- [Theory]
508
- [InlineData(EOLType.CR)]
509
- [InlineData(EOLType.LF)]
510
- [InlineData(EOLType.CRLF)]
511
- public async Task PrivateSourceAuthenticationFailureIsForwaredToApiHandler(EOLType EOL)
501
+ [Fact]
502
+ public async Task ErrorsThrownFromDiscoveryWorkerAreForwaredToApiHandler()
512
503
  {
513
504
  await RunAsync(
514
505
  packages:
@@ -532,7 +523,7 @@ public class RunWorkerTests
532
523
  <add key="private_feed" value="http://example.com/nuget/index.json" allowInsecureConnections="true" />
533
524
  </packageSources>
534
525
  </configuration>
535
- """.SetEOL(EOL)),
526
+ """),
536
527
  ("project.csproj", """
537
528
  <Project Sdk="Microsoft.NET.Sdk">
538
529
  <PropertyGroup>
@@ -542,14 +533,14 @@ public class RunWorkerTests
542
533
  <PackageReference Include="Some.Package" Version="1.0.0" />
543
534
  </ItemGroup>
544
535
  </Project>
545
- """.SetEOL(EOL))
536
+ """)
546
537
  ],
547
538
  discoveryWorker: new TestDiscoveryWorker((_input) =>
548
539
  {
549
540
  throw new HttpRequestException(message: null, inner: null, statusCode: HttpStatusCode.Unauthorized);
550
541
  }),
551
- analyzeWorker: TestAnalyzeWorker.FromResults(),
552
- updaterWorker: TestUpdaterWorker.FromResults(),
542
+ analyzeWorker: new TestAnalyzeWorker((_input) => throw new NotImplementedException("shouldn't get this far")),
543
+ updaterWorker: new TestUpdaterWorker((_input) => throw new NotImplementedException("shouldn't get this far")),
553
544
  expectedResult: new RunResult()
554
545
  {
555
546
  Base64DependencyFiles = [],
@@ -563,35 +554,71 @@ public class RunWorkerTests
563
554
  );
564
555
  }
565
556
 
566
- [Theory]
567
- [InlineData(EOLType.CR)]
568
- [InlineData(EOLType.LF)]
569
- [InlineData(EOLType.CRLF)]
570
- public async Task UpdateHandlesPackagesConfigFiles(EOLType EOL)
557
+ [Fact]
558
+ public async Task ErrorsReturnedFromDiscoveryWorkerAreForwaredToApiHandler()
571
559
  {
572
- var repoMetadata = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package" />""".SetEOL(EOL));
573
- var repoMetadata2 = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package2" />""".SetEOL(EOL));
574
560
  await RunAsync(
575
- packages:
561
+ packages: [],
562
+ job: new Job()
563
+ {
564
+ Source = new()
565
+ {
566
+ Provider = "github",
567
+ Repo = "test/repo",
568
+ Directory = "/",
569
+ }
570
+ },
571
+ files: [],
572
+ discoveryWorker: new TestDiscoveryWorker((_input) =>
573
+ {
574
+ return Task.FromResult(new WorkspaceDiscoveryResult()
575
+ {
576
+ Path = "/",
577
+ IsSuccess = false,
578
+ Projects = [],
579
+ Error = new PrivateSourceAuthenticationFailure(["http://example.com/nuget/index.json"]),
580
+ });
581
+ }),
582
+ analyzeWorker: new TestAnalyzeWorker((_input) => throw new NotImplementedException("shouldn't get this far")),
583
+ updaterWorker: new TestUpdaterWorker((_input) => throw new NotImplementedException("shouldn't get this far")),
584
+ expectedResult: new RunResult()
585
+ {
586
+ Base64DependencyFiles = [],
587
+ BaseCommitSha = "TEST-COMMIT-SHA",
588
+ },
589
+ expectedApiMessages:
576
590
  [
577
- MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0", additionalMetadata: [repoMetadata]),
578
- MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.1", "net8.0", additionalMetadata: [repoMetadata]),
579
- MockNuGetPackage.CreateSimplePackage("Some.Package2", "2.0.0", "net8.0", additionalMetadata: [repoMetadata2]),
580
- MockNuGetPackage.CreateSimplePackage("Some.Package2", "2.0.1", "net8.0", additionalMetadata: [repoMetadata2]),
581
- ],
591
+ new PrivateSourceAuthenticationFailure(["http://example.com/nuget/index.json"]),
592
+ new MarkAsProcessed("TEST-COMMIT-SHA")
593
+ ]
594
+ );
595
+ }
596
+
597
+ [Fact]
598
+ public async Task ErrorsThrownFromAnalyzeWorkerAreForwaredToApiHandler()
599
+ {
600
+ await RunAsync(
601
+ packages: [],
582
602
  job: new Job()
583
603
  {
584
- PackageManager = "nuget",
585
604
  Source = new()
586
605
  {
587
606
  Provider = "github",
588
607
  Repo = "test/repo",
589
- Directory = "some-dir",
608
+ Directory = "/",
590
609
  }
591
610
  },
592
611
  files:
593
612
  [
594
- ("some-dir/project.csproj", """
613
+ ("NuGet.Config", """
614
+ <configuration>
615
+ <packageSources>
616
+ <clear />
617
+ <add key="private_feed" value="http://example.com/nuget/index.json" allowInsecureConnections="true" />
618
+ </packageSources>
619
+ </configuration>
620
+ """),
621
+ ("project.csproj", """
595
622
  <Project Sdk="Microsoft.NET.Sdk">
596
623
  <PropertyGroup>
597
624
  <TargetFramework>net8.0</TargetFramework>
@@ -600,147 +627,131 @@ public class RunWorkerTests
600
627
  <PackageReference Include="Some.Package" Version="1.0.0" />
601
628
  </ItemGroup>
602
629
  </Project>
603
- """.SetEOL(EOL)),
604
- ("some-dir/packages.config", """
605
- <?xml version="1.0" encoding="utf-8"?>
606
- <packages>
607
- <package id="Some.Package2" version="2.0.0" targetFramework="net8.0" />
608
- </packages>
609
- """.SetEOL(EOL)),
630
+ """)
610
631
  ],
611
- discoveryWorker: new TestDiscoveryWorker(_input =>
632
+ discoveryWorker: new TestDiscoveryWorker((_input) =>
612
633
  {
613
634
  return Task.FromResult(new WorkspaceDiscoveryResult()
614
635
  {
615
- Path = "some-dir",
616
- Projects =
617
- [
636
+ Path = "",
637
+ Projects = [
618
638
  new()
619
639
  {
620
640
  FilePath = "project.csproj",
621
- TargetFrameworks = ["net8.0"],
622
- Dependencies =
623
- [
624
- new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"]),
625
- new("Some.Package2", "2.0.0", DependencyType.PackagesConfig, TargetFrameworks: ["net8.0"]),
626
- ],
627
- ReferencedProjectPaths = [],
641
+ Dependencies = [new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"])],
628
642
  ImportedFiles = [],
629
- AdditionalFiles = ["packages.config"],
643
+ AdditionalFiles = [],
630
644
  }
631
645
  ]
632
646
  });
633
647
  }),
634
- analyzeWorker: new TestAnalyzeWorker(input =>
648
+ analyzeWorker: new TestAnalyzeWorker((_input) =>
635
649
  {
636
- var result = input.Item3.Name switch
650
+ throw new HttpRequestException(message: null, inner: null, statusCode: HttpStatusCode.Unauthorized);
651
+ }),
652
+ updaterWorker: new TestUpdaterWorker((_input) => throw new NotImplementedException("shouldn't get this far")),
653
+ expectedResult: new RunResult()
654
+ {
655
+ Base64DependencyFiles = [],
656
+ BaseCommitSha = "TEST-COMMIT-SHA",
657
+ },
658
+ expectedApiMessages:
659
+ [
660
+ new UpdatedDependencyList()
637
661
  {
638
- "Some.Package" => new AnalysisResult()
639
- {
640
- CanUpdate = true,
641
- UpdatedVersion = "1.0.1",
642
- UpdatedDependencies =
662
+ Dependencies =
663
+ [
664
+ new ReportedDependency()
665
+ {
666
+ Name = "Some.Package",
667
+ Version = "1.0.0",
668
+ Requirements =
643
669
  [
644
- new("Some.Package", "1.0.1", DependencyType.Unknown, TargetFrameworks: ["net8.0"], InfoUrl: "https://nuget.example.com/some-package"),
670
+ new ReportedRequirement()
671
+ {
672
+ Requirement = "1.0.0",
673
+ File = "/project.csproj",
674
+ Groups = ["dependencies"],
675
+ }
645
676
  ]
646
- },
647
- "Some.Package2" => new AnalysisResult()
677
+ }
678
+ ],
679
+ DependencyFiles = ["/project.csproj"],
680
+ },
681
+ new IncrementMetric()
682
+ {
683
+ Metric = "updater.started",
684
+ Tags = new()
648
685
  {
649
- CanUpdate = true,
650
- UpdatedVersion = "2.0.1",
651
- UpdatedDependencies =
652
- [
653
- new("Some.Package2", "2.0.1", DependencyType.Unknown, TargetFrameworks: ["net8.0"], InfoUrl: "https://nuget.example.com/some-package2"),
654
- ]
655
- },
656
- _ => throw new NotSupportedException(),
657
- };
658
- return Task.FromResult(result);
659
- }),
660
- updaterWorker: new TestUpdaterWorker(async input =>
661
- {
662
- var repoRootPath = input.Item1;
663
- var filePath = input.Item2;
664
- var packageName = input.Item3;
665
- var previousVersion = input.Item4;
666
- var newVersion = input.Item5;
667
- var _isTransitive = input.Item6;
686
+ ["operation"] = "group_update_all_versions"
687
+ }
688
+ },
689
+ new PrivateSourceAuthenticationFailure(["http://example.com/nuget/index.json"]),
690
+ new MarkAsProcessed("TEST-COMMIT-SHA")
691
+ ]
692
+ );
693
+ }
668
694
 
669
- var projectPath = Path.Join(repoRootPath, filePath);
670
- switch (packageName)
695
+ [Fact]
696
+ public async Task ErrorsReturnedFromAnalyzeWorkerAreForwaredToApiHandler()
697
+ {
698
+ await RunAsync(
699
+ packages: [],
700
+ job: new Job()
701
+ {
702
+ Source = new()
671
703
  {
672
- case "Some.Package":
673
- await File.WriteAllTextAsync(projectPath, """
674
- <Project Sdk="Microsoft.NET.Sdk">
675
- <PropertyGroup>
676
- <TargetFramework>net8.0</TargetFramework>
677
- </PropertyGroup>
678
- <ItemGroup>
679
- <PackageReference Include="Some.Package" Version="1.0.1" />
680
- </ItemGroup>
681
- </Project>
682
- """.SetEOL(EOL));
683
- break;
684
- case "Some.Package2":
685
- await File.WriteAllTextAsync(projectPath, """
686
- <Project Sdk="Microsoft.NET.Sdk">
687
- <PropertyGroup>
688
- <TargetFramework>net8.0</TargetFramework>
689
- </PropertyGroup>
690
- <ItemGroup>
691
- <PackageReference Include="Some.Package" Version="1.0.1" />
692
- </ItemGroup>
693
- <ItemGroup>
694
- <Reference Include="Some.Package2">
695
- <HintPath>..\packages\Some.Package2.2.0.1\lib\net8.0\Some.Package2.dll</HintPath>
696
- <Private>True</Private>
697
- </Reference>
698
- </ItemGroup>
699
- </Project>
700
- """.SetEOL(EOL));
701
- var packagesConfigPath = Path.Join(Path.GetDirectoryName(projectPath)!, "packages.config");
702
- await File.WriteAllTextAsync(packagesConfigPath, """
703
- <?xml version="1.0" encoding="utf-8"?>
704
- <packages>
705
- <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
706
- </packages>
707
- """.SetEOL(EOL));
708
- break;
709
- default:
710
- throw new NotSupportedException();
704
+ Provider = "github",
705
+ Repo = "test/repo",
706
+ Directory = "/",
711
707
  }
712
-
713
- return new UpdateOperationResult()
708
+ },
709
+ files: [
710
+ ("project.csproj", """
711
+ <Project Sdk="Microsoft.NET.Sdk">
712
+ <PropertyGroup>
713
+ <TargetFramework>net8.0</TargetFramework>
714
+ </PropertyGroup>
715
+ <ItemGroup>
716
+ <PackageReference Include="Some.Package" Version="1.0.0" />
717
+ </ItemGroup>
718
+ </Project>
719
+ """)
720
+ ],
721
+ discoveryWorker: new TestDiscoveryWorker((_input) =>
722
+ {
723
+ return Task.FromResult(new WorkspaceDiscoveryResult()
714
724
  {
715
- UpdateOperations = [
716
- new DirectUpdate()
725
+ Path = "",
726
+ Projects = [
727
+ new()
717
728
  {
718
- DependencyName = packageName,
719
- NewVersion = NuGetVersion.Parse(newVersion),
720
- UpdatedFiles = [filePath]
729
+ FilePath = "project.csproj",
730
+ Dependencies = [new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"])],
731
+ ImportedFiles = [],
732
+ AdditionalFiles = [],
721
733
  }
722
- ],
723
- };
734
+ ]
735
+ });
736
+ }),
737
+ analyzeWorker: new TestAnalyzeWorker((_input) =>
738
+ {
739
+ return Task.FromResult(new AnalysisResult()
740
+ {
741
+ UpdatedVersion = "",
742
+ CanUpdate = false,
743
+ VersionComesFromMultiDependencyProperty = false,
744
+ UpdatedDependencies = [],
745
+ Error = new PrivateSourceAuthenticationFailure(["http://example.com/nuget/index.json"]),
746
+ });
724
747
  }),
748
+ updaterWorker: new TestUpdaterWorker((_input) => throw new NotImplementedException("shouldn't get this far")),
725
749
  expectedResult: new RunResult()
726
750
  {
727
- Base64DependencyFiles =
728
- [
729
- new DependencyFile()
730
- {
731
- Directory = "/some-dir",
732
- Name = "packages.config",
733
- Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
734
- <?xml version="1.0" encoding="utf-8"?>
735
- <packages>
736
- <package id="Some.Package2" version="2.0.0" targetFramework="net8.0" />
737
- </packages>
738
- """.SetEOL(EOL))),
739
- ContentEncoding = "base64"
740
- },
741
- new DependencyFile()
751
+ Base64DependencyFiles = [
752
+ new()
742
753
  {
743
- Directory = "/some-dir",
754
+ Directory = "/",
744
755
  Name = "project.csproj",
745
756
  Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
746
757
  <Project Sdk="Microsoft.NET.Sdk">
@@ -751,9 +762,9 @@ public class RunWorkerTests
751
762
  <PackageReference Include="Some.Package" Version="1.0.0" />
752
763
  </ItemGroup>
753
764
  </Project>
754
- """.SetEOL(EOL))),
765
+ """)),
755
766
  ContentEncoding = "base64"
756
- },
767
+ }
757
768
  ],
758
769
  BaseCommitSha = "TEST-COMMIT-SHA",
759
770
  },
@@ -772,27 +783,13 @@ public class RunWorkerTests
772
783
  new ReportedRequirement()
773
784
  {
774
785
  Requirement = "1.0.0",
775
- File = "/some-dir/project.csproj",
776
- Groups = ["dependencies"],
777
- }
778
- ]
779
- },
780
- new ReportedDependency()
781
- {
782
- Name = "Some.Package2",
783
- Version = "2.0.0",
784
- Requirements =
785
- [
786
- new ReportedRequirement()
787
- {
788
- Requirement = "2.0.0",
789
- File = "/some-dir/project.csproj",
786
+ File = "/project.csproj",
790
787
  Groups = ["dependencies"],
791
788
  }
792
789
  ]
793
790
  }
794
791
  ],
795
- DependencyFiles = ["/some-dir/packages.config", "/some-dir/project.csproj"],
792
+ DependencyFiles = ["/project.csproj"],
796
793
  },
797
794
  new IncrementMetric()
798
795
  {
@@ -802,122 +799,248 @@ public class RunWorkerTests
802
799
  ["operation"] = "group_update_all_versions"
803
800
  }
804
801
  },
805
- new CreatePullRequest()
802
+ new PrivateSourceAuthenticationFailure(["http://example.com/nuget/index.json"]),
803
+ new MarkAsProcessed("TEST-COMMIT-SHA")
804
+ ]
805
+ );
806
+ }
807
+
808
+ [Fact]
809
+ public async Task ErrorsThrownFromUpdaterWorkerAreForwaredToApiHandler()
810
+ {
811
+ await RunAsync(
812
+ packages: [],
813
+ job: new Job()
814
+ {
815
+ Source = new()
816
+ {
817
+ Provider = "github",
818
+ Repo = "test/repo",
819
+ Directory = "/",
820
+ }
821
+ },
822
+ files:
823
+ [
824
+ ("NuGet.Config", """
825
+ <configuration>
826
+ <packageSources>
827
+ <clear />
828
+ <add key="private_feed" value="http://example.com/nuget/index.json" allowInsecureConnections="true" />
829
+ </packageSources>
830
+ </configuration>
831
+ """),
832
+ ("project.csproj", """
833
+ <Project Sdk="Microsoft.NET.Sdk">
834
+ <PropertyGroup>
835
+ <TargetFramework>net8.0</TargetFramework>
836
+ </PropertyGroup>
837
+ <ItemGroup>
838
+ <PackageReference Include="Some.Package" Version="1.0.0" />
839
+ </ItemGroup>
840
+ </Project>
841
+ """)
842
+ ],
843
+ discoveryWorker: new TestDiscoveryWorker((_input) =>
844
+ {
845
+ return Task.FromResult(new WorkspaceDiscoveryResult()
846
+ {
847
+ Path = "",
848
+ Projects = [
849
+ new()
850
+ {
851
+ FilePath = "project.csproj",
852
+ Dependencies = [new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"])],
853
+ ImportedFiles = [],
854
+ AdditionalFiles = [],
855
+ }
856
+ ]
857
+ });
858
+ }),
859
+ analyzeWorker: new TestAnalyzeWorker((_input) =>
860
+ {
861
+ return Task.FromResult(new AnalysisResult()
862
+ {
863
+ UpdatedVersion = "1.0.1",
864
+ CanUpdate = true,
865
+ UpdatedDependencies =
866
+ [
867
+ new("Some.Package", "1.0.1", DependencyType.Unknown, TargetFrameworks: ["net8.0"], InfoUrl: "https://nuget.example.com/some-package"),
868
+ ]
869
+ });
870
+ }),
871
+ updaterWorker: new TestUpdaterWorker((_input) =>
872
+ {
873
+ throw new HttpRequestException(message: null, inner: null, statusCode: HttpStatusCode.Unauthorized);
874
+ }),
875
+ expectedResult: new RunResult()
876
+ {
877
+ Base64DependencyFiles = [],
878
+ BaseCommitSha = "TEST-COMMIT-SHA",
879
+ },
880
+ expectedApiMessages:
881
+ [
882
+ new UpdatedDependencyList()
806
883
  {
807
884
  Dependencies =
808
885
  [
809
886
  new ReportedDependency()
810
887
  {
811
888
  Name = "Some.Package",
812
- Version = "1.0.1",
889
+ Version = "1.0.0",
813
890
  Requirements =
814
- [
815
- new ReportedRequirement()
816
- {
817
- Requirement = "1.0.1",
818
- File = "/some-dir/project.csproj",
819
- Groups = ["dependencies"],
820
- Source = new()
821
- {
822
- SourceUrl = "https://nuget.example.com/some-package",
823
- Type = "nuget_repo",
824
- }
825
- }
826
- ],
827
- PreviousVersion = "1.0.0",
828
- PreviousRequirements =
829
891
  [
830
892
  new ReportedRequirement()
831
893
  {
832
894
  Requirement = "1.0.0",
833
- File = "/some-dir/project.csproj",
895
+ File = "/project.csproj",
834
896
  Groups = ["dependencies"],
835
897
  }
836
- ],
837
- },
898
+ ]
899
+ }
900
+ ],
901
+ DependencyFiles = ["/project.csproj"],
902
+ },
903
+ new IncrementMetric()
904
+ {
905
+ Metric = "updater.started",
906
+ Tags = new()
907
+ {
908
+ ["operation"] = "group_update_all_versions"
909
+ }
910
+ },
911
+ new PrivateSourceAuthenticationFailure(["http://example.com/nuget/index.json"]),
912
+ new MarkAsProcessed("TEST-COMMIT-SHA")
913
+ ]
914
+ );
915
+ }
916
+
917
+ [Fact]
918
+ public async Task ErrorsReturnedFromUpdaterWorkerAreForwaredToApiHandler()
919
+ {
920
+ await RunAsync(
921
+ packages: [],
922
+ job: new Job()
923
+ {
924
+ Source = new()
925
+ {
926
+ Provider = "github",
927
+ Repo = "test/repo",
928
+ Directory = "/",
929
+ }
930
+ },
931
+ files:
932
+ [
933
+ ("project.csproj", """
934
+ <Project Sdk="Microsoft.NET.Sdk">
935
+ <PropertyGroup>
936
+ <TargetFramework>net8.0</TargetFramework>
937
+ </PropertyGroup>
938
+ <ItemGroup>
939
+ <PackageReference Include="Some.Package" Version="1.0.0" />
940
+ </ItemGroup>
941
+ </Project>
942
+ """)
943
+ ],
944
+ discoveryWorker: new TestDiscoveryWorker((_input) =>
945
+ {
946
+ return Task.FromResult(new WorkspaceDiscoveryResult()
947
+ {
948
+ Path = "",
949
+ Projects = [
950
+ new()
951
+ {
952
+ FilePath = "project.csproj",
953
+ Dependencies = [new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"])],
954
+ ImportedFiles = [],
955
+ AdditionalFiles = [],
956
+ }
957
+ ]
958
+ });
959
+ }),
960
+ analyzeWorker: new TestAnalyzeWorker((_input) =>
961
+ {
962
+ return Task.FromResult(new AnalysisResult()
963
+ {
964
+ UpdatedVersion = "1.0.1",
965
+ CanUpdate = true,
966
+ UpdatedDependencies =
967
+ [
968
+ new("Some.Package", "1.0.1", DependencyType.Unknown, TargetFrameworks: ["net8.0"], InfoUrl: "https://nuget.example.com/some-package"),
969
+ ]
970
+ });
971
+ }),
972
+ updaterWorker: new TestUpdaterWorker((_input) =>
973
+ {
974
+ return Task.FromResult(new UpdateOperationResult()
975
+ {
976
+ UpdateOperations = [],
977
+ Error = new PrivateSourceAuthenticationFailure(["http://example.com/nuget/index.json"]),
978
+ });
979
+ }),
980
+ expectedResult: new RunResult()
981
+ {
982
+ Base64DependencyFiles = [
983
+ new()
984
+ {
985
+ Directory = "/",
986
+ Name = "project.csproj",
987
+ Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
988
+ <Project Sdk="Microsoft.NET.Sdk">
989
+ <PropertyGroup>
990
+ <TargetFramework>net8.0</TargetFramework>
991
+ </PropertyGroup>
992
+ <ItemGroup>
993
+ <PackageReference Include="Some.Package" Version="1.0.0" />
994
+ </ItemGroup>
995
+ </Project>
996
+ """)),
997
+ ContentEncoding = "base64"
998
+ }
999
+ ],
1000
+ BaseCommitSha = "TEST-COMMIT-SHA",
1001
+ },
1002
+ expectedApiMessages:
1003
+ [
1004
+ new UpdatedDependencyList()
1005
+ {
1006
+ Dependencies =
1007
+ [
838
1008
  new ReportedDependency()
839
1009
  {
840
- Name = "Some.Package2",
841
- Version = "2.0.1",
1010
+ Name = "Some.Package",
1011
+ Version = "1.0.0",
842
1012
  Requirements =
843
1013
  [
844
1014
  new ReportedRequirement()
845
1015
  {
846
- Requirement = "2.0.1",
847
- File = "/some-dir/project.csproj",
848
- Groups = ["dependencies"],
849
- Source = new()
850
- {
851
- SourceUrl = "https://nuget.example.com/some-package2",
852
- Type = "nuget_repo",
853
- }
854
- }
855
- ],
856
- PreviousVersion = "2.0.0",
857
- PreviousRequirements =
858
- [
859
- new ReportedRequirement()
860
- {
861
- Requirement = "2.0.0",
862
- File = "/some-dir/project.csproj",
1016
+ Requirement = "1.0.0",
1017
+ File = "/project.csproj",
863
1018
  Groups = ["dependencies"],
864
1019
  }
865
- ],
866
- },
867
- ],
868
- UpdatedDependencyFiles =
869
- [
870
- new DependencyFile()
871
- {
872
- Name = "packages.config",
873
- Directory = "/some-dir",
874
- Content = """
875
- <?xml version="1.0" encoding="utf-8"?>
876
- <packages>
877
- <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
878
- </packages>
879
- """.SetEOL(EOL),
880
- },
881
- new DependencyFile()
882
- {
883
- Name = "project.csproj",
884
- Directory = "/some-dir",
885
- Content = """
886
- <Project Sdk="Microsoft.NET.Sdk">
887
- <PropertyGroup>
888
- <TargetFramework>net8.0</TargetFramework>
889
- </PropertyGroup>
890
- <ItemGroup>
891
- <PackageReference Include="Some.Package" Version="1.0.1" />
892
- </ItemGroup>
893
- <ItemGroup>
894
- <Reference Include="Some.Package2">
895
- <HintPath>..\packages\Some.Package2.2.0.1\lib\net8.0\Some.Package2.dll</HintPath>
896
- <Private>True</Private>
897
- </Reference>
898
- </ItemGroup>
899
- </Project>
900
- """.SetEOL(EOL),
901
- },
1020
+ ]
1021
+ }
902
1022
  ],
903
- BaseCommitSha = "TEST-COMMIT-SHA",
904
- CommitMessage = TestPullRequestCommitMessage,
905
- PrTitle = TestPullRequestTitle,
906
- PrBody = TestPullRequestBody,
1023
+ DependencyFiles = ["/project.csproj"],
1024
+ },
1025
+ new IncrementMetric()
1026
+ {
1027
+ Metric = "updater.started",
1028
+ Tags = new()
1029
+ {
1030
+ ["operation"] = "group_update_all_versions"
1031
+ }
907
1032
  },
1033
+ new PrivateSourceAuthenticationFailure(["http://example.com/nuget/index.json"]),
908
1034
  new MarkAsProcessed("TEST-COMMIT-SHA")
909
1035
  ]
910
1036
  );
911
1037
  }
912
1038
 
913
- [Theory]
914
- [InlineData(EOLType.CR)]
915
- [InlineData(EOLType.LF)]
916
- [InlineData(EOLType.CRLF)]
917
- public async Task UpdateHandlesPackagesConfigFromReferencedCsprojFiles(EOLType EOL)
1039
+ [Fact]
1040
+ public async Task UpdateHandlesPackagesConfigFiles()
918
1041
  {
919
- var repoMetadata = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package" />""".SetEOL(EOL));
920
- var repoMetadata2 = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package2" />""".SetEOL(EOL));
1042
+ var repoMetadata = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package" />""");
1043
+ var repoMetadata2 = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package2" />""");
921
1044
  await RunAsync(
922
1045
  packages:
923
1046
  [
@@ -933,31 +1056,12 @@ public class RunWorkerTests
933
1056
  {
934
1057
  Provider = "github",
935
1058
  Repo = "test/repo",
936
- Directory = "some-dir/ProjectA",
1059
+ Directory = "some-dir",
937
1060
  }
938
1061
  },
939
1062
  files:
940
1063
  [
941
- ("some-dir/ProjectA/ProjectA.csproj", """
942
- <Project Sdk="Microsoft.NET.Sdk">
943
- <PropertyGroup>
944
- <TargetFramework>net8.0</TargetFramework>
945
- </PropertyGroup>
946
- <ItemGroup>
947
- <PackageReference Include="Some.Package" Version="1.0.0" />
948
- </ItemGroup>
949
- <ItemGroup>
950
- <ProjectReference Include="../ProjectB/ProjectB.csproj" />
951
- </ItemGroup>
952
- </Project>
953
- """.SetEOL(EOL)),
954
- ("some-dir/ProjectA/packages.config", """
955
- <?xml version="1.0" encoding="utf-8"?>
956
- <packages>
957
- <package id="Some.Package2" version="2.0.0" targetFramework="net8.0" />
958
- </packages>
959
- """.SetEOL(EOL)),
960
- ("some-dir/ProjectB/ProjectB.csproj", """
1064
+ ("some-dir/project.csproj", """
961
1065
  <Project Sdk="Microsoft.NET.Sdk">
962
1066
  <PropertyGroup>
963
1067
  <TargetFramework>net8.0</TargetFramework>
@@ -966,37 +1070,24 @@ public class RunWorkerTests
966
1070
  <PackageReference Include="Some.Package" Version="1.0.0" />
967
1071
  </ItemGroup>
968
1072
  </Project>
969
- """.SetEOL(EOL)),
970
- ("some-dir/ProjectB/packages.config", """
1073
+ """),
1074
+ ("some-dir/packages.config", """
971
1075
  <?xml version="1.0" encoding="utf-8"?>
972
1076
  <packages>
973
1077
  <package id="Some.Package2" version="2.0.0" targetFramework="net8.0" />
974
1078
  </packages>
975
- """.SetEOL(EOL)),
1079
+ """),
976
1080
  ],
977
1081
  discoveryWorker: new TestDiscoveryWorker(_input =>
978
1082
  {
979
1083
  return Task.FromResult(new WorkspaceDiscoveryResult()
980
1084
  {
981
- Path = "some-dir/ProjectA",
1085
+ Path = "some-dir",
982
1086
  Projects =
983
1087
  [
984
1088
  new()
985
1089
  {
986
- FilePath = "../ProjectB/ProjectB.csproj",
987
- TargetFrameworks = ["net8.0"],
988
- Dependencies =
989
- [
990
- new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"]),
991
- new("Some.Package2", "2.0.0", DependencyType.PackagesConfig, TargetFrameworks: ["net8.0"]),
992
- ],
993
- ReferencedProjectPaths = [],
994
- ImportedFiles = [],
995
- AdditionalFiles = ["packages.config"],
996
- },
997
- new()
998
- {
999
- FilePath = "ProjectA.csproj",
1090
+ FilePath = "project.csproj",
1000
1091
  TargetFrameworks = ["net8.0"],
1001
1092
  Dependencies =
1002
1093
  [
@@ -1046,53 +1137,9 @@ public class RunWorkerTests
1046
1137
  var _isTransitive = input.Item6;
1047
1138
 
1048
1139
  var projectPath = Path.Join(repoRootPath, filePath);
1049
- var projectName = Path.GetFileName(projectPath);
1050
- var packagesConfigPath = Path.Join(Path.GetDirectoryName(projectPath)!, "packages.config");
1051
- switch ((projectName, packageName))
1140
+ switch (packageName)
1052
1141
  {
1053
- case ("ProjectA.csproj", "Some.Package"):
1054
- await File.WriteAllTextAsync(projectPath, """
1055
- <Project Sdk="Microsoft.NET.Sdk">
1056
- <PropertyGroup>
1057
- <TargetFramework>net8.0</TargetFramework>
1058
- </PropertyGroup>
1059
- <ItemGroup>
1060
- <PackageReference Include="Some.Package" Version="1.0.1" />
1061
- </ItemGroup>
1062
- <ItemGroup>
1063
- <ProjectReference Include="../ProjectB/ProjectB.csproj" />
1064
- </ItemGroup>
1065
- </Project>
1066
- """.SetEOL(EOL));
1067
- break;
1068
- case ("ProjectA.csproj", "Some.Package2"):
1069
- await File.WriteAllTextAsync(projectPath, """
1070
- <Project Sdk="Microsoft.NET.Sdk">
1071
- <PropertyGroup>
1072
- <TargetFramework>net8.0</TargetFramework>
1073
- </PropertyGroup>
1074
- <ItemGroup>
1075
- <PackageReference Include="Some.Package" Version="1.0.1" />
1076
- </ItemGroup>
1077
- <ItemGroup>
1078
- <ProjectReference Include="../ProjectB/ProjectB.csproj" />
1079
- </ItemGroup>
1080
- <ItemGroup>
1081
- <Reference Include="Some.Package2">
1082
- <HintPath>..\packages\Some.Package2.2.0.1\lib\net8.0\Some.Package2.dll</HintPath>
1083
- <Private>True</Private>
1084
- </Reference>
1085
- </ItemGroup>
1086
- </Project>
1087
- """.SetEOL(EOL));
1088
- await File.WriteAllTextAsync(packagesConfigPath, """
1089
- <?xml version="1.0" encoding="utf-8"?>
1090
- <packages>
1091
- <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
1092
- </packages>
1093
- """.SetEOL(EOL));
1094
- break;
1095
- case ("ProjectB.csproj", "Some.Package"):
1142
+ case "Some.Package":
1096
1143
  await File.WriteAllTextAsync(projectPath, """
1097
1144
  <Project Sdk="Microsoft.NET.Sdk">
1098
1145
  <PropertyGroup>
@@ -1101,10 +1148,10 @@ public class RunWorkerTests
1101
1148
  <ItemGroup>
1102
1149
  <PackageReference Include="Some.Package" Version="1.0.1" />
1103
1150
  </ItemGroup>
1104
- </Project>
1105
- """.SetEOL(EOL));
1151
+ </Project>
1152
+ """);
1106
1153
  break;
1107
- case ("ProjectB.csproj", "Some.Package2"):
1154
+ case "Some.Package2":
1108
1155
  await File.WriteAllTextAsync(projectPath, """
1109
1156
  <Project Sdk="Microsoft.NET.Sdk">
1110
1157
  <PropertyGroup>
@@ -1120,13 +1167,14 @@ public class RunWorkerTests
1120
1167
  </Reference>
1121
1168
  </ItemGroup>
1122
1169
  </Project>
1123
- """.SetEOL(EOL));
1170
+ """);
1171
+ var packagesConfigPath = Path.Join(Path.GetDirectoryName(projectPath)!, "packages.config");
1124
1172
  await File.WriteAllTextAsync(packagesConfigPath, """
1125
1173
  <?xml version="1.0" encoding="utf-8"?>
1126
1174
  <packages>
1127
1175
  <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
1128
1176
  </packages>
1129
- """.SetEOL(EOL));
1177
+ """);
1130
1178
  break;
1131
1179
  default:
1132
1180
  throw new NotSupportedException();
@@ -1150,100 +1198,41 @@ public class RunWorkerTests
1150
1198
  [
1151
1199
  new DependencyFile()
1152
1200
  {
1153
- Directory = "/some-dir/ProjectA",
1154
- Name = "packages.config",
1155
- Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1156
- <?xml version="1.0" encoding="utf-8"?>
1157
- <packages>
1158
- <package id="Some.Package2" version="2.0.0" targetFramework="net8.0" />
1159
- </packages>
1160
- """.SetEOL(EOL))),
1161
- ContentEncoding = "base64"
1162
- },
1163
- new DependencyFile()
1164
- {
1165
- Directory = "/some-dir/ProjectA",
1166
- Name = "ProjectA.csproj",
1167
- Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1168
- <Project Sdk="Microsoft.NET.Sdk">
1169
- <PropertyGroup>
1170
- <TargetFramework>net8.0</TargetFramework>
1171
- </PropertyGroup>
1172
- <ItemGroup>
1173
- <PackageReference Include="Some.Package" Version="1.0.0" />
1174
- </ItemGroup>
1175
- <ItemGroup>
1176
- <ProjectReference Include="../ProjectB/ProjectB.csproj" />
1177
- </ItemGroup>
1178
- </Project>
1179
- """.SetEOL(EOL))),
1180
- ContentEncoding = "base64"
1181
- },
1182
- new DependencyFile()
1183
- {
1184
- Directory = "/some-dir/ProjectB",
1201
+ Directory = "/some-dir",
1185
1202
  Name = "packages.config",
1186
1203
  Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1187
1204
  <?xml version="1.0" encoding="utf-8"?>
1188
1205
  <packages>
1189
1206
  <package id="Some.Package2" version="2.0.0" targetFramework="net8.0" />
1190
1207
  </packages>
1191
- """.SetEOL(EOL))),
1192
- ContentEncoding = "base64"
1193
- },
1194
- new DependencyFile()
1195
- {
1196
- Directory = "/some-dir/ProjectB",
1197
- Name = "ProjectB.csproj",
1198
- Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1199
- <Project Sdk="Microsoft.NET.Sdk">
1200
- <PropertyGroup>
1201
- <TargetFramework>net8.0</TargetFramework>
1202
- </PropertyGroup>
1203
- <ItemGroup>
1204
- <PackageReference Include="Some.Package" Version="1.0.0" />
1205
- </ItemGroup>
1206
- </Project>
1207
- """.SetEOL(EOL))),
1208
- ContentEncoding = "base64"
1209
- },
1210
- ],
1211
- BaseCommitSha = "TEST-COMMIT-SHA",
1212
- },
1213
- expectedApiMessages:
1214
- [
1215
- new UpdatedDependencyList()
1216
- {
1217
- Dependencies =
1218
- [
1219
- new ReportedDependency()
1220
- {
1221
- Name = "Some.Package",
1222
- Version = "1.0.0",
1223
- Requirements =
1224
- [
1225
- new ReportedRequirement()
1226
- {
1227
- Requirement = "1.0.0",
1228
- File = "/some-dir/ProjectA/ProjectA.csproj",
1229
- Groups = ["dependencies"],
1230
- }
1231
- ]
1232
- },
1233
- new ReportedDependency()
1234
- {
1235
- Name = "Some.Package2",
1236
- Version = "2.0.0",
1237
- Requirements =
1238
- [
1239
- new ReportedRequirement()
1240
- {
1241
- Requirement = "2.0.0",
1242
- File = "/some-dir/ProjectA/ProjectA.csproj",
1243
- Groups = ["dependencies"],
1244
- }
1245
- ]
1246
- },
1208
+ """)),
1209
+ ContentEncoding = "base64"
1210
+ },
1211
+ new DependencyFile()
1212
+ {
1213
+ Directory = "/some-dir",
1214
+ Name = "project.csproj",
1215
+ Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1216
+ <Project Sdk="Microsoft.NET.Sdk">
1217
+ <PropertyGroup>
1218
+ <TargetFramework>net8.0</TargetFramework>
1219
+ </PropertyGroup>
1220
+ <ItemGroup>
1221
+ <PackageReference Include="Some.Package" Version="1.0.0" />
1222
+ </ItemGroup>
1223
+ </Project>
1224
+ """)),
1225
+ ContentEncoding = "base64"
1226
+ },
1227
+ ],
1228
+ BaseCommitSha = "TEST-COMMIT-SHA",
1229
+ },
1230
+ expectedApiMessages:
1231
+ [
1232
+ new UpdatedDependencyList()
1233
+ {
1234
+ Dependencies =
1235
+ [
1247
1236
  new ReportedDependency()
1248
1237
  {
1249
1238
  Name = "Some.Package",
@@ -1253,7 +1242,7 @@ public class RunWorkerTests
1253
1242
  new ReportedRequirement()
1254
1243
  {
1255
1244
  Requirement = "1.0.0",
1256
- File = "/some-dir/ProjectB/ProjectB.csproj",
1245
+ File = "/some-dir/project.csproj",
1257
1246
  Groups = ["dependencies"],
1258
1247
  }
1259
1248
  ]
@@ -1267,13 +1256,13 @@ public class RunWorkerTests
1267
1256
  new ReportedRequirement()
1268
1257
  {
1269
1258
  Requirement = "2.0.0",
1270
- File = "/some-dir/ProjectB/ProjectB.csproj",
1259
+ File = "/some-dir/project.csproj",
1271
1260
  Groups = ["dependencies"],
1272
1261
  }
1273
1262
  ]
1274
- },
1263
+ }
1275
1264
  ],
1276
- DependencyFiles = ["/some-dir/ProjectA/packages.config", "/some-dir/ProjectA/ProjectA.csproj", "/some-dir/ProjectB/packages.config", "/some-dir/ProjectB/ProjectB.csproj"],
1265
+ DependencyFiles = ["/some-dir/packages.config", "/some-dir/project.csproj"],
1277
1266
  },
1278
1267
  new IncrementMetric()
1279
1268
  {
@@ -1296,36 +1285,7 @@ public class RunWorkerTests
1296
1285
  new ReportedRequirement()
1297
1286
  {
1298
1287
  Requirement = "1.0.1",
1299
- File = "/some-dir/ProjectA/ProjectA.csproj",
1300
- Groups = ["dependencies"],
1301
- Source = new()
1302
- {
1303
- SourceUrl = "https://nuget.example.com/some-package",
1304
- Type = "nuget_repo",
1305
- }
1306
- }
1307
- ],
1308
- PreviousVersion = "1.0.0",
1309
- PreviousRequirements =
1310
- [
1311
- new ReportedRequirement()
1312
- {
1313
- Requirement = "1.0.0",
1314
- File = "/some-dir/ProjectA/ProjectA.csproj",
1315
- Groups = ["dependencies"],
1316
- }
1317
- ],
1318
- },
1319
- new ReportedDependency()
1320
- {
1321
- Name = "Some.Package",
1322
- Version = "1.0.1",
1323
- Requirements =
1324
- [
1325
- new ReportedRequirement()
1326
- {
1327
- Requirement = "1.0.1",
1328
- File = "/some-dir/ProjectB/ProjectB.csproj",
1288
+ File = "/some-dir/project.csproj",
1329
1289
  Groups = ["dependencies"],
1330
1290
  Source = new()
1331
1291
  {
@@ -1340,36 +1300,7 @@ public class RunWorkerTests
1340
1300
  new ReportedRequirement()
1341
1301
  {
1342
1302
  Requirement = "1.0.0",
1343
- File = "/some-dir/ProjectB/ProjectB.csproj",
1344
- Groups = ["dependencies"],
1345
- }
1346
- ],
1347
- },
1348
- new ReportedDependency()
1349
- {
1350
- Name = "Some.Package2",
1351
- Version = "2.0.1",
1352
- Requirements =
1353
- [
1354
- new ReportedRequirement()
1355
- {
1356
- Requirement = "2.0.1",
1357
- File = "/some-dir/ProjectA/ProjectA.csproj",
1358
- Groups = ["dependencies"],
1359
- Source = new()
1360
- {
1361
- SourceUrl = "https://nuget.example.com/some-package2",
1362
- Type = "nuget_repo",
1363
- }
1364
- }
1365
- ],
1366
- PreviousVersion = "2.0.0",
1367
- PreviousRequirements =
1368
- [
1369
- new ReportedRequirement()
1370
- {
1371
- Requirement = "2.0.0",
1372
- File = "/some-dir/ProjectA/ProjectA.csproj",
1303
+ File = "/some-dir/project.csproj",
1373
1304
  Groups = ["dependencies"],
1374
1305
  }
1375
1306
  ],
@@ -1383,7 +1314,7 @@ public class RunWorkerTests
1383
1314
  new ReportedRequirement()
1384
1315
  {
1385
1316
  Requirement = "2.0.1",
1386
- File = "/some-dir/ProjectB/ProjectB.csproj",
1317
+ File = "/some-dir/project.csproj",
1387
1318
  Groups = ["dependencies"],
1388
1319
  Source = new()
1389
1320
  {
@@ -1398,7 +1329,7 @@ public class RunWorkerTests
1398
1329
  new ReportedRequirement()
1399
1330
  {
1400
1331
  Requirement = "2.0.0",
1401
- File = "/some-dir/ProjectB/ProjectB.csproj",
1332
+ File = "/some-dir/project.csproj",
1402
1333
  Groups = ["dependencies"],
1403
1334
  }
1404
1335
  ],
@@ -1409,53 +1340,18 @@ public class RunWorkerTests
1409
1340
  new DependencyFile()
1410
1341
  {
1411
1342
  Name = "packages.config",
1412
- Directory = "/some-dir/ProjectA",
1413
- Content = """
1414
- <?xml version="1.0" encoding="utf-8"?>
1415
- <packages>
1416
- <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
1417
- </packages>
1418
- """.SetEOL(EOL),
1419
- },
1420
- new DependencyFile()
1421
- {
1422
- Name = "ProjectA.csproj",
1423
- Directory = "/some-dir/ProjectA",
1424
- Content = """
1425
- <Project Sdk="Microsoft.NET.Sdk">
1426
- <PropertyGroup>
1427
- <TargetFramework>net8.0</TargetFramework>
1428
- </PropertyGroup>
1429
- <ItemGroup>
1430
- <PackageReference Include="Some.Package" Version="1.0.1" />
1431
- </ItemGroup>
1432
- <ItemGroup>
1433
- <ProjectReference Include="../ProjectB/ProjectB.csproj" />
1434
- </ItemGroup>
1435
- <ItemGroup>
1436
- <Reference Include="Some.Package2">
1437
- <HintPath>..\packages\Some.Package2.2.0.1\lib\net8.0\Some.Package2.dll</HintPath>
1438
- <Private>True</Private>
1439
- </Reference>
1440
- </ItemGroup>
1441
- </Project>
1442
- """.SetEOL(EOL),
1443
- },
1444
- new DependencyFile()
1445
- {
1446
- Name = "packages.config",
1447
- Directory = "/some-dir/ProjectB",
1343
+ Directory = "/some-dir",
1448
1344
  Content = """
1449
1345
  <?xml version="1.0" encoding="utf-8"?>
1450
1346
  <packages>
1451
1347
  <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
1452
1348
  </packages>
1453
- """.SetEOL(EOL),
1349
+ """,
1454
1350
  },
1455
1351
  new DependencyFile()
1456
1352
  {
1457
- Name = "ProjectB.csproj",
1458
- Directory = "/some-dir/ProjectB",
1353
+ Name = "project.csproj",
1354
+ Directory = "/some-dir",
1459
1355
  Content = """
1460
1356
  <Project Sdk="Microsoft.NET.Sdk">
1461
1357
  <PropertyGroup>
@@ -1471,7 +1367,7 @@ public class RunWorkerTests
1471
1367
  </Reference>
1472
1368
  </ItemGroup>
1473
1369
  </Project>
1474
- """.SetEOL(EOL),
1370
+ """,
1475
1371
  },
1476
1372
  ],
1477
1373
  BaseCommitSha = "TEST-COMMIT-SHA",
@@ -1484,112 +1380,128 @@ public class RunWorkerTests
1484
1380
  );
1485
1381
  }
1486
1382
 
1487
- [Theory]
1488
- [InlineData(EOLType.CR)]
1489
- [InlineData(EOLType.LF)]
1490
- [InlineData(EOLType.CRLF)]
1491
- public async Task UpdatedFilesAreOnlyReportedOnce(EOLType EOL)
1383
+ [Fact]
1384
+ public async Task UpdateHandlesPackagesConfigFromReferencedCsprojFiles()
1492
1385
  {
1386
+ var repoMetadata = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package" />""");
1387
+ var repoMetadata2 = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package2" />""");
1493
1388
  await RunAsync(
1494
- job: new()
1389
+ packages:
1390
+ [
1391
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0", additionalMetadata: [repoMetadata]),
1392
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.1", "net8.0", additionalMetadata: [repoMetadata]),
1393
+ MockNuGetPackage.CreateSimplePackage("Some.Package2", "2.0.0", "net8.0", additionalMetadata: [repoMetadata2]),
1394
+ MockNuGetPackage.CreateSimplePackage("Some.Package2", "2.0.1", "net8.0", additionalMetadata: [repoMetadata2]),
1395
+ ],
1396
+ job: new Job()
1495
1397
  {
1496
1398
  PackageManager = "nuget",
1497
1399
  Source = new()
1498
1400
  {
1499
1401
  Provider = "github",
1500
1402
  Repo = "test/repo",
1501
- Directory = "/",
1403
+ Directory = "some-dir/ProjectA",
1502
1404
  }
1503
1405
  },
1504
- packages:
1505
- [
1506
- MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0"),
1507
- MockNuGetPackage.CreateSimplePackage("Some.Package", "1.1.0", "net8.0"),
1508
- ],
1509
1406
  files:
1510
1407
  [
1511
- ("dirs.proj", """
1512
- <Project>
1513
- <ItemGroup>
1514
- <ProjectFile Include="project1/project1.csproj" />
1515
- <ProjectFile Include="project2/project2.csproj" />
1516
- </ItemGroup>
1517
- </Project>
1518
- """.SetEOL(EOL)),
1519
- ("Directory.Build.props", """
1520
- <Project>
1521
- <PropertyGroup>
1522
- <SomePackageVersion>1.0.0</SomePackageVersion>
1523
- </PropertyGroup>
1524
- </Project>
1525
- """.SetEOL(EOL)),
1526
- ("project1/project1.csproj", """
1408
+ ("some-dir/ProjectA/ProjectA.csproj", """
1527
1409
  <Project Sdk="Microsoft.NET.Sdk">
1528
1410
  <PropertyGroup>
1529
1411
  <TargetFramework>net8.0</TargetFramework>
1530
1412
  </PropertyGroup>
1531
1413
  <ItemGroup>
1532
- <PackageReference Include="Some.Package" Version="$(SomePackageVersion)" />
1414
+ <PackageReference Include="Some.Package" Version="1.0.0" />
1415
+ </ItemGroup>
1416
+ <ItemGroup>
1417
+ <ProjectReference Include="../ProjectB/ProjectB.csproj" />
1533
1418
  </ItemGroup>
1534
1419
  </Project>
1535
- """.SetEOL(EOL)),
1536
- ("project2/project2.csproj", """
1420
+ """),
1421
+ ("some-dir/ProjectA/packages.config", """
1422
+ <?xml version="1.0" encoding="utf-8"?>
1423
+ <packages>
1424
+ <package id="Some.Package2" version="2.0.0" targetFramework="net8.0" />
1425
+ </packages>
1426
+ """),
1427
+ ("some-dir/ProjectB/ProjectB.csproj", """
1537
1428
  <Project Sdk="Microsoft.NET.Sdk">
1538
1429
  <PropertyGroup>
1539
1430
  <TargetFramework>net8.0</TargetFramework>
1540
1431
  </PropertyGroup>
1541
1432
  <ItemGroup>
1542
- <PackageReference Include="Some.Package" Version="$(SomePackageVersion)" />
1433
+ <PackageReference Include="Some.Package" Version="1.0.0" />
1543
1434
  </ItemGroup>
1544
1435
  </Project>
1545
- """.SetEOL(EOL))
1436
+ """),
1437
+ ("some-dir/ProjectB/packages.config", """
1438
+ <?xml version="1.0" encoding="utf-8"?>
1439
+ <packages>
1440
+ <package id="Some.Package2" version="2.0.0" targetFramework="net8.0" />
1441
+ </packages>
1442
+ """),
1546
1443
  ],
1547
1444
  discoveryWorker: new TestDiscoveryWorker(_input =>
1548
1445
  {
1549
1446
  return Task.FromResult(new WorkspaceDiscoveryResult()
1550
1447
  {
1551
- Path = "",
1552
- Projects = [
1448
+ Path = "some-dir/ProjectA",
1449
+ Projects =
1450
+ [
1553
1451
  new()
1554
1452
  {
1555
- FilePath = "project1/project1.csproj",
1453
+ FilePath = "../ProjectB/ProjectB.csproj",
1556
1454
  TargetFrameworks = ["net8.0"],
1557
- Dependencies = [
1455
+ Dependencies =
1456
+ [
1558
1457
  new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"]),
1458
+ new("Some.Package2", "2.0.0", DependencyType.PackagesConfig, TargetFrameworks: ["net8.0"]),
1559
1459
  ],
1560
1460
  ReferencedProjectPaths = [],
1561
- ImportedFiles = [
1562
- "../Directory.Build.props",
1563
- ],
1564
- AdditionalFiles = [],
1461
+ ImportedFiles = [],
1462
+ AdditionalFiles = ["packages.config"],
1565
1463
  },
1566
1464
  new()
1567
1465
  {
1568
- FilePath = "project2/project2.csproj",
1466
+ FilePath = "ProjectA.csproj",
1569
1467
  TargetFrameworks = ["net8.0"],
1570
- Dependencies = [
1468
+ Dependencies =
1469
+ [
1571
1470
  new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"]),
1471
+ new("Some.Package2", "2.0.0", DependencyType.PackagesConfig, TargetFrameworks: ["net8.0"]),
1572
1472
  ],
1573
1473
  ReferencedProjectPaths = [],
1574
- ImportedFiles = [
1575
- "../Directory.Build.props",
1576
- ],
1577
- AdditionalFiles = [],
1578
- },
1474
+ ImportedFiles = [],
1475
+ AdditionalFiles = ["packages.config"],
1476
+ }
1579
1477
  ]
1580
1478
  });
1581
1479
  }),
1582
- analyzeWorker: new TestAnalyzeWorker(_input =>
1480
+ analyzeWorker: new TestAnalyzeWorker(input =>
1583
1481
  {
1584
- return Task.FromResult(new AnalysisResult()
1482
+ var result = input.Item3.Name switch
1585
1483
  {
1586
- CanUpdate = true,
1587
- UpdatedVersion = "1.1.0",
1588
- UpdatedDependencies =
1589
- [
1590
- new("Some.Package", "1.1.0", DependencyType.Unknown, TargetFrameworks: ["net8.0"]),
1591
- ]
1592
- });
1484
+ "Some.Package" => new AnalysisResult()
1485
+ {
1486
+ CanUpdate = true,
1487
+ UpdatedVersion = "1.0.1",
1488
+ UpdatedDependencies =
1489
+ [
1490
+ new("Some.Package", "1.0.1", DependencyType.Unknown, TargetFrameworks: ["net8.0"], InfoUrl: "https://nuget.example.com/some-package"),
1491
+ ]
1492
+ },
1493
+ "Some.Package2" => new AnalysisResult()
1494
+ {
1495
+ CanUpdate = true,
1496
+ UpdatedVersion = "2.0.1",
1497
+ UpdatedDependencies =
1498
+ [
1499
+ new("Some.Package2", "2.0.1", DependencyType.Unknown, TargetFrameworks: ["net8.0"], InfoUrl: "https://nuget.example.com/some-package2"),
1500
+ ]
1501
+ },
1502
+ _ => throw new NotSupportedException(),
1503
+ };
1504
+ return Task.FromResult(result);
1593
1505
  }),
1594
1506
  updaterWorker: new TestUpdaterWorker(async input =>
1595
1507
  {
@@ -1600,14 +1512,93 @@ public class RunWorkerTests
1600
1512
  var newVersion = input.Item5;
1601
1513
  var _isTransitive = input.Item6;
1602
1514
 
1603
- var directoryBuildPropsPath = Path.Join(repoRootPath, "Directory.Build.props");
1604
- await File.WriteAllTextAsync(directoryBuildPropsPath, """
1605
- <Project>
1606
- <PropertyGroup>
1607
- <SomePackageVersion>1.1.0</SomePackageVersion>
1608
- </PropertyGroup>
1609
- </Project>
1610
- """.SetEOL(EOL));
1515
+ var projectPath = Path.Join(repoRootPath, filePath);
1516
+ var projectName = Path.GetFileName(projectPath);
1517
+ var packagesConfigPath = Path.Join(Path.GetDirectoryName(projectPath)!, "packages.config");
1518
+ switch ((projectName, packageName))
1519
+ {
1520
+ case ("ProjectA.csproj", "Some.Package"):
1521
+ await File.WriteAllTextAsync(projectPath, """
1522
+ <Project Sdk="Microsoft.NET.Sdk">
1523
+ <PropertyGroup>
1524
+ <TargetFramework>net8.0</TargetFramework>
1525
+ </PropertyGroup>
1526
+ <ItemGroup>
1527
+ <PackageReference Include="Some.Package" Version="1.0.1" />
1528
+ </ItemGroup>
1529
+ <ItemGroup>
1530
+ <ProjectReference Include="../ProjectB/ProjectB.csproj" />
1531
+ </ItemGroup>
1532
+ </Project>
1533
+ """);
1534
+ break;
1535
+ case ("ProjectA.csproj", "Some.Package2"):
1536
+ await File.WriteAllTextAsync(projectPath, """
1537
+ <Project Sdk="Microsoft.NET.Sdk">
1538
+ <PropertyGroup>
1539
+ <TargetFramework>net8.0</TargetFramework>
1540
+ </PropertyGroup>
1541
+ <ItemGroup>
1542
+ <PackageReference Include="Some.Package" Version="1.0.1" />
1543
+ </ItemGroup>
1544
+ <ItemGroup>
1545
+ <ProjectReference Include="../ProjectB/ProjectB.csproj" />
1546
+ </ItemGroup>
1547
+ <ItemGroup>
1548
+ <Reference Include="Some.Package2">
1549
+ <HintPath>..\packages\Some.Package2.2.0.1\lib\net8.0\Some.Package2.dll</HintPath>
1550
+ <Private>True</Private>
1551
+ </Reference>
1552
+ </ItemGroup>
1553
+ </Project>
1554
+ """);
1555
+ await File.WriteAllTextAsync(packagesConfigPath, """
1556
+ <?xml version="1.0" encoding="utf-8"?>
1557
+ <packages>
1558
+ <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
1559
+ </packages>
1560
+ """);
1561
+ break;
1562
+ case ("ProjectB.csproj", "Some.Package"):
1563
+ await File.WriteAllTextAsync(projectPath, """
1564
+ <Project Sdk="Microsoft.NET.Sdk">
1565
+ <PropertyGroup>
1566
+ <TargetFramework>net8.0</TargetFramework>
1567
+ </PropertyGroup>
1568
+ <ItemGroup>
1569
+ <PackageReference Include="Some.Package" Version="1.0.1" />
1570
+ </ItemGroup>
1571
+ </Project>
1572
+ """);
1573
+ break;
1574
+ case ("ProjectB.csproj", "Some.Package2"):
1575
+ await File.WriteAllTextAsync(projectPath, """
1576
+ <Project Sdk="Microsoft.NET.Sdk">
1577
+ <PropertyGroup>
1578
+ <TargetFramework>net8.0</TargetFramework>
1579
+ </PropertyGroup>
1580
+ <ItemGroup>
1581
+ <PackageReference Include="Some.Package" Version="1.0.1" />
1582
+ </ItemGroup>
1583
+ <ItemGroup>
1584
+ <Reference Include="Some.Package2">
1585
+ <HintPath>..\packages\Some.Package2.2.0.1\lib\net8.0\Some.Package2.dll</HintPath>
1586
+ <Private>True</Private>
1587
+ </Reference>
1588
+ </ItemGroup>
1589
+ </Project>
1590
+ """);
1591
+ await File.WriteAllTextAsync(packagesConfigPath, """
1592
+ <?xml version="1.0" encoding="utf-8"?>
1593
+ <packages>
1594
+ <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
1595
+ </packages>
1596
+ """);
1597
+ break;
1598
+ default:
1599
+ throw new NotSupportedException();
1600
+ }
1601
+
1611
1602
  return new UpdateOperationResult()
1612
1603
  {
1613
1604
  UpdateOperations = [
@@ -1626,47 +1617,61 @@ public class RunWorkerTests
1626
1617
  [
1627
1618
  new DependencyFile()
1628
1619
  {
1629
- Directory = "/",
1630
- Name = "Directory.Build.props",
1620
+ Directory = "/some-dir/ProjectA",
1621
+ Name = "packages.config",
1631
1622
  Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1632
- <Project>
1633
- <PropertyGroup>
1634
- <SomePackageVersion>1.0.0</SomePackageVersion>
1635
- </PropertyGroup>
1636
- </Project>
1637
- """.SetEOL(EOL))),
1623
+ <?xml version="1.0" encoding="utf-8"?>
1624
+ <packages>
1625
+ <package id="Some.Package2" version="2.0.0" targetFramework="net8.0" />
1626
+ </packages>
1627
+ """)),
1638
1628
  ContentEncoding = "base64"
1639
1629
  },
1640
1630
  new DependencyFile()
1641
1631
  {
1642
- Directory = "/project1",
1643
- Name = "project1.csproj",
1632
+ Directory = "/some-dir/ProjectA",
1633
+ Name = "ProjectA.csproj",
1644
1634
  Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1645
1635
  <Project Sdk="Microsoft.NET.Sdk">
1646
1636
  <PropertyGroup>
1647
1637
  <TargetFramework>net8.0</TargetFramework>
1648
1638
  </PropertyGroup>
1649
1639
  <ItemGroup>
1650
- <PackageReference Include="Some.Package" Version="$(SomePackageVersion)" />
1640
+ <PackageReference Include="Some.Package" Version="1.0.0" />
1641
+ </ItemGroup>
1642
+ <ItemGroup>
1643
+ <ProjectReference Include="../ProjectB/ProjectB.csproj" />
1651
1644
  </ItemGroup>
1652
1645
  </Project>
1653
- """.SetEOL(EOL))),
1646
+ """)),
1654
1647
  ContentEncoding = "base64"
1655
1648
  },
1656
1649
  new DependencyFile()
1657
1650
  {
1658
- Directory = "/project2",
1659
- Name = "project2.csproj",
1651
+ Directory = "/some-dir/ProjectB",
1652
+ Name = "packages.config",
1653
+ Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1654
+ <?xml version="1.0" encoding="utf-8"?>
1655
+ <packages>
1656
+ <package id="Some.Package2" version="2.0.0" targetFramework="net8.0" />
1657
+ </packages>
1658
+ """)),
1659
+ ContentEncoding = "base64"
1660
+ },
1661
+ new DependencyFile()
1662
+ {
1663
+ Directory = "/some-dir/ProjectB",
1664
+ Name = "ProjectB.csproj",
1660
1665
  Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1661
1666
  <Project Sdk="Microsoft.NET.Sdk">
1662
1667
  <PropertyGroup>
1663
1668
  <TargetFramework>net8.0</TargetFramework>
1664
1669
  </PropertyGroup>
1665
1670
  <ItemGroup>
1666
- <PackageReference Include="Some.Package" Version="$(SomePackageVersion)" />
1671
+ <PackageReference Include="Some.Package" Version="1.0.0" />
1667
1672
  </ItemGroup>
1668
1673
  </Project>
1669
- """.SetEOL(EOL))),
1674
+ """)),
1670
1675
  ContentEncoding = "base64"
1671
1676
  },
1672
1677
  ],
@@ -1687,7 +1692,21 @@ public class RunWorkerTests
1687
1692
  new ReportedRequirement()
1688
1693
  {
1689
1694
  Requirement = "1.0.0",
1690
- File = "/project1/project1.csproj",
1695
+ File = "/some-dir/ProjectA/ProjectA.csproj",
1696
+ Groups = ["dependencies"],
1697
+ }
1698
+ ]
1699
+ },
1700
+ new ReportedDependency()
1701
+ {
1702
+ Name = "Some.Package2",
1703
+ Version = "2.0.0",
1704
+ Requirements =
1705
+ [
1706
+ new ReportedRequirement()
1707
+ {
1708
+ Requirement = "2.0.0",
1709
+ File = "/some-dir/ProjectA/ProjectA.csproj",
1691
1710
  Groups = ["dependencies"],
1692
1711
  }
1693
1712
  ]
@@ -1701,13 +1720,27 @@ public class RunWorkerTests
1701
1720
  new ReportedRequirement()
1702
1721
  {
1703
1722
  Requirement = "1.0.0",
1704
- File = "/project2/project2.csproj",
1723
+ File = "/some-dir/ProjectB/ProjectB.csproj",
1705
1724
  Groups = ["dependencies"],
1706
1725
  }
1707
1726
  ]
1708
- }
1727
+ },
1728
+ new ReportedDependency()
1729
+ {
1730
+ Name = "Some.Package2",
1731
+ Version = "2.0.0",
1732
+ Requirements =
1733
+ [
1734
+ new ReportedRequirement()
1735
+ {
1736
+ Requirement = "2.0.0",
1737
+ File = "/some-dir/ProjectB/ProjectB.csproj",
1738
+ Groups = ["dependencies"],
1739
+ }
1740
+ ]
1741
+ },
1709
1742
  ],
1710
- DependencyFiles = ["/Directory.Build.props", "/project1/project1.csproj", "/project2/project2.csproj"],
1743
+ DependencyFiles = ["/some-dir/ProjectA/packages.config", "/some-dir/ProjectA/ProjectA.csproj", "/some-dir/ProjectB/packages.config", "/some-dir/ProjectB/ProjectB.csproj"],
1711
1744
  },
1712
1745
  new IncrementMetric()
1713
1746
  {
@@ -1724,17 +1757,17 @@ public class RunWorkerTests
1724
1757
  new ReportedDependency()
1725
1758
  {
1726
1759
  Name = "Some.Package",
1727
- Version = "1.1.0",
1760
+ Version = "1.0.1",
1728
1761
  Requirements =
1729
1762
  [
1730
1763
  new ReportedRequirement()
1731
1764
  {
1732
- Requirement = "1.1.0",
1733
- File = "/project1/project1.csproj",
1765
+ Requirement = "1.0.1",
1766
+ File = "/some-dir/ProjectA/ProjectA.csproj",
1734
1767
  Groups = ["dependencies"],
1735
1768
  Source = new()
1736
1769
  {
1737
- SourceUrl = null,
1770
+ SourceUrl = "https://nuget.example.com/some-package",
1738
1771
  Type = "nuget_repo",
1739
1772
  }
1740
1773
  }
@@ -1745,7 +1778,7 @@ public class RunWorkerTests
1745
1778
  new ReportedRequirement()
1746
1779
  {
1747
1780
  Requirement = "1.0.0",
1748
- File = "/project1/project1.csproj",
1781
+ File = "/some-dir/ProjectA/ProjectA.csproj",
1749
1782
  Groups = ["dependencies"],
1750
1783
  }
1751
1784
  ],
@@ -1753,17 +1786,17 @@ public class RunWorkerTests
1753
1786
  new ReportedDependency()
1754
1787
  {
1755
1788
  Name = "Some.Package",
1756
- Version = "1.1.0",
1789
+ Version = "1.0.1",
1757
1790
  Requirements =
1758
1791
  [
1759
1792
  new ReportedRequirement()
1760
1793
  {
1761
- Requirement = "1.1.0",
1762
- File = "/project2/project2.csproj",
1794
+ Requirement = "1.0.1",
1795
+ File = "/some-dir/ProjectB/ProjectB.csproj",
1763
1796
  Groups = ["dependencies"],
1764
1797
  Source = new()
1765
1798
  {
1766
- SourceUrl = null,
1799
+ SourceUrl = "https://nuget.example.com/some-package",
1767
1800
  Type = "nuget_repo",
1768
1801
  }
1769
1802
  }
@@ -1774,26 +1807,139 @@ public class RunWorkerTests
1774
1807
  new ReportedRequirement()
1775
1808
  {
1776
1809
  Requirement = "1.0.0",
1777
- File = "/project2/project2.csproj",
1810
+ File = "/some-dir/ProjectB/ProjectB.csproj",
1811
+ Groups = ["dependencies"],
1812
+ }
1813
+ ],
1814
+ },
1815
+ new ReportedDependency()
1816
+ {
1817
+ Name = "Some.Package2",
1818
+ Version = "2.0.1",
1819
+ Requirements =
1820
+ [
1821
+ new ReportedRequirement()
1822
+ {
1823
+ Requirement = "2.0.1",
1824
+ File = "/some-dir/ProjectA/ProjectA.csproj",
1825
+ Groups = ["dependencies"],
1826
+ Source = new()
1827
+ {
1828
+ SourceUrl = "https://nuget.example.com/some-package2",
1829
+ Type = "nuget_repo",
1830
+ }
1831
+ }
1832
+ ],
1833
+ PreviousVersion = "2.0.0",
1834
+ PreviousRequirements =
1835
+ [
1836
+ new ReportedRequirement()
1837
+ {
1838
+ Requirement = "2.0.0",
1839
+ File = "/some-dir/ProjectA/ProjectA.csproj",
1840
+ Groups = ["dependencies"],
1841
+ }
1842
+ ],
1843
+ },
1844
+ new ReportedDependency()
1845
+ {
1846
+ Name = "Some.Package2",
1847
+ Version = "2.0.1",
1848
+ Requirements =
1849
+ [
1850
+ new ReportedRequirement()
1851
+ {
1852
+ Requirement = "2.0.1",
1853
+ File = "/some-dir/ProjectB/ProjectB.csproj",
1854
+ Groups = ["dependencies"],
1855
+ Source = new()
1856
+ {
1857
+ SourceUrl = "https://nuget.example.com/some-package2",
1858
+ Type = "nuget_repo",
1859
+ }
1860
+ }
1861
+ ],
1862
+ PreviousVersion = "2.0.0",
1863
+ PreviousRequirements =
1864
+ [
1865
+ new ReportedRequirement()
1866
+ {
1867
+ Requirement = "2.0.0",
1868
+ File = "/some-dir/ProjectB/ProjectB.csproj",
1778
1869
  Groups = ["dependencies"],
1779
1870
  }
1780
1871
  ],
1781
1872
  },
1782
- ],
1783
- UpdatedDependencyFiles =
1784
- [
1873
+ ],
1874
+ UpdatedDependencyFiles =
1875
+ [
1876
+ new DependencyFile()
1877
+ {
1878
+ Name = "packages.config",
1879
+ Directory = "/some-dir/ProjectA",
1880
+ Content = """
1881
+ <?xml version="1.0" encoding="utf-8"?>
1882
+ <packages>
1883
+ <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
1884
+ </packages>
1885
+ """,
1886
+ },
1887
+ new DependencyFile()
1888
+ {
1889
+ Name = "ProjectA.csproj",
1890
+ Directory = "/some-dir/ProjectA",
1891
+ Content = """
1892
+ <Project Sdk="Microsoft.NET.Sdk">
1893
+ <PropertyGroup>
1894
+ <TargetFramework>net8.0</TargetFramework>
1895
+ </PropertyGroup>
1896
+ <ItemGroup>
1897
+ <PackageReference Include="Some.Package" Version="1.0.1" />
1898
+ </ItemGroup>
1899
+ <ItemGroup>
1900
+ <ProjectReference Include="../ProjectB/ProjectB.csproj" />
1901
+ </ItemGroup>
1902
+ <ItemGroup>
1903
+ <Reference Include="Some.Package2">
1904
+ <HintPath>..\packages\Some.Package2.2.0.1\lib\net8.0\Some.Package2.dll</HintPath>
1905
+ <Private>True</Private>
1906
+ </Reference>
1907
+ </ItemGroup>
1908
+ </Project>
1909
+ """,
1910
+ },
1785
1911
  new DependencyFile()
1786
1912
  {
1787
- Name = "Directory.Build.props",
1788
- Directory = "/",
1913
+ Name = "packages.config",
1914
+ Directory = "/some-dir/ProjectB",
1789
1915
  Content = """
1790
- <Project>
1916
+ <?xml version="1.0" encoding="utf-8"?>
1917
+ <packages>
1918
+ <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
1919
+ </packages>
1920
+ """,
1921
+ },
1922
+ new DependencyFile()
1923
+ {
1924
+ Name = "ProjectB.csproj",
1925
+ Directory = "/some-dir/ProjectB",
1926
+ Content = """
1927
+ <Project Sdk="Microsoft.NET.Sdk">
1791
1928
  <PropertyGroup>
1792
- <SomePackageVersion>1.1.0</SomePackageVersion>
1929
+ <TargetFramework>net8.0</TargetFramework>
1793
1930
  </PropertyGroup>
1931
+ <ItemGroup>
1932
+ <PackageReference Include="Some.Package" Version="1.0.1" />
1933
+ </ItemGroup>
1934
+ <ItemGroup>
1935
+ <Reference Include="Some.Package2">
1936
+ <HintPath>..\packages\Some.Package2.2.0.1\lib\net8.0\Some.Package2.dll</HintPath>
1937
+ <Private>True</Private>
1938
+ </Reference>
1939
+ </ItemGroup>
1794
1940
  </Project>
1795
- """.SetEOL(EOL),
1796
- }
1941
+ """,
1942
+ },
1797
1943
  ],
1798
1944
  BaseCommitSha = "TEST-COMMIT-SHA",
1799
1945
  CommitMessage = TestPullRequestCommitMessage,
@@ -1805,96 +1951,139 @@ public class RunWorkerTests
1805
1951
  );
1806
1952
  }
1807
1953
 
1808
- [Theory]
1809
- [InlineData(EOLType.CR)]
1810
- [InlineData(EOLType.LF)]
1811
- [InlineData(EOLType.CRLF)]
1812
- public async Task UpdatePackageWithDifferentVersionsInDifferentDirectories(EOLType EOL)
1954
+ [Fact]
1955
+ public async Task UpdatedFilesAreOnlyReportedOnce()
1813
1956
  {
1814
- // this test passes `null` for discovery, analyze, and update workers to fully test the desired behavior
1815
-
1816
- // the same dependency Some.Package is reported for 3 cases:
1817
- // library1.csproj - top level dependency, already up to date
1818
- // library2.csproj - top level dependency, needs direct update
1819
- // library3.csproj - transitive dependency, needs pin
1820
1957
  await RunAsync(
1821
- experimentsManager: new ExperimentsManager() { UseDirectDiscovery = true },
1822
- packages: [
1823
- MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0"),
1824
- MockNuGetPackage.CreateSimplePackage("Some.Package", "2.0.0", "net8.0"),
1825
- MockNuGetPackage.CreateSimplePackage("Package.With.Transitive.Dependency", "0.1.0", "net8.0", [(null, [("Some.Package", "1.0.0")])]),
1826
- ],
1827
- job: new Job()
1958
+ job: new()
1828
1959
  {
1829
- AllowedUpdates = [new() { UpdateType = UpdateType.Security }],
1830
- SecurityAdvisories =
1831
- [
1832
- new()
1833
- {
1834
- DependencyName = "Some.Package",
1835
- AffectedVersions = [Requirement.Parse("= 1.0.0")]
1836
- }
1837
- ],
1960
+ PackageManager = "nuget",
1838
1961
  Source = new()
1839
1962
  {
1840
1963
  Provider = "github",
1841
1964
  Repo = "test/repo",
1842
- Directory = "/"
1965
+ Directory = "/",
1843
1966
  }
1844
1967
  },
1845
- files: [
1968
+ packages:
1969
+ [
1970
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0"),
1971
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.1.0", "net8.0"),
1972
+ ],
1973
+ files:
1974
+ [
1846
1975
  ("dirs.proj", """
1847
1976
  <Project>
1848
1977
  <ItemGroup>
1849
- <ProjectFile Include="library1\library1.csproj" />
1850
- <ProjectFile Include="library2\library2.csproj" />
1851
- <ProjectFile Include="library3\library3.csproj" />
1978
+ <ProjectFile Include="project1/project1.csproj" />
1979
+ <ProjectFile Include="project2/project2.csproj" />
1852
1980
  </ItemGroup>
1853
1981
  </Project>
1854
- """.SetEOL(EOL)),
1855
- ("Directory.Build.props", "<Project />"),
1856
- ("Directory.Build.targets", "<Project />"),
1857
- ("Directory.Packages.props", """
1982
+ """),
1983
+ ("Directory.Build.props", """
1858
1984
  <Project>
1859
1985
  <PropertyGroup>
1860
- <ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
1986
+ <SomePackageVersion>1.0.0</SomePackageVersion>
1861
1987
  </PropertyGroup>
1862
1988
  </Project>
1863
- """.SetEOL(EOL)),
1864
- ("library1/library1.csproj", """
1989
+ """),
1990
+ ("project1/project1.csproj", """
1865
1991
  <Project Sdk="Microsoft.NET.Sdk">
1866
1992
  <PropertyGroup>
1867
1993
  <TargetFramework>net8.0</TargetFramework>
1868
1994
  </PropertyGroup>
1869
1995
  <ItemGroup>
1870
- <PackageReference Include="Some.Package" Version="2.0.0" />
1996
+ <PackageReference Include="Some.Package" Version="$(SomePackageVersion)" />
1871
1997
  </ItemGroup>
1872
1998
  </Project>
1873
- """.SetEOL(EOL)),
1874
- ("library2/library2.csproj", """
1999
+ """),
2000
+ ("project2/project2.csproj", """
1875
2001
  <Project Sdk="Microsoft.NET.Sdk">
1876
2002
  <PropertyGroup>
1877
2003
  <TargetFramework>net8.0</TargetFramework>
1878
2004
  </PropertyGroup>
1879
2005
  <ItemGroup>
1880
- <PackageReference Include="Some.Package" Version="1.0.0" />
2006
+ <PackageReference Include="Some.Package" Version="$(SomePackageVersion)" />
1881
2007
  </ItemGroup>
1882
2008
  </Project>
1883
- """.SetEOL(EOL)),
1884
- ("library3/library3.csproj", """
1885
- <Project Sdk="Microsoft.NET.Sdk">
2009
+ """)
2010
+ ],
2011
+ discoveryWorker: new TestDiscoveryWorker(_input =>
2012
+ {
2013
+ return Task.FromResult(new WorkspaceDiscoveryResult()
2014
+ {
2015
+ Path = "",
2016
+ Projects = [
2017
+ new()
2018
+ {
2019
+ FilePath = "project1/project1.csproj",
2020
+ TargetFrameworks = ["net8.0"],
2021
+ Dependencies = [
2022
+ new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"]),
2023
+ ],
2024
+ ReferencedProjectPaths = [],
2025
+ ImportedFiles = [
2026
+ "../Directory.Build.props",
2027
+ ],
2028
+ AdditionalFiles = [],
2029
+ },
2030
+ new()
2031
+ {
2032
+ FilePath = "project2/project2.csproj",
2033
+ TargetFrameworks = ["net8.0"],
2034
+ Dependencies = [
2035
+ new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"]),
2036
+ ],
2037
+ ReferencedProjectPaths = [],
2038
+ ImportedFiles = [
2039
+ "../Directory.Build.props",
2040
+ ],
2041
+ AdditionalFiles = [],
2042
+ },
2043
+ ]
2044
+ });
2045
+ }),
2046
+ analyzeWorker: new TestAnalyzeWorker(_input =>
2047
+ {
2048
+ return Task.FromResult(new AnalysisResult()
2049
+ {
2050
+ CanUpdate = true,
2051
+ UpdatedVersion = "1.1.0",
2052
+ UpdatedDependencies =
2053
+ [
2054
+ new("Some.Package", "1.1.0", DependencyType.Unknown, TargetFrameworks: ["net8.0"]),
2055
+ ]
2056
+ });
2057
+ }),
2058
+ updaterWorker: new TestUpdaterWorker(async input =>
2059
+ {
2060
+ var repoRootPath = input.Item1;
2061
+ var filePath = input.Item2;
2062
+ var packageName = input.Item3;
2063
+ var previousVersion = input.Item4;
2064
+ var newVersion = input.Item5;
2065
+ var _isTransitive = input.Item6;
2066
+
2067
+ var directoryBuildPropsPath = Path.Join(repoRootPath, "Directory.Build.props");
2068
+ await File.WriteAllTextAsync(directoryBuildPropsPath, """
2069
+ <Project>
1886
2070
  <PropertyGroup>
1887
- <TargetFramework>net8.0</TargetFramework>
2071
+ <SomePackageVersion>1.1.0</SomePackageVersion>
1888
2072
  </PropertyGroup>
1889
- <ItemGroup>
1890
- <PackageReference Include="Package.With.Transitive.Dependency" Version="0.1.0" />
1891
- </ItemGroup>
1892
2073
  </Project>
1893
- """.SetEOL(EOL)),
1894
- ],
1895
- discoveryWorker: null,
1896
- analyzeWorker: null,
1897
- updaterWorker: null,
2074
+ """);
2075
+ return new UpdateOperationResult()
2076
+ {
2077
+ UpdateOperations = [
2078
+ new DirectUpdate()
2079
+ {
2080
+ DependencyName = packageName,
2081
+ NewVersion = NuGetVersion.Parse(newVersion),
2082
+ UpdatedFiles = [filePath]
2083
+ }
2084
+ ],
2085
+ };
2086
+ }),
1898
2087
  expectedResult: new RunResult()
1899
2088
  {
1900
2089
  Base64DependencyFiles =
@@ -1903,166 +2092,109 @@ public class RunWorkerTests
1903
2092
  {
1904
2093
  Directory = "/",
1905
2094
  Name = "Directory.Build.props",
1906
- Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("<Project />")),
1907
- ContentEncoding = "base64"
1908
- },
1909
- new DependencyFile()
1910
- {
1911
- Directory = "/",
1912
- Name = "Directory.Build.targets",
1913
- Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("<Project />")),
1914
- ContentEncoding = "base64"
1915
- },
1916
- new DependencyFile()
1917
- {
1918
- Directory = "/",
1919
- Name = "Directory.Packages.props",
1920
2095
  Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1921
2096
  <Project>
1922
2097
  <PropertyGroup>
1923
- <ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
2098
+ <SomePackageVersion>1.0.0</SomePackageVersion>
1924
2099
  </PropertyGroup>
1925
2100
  </Project>
1926
- """.SetEOL(EOL))),
2101
+ """)),
1927
2102
  ContentEncoding = "base64"
1928
2103
  },
1929
2104
  new DependencyFile()
1930
2105
  {
1931
- Directory = "/library1",
1932
- Name = "library1.csproj",
2106
+ Directory = "/project1",
2107
+ Name = "project1.csproj",
1933
2108
  Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1934
2109
  <Project Sdk="Microsoft.NET.Sdk">
1935
2110
  <PropertyGroup>
1936
2111
  <TargetFramework>net8.0</TargetFramework>
1937
2112
  </PropertyGroup>
1938
2113
  <ItemGroup>
1939
- <PackageReference Include="Some.Package" Version="2.0.0" />
2114
+ <PackageReference Include="Some.Package" Version="$(SomePackageVersion)" />
1940
2115
  </ItemGroup>
1941
2116
  </Project>
1942
- """.SetEOL(EOL))),
2117
+ """)),
1943
2118
  ContentEncoding = "base64"
1944
2119
  },
1945
2120
  new DependencyFile()
1946
2121
  {
1947
- Directory = "/library2",
1948
- Name = "library2.csproj",
2122
+ Directory = "/project2",
2123
+ Name = "project2.csproj",
1949
2124
  Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1950
2125
  <Project Sdk="Microsoft.NET.Sdk">
1951
2126
  <PropertyGroup>
1952
2127
  <TargetFramework>net8.0</TargetFramework>
1953
2128
  </PropertyGroup>
1954
2129
  <ItemGroup>
1955
- <PackageReference Include="Some.Package" Version="1.0.0" />
2130
+ <PackageReference Include="Some.Package" Version="$(SomePackageVersion)" />
1956
2131
  </ItemGroup>
1957
2132
  </Project>
1958
- """.SetEOL(EOL))),
2133
+ """)),
1959
2134
  ContentEncoding = "base64"
1960
2135
  },
1961
- new DependencyFile()
1962
- {
1963
- Directory = "/library3",
1964
- Name = "library3.csproj",
1965
- Content = Convert.ToBase64String(Encoding.UTF8.GetBytes("""
1966
- <Project Sdk="Microsoft.NET.Sdk">
1967
- <PropertyGroup>
1968
- <TargetFramework>net8.0</TargetFramework>
1969
- </PropertyGroup>
1970
- <ItemGroup>
1971
- <PackageReference Include="Package.With.Transitive.Dependency" Version="0.1.0" />
1972
- </ItemGroup>
1973
- </Project>
1974
- """.SetEOL(EOL))),
1975
- ContentEncoding = "base64"
1976
- }
1977
2136
  ],
1978
2137
  BaseCommitSha = "TEST-COMMIT-SHA",
1979
2138
  },
1980
- expectedApiMessages: [
2139
+ expectedApiMessages:
2140
+ [
1981
2141
  new UpdatedDependencyList()
1982
2142
  {
1983
- Dependencies = [
1984
- new()
1985
- {
1986
- Name = "Some.Package",
1987
- Version = "2.0.0",
1988
- Requirements = [
1989
- new()
1990
- {
1991
- Requirement = "2.0.0",
1992
- File = "/library1/library1.csproj",
1993
- Groups = ["dependencies"],
1994
- }
1995
- ]
1996
- },
1997
- new()
2143
+ Dependencies =
2144
+ [
2145
+ new ReportedDependency()
1998
2146
  {
1999
2147
  Name = "Some.Package",
2000
2148
  Version = "1.0.0",
2001
- Requirements = [
2002
- new()
2149
+ Requirements =
2150
+ [
2151
+ new ReportedRequirement()
2003
2152
  {
2004
2153
  Requirement = "1.0.0",
2005
- File = "/library2/library2.csproj",
2006
- Groups = ["dependencies"],
2007
- }
2008
- ]
2009
- },
2010
- new()
2011
- {
2012
- Name = "Package.With.Transitive.Dependency",
2013
- Version = "0.1.0",
2014
- Requirements = [
2015
- new()
2016
- {
2017
- Requirement = "0.1.0",
2018
- File = "/library3/library3.csproj",
2154
+ File = "/project1/project1.csproj",
2019
2155
  Groups = ["dependencies"],
2020
2156
  }
2021
2157
  ]
2022
2158
  },
2023
- new()
2159
+ new ReportedDependency()
2024
2160
  {
2025
2161
  Name = "Some.Package",
2026
2162
  Version = "1.0.0",
2027
- Requirements = [
2028
- new()
2163
+ Requirements =
2164
+ [
2165
+ new ReportedRequirement()
2029
2166
  {
2030
2167
  Requirement = "1.0.0",
2031
- File = "/library3/library3.csproj",
2168
+ File = "/project2/project2.csproj",
2032
2169
  Groups = ["dependencies"],
2033
2170
  }
2034
2171
  ]
2035
- },
2036
- ],
2037
- DependencyFiles = [
2038
- "/Directory.Build.props",
2039
- "/Directory.Build.targets",
2040
- "/Directory.Packages.props",
2041
- "/library1/library1.csproj",
2042
- "/library2/library2.csproj",
2043
- "/library3/library3.csproj",
2172
+ }
2044
2173
  ],
2174
+ DependencyFiles = ["/Directory.Build.props", "/project1/project1.csproj", "/project2/project2.csproj"],
2045
2175
  },
2046
2176
  new IncrementMetric()
2047
2177
  {
2048
2178
  Metric = "updater.started",
2049
2179
  Tags = new()
2050
2180
  {
2051
- ["operation"] = "create_security_pr"
2181
+ ["operation"] = "group_update_all_versions"
2052
2182
  }
2053
2183
  },
2054
2184
  new CreatePullRequest()
2055
2185
  {
2056
- Dependencies = [
2057
- new()
2186
+ Dependencies =
2187
+ [
2188
+ new ReportedDependency()
2058
2189
  {
2059
2190
  Name = "Some.Package",
2060
- Version = "2.0.0",
2061
- Requirements = [
2062
- new()
2191
+ Version = "1.1.0",
2192
+ Requirements =
2193
+ [
2194
+ new ReportedRequirement()
2063
2195
  {
2064
- Requirement = "2.0.0",
2065
- File = "/library2/library2.csproj",
2196
+ Requirement = "1.1.0",
2197
+ File = "/project1/project1.csproj",
2066
2198
  Groups = ["dependencies"],
2067
2199
  Source = new()
2068
2200
  {
@@ -2072,24 +2204,26 @@ public class RunWorkerTests
2072
2204
  }
2073
2205
  ],
2074
2206
  PreviousVersion = "1.0.0",
2075
- PreviousRequirements = [
2076
- new()
2207
+ PreviousRequirements =
2208
+ [
2209
+ new ReportedRequirement()
2077
2210
  {
2078
2211
  Requirement = "1.0.0",
2079
- File = "/library2/library2.csproj",
2212
+ File = "/project1/project1.csproj",
2080
2213
  Groups = ["dependencies"],
2081
2214
  }
2082
2215
  ],
2083
2216
  },
2084
- new()
2217
+ new ReportedDependency()
2085
2218
  {
2086
2219
  Name = "Some.Package",
2087
- Version = "2.0.0",
2088
- Requirements = [
2089
- new()
2220
+ Version = "1.1.0",
2221
+ Requirements =
2222
+ [
2223
+ new ReportedRequirement()
2090
2224
  {
2091
- Requirement = "2.0.0",
2092
- File = "/library3/library3.csproj",
2225
+ Requirement = "1.1.0",
2226
+ File = "/project2/project2.csproj",
2093
2227
  Groups = ["dependencies"],
2094
2228
  Source = new()
2095
2229
  {
@@ -2099,53 +2233,36 @@ public class RunWorkerTests
2099
2233
  }
2100
2234
  ],
2101
2235
  PreviousVersion = "1.0.0",
2102
- PreviousRequirements = [
2103
- new()
2236
+ PreviousRequirements =
2237
+ [
2238
+ new ReportedRequirement()
2104
2239
  {
2105
2240
  Requirement = "1.0.0",
2106
- File = "/library3/library3.csproj",
2241
+ File = "/project2/project2.csproj",
2107
2242
  Groups = ["dependencies"],
2108
2243
  }
2109
2244
  ],
2110
2245
  },
2111
2246
  ],
2112
- UpdatedDependencyFiles = [
2113
- new()
2114
- {
2115
- Directory = "/library2",
2116
- Name = "library2.csproj",
2117
- Content = """
2118
- <Project Sdk="Microsoft.NET.Sdk">
2119
- <PropertyGroup>
2120
- <TargetFramework>net8.0</TargetFramework>
2121
- </PropertyGroup>
2122
- <ItemGroup>
2123
- <PackageReference Include="Some.Package" Version="2.0.0" />
2124
- </ItemGroup>
2125
- </Project>
2126
- """.SetEOL(EOL)
2127
- },
2128
- new()
2247
+ UpdatedDependencyFiles =
2248
+ [
2249
+ new DependencyFile()
2129
2250
  {
2130
- Directory = "/library3",
2131
- Name = "library3.csproj",
2251
+ Name = "Directory.Build.props",
2252
+ Directory = "/",
2132
2253
  Content = """
2133
- <Project Sdk="Microsoft.NET.Sdk">
2254
+ <Project>
2134
2255
  <PropertyGroup>
2135
- <TargetFramework>net8.0</TargetFramework>
2256
+ <SomePackageVersion>1.1.0</SomePackageVersion>
2136
2257
  </PropertyGroup>
2137
- <ItemGroup>
2138
- <PackageReference Include="Package.With.Transitive.Dependency" Version="0.1.0" />
2139
- <PackageReference Include="Some.Package" Version="2.0.0" />
2140
- </ItemGroup>
2141
2258
  </Project>
2142
- """.SetEOL(EOL)
2259
+ """,
2143
2260
  }
2144
2261
  ],
2145
2262
  BaseCommitSha = "TEST-COMMIT-SHA",
2146
2263
  CommitMessage = TestPullRequestCommitMessage,
2147
2264
  PrTitle = TestPullRequestTitle,
2148
- PrBody = TestPullRequestBody
2265
+ PrBody = TestPullRequestBody,
2149
2266
  },
2150
2267
  new MarkAsProcessed("TEST-COMMIT-SHA")
2151
2268
  ]
@@ -2894,7 +3011,262 @@ public class RunWorkerTests
2894
3011
  );
2895
3012
  }
2896
3013
 
2897
- private static Task RunAsync(Job job, TestFile[] files, IDiscoveryWorker? discoveryWorker, IAnalyzeWorker? analyzeWorker, IUpdaterWorker? updaterWorker, RunResult expectedResult, object[] expectedApiMessages, MockNuGetPackage[]? packages = null, ExperimentsManager? experimentsManager = null, string? repoContentsPath = null)
3014
+ [Fact]
3015
+ public async Task LineEndingsAreDetectedAndRestored()
3016
+ {
3017
+ await RunAsync(
3018
+ job: new Job()
3019
+ {
3020
+ Source = new()
3021
+ {
3022
+ Provider = "github",
3023
+ Repo = "test/repo",
3024
+ Directory = "/",
3025
+ }
3026
+ },
3027
+ files:
3028
+ [
3029
+ // initially LF
3030
+ ("file1", string.Concat(
3031
+ "file1-line1\n",
3032
+ "file1-line2\n",
3033
+ "file1-line3\n"
3034
+ )
3035
+ ),
3036
+ // initially CRLF
3037
+ ("file2", string.Concat(
3038
+ "file2-line1\r\n",
3039
+ "file2-line2\r\n",
3040
+ "file2-line3\r\n"
3041
+ )
3042
+ )
3043
+ ],
3044
+ discoveryWorker: TestDiscoveryWorker.FromResults(("/", new()
3045
+ {
3046
+ Path = "/",
3047
+ Projects = [
3048
+ new()
3049
+ {
3050
+ FilePath = "file1",
3051
+ Dependencies = [new("Dependency1", "1.0.0", DependencyType.PackageReference)],
3052
+ ImportedFiles = [],
3053
+ AdditionalFiles = [],
3054
+ },
3055
+ new()
3056
+ {
3057
+ FilePath = "file2",
3058
+ Dependencies = [new("Dependency2", "2.0.0", DependencyType.PackageReference)],
3059
+ ImportedFiles = [],
3060
+ AdditionalFiles = [],
3061
+ }
3062
+ ]
3063
+ })),
3064
+ analyzeWorker: new TestAnalyzeWorker(args =>
3065
+ {
3066
+ AnalysisResult result = args.Item3.Name switch
3067
+ {
3068
+ "Dependency1" => new()
3069
+ {
3070
+ CanUpdate = true,
3071
+ UpdatedVersion = "1.0.1",
3072
+ UpdatedDependencies = [new("Dependency1", "1.0.1", DependencyType.PackageReference)],
3073
+ },
3074
+ "Dependency2" => new()
3075
+ {
3076
+ CanUpdate = true,
3077
+ UpdatedVersion = "2.0.1",
3078
+ UpdatedDependencies = [new("Dependency2", "2.0.1", DependencyType.PackageReference)],
3079
+ },
3080
+ _ => throw new NotImplementedException()
3081
+ };
3082
+ return Task.FromResult(result);
3083
+ }),
3084
+ updaterWorker: new TestUpdaterWorker(async args =>
3085
+ {
3086
+ var (repoRoot, filePath, dependencyName, _previousVersion, _newVersion, _isTransitive) = args;
3087
+
3088
+ // file is explicitly updated with CR
3089
+ var (updatedFileContent, newVersion) = dependencyName switch
3090
+ {
3091
+ "Dependency1" => (string.Concat(
3092
+ "file1-line1-updated\r",
3093
+ "file1-line2-updated\r",
3094
+ "file1-line3-updated\r"), "1.0.1"),
3095
+ "Dependency2" => (string.Concat(
3096
+ "file2-line1-updated\r",
3097
+ "file2-line2-updated\r",
3098
+ "file2-line3-updated\r"), "2.0.1"),
3099
+ _ => throw new NotImplementedException(),
3100
+ };
3101
+ var fullFilePath = Path.Join(repoRoot, filePath);
3102
+ await File.WriteAllTextAsync(fullFilePath, updatedFileContent);
3103
+ return new UpdateOperationResult()
3104
+ {
3105
+ UpdateOperations = [new DirectUpdate()
3106
+ {
3107
+ DependencyName = dependencyName,
3108
+ NewVersion = NuGetVersion.Parse(newVersion),
3109
+ UpdatedFiles = [filePath],
3110
+ }],
3111
+ };
3112
+ }),
3113
+ expectedResult: new()
3114
+ {
3115
+ Base64DependencyFiles = [
3116
+ new()
3117
+ {
3118
+ Directory = "/",
3119
+ Name = "file1",
3120
+ Content = Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Concat(
3121
+ "file1-line1\n",
3122
+ "file1-line2\n",
3123
+ "file1-line3\n"))),
3124
+ ContentEncoding = "base64",
3125
+ },
3126
+ new()
3127
+ {
3128
+ Directory = "/",
3129
+ Name = "file2",
3130
+ Content = Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Concat(
3131
+ "file2-line1\r\n",
3132
+ "file2-line2\r\n",
3133
+ "file2-line3\r\n"))),
3134
+ ContentEncoding = "base64",
3135
+ }
3136
+ ],
3137
+ BaseCommitSha = "TEST-COMMIT-SHA",
3138
+ },
3139
+ expectedApiMessages: [
3140
+ new UpdatedDependencyList()
3141
+ {
3142
+ Dependencies = [
3143
+ new()
3144
+ {
3145
+ Name = "Dependency1",
3146
+ Version = "1.0.0",
3147
+ Requirements = [
3148
+ new()
3149
+ {
3150
+ Requirement = "1.0.0",
3151
+ File = "/file1",
3152
+ Groups = ["dependencies"],
3153
+ }
3154
+ ]
3155
+ },
3156
+ new()
3157
+ {
3158
+ Name = "Dependency2",
3159
+ Version = "2.0.0",
3160
+ Requirements = [
3161
+ new()
3162
+ {
3163
+ Requirement = "2.0.0",
3164
+ File = "/file2",
3165
+ Groups = ["dependencies"]
3166
+ }
3167
+ ]
3168
+ }
3169
+ ],
3170
+ DependencyFiles = ["/file1", "/file2"]
3171
+ },
3172
+ new IncrementMetric()
3173
+ {
3174
+ Metric = "updater.started",
3175
+ Tags = new()
3176
+ {
3177
+ ["operation"] = "group_update_all_versions"
3178
+ }
3179
+ },
3180
+ new CreatePullRequest()
3181
+ {
3182
+ Dependencies =
3183
+ [
3184
+ new ReportedDependency()
3185
+ {
3186
+ Name = "Dependency1",
3187
+ Version = "1.0.1",
3188
+ Requirements =
3189
+ [
3190
+ new ReportedRequirement()
3191
+ {
3192
+ Requirement = "1.0.1",
3193
+ File = "/file1",
3194
+ Groups = ["dependencies"],
3195
+ Source = new() { SourceUrl = null },
3196
+ }
3197
+ ],
3198
+ PreviousVersion = "1.0.0",
3199
+ PreviousRequirements =
3200
+ [
3201
+ new ReportedRequirement()
3202
+ {
3203
+ Requirement = "1.0.0",
3204
+ File = "/file1",
3205
+ Groups = ["dependencies"],
3206
+ }
3207
+ ],
3208
+ },
3209
+ new ReportedDependency()
3210
+ {
3211
+ Name = "Dependency2",
3212
+ Version = "2.0.1",
3213
+ Requirements =
3214
+ [
3215
+ new ReportedRequirement()
3216
+ {
3217
+ Requirement = "2.0.1",
3218
+ File = "/file2",
3219
+ Groups = ["dependencies"],
3220
+ Source = new() { SourceUrl = null },
3221
+ }
3222
+ ],
3223
+ PreviousVersion = "2.0.0",
3224
+ PreviousRequirements =
3225
+ [
3226
+ new ReportedRequirement()
3227
+ {
3228
+ Requirement = "2.0.0",
3229
+ File = "/file2",
3230
+ Groups = ["dependencies"],
3231
+ }
3232
+ ],
3233
+ },
3234
+ ],
3235
+ UpdatedDependencyFiles =
3236
+ [
3237
+ // original line endings have been restored
3238
+ new DependencyFile()
3239
+ {
3240
+ Name = "file1",
3241
+ Directory = "/",
3242
+ Content = string.Concat(
3243
+ "file1-line1-updated\n",
3244
+ "file1-line2-updated\n",
3245
+ "file1-line3-updated\n"
3246
+ ),
3247
+ },
3248
+ new DependencyFile()
3249
+ {
3250
+ Name = "file2",
3251
+ Directory = "/",
3252
+ Content = string.Concat(
3253
+ "file2-line1-updated\r\n",
3254
+ "file2-line2-updated\r\n",
3255
+ "file2-line3-updated\r\n"
3256
+ ),
3257
+ },
3258
+ ],
3259
+ BaseCommitSha = "TEST-COMMIT-SHA",
3260
+ CommitMessage = TestPullRequestCommitMessage,
3261
+ PrTitle = TestPullRequestTitle,
3262
+ PrBody = TestPullRequestBody,
3263
+ },
3264
+ new MarkAsProcessed("TEST-COMMIT-SHA"),
3265
+ ]
3266
+ );
3267
+ }
3268
+
3269
+ internal static Task RunAsync(Job job, TestFile[] files, IDiscoveryWorker? discoveryWorker, IAnalyzeWorker? analyzeWorker, IUpdaterWorker? updaterWorker, RunResult expectedResult, object[] expectedApiMessages, MockNuGetPackage[]? packages = null, ExperimentsManager? experimentsManager = null, string? repoContentsPath = null)
2898
3270
  {
2899
3271
  var rawTestFiles = files.Select(f => (f.Path, Encoding.UTF8.GetBytes(f.Content))).ToArray();
2900
3272
  return RunAsync(job, rawTestFiles, discoveryWorker, analyzeWorker, updaterWorker, expectedResult, expectedApiMessages, packages, experimentsManager, repoContentsPath);