dependabot-nuget 0.323.0 → 0.325.1

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Program.cs +0 -4
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +1 -31
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyFinder.cs +0 -3
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyInfo.cs +1 -0
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +64 -10
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Clone/CloneWorker.cs +1 -1
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/DependencySolver/MSBuildDependencySolver.cs +10 -4
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +4 -4
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscovery.cs +2 -2
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +31 -41
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +3 -6
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Cooldown.cs +83 -0
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +2 -1
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ModifiedFilesTracker.cs +9 -1
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestBodyGenerator/DetailedPullRequestBodyGenerator.cs +6 -0
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +8 -1
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs +1 -1
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/GroupUpdateAllVersionsHandler.cs +79 -67
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandler.cs +1 -1
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshSecurityUpdatePullRequestHandler.cs +1 -1
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshVersionUpdatePullRequestHandler.cs +1 -1
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/FileWriterWorker.cs +10 -7
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/XmlFileWriter.cs +245 -125
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +4 -11
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +4 -5
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +1 -1
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/DependencyConflictResolver.cs +2 -2
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +14 -31
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +3 -5
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProcessExtensions.cs +12 -13
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/XmlExtensions.cs +3 -3
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +78 -2
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/VersionFinderTests.cs +126 -3
  35. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Clone/CloneWorkerTests.cs +14 -0
  36. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/DependencySolver/MSBuildDependencySolverTests.cs +1 -2
  37. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +2 -2
  38. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +1 -2
  39. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +0 -6
  40. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +2 -3
  41. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +1 -2
  42. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/ApiModel/CooldownTests.cs +99 -0
  43. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +168 -4
  44. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestBodyGenerator/DetailedPullRequestBodyGeneratorTests.cs +71 -0
  45. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +71 -0
  46. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/GroupUpdateAllVersionsHandlerTests.cs +70 -39
  47. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/FileWriterWorkerTests.cs +43 -30
  48. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/XmlFileWriterTests.cs +76 -3
  49. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackageReferenceUpdaterTests.cs +0 -2
  50. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +11 -27
  51. data/lib/dependabot/nuget.rb +3 -11
  52. metadata +8 -54
  53. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +0 -49
  54. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs +0 -60
  55. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/FrameworkCheckCommand.cs +0 -35
  56. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs +0 -58
  57. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +0 -380
  58. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +0 -557
  59. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.FrameworkCheck.cs +0 -37
  60. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +0 -226
  61. data/lib/dependabot/nuget/analysis/analysis_json_reader.rb +0 -65
  62. data/lib/dependabot/nuget/analysis/dependency_analysis.rb +0 -66
  63. data/lib/dependabot/nuget/cache_manager.rb +0 -29
  64. data/lib/dependabot/nuget/discovery/dependency_details.rb +0 -102
  65. data/lib/dependabot/nuget/discovery/dependency_file_discovery.rb +0 -122
  66. data/lib/dependabot/nuget/discovery/discovery_json_reader.rb +0 -266
  67. data/lib/dependabot/nuget/discovery/evaluation_details.rb +0 -63
  68. data/lib/dependabot/nuget/discovery/project_discovery.rb +0 -104
  69. data/lib/dependabot/nuget/discovery/property_details.rb +0 -43
  70. data/lib/dependabot/nuget/discovery/workspace_discovery.rb +0 -61
  71. data/lib/dependabot/nuget/file_fetcher.rb +0 -46
  72. data/lib/dependabot/nuget/file_parser.rb +0 -153
  73. data/lib/dependabot/nuget/file_updater.rb +0 -256
  74. data/lib/dependabot/nuget/language.rb +0 -98
  75. data/lib/dependabot/nuget/metadata_finder.rb +0 -197
  76. data/lib/dependabot/nuget/native_helpers.rb +0 -364
  77. data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +0 -88
  78. data/lib/dependabot/nuget/package_manager.rb +0 -51
  79. data/lib/dependabot/nuget/update_checker/requirements_updater.rb +0 -105
  80. data/lib/dependabot/nuget/update_checker.rb +0 -210
@@ -0,0 +1,99 @@
1
+ using System.Collections.Immutable;
2
+
3
+ using NuGet.Versioning;
4
+
5
+ using NuGetUpdater.Core.Run.ApiModel;
6
+
7
+ using Xunit;
8
+
9
+ namespace NuGetUpdater.Core.Test.Run.ApiModel;
10
+
11
+ public class CooldownTests
12
+ {
13
+ [Theory]
14
+ [InlineData("2025-07-04T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "2.0.0", true)] // 3 days later - major allowed
15
+ [InlineData("2025-07-04T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "1.1.0", true)] // 3 days later - minor allowed
16
+ [InlineData("2025-07-04T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "1.0.1", true)] // 3 days later - patch allowed
17
+ [InlineData("2025-07-03T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "2.0.0", false)] // 2 days later - major not allowed
18
+ [InlineData("2025-07-03T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "1.1.0", true)] // 2 days later - minor allowed
19
+ [InlineData("2025-07-03T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "1.0.1", true)] // 2 days later - patch allowed
20
+ [InlineData("2025-07-02T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "2.0.0", false)] // 1 day later - major not allowed
21
+ [InlineData("2025-07-02T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "1.1.0", false)] // 1 day later - minor not allowed
22
+ [InlineData("2025-07-02T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "1.0.1", true)] // 1 day later - patch allowed
23
+ [InlineData("2025-07-01T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "2.0.0", false)] // same day - major not allowed
24
+ [InlineData("2025-07-01T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "1.1.0", false)] // same day - minor not allowed
25
+ [InlineData("2025-07-01T00:00:00Z", "2025-07-01T00:00:00Z", "1.0.0", "1.0.1", false)] // same day - patch not allowed
26
+ [InlineData("2025-07-01T00:00:00Z", null, "1.0.0", "2.0.0", true)] // no publish date - major allowed
27
+ [InlineData("2025-07-01T00:00:00Z", null, "1.0.0", "1.1.0", true)] // no publish date - minor allowed
28
+ [InlineData("2025-07-01T00:00:00Z", null, "1.0.0", "1.0.1", true)] // no publish date - patch allowed
29
+ public void Cooldown(string currentTimeString, string? packagePublishTimeString, string currentVersionString, string candidateVersionString, bool expectedIsUpdateAllowed)
30
+ {
31
+ // all scenarios use the same configuration
32
+ var cooldown = new Cooldown()
33
+ {
34
+ DefaultDays = 4,
35
+ SemVerMajorDays = 3,
36
+ SemVerMinorDays = 2,
37
+ SemVerPatchDays = 1,
38
+ };
39
+ var currentTime = DateTimeOffset.Parse(currentTimeString);
40
+ var packagePublishTime = packagePublishTimeString is null ? (DateTimeOffset?)null : DateTimeOffset.Parse(packagePublishTimeString);
41
+ var currentVersion = NuGetVersion.Parse(currentVersionString);
42
+ var candidateVersion = NuGetVersion.Parse(candidateVersionString);
43
+ var actualIsUpdateAllowed = cooldown.IsVersionUpdateAllowed(currentTime, packagePublishTime, currentVersion, candidateVersion);
44
+ Assert.Equal(expectedIsUpdateAllowed, actualIsUpdateAllowed);
45
+ }
46
+
47
+ [Theory]
48
+ [InlineData(4, 3, 2, 1, "1.0.0", "2.0.0", 3)] // major update allowed after 3 days
49
+ [InlineData(4, 3, 2, 1, "1.0.0", "1.1.0", 2)] // minor update allowed after 2 days
50
+ [InlineData(4, 3, 2, 1, "1.0.0", "1.0.1", 1)] // patch update allowed after 1 day
51
+ [InlineData(4, 0, 0, 0, "1.0.0", "2.0.0", 4)] // major update allowed after default days
52
+ [InlineData(4, 0, 0, 0, "1.0.0", "1.1.0", 4)] // minor update allowed after default days
53
+ [InlineData(4, 0, 0, 0, "1.0.0", "1.0.1", 4)] // patch update allowed after default day
54
+ [InlineData(4, 3, 2, 1, "1.0.0-beta1", "1.0.0-beta2", 4)] // default update allowed after 4 days
55
+ public void GetCooldownDays(int defaultDays, int semverMajorDays, int semverMinorDays, int semverPatchDays, string currentVersionString, string candidateUpdateVersioString, int expectedDaysDelay)
56
+ {
57
+ var cooldown = new Cooldown()
58
+ {
59
+ DefaultDays = defaultDays,
60
+ SemVerMajorDays = semverMajorDays,
61
+ SemVerMinorDays = semverMinorDays,
62
+ SemVerPatchDays = semverPatchDays,
63
+ };
64
+ var currentVersion = NuGetVersion.Parse(currentVersionString);
65
+ var candidateUpdateVersion = NuGetVersion.Parse(candidateUpdateVersioString);
66
+ var actualDaysDelay = cooldown.GetCooldownDays(currentVersion, candidateUpdateVersion);
67
+ Assert.Equal(expectedDaysDelay, actualDaysDelay);
68
+ }
69
+
70
+ [Theory]
71
+ [InlineData(null, null, "Some.Package", true)] // no include, no exclude - always applies
72
+ [InlineData("", null, "Some.Package", true)] // empty include, no exclude - always applies
73
+ [InlineData("*", null, "Some.Package", true)] // wildcard include, no exclude - always applies
74
+ [InlineData(null, "", "Some.Package", true)] // no include, empty exclude - always applies
75
+ [InlineData("", "", "Some.Package", true)] // empty include, empty exclude - always applies
76
+ [InlineData("*", "", "Some.Package", true)] // wildcard include, empty exclude - always applies
77
+ [InlineData(null, "*", "Some.Package", false)] // no include, wildcard exclude - never applies
78
+ [InlineData("", "*", "Some.Package", false)] // empty include, wildcard exclude - never applies
79
+ [InlineData(null, "Some.*", "Some.Package", false)] // no include, exclude pattern match - doesn't apply
80
+ [InlineData("", "Some.*", "Some.Package", false)] // empty include, exclude pattern match - doesn't apply
81
+ [InlineData("*", "Some.*", "Some.Package", false)] // wildcard include, exclude pattern match - doesn't apply
82
+ [InlineData("*", "Some.*", "Other.Package", true)] // wildcard include, exclude doesn't match - applies
83
+ [InlineData("Some.*", null, "Some.Package", true)] // include pattern match, no exclude - applies
84
+ [InlineData("Some.*", "", "Some.Package", true)] // include pattern match, empty exclude - applies
85
+ [InlineData("Some.*", null, "Other.Package", false)] // include pattern doesn't match, no exclude - doesn't apply
86
+ [InlineData("Some.*", "", "Other.Package", false)] // include pattern doesn't match, empty exclude - doesn't apply
87
+ [InlineData("Some.*", "Some.Other.*", "Some.Package", true)] // include pattern match, exclude pattern doesn't match - applies
88
+ [InlineData("Some.*", "Some.Other.*", "Some.Other.Package", false)] // include pattern match, exclude pattern match - doesn't apply
89
+ public void CooldownAppliesToPackage(string? includeString, string? excludeString, string packageName, bool expectedResult)
90
+ {
91
+ var cooldown = new Cooldown()
92
+ {
93
+ Include = includeString?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToImmutableArray(),
94
+ Exclude = excludeString?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToImmutableArray(),
95
+ };
96
+ var actualResult = cooldown.AppliesToPackage(packageName);
97
+ Assert.Equal(expectedResult, actualResult);
98
+ }
99
+ }
@@ -515,9 +515,9 @@ public class MiscellaneousTests
515
515
 
516
516
  [Theory]
517
517
  [MemberData(nameof(DependencyInfoFromJobData))]
518
- public void DependencyInfoFromJob(Job job, Dependency dependency, DependencyInfo expectedDependencyInfo)
518
+ public void DependencyInfoFromJob(Job job, Dependency dependency, bool enableCooldown, DependencyInfo expectedDependencyInfo)
519
519
  {
520
- var actualDependencyInfo = RunWorker.GetDependencyInfo(job, dependency);
520
+ var actualDependencyInfo = RunWorker.GetDependencyInfo(job, dependency, enableCooldown);
521
521
  var expectedString = JsonSerializer.Serialize(expectedDependencyInfo, AnalyzeWorker.SerializerOptions);
522
522
  var actualString = JsonSerializer.Serialize(actualDependencyInfo, AnalyzeWorker.SerializerOptions);
523
523
  Assert.Equal(expectedString, actualString);
@@ -634,6 +634,8 @@ public class MiscellaneousTests
634
634
  },
635
635
  // dependency
636
636
  new Dependency("Some.Dependency", "1.0.0", DependencyType.PackageReference),
637
+ // enableCooldown
638
+ true,
637
639
  // expectedDependencyInfo
638
640
  new DependencyInfo()
639
641
  {
@@ -651,7 +653,7 @@ public class MiscellaneousTests
651
653
  }
652
654
  ],
653
655
  IgnoredUpdateTypes = [],
654
- }
656
+ },
655
657
  ];
656
658
 
657
659
  yield return
@@ -679,6 +681,8 @@ public class MiscellaneousTests
679
681
  },
680
682
  // dependency
681
683
  new Dependency("Some.Dependency", "1.0.0", DependencyType.PackageReference),
684
+ // enableCooldown
685
+ true,
682
686
  // expectedDependencyInfo
683
687
  new DependencyInfo()
684
688
  {
@@ -688,7 +692,167 @@ public class MiscellaneousTests
688
692
  IgnoredVersions = [],
689
693
  Vulnerabilities = [],
690
694
  IgnoredUpdateTypes = [ConditionUpdateType.SemVerMajor],
691
- }
695
+ },
696
+ ];
697
+
698
+ // with cooldown object when `include` and `exclude` are empty
699
+ yield return
700
+ [
701
+ // job
702
+ new Job()
703
+ {
704
+ Source = new()
705
+ {
706
+ Provider = "github",
707
+ Repo = "some/repo",
708
+ },
709
+ Cooldown = new()
710
+ {
711
+ DefaultDays = 4,
712
+ SemVerMajorDays = 3,
713
+ SemVerMinorDays = 2,
714
+ SemVerPatchDays = 1,
715
+ }
716
+ },
717
+ // dependency
718
+ new Dependency("Some.Dependency", "1.0.0", DependencyType.PackageReference),
719
+ // enableCooldown
720
+ true,
721
+ // expectedDependencyInfo
722
+ new DependencyInfo()
723
+ {
724
+ Name = "Some.Dependency",
725
+ Version = "1.0.0",
726
+ IsVulnerable = false,
727
+ IgnoredVersions = [],
728
+ Vulnerabilities = [],
729
+ IgnoredUpdateTypes = [],
730
+ Cooldown = new()
731
+ {
732
+ DefaultDays = 4,
733
+ SemVerMajorDays = 3,
734
+ SemVerMinorDays = 2,
735
+ SemVerPatchDays = 1,
736
+ }
737
+ },
738
+ ];
739
+
740
+ // with cooldown object when `include` matches and `exclude` is empty
741
+ yield return
742
+ [
743
+ // job
744
+ new Job()
745
+ {
746
+ Source = new()
747
+ {
748
+ Provider = "github",
749
+ Repo = "some/repo",
750
+ },
751
+ Cooldown = new()
752
+ {
753
+ DefaultDays = 4,
754
+ SemVerMajorDays = 3,
755
+ SemVerMinorDays = 2,
756
+ SemVerPatchDays = 1,
757
+ Include = ["Some.*"],
758
+ }
759
+ },
760
+ // dependency
761
+ new Dependency("Some.Dependency", "1.0.0", DependencyType.PackageReference),
762
+ // enableCooldown
763
+ true,
764
+ // expectedDependencyInfo
765
+ new DependencyInfo()
766
+ {
767
+ Name = "Some.Dependency",
768
+ Version = "1.0.0",
769
+ IsVulnerable = false,
770
+ IgnoredVersions = [],
771
+ Vulnerabilities = [],
772
+ IgnoredUpdateTypes = [],
773
+ Cooldown = new()
774
+ {
775
+ DefaultDays = 4,
776
+ SemVerMajorDays = 3,
777
+ SemVerMinorDays = 2,
778
+ SemVerPatchDays = 1,
779
+ Include = ["Some.*"],
780
+ }
781
+ },
782
+ ];
783
+
784
+ // without cooldown object `exclude` matches
785
+ yield return
786
+ [
787
+ // job
788
+ new Job()
789
+ {
790
+ Source = new()
791
+ {
792
+ Provider = "github",
793
+ Repo = "some/repo",
794
+ },
795
+ Cooldown = new()
796
+ {
797
+ DefaultDays = 4,
798
+ SemVerMajorDays = 3,
799
+ SemVerMinorDays = 2,
800
+ SemVerPatchDays = 1,
801
+ Exclude = ["Some.*"],
802
+ }
803
+ },
804
+ // dependency
805
+ new Dependency("Some.Dependency", "1.0.0", DependencyType.PackageReference),
806
+ // enableCooldown
807
+ true,
808
+ // expectedDependencyInfo
809
+ new DependencyInfo()
810
+ {
811
+ Name = "Some.Dependency",
812
+ Version = "1.0.0",
813
+ IsVulnerable = false,
814
+ IgnoredVersions = [],
815
+ Vulnerabilities = [],
816
+ IgnoredUpdateTypes = [],
817
+ Cooldown = null,
818
+ },
819
+ ];
820
+
821
+ // with cooldown object when `include` matches but experiment flag is false
822
+ yield return
823
+ [
824
+ // job
825
+ new Job()
826
+ {
827
+ Source = new()
828
+ {
829
+ Provider = "github",
830
+ Repo = "some/repo",
831
+ },
832
+ Cooldown = new()
833
+ {
834
+ DefaultDays = 4,
835
+ SemVerMajorDays = 3,
836
+ SemVerMinorDays = 2,
837
+ SemVerPatchDays = 1,
838
+ Include = ["Some.*"],
839
+ }
840
+ },
841
+ // dependency
842
+ new Dependency("Some.Dependency", "1.0.0", DependencyType.PackageReference),
843
+ // enableCooldown
844
+ false,
845
+ // expectedDependencyInfo
846
+ new DependencyInfo()
847
+ {
848
+ Name = "Some.Dependency",
849
+ Version = "1.0.0",
850
+ IsVulnerable = false,
851
+ IgnoredVersions = [],
852
+ Vulnerabilities = [],
853
+ IgnoredUpdateTypes = [],
854
+ Cooldown = null
855
+ },
692
856
  ];
693
857
  }
694
858
  }
@@ -841,6 +841,77 @@ public class DetailedPullRequestBodyGeneratorTests
841
841
  );
842
842
  }
843
843
 
844
+ [Fact]
845
+ public async Task GeneratePrBody_GitSuffixIsHandled()
846
+ {
847
+ await TestAsync(
848
+ updateOperationsPerformed: [
849
+ new DirectUpdate() { DependencyName = "Some.Dependency", OldVersion = NuGetVersion.Parse("1.0.0"), NewVersion = NuGetVersion.Parse("2.0.0"), UpdatedFiles = [] },
850
+ ],
851
+ updatedDependencies: [
852
+ new ReportedDependency()
853
+ {
854
+ Name = "Some.Dependency",
855
+ PreviousVersion = "1.0.0",
856
+ Version = "2.0.0",
857
+ Requirements = [
858
+ new ReportedRequirement()
859
+ {
860
+ File = "",
861
+ Requirement = "2.0.0",
862
+ Source = new()
863
+ {
864
+ SourceUrl = "https://github.com/Some.Owner/Some.Dependency.git",
865
+ },
866
+ }
867
+ ],
868
+ }
869
+ ],
870
+ httpResponses: [
871
+ ("https://api.github.com/repos/Some.Owner/Some.Dependency/releases?per_page=100", """
872
+ [
873
+ {
874
+ "name": "2.0.0",
875
+ "tag_name": "2.0.0",
876
+ "body": "* point 5\n* point 6"
877
+ },
878
+ {
879
+ "name": "1.0.1",
880
+ "tag_name": "1.0.1",
881
+ "body": "* point 3\n* point 4"
882
+ },
883
+ {
884
+ "name": "1.0.0",
885
+ "tag_name": "1.0.0",
886
+ "body": "* point 1\n* point 2"
887
+ }
888
+ ]
889
+ """)
890
+ ],
891
+ expectedBody: $"""
892
+ Updated [Some.Dependency](https://github.com/Some.Owner/Some.Dependency) from 1.0.0 to 2.0.0.
893
+
894
+ <details>
895
+ <summary>Release notes</summary>
896
+
897
+ _Sourced from [Some.Dependency's releases](https://github.com/Some.Owner/Some.Dependency/releases)._
898
+
899
+ ## 2.0.0
900
+
901
+ * point 5
902
+ * point 6
903
+
904
+ ## 1.0.1
905
+
906
+ * point 3
907
+ * point 4
908
+
909
+ Commits viewable in [compare view](https://github.com/Some.Owner/Some.Dependency/compare/1.0.0...2.0.0).
910
+ </details>
911
+ """
912
+ );
913
+ }
914
+
844
915
  private static async Task TestAsync(
845
916
  ImmutableArray<UpdateOperationBase> updateOperationsPerformed,
846
917
  ImmutableArray<ReportedDependency> updatedDependencies,
@@ -1,3 +1,5 @@
1
+ using System.Text.Json;
2
+
1
3
  using NuGet.Versioning;
2
4
 
3
5
  using NuGetUpdater.Core.Run;
@@ -61,6 +63,26 @@ public class SerializationTests : TestBase
61
63
  Assert.Equal("github", jobWrapper.Job.Source.Provider);
62
64
  Assert.Equal("some-org/some-repo", jobWrapper.Job.Source.Repo);
63
65
  Assert.Equal("specific-sdk", jobWrapper.Job.Source.Directory);
66
+ Assert.Null(jobWrapper.Job.Cooldown);
67
+ }
68
+
69
+ [Fact]
70
+ public void DeserializeJob_Cooldown()
71
+ {
72
+ var jobWrapper = RunWorker.Deserialize("""
73
+ {
74
+ "job": {
75
+ "package-manager": "nuget",
76
+ "source": {
77
+ "provider": "github",
78
+ "repo": "test/repo",
79
+ "directory": "/"
80
+ },
81
+ "cooldown": {}
82
+ }
83
+ }
84
+ """);
85
+ Assert.NotNull(jobWrapper.Job.Cooldown);
64
86
  }
65
87
 
66
88
  [Fact]
@@ -536,6 +558,55 @@ public class SerializationTests : TestBase
536
558
  Assert.Equal(expectedIncludeScopeValue, jobWrapper.Job.CommitMessageOptions!.IncludeScope);
537
559
  }
538
560
 
561
+ [Fact]
562
+ public void DeserializeCooldown_DefaultValues()
563
+ {
564
+ var cooldown = JsonSerializer.Deserialize<Cooldown>("{}", RunWorker.SerializerOptions);
565
+ Assert.NotNull(cooldown);
566
+ Assert.Equal(0, cooldown.DefaultDays);
567
+ Assert.Equal(0, cooldown.SemVerMajorDays);
568
+ Assert.Equal(0, cooldown.SemVerMinorDays);
569
+ Assert.Equal(0, cooldown.SemVerPatchDays);
570
+ Assert.Null(cooldown.Include);
571
+ Assert.Null(cooldown.Exclude);
572
+ }
573
+
574
+ [Fact]
575
+ public void DeserializeCooldown_ExplicitlyNullIncudeAndExclude()
576
+ {
577
+ var cooldown = JsonSerializer.Deserialize<Cooldown>("""
578
+ {
579
+ "include": null,
580
+ "exclude": null
581
+ }
582
+ """, RunWorker.SerializerOptions);
583
+ Assert.NotNull(cooldown);
584
+ Assert.Null(cooldown.Include);
585
+ Assert.Null(cooldown.Exclude);
586
+ }
587
+
588
+ [Fact]
589
+ public void DeserializeCooldown_SpecificValues()
590
+ {
591
+ var cooldown = JsonSerializer.Deserialize<Cooldown>("""
592
+ {
593
+ "default-days": 1,
594
+ "semver-major-days": 2,
595
+ "semver-minor-days": 3,
596
+ "semver-patch-days": 4,
597
+ "include": ["dependency-1"],
598
+ "exclude": ["dependency-2"]
599
+ }
600
+ """, RunWorker.SerializerOptions);
601
+ Assert.NotNull(cooldown);
602
+ Assert.Equal(1, cooldown.DefaultDays);
603
+ Assert.Equal(2, cooldown.SemVerMajorDays);
604
+ Assert.Equal(3, cooldown.SemVerMinorDays);
605
+ Assert.Equal(4, cooldown.SemVerPatchDays);
606
+ AssertEx.Equal(["dependency-1"], cooldown.Include);
607
+ AssertEx.Equal(["dependency-2"], cooldown.Exclude);
608
+ }
609
+
539
610
  [Fact]
540
611
  public void SerializeClosePullRequest()
541
612
  {
@@ -4,6 +4,7 @@ using NuGetUpdater.Core.Analyze;
4
4
  using NuGetUpdater.Core.Discover;
5
5
  using NuGetUpdater.Core.Run.ApiModel;
6
6
  using NuGetUpdater.Core.Run.UpdateHandlers;
7
+ using NuGetUpdater.Core.Test.Utilities;
7
8
  using NuGetUpdater.Core.Updater;
8
9
 
9
10
  using Xunit;
@@ -12,10 +13,40 @@ namespace NuGetUpdater.Core.Test.Run.UpdateHandlers;
12
13
 
13
14
  public class GroupUpdateAllVersionsHandlerTests : UpdateHandlersTestsBase
14
15
  {
16
+ [Fact]
17
+ public void UpdatesAreCollectedByDependencyNameAndVersion()
18
+ {
19
+ var discovery = new WorkspaceDiscoveryResult()
20
+ {
21
+ Path = "/",
22
+ Projects = [
23
+ new()
24
+ {
25
+ FilePath = "project1.csproj",
26
+ Dependencies = [new("SOME.DEPENDENCY", "1.0.0", DependencyType.PackageReference, IsTransitive: true)],
27
+ ImportedFiles = [],
28
+ AdditionalFiles = [],
29
+ },
30
+ new()
31
+ {
32
+ FilePath = "project2.csproj",
33
+ Dependencies = [new("some.dependency", "1.0.0", DependencyType.PackageReference, IsTransitive: false)],
34
+ ImportedFiles = [],
35
+ AdditionalFiles = [],
36
+ }
37
+ ]
38
+ };
39
+ var updateOperations = GroupUpdateAllVersionsHandler.CollectUpdateOperationsByDependency(discovery);
40
+ var updateOperation = Assert.Single(updateOperations);
41
+ Assert.Equal("some.dependency/1.0.0", updateOperation.Key.ToString());
42
+ var operationProjects = updateOperation.Select(p => p.ProjectPath).ToArray();
43
+ AssertEx.Equal(["/project1.csproj", "/project2.csproj"], operationProjects);
44
+ }
45
+
15
46
  [Fact]
16
47
  public async Task GeneratesCreatePullRequest_NoGroups()
17
48
  {
18
- // no groups specified; create 1 PR for each directory
49
+ // no groups specified; create 1 PR for each directory for each dependency
19
50
  await TestAsync(
20
51
  job: new Job()
21
52
  {
@@ -34,8 +65,8 @@ public class GroupUpdateAllVersionsHandlerTests : UpdateHandlersTestsBase
34
65
  {
35
66
  FilePath = "project.csproj",
36
67
  Dependencies = [
37
- new("Some.Dependency", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net9.0"]),
38
- new("Some.Other.Dependency", "3.0.0", DependencyType.PackageReference, TargetFrameworks: ["net9.0"]),
68
+ new("Production.Dependency.1", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net9.0"]),
69
+ new("Production.Dependency.2", "3.0.0", DependencyType.PackageReference, TargetFrameworks: ["net9.0"]),
39
70
  ],
40
71
  ImportedFiles = [],
41
72
  AdditionalFiles = [],
@@ -50,8 +81,7 @@ public class GroupUpdateAllVersionsHandlerTests : UpdateHandlersTestsBase
50
81
  {
51
82
  FilePath = "project.csproj",
52
83
  Dependencies = [
53
- new("Some.Dependency", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net9.0"]),
54
- new("Some.Other.Dependency", "3.0.0", DependencyType.PackageReference, TargetFrameworks: ["net9.0"]),
84
+ new("Test.Dependency", "5.0.0", DependencyType.PackageReference, TargetFrameworks: ["net9.0"]),
55
85
  ],
56
86
  ImportedFiles = [],
57
87
  AdditionalFiles = [],
@@ -66,8 +96,9 @@ public class GroupUpdateAllVersionsHandlerTests : UpdateHandlersTestsBase
66
96
  var dependencyInfo = input.Item3;
67
97
  var newVersion = dependencyInfo.Name switch
68
98
  {
69
- "Some.Dependency" => "2.0.0",
70
- "Some.Other.Dependency" => "4.0.0",
99
+ "Production.Dependency.1" => "2.0.0",
100
+ "Production.Dependency.2" => "4.0.0",
101
+ "Test.Dependency" => "6.0.0",
71
102
  _ => throw new NotImplementedException($"Test didn't expect to update dependency {dependencyInfo.Name}"),
72
103
  };
73
104
  return Task.FromResult(new AnalysisResult()
@@ -109,7 +140,7 @@ public class GroupUpdateAllVersionsHandlerTests : UpdateHandlersTestsBase
109
140
  Dependencies = [
110
141
  new()
111
142
  {
112
- Name = "Some.Dependency",
143
+ Name = "Production.Dependency.1",
113
144
  Version = "1.0.0",
114
145
  Requirements = [
115
146
  new() { Requirement = "1.0.0", File = "/src/project.csproj", Groups = ["dependencies"] },
@@ -117,7 +148,7 @@ public class GroupUpdateAllVersionsHandlerTests : UpdateHandlersTestsBase
117
148
  },
118
149
  new()
119
150
  {
120
- Name = "Some.Other.Dependency",
151
+ Name = "Production.Dependency.2",
121
152
  Version = "3.0.0",
122
153
  Requirements = [
123
154
  new() { Requirement = "3.0.0", File = "/src/project.csproj", Groups = ["dependencies"] },
@@ -126,12 +157,13 @@ public class GroupUpdateAllVersionsHandlerTests : UpdateHandlersTestsBase
126
157
  ],
127
158
  DependencyFiles = ["/src/project.csproj"],
128
159
  },
160
+ // for "/src" and Production.Dependency.1
129
161
  new CreatePullRequest()
130
162
  {
131
163
  Dependencies = [
132
164
  new()
133
165
  {
134
- Name = "Some.Dependency",
166
+ Name = "Production.Dependency.1",
135
167
  Version = "2.0.0",
136
168
  Requirements = [
137
169
  new() { Requirement = "2.0.0", File = "/src/project.csproj", Groups = ["dependencies"], Source = new() { SourceUrl = null } },
@@ -141,9 +173,28 @@ public class GroupUpdateAllVersionsHandlerTests : UpdateHandlersTestsBase
141
173
  new() { Requirement = "1.0.0", File = "/src/project.csproj", Groups = ["dependencies"] },
142
174
  ],
143
175
  },
176
+ ],
177
+ UpdatedDependencyFiles = [
144
178
  new()
145
179
  {
146
- Name = "Some.Other.Dependency",
180
+ Directory = "/src",
181
+ Name = "project.csproj",
182
+ Content = "updated contents",
183
+ },
184
+ ],
185
+ BaseCommitSha = "TEST-COMMIT-SHA",
186
+ CommitMessage = EndToEndTests.TestPullRequestCommitMessage,
187
+ PrTitle = EndToEndTests.TestPullRequestTitle,
188
+ PrBody = EndToEndTests.TestPullRequestBody,
189
+ DependencyGroup = null,
190
+ },
191
+ // for "/src" and Production.Dependency.2
192
+ new CreatePullRequest()
193
+ {
194
+ Dependencies = [
195
+ new()
196
+ {
197
+ Name = "Production.Dependency.2",
147
198
  Version = "4.0.0",
148
199
  Requirements = [
149
200
  new() { Requirement = "4.0.0", File = "/src/project.csproj", Groups = ["dependencies"], Source = new() { SourceUrl = null } },
@@ -174,18 +225,10 @@ public class GroupUpdateAllVersionsHandlerTests : UpdateHandlersTestsBase
174
225
  Dependencies = [
175
226
  new()
176
227
  {
177
- Name = "Some.Dependency",
178
- Version = "1.0.0",
179
- Requirements = [
180
- new() { Requirement = "1.0.0", File = "/test/project.csproj", Groups = ["dependencies"] },
181
- ],
182
- },
183
- new()
184
- {
185
- Name = "Some.Other.Dependency",
186
- Version = "3.0.0",
228
+ Name = "Test.Dependency",
229
+ Version = "5.0.0",
187
230
  Requirements = [
188
- new() { Requirement = "3.0.0", File = "/test/project.csproj", Groups = ["dependencies"] },
231
+ new() { Requirement = "5.0.0", File = "/test/project.csproj", Groups = ["dependencies"] },
189
232
  ],
190
233
  },
191
234
  ],
@@ -196,26 +239,14 @@ public class GroupUpdateAllVersionsHandlerTests : UpdateHandlersTestsBase
196
239
  Dependencies = [
197
240
  new()
198
241
  {
199
- Name = "Some.Dependency",
200
- Version = "2.0.0",
242
+ Name = "Test.Dependency",
243
+ Version = "6.0.0",
201
244
  Requirements = [
202
- new() { Requirement = "2.0.0", File = "/test/project.csproj", Groups = ["dependencies"], Source = new() { SourceUrl = null } },
203
- ],
204
- PreviousVersion = "1.0.0",
205
- PreviousRequirements = [
206
- new() { Requirement = "1.0.0", File = "/test/project.csproj", Groups = ["dependencies"] },
207
- ],
208
- },
209
- new()
210
- {
211
- Name = "Some.Other.Dependency",
212
- Version = "4.0.0",
213
- Requirements = [
214
- new() { Requirement = "4.0.0", File = "/test/project.csproj", Groups = ["dependencies"], Source = new() { SourceUrl = null } },
245
+ new() { Requirement = "6.0.0", File = "/test/project.csproj", Groups = ["dependencies"], Source = new() { SourceUrl = null } },
215
246
  ],
216
- PreviousVersion = "3.0.0",
247
+ PreviousVersion = "5.0.0",
217
248
  PreviousRequirements = [
218
- new() { Requirement = "3.0.0", File = "/test/project.csproj", Groups = ["dependencies"] },
249
+ new() { Requirement = "5.0.0", File = "/test/project.csproj", Groups = ["dependencies"] },
219
250
  ],
220
251
  },
221
252
  ],