dependabot-nuget 0.317.0 → 0.318.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 (22) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyInfo.cs +3 -0
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +30 -1
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/FrameworkCompatibilityService.cs +25 -1
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Condition.cs +13 -1
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyGroup.cs +29 -18
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +6 -7
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +13 -1
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs +18 -10
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/GroupUpdateAllVersionsHandler.cs +4 -16
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandler.cs +1 -1
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshSecurityUpdatePullRequestHandler.cs +1 -1
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshVersionUpdatePullRequestHandler.cs +1 -1
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +15 -8
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +11 -3
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/VersionFinderTests.cs +39 -0
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/FrameworkChecker/FrameworkCompatibilityServiceFacts.cs +8 -11
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +108 -15
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +2 -2
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/GroupUpdateAllVersionsHandlerTests.cs +129 -0
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackageReferenceUpdaterTests.cs +51 -1
  22. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f345f9ee257e7f76d38a1895964aaf6f6356182d190037a19df23107f62c18b
4
- data.tar.gz: 47c6ec4d4a5157c2a644856532129923aa9a65d6710d01a40bf18c59f8483971
3
+ metadata.gz: 59a38e30a99a2cfa01adea0a410d889454db7c97be7403dc961f3a657cef9057
4
+ data.tar.gz: 9cd7cf460715c6bcd81b7a879eb9e18410e6bb7a5e3312f6c97e491530377d77
5
5
  SHA512:
6
- metadata.gz: 453d1742deef75f810dab148d9d9344a79f39ce893d1dfec90020d7bec36b6018b1acddf0d02c5e109e9957a94f7e3b1d09a4808b2f35e3e9b1e20f5b8bc1e15
7
- data.tar.gz: 25bf0a85529e9fa9af427d5fa860b4208c7df6cd763d4059ce66fe8c1f6ee04596322f75cf20d5c4cfb6132d0157edb92f63a956191fa67f0c95d43f99444a29
6
+ metadata.gz: 973628f0b72b612b75538f4428d1a71dd98517aed42f9725353455cfbb80bc9da8b5c92688a83197e3651f01084dcd97859f2bf2921dfdafdf8d26ae3f32280c
7
+ data.tar.gz: 9a5fc49a9cb8a586cde53c7f472be221712aa11a61349be64feddb42ab174257d7cdffab7954f3f0ccfc78d07a380c75c4f9001902ffbdbbb9a4a6790e0d8c8a
@@ -1,5 +1,7 @@
1
1
  using System.Collections.Immutable;
2
2
 
3
+ using NuGetUpdater.Core.Run.ApiModel;
4
+
3
5
  namespace NuGetUpdater.Core.Analyze;
4
6
 
5
7
  public sealed record DependencyInfo
@@ -9,4 +11,5 @@ public sealed record DependencyInfo
9
11
  public required bool IsVulnerable { get; init; }
10
12
  public ImmutableArray<Requirement> IgnoredVersions { get; init; }
11
13
  public ImmutableArray<SecurityVulnerability> Vulnerabilities { get; init; }
14
+ public ImmutableArray<ConditionUpdateType> IgnoredUpdateTypes { get; init; } = [];
12
15
  }
@@ -10,6 +10,8 @@ using NuGet.Protocol;
10
10
  using NuGet.Protocol.Core.Types;
11
11
  using NuGet.Versioning;
12
12
 
13
+ using NuGetUpdater.Core.Run.ApiModel;
14
+
13
15
  namespace NuGetUpdater.Core.Analyze;
14
16
 
15
17
  internal static class VersionFinder
@@ -155,12 +157,39 @@ internal static class VersionFinder
155
157
  var isIgnoredVersion = dependencyInfo.IgnoredVersions.Any(i => i.IsSatisfiedBy(version));
156
158
  var isVulnerableVersion = dependencyInfo.Vulnerabilities.Any(v => v.IsVulnerable(version));
157
159
  var isSafeVersion = !safeVersions.Any() || safeVersions.Any(s => s.IsSatisfiedBy(version));
160
+
161
+ var isIgnoredByType = false;
162
+ if (currentVersion is not null)
163
+ {
164
+ var isMajorBump = version.Major > currentVersion.Major;
165
+ var isMinorBump = version.Major == currentVersion.Major && version.Minor > currentVersion.Minor;
166
+ var isPatchBump = version.Major == currentVersion.Major && version.Minor == currentVersion.Minor && version.Patch > currentVersion.Patch;
167
+ foreach (var ignoreType in dependencyInfo.IgnoredUpdateTypes)
168
+ {
169
+ switch (ignoreType)
170
+ {
171
+ case ConditionUpdateType.SemVerPatch:
172
+ isIgnoredByType = isIgnoredByType || isPatchBump || isMinorBump || isMajorBump;
173
+ break;
174
+ case ConditionUpdateType.SemVerMinor:
175
+ isIgnoredByType = isIgnoredByType || isMinorBump || isMajorBump;
176
+ break;
177
+ case ConditionUpdateType.SemVerMajor:
178
+ isIgnoredByType = isIgnoredByType || isMajorBump;
179
+ break;
180
+ default:
181
+ break;
182
+ }
183
+ }
184
+ }
185
+
158
186
  return versionGreaterThanCurrent
159
187
  && rangeSatisfies
160
188
  && prereleaseTypeMatches
161
189
  && !isIgnoredVersion
162
190
  && !isVulnerableVersion
163
- && isSafeVersion;
191
+ && isSafeVersion
192
+ && !isIgnoredByType;
164
193
  };
165
194
  }
166
195
 
@@ -24,7 +24,7 @@ public class FrameworkCompatibilityService
24
24
 
25
25
  foreach (var packageFramework in packageFrameworks)
26
26
  {
27
- if (packageFrameworks == null || packageFramework.IsUnsupported || packageFramework.IsPCL)
27
+ if (packageFrameworks == null || packageFramework.IsUnsupported)
28
28
  {
29
29
  continue;
30
30
  }
@@ -79,6 +79,30 @@ public class FrameworkCompatibilityService
79
79
  }
80
80
  }
81
81
 
82
+ // portable profiles
83
+ var portableMappings = new DefaultPortableFrameworkMappings();
84
+ var portableFrameworks = portableMappings.ProfileFrameworks.ToDictionary(p => p.Key, p => p.Value);
85
+ foreach (var (profileNumber, frameworkRange) in portableMappings.CompatibilityMappings)
86
+ {
87
+ var profileFramework = new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Portable, new Version(0, 0, 0, 0), $"Profile{profileNumber}");
88
+ var compatibleFrameworks = new HashSet<NuGetFramework>();
89
+ matrix.Add(profileFramework, compatibleFrameworks);
90
+
91
+ foreach (var packageFramework in AllSupportedFrameworks)
92
+ {
93
+ if (frameworkRange.Satisfies(packageFramework))
94
+ {
95
+ foreach (var projectFramework in AllSupportedFrameworks)
96
+ {
97
+ if (CompatibilityProvider.IsCompatible(projectFramework, packageFramework))
98
+ {
99
+ compatibleFrameworks.Add(projectFramework);
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+
82
106
  return matrix;
83
107
  }
84
108
  }
@@ -11,9 +11,21 @@ public sealed record Condition
11
11
  [JsonPropertyName("source")]
12
12
  public string? Source { get; init; } = null;
13
13
  [JsonPropertyName("update-types")]
14
- public string[] UpdateTypes { get; init; } = [];
14
+ public ConditionUpdateType[]? UpdateTypes { get; init; } = null;
15
15
  [JsonPropertyName("updated-at")]
16
16
  public DateTime? UpdatedAt { get; init; } = null;
17
17
  [JsonPropertyName("version-requirement")]
18
18
  public Requirement? VersionRequirement { get; init; } = null;
19
19
  }
20
+
21
+ public enum ConditionUpdateType
22
+ {
23
+ [JsonStringEnumMemberName("version-update:semver-major")]
24
+ SemVerMajor,
25
+
26
+ [JsonStringEnumMemberName("version-update:semver-minor")]
27
+ SemVerMinor,
28
+
29
+ [JsonStringEnumMemberName("version-update:semver-patch")]
30
+ SemVerPatch,
31
+ }
@@ -1,5 +1,6 @@
1
1
  using System.Collections.Immutable;
2
2
  using System.IO.Enumeration;
3
+ using System.Text.Json;
3
4
 
4
5
  namespace NuGetUpdater.Core.Run.ApiModel;
5
6
 
@@ -32,33 +33,43 @@ public class GroupMatcher
32
33
 
33
34
  public static GroupMatcher FromRules(Dictionary<string, object> rules)
34
35
  {
35
- string[] patterns;
36
- if (rules.TryGetValue("patterns", out var patternsObject) &&
37
- patternsObject is string[] patternsArray)
36
+ var patterns = GetStringArray(rules, "patterns", ["*"]); // default to matching everything unless explicitly excluded
37
+ var excludePatterns = GetStringArray(rules, "exclude-patterns", []);
38
+
39
+ return new GroupMatcher()
38
40
  {
39
- patterns = patternsArray;
40
- }
41
- else
41
+ Patterns = patterns,
42
+ ExcludePatterns = excludePatterns,
43
+ };
44
+ }
45
+
46
+ private static ImmutableArray<string> GetStringArray(Dictionary<string, object> rules, string propertyName, ImmutableArray<string> defaultValue)
47
+ {
48
+ if (!rules.TryGetValue(propertyName, out var propertyObject))
42
49
  {
43
- patterns = ["*"]; // default to matching everything unless excluded below
50
+ return defaultValue;
44
51
  }
45
52
 
46
- string[] excludePatterns;
47
- if (rules.TryGetValue("exclude-patterns", out var excludePatternsObject) &&
48
- excludePatternsObject is string[] excludePatternsArray)
53
+ if (propertyObject is string[] stringArray)
49
54
  {
50
- excludePatterns = excludePatternsArray;
55
+ // shortcut for unit tests which directly supply the array
56
+ return [.. stringArray];
51
57
  }
52
- else
58
+
59
+ var patternsElements = new List<string>();
60
+ if (propertyObject is JsonElement element &&
61
+ element.ValueKind == JsonValueKind.Array)
53
62
  {
54
- excludePatterns = [];
63
+ foreach (var arrayElement in element.EnumerateArray())
64
+ {
65
+ if (arrayElement.ValueKind == JsonValueKind.String)
66
+ {
67
+ patternsElements.Add(arrayElement.GetString()!);
68
+ }
69
+ }
55
70
  }
56
71
 
57
- return new GroupMatcher()
58
- {
59
- Patterns = [.. patterns],
60
- ExcludePatterns = [.. excludePatterns],
61
- };
72
+ return [.. patternsElements];
62
73
  }
63
74
  }
64
75
 
@@ -100,15 +100,14 @@ public sealed record Job
100
100
  return existingPullRequest;
101
101
  }
102
102
 
103
- public bool IsDependencyIgnored(string dependencyName, string dependencyVersion)
103
+ public bool IsDependencyIgnoredByNameOnly(string dependencyName)
104
104
  {
105
- var versionsToIgnore = IgnoreConditions
106
- .Where(c => FileSystemName.MatchesSimpleExpression(c.DependencyName, dependencyName))
107
- .Select(c => c.VersionRequirement ?? Requirement.Parse(">= 0.0.0")) // no range means ignore everything
105
+ var packageNamesToIgnore = IgnoreConditions
106
+ .Where(c => (c.UpdateTypes ?? []).Length == 0 && c.VersionRequirement is null) // ignoring by name means there can't be any qualification
107
+ .Select(c => c.DependencyName)
108
108
  .ToArray();
109
- var parsedDependencyVersion = NuGetVersion.Parse(dependencyVersion);
110
- var isIgnored = versionsToIgnore
111
- .Any(r => r.IsSatisfiedBy(parsedDependencyVersion));
109
+ var isIgnored = packageNamesToIgnore
110
+ .Any(p => FileSystemName.MatchesSimpleExpression(p, dependencyName));
112
111
  return isIgnored;
113
112
  }
114
113
 
@@ -1,5 +1,6 @@
1
1
  using System.Collections.Immutable;
2
2
  using System.IO;
3
+ using System.IO.Enumeration;
3
4
  using System.Text;
4
5
  using System.Text.Json;
5
6
  using System.Text.Json.Serialization;
@@ -677,7 +678,12 @@ public class RunWorker
677
678
  var dependencyVersion = NuGetVersion.Parse(dependency.Version!);
678
679
  var securityAdvisories = job.SecurityAdvisories.Where(s => s.DependencyName.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase)).ToArray();
679
680
  var isVulnerable = securityAdvisories.Any(s => (s.AffectedVersions ?? []).Any(v => v.IsSatisfiedBy(dependencyVersion)));
680
- var ignoredVersions = GetIgnoredRequirementsForDependency(job, dependency.Name);
681
+ var ignoredVersions = job.IgnoreConditions
682
+ .Where(c => FileSystemName.MatchesSimpleExpression(c.DependencyName, dependency.Name))
683
+ .Select(c => c.VersionRequirement)
684
+ .Where(r => r is not null)
685
+ .Cast<Requirement>()
686
+ .ToImmutableArray();
681
687
  var vulnerabilities = securityAdvisories.Select(s => new SecurityVulnerability()
682
688
  {
683
689
  DependencyName = dependency.Name,
@@ -685,6 +691,11 @@ public class RunWorker
685
691
  VulnerableVersions = s.AffectedVersions ?? [],
686
692
  SafeVersions = s.SafeVersions.ToImmutableArray(),
687
693
  }).ToImmutableArray();
694
+ var ignoredUpdateTypes = job.IgnoreConditions
695
+ .Where(c => FileSystemName.MatchesSimpleExpression(c.DependencyName, dependency.Name))
696
+ .SelectMany(c => c.UpdateTypes ?? [])
697
+ .Distinct()
698
+ .ToImmutableArray();
688
699
  var dependencyInfo = new DependencyInfo()
689
700
  {
690
701
  Name = dependency.Name,
@@ -692,6 +703,7 @@ public class RunWorker
692
703
  IsVulnerable = isVulnerable,
693
704
  IgnoredVersions = ignoredVersions,
694
705
  Vulnerabilities = vulnerabilities,
706
+ IgnoredUpdateTypes = ignoredUpdateTypes,
695
707
  };
696
708
  return dependencyInfo;
697
709
  }
@@ -65,13 +65,29 @@ internal class CreateSecurityUpdatePullRequestHandler : IUpdateHandler
65
65
  foreach (var dependencyGroupToUpdate in groupedUpdateOperationsToPerform)
66
66
  {
67
67
  var dependencyName = dependencyGroupToUpdate.Key;
68
- var vulnerableDependenciesToUpdate = dependencyGroupToUpdate.Value
68
+ var vulnerableCandidateDependenciesToUpdate = dependencyGroupToUpdate.Value
69
69
  .Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency)))
70
70
  .Where(set => set.Item3.IsVulnerable)
71
71
  .ToArray();
72
+ var vulnerableDependenciesToUpdate = vulnerableCandidateDependenciesToUpdate
73
+ .Where(o => !job.IsDependencyIgnoredByNameOnly(o.Dependency.Name))
74
+ .ToArray();
72
75
  if (vulnerableDependenciesToUpdate.Length == 0)
73
76
  {
74
- await apiHandler.RecordUpdateJobError(new SecurityUpdateNotNeeded(dependencyName));
77
+ // no update possible, check backwards to see if it's because of ignore conditions
78
+ var ignoredUpdates = vulnerableCandidateDependenciesToUpdate
79
+ .Where(set => set.Dependency.Name.Equals(dependencyName, StringComparison.OrdinalIgnoreCase))
80
+ .ToArray();
81
+ if (ignoredUpdates.Length > 0)
82
+ {
83
+ logger.Error($"Cannot update {dependencyName} because all versions are ignored.");
84
+ await apiHandler.RecordUpdateJobError(new SecurityUpdateIgnored(dependencyName));
85
+ }
86
+ else
87
+ {
88
+ await apiHandler.RecordUpdateJobError(new SecurityUpdateNotNeeded(dependencyName));
89
+ }
90
+
75
91
  continue;
76
92
  }
77
93
 
@@ -92,14 +108,6 @@ internal class CreateSecurityUpdatePullRequestHandler : IUpdateHandler
92
108
  continue;
93
109
  }
94
110
 
95
- if (dependencyInfo.IgnoredVersions.Any(ignored => ignored.IsSatisfiedBy(NuGetVersion.Parse(analysisResult.UpdatedVersion))) ||
96
- job.IsDependencyIgnored(dependency.Name, dependency.Version!))
97
- {
98
- logger.Error($"Cannot update {dependency.Name} for {projectPath} because all versions are ignored.");
99
- await apiHandler.RecordUpdateJobError(new SecurityUpdateIgnored(dependencyName));
100
- continue;
101
- }
102
-
103
111
  logger.Info($"Attempting update of {dependency.Name} from {dependency.Version} to {analysisResult.UpdatedVersion} for {projectPath}.");
104
112
  var projectDiscovery = discoveryResult.GetProjectDiscoveryFromPath(projectPath);
105
113
  var updaterResult = await updaterWorker.RunAsync(repoContentsPath.FullName, projectPath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, dependency.IsTransitive);
@@ -98,9 +98,9 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
98
98
  continue;
99
99
  }
100
100
 
101
- if (job.IsDependencyIgnored(dependency.Name, dependency.Version!))
101
+ if (job.IsDependencyIgnoredByNameOnly(dependency.Name))
102
102
  {
103
- logger.Info($"Skipping ignored dependency {dependency.Name}/{dependency.Version}.");
103
+ logger.Info($"Skipping ignored dependency {dependency.Name}.");
104
104
  continue;
105
105
  }
106
106
 
@@ -119,12 +119,6 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
119
119
  continue;
120
120
  }
121
121
 
122
- if (dependencyInfo.IgnoredVersions.Any(ignored => ignored.IsSatisfiedBy(NuGetVersion.Parse(analysisResult.UpdatedVersion))))
123
- {
124
- logger.Info($"Cannot update {dependency.Name} for {projectPath} because all versions are ignored.");
125
- continue;
126
- }
127
-
128
122
  var projectDiscovery = discoveryResult.GetProjectDiscoveryFromPath(projectPath);
129
123
  var updaterResult = await updaterWorker.RunAsync(repoContentsPath.FullName, projectPath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, dependency.IsTransitive);
130
124
  if (updaterResult.Error is not null)
@@ -203,9 +197,9 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
203
197
  continue;
204
198
  }
205
199
 
206
- if (job.IsDependencyIgnored(dependency.Name, dependency.Version!))
200
+ if (job.IsDependencyIgnoredByNameOnly(dependency.Name))
207
201
  {
208
- logger.Info($"Skipping ignored dependency {dependency.Name}/{dependency.Version}.");
202
+ logger.Info($"Skipping ignored dependency {dependency.Name}.");
209
203
  continue;
210
204
  }
211
205
 
@@ -224,12 +218,6 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
224
218
  continue;
225
219
  }
226
220
 
227
- if (dependencyInfo.IgnoredVersions.Any(ignored => ignored.IsSatisfiedBy(NuGetVersion.Parse(analysisResult.UpdatedVersion))))
228
- {
229
- logger.Info($"Cannot update {dependency.Name} for {projectPath} because all versions are ignored.");
230
- continue;
231
- }
232
-
233
221
  var projectDiscovery = discoveryResult.GetProjectDiscoveryFromPath(projectPath);
234
222
  var updaterResult = await updaterWorker.RunAsync(repoContentsPath.FullName, projectPath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, dependency.IsTransitive);
235
223
  if (updaterResult.Error is not null)
@@ -91,8 +91,8 @@ internal class RefreshGroupUpdatePullRequestHandler : IUpdateHandler
91
91
  {
92
92
  var dependencyName = dependencyGroupToUpdate.Key;
93
93
  var relevantDependenciesToUpdate = dependencyGroupToUpdate.Value
94
+ .Where(o => !job.IsDependencyIgnoredByNameOnly(o.Dependency.Name))
94
95
  .Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency)))
95
- .Where(set => !job.IsDependencyIgnored(set.Dependency.Name, set.Dependency.Version!))
96
96
  .ToArray();
97
97
 
98
98
  foreach (var (projectPath, dependency, dependencyInfo) in relevantDependenciesToUpdate)
@@ -80,8 +80,8 @@ internal class RefreshSecurityUpdatePullRequestHandler : IUpdateHandler
80
80
  {
81
81
  var dependencyName = dependencyGroupToUpdate.Key;
82
82
  var vulnerableDependenciesToUpdate = dependencyGroupToUpdate.Value
83
+ .Where(o => !job.IsDependencyIgnoredByNameOnly(o.Dependency.Name))
83
84
  .Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency)))
84
- .Where(set => !job.IsDependencyIgnored(set.Dependency.Name, set.Dependency.Version!))
85
85
  .Where(set => set.Item3.IsVulnerable)
86
86
  .ToArray();
87
87
 
@@ -79,8 +79,8 @@ internal class RefreshVersionUpdatePullRequestHandler : IUpdateHandler
79
79
  {
80
80
  var dependencyName = dependencyUpdatesToPeform.Key;
81
81
  var dependencyInfosToUpdate = dependencyUpdatesToPeform.Value
82
+ .Where(o => !job.IsDependencyIgnoredByNameOnly(o.Dependency.Name))
82
83
  .Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency)))
83
- .Where(set => !job.IsDependencyIgnored(set.Dependency.Name, set.Dependency.Version!))
84
84
  .ToArray();
85
85
 
86
86
  foreach (var (projectPath, dependency, dependencyInfo) in dependencyInfosToUpdate)
@@ -201,6 +201,7 @@ internal static class PackageReferenceUpdater
201
201
  )
202
202
  {
203
203
  var topLevelNames = topLevelDependencies.Select(d => d.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
204
+ var topLevelVersionStrings = topLevelDependencies.ToDictionary(d => d.Name, d => d.Version!, StringComparer.OrdinalIgnoreCase);
204
205
  var requestedVersions = requestedUpdates.ToDictionary(d => d.Name, d => NuGetVersion.Parse(d.Version!), StringComparer.OrdinalIgnoreCase);
205
206
  var resolvedVersions = resolvedDependencies
206
207
  .Select(d => (d.Name, NuGetVersion.TryParse(d.Version, out var version), version))
@@ -248,16 +249,22 @@ internal static class PackageReferenceUpdater
248
249
  }
249
250
  }
250
251
 
251
- if (rootPackageName is not null)
252
+ if (rootPackageName is not null && resolvedVersions.TryGetValue(rootPackageName, out var rootPackageVersion))
252
253
  {
253
- updateOperations.Add(new ParentUpdate()
254
+ // from a few lines up we've already confirmed that `rootPackageName` was a top-level dependency
255
+ var rootPackageVersionString = topLevelVersionStrings[rootPackageName];
256
+ if (NuGetVersion.TryParse(rootPackageVersionString, out var resolvedRootPackageVersion)
257
+ && rootPackageVersion > resolvedRootPackageVersion)
254
258
  {
255
- DependencyName = requestedDependencyName,
256
- NewVersion = requestedVersions[requestedDependencyName],
257
- UpdatedFiles = [],
258
- ParentDependencyName = rootPackageName,
259
- ParentNewVersion = packageVersions[rootPackageName],
260
- });
259
+ updateOperations.Add(new ParentUpdate()
260
+ {
261
+ DependencyName = requestedDependencyName,
262
+ NewVersion = requestedVersions[requestedDependencyName],
263
+ UpdatedFiles = [],
264
+ ParentDependencyName = rootPackageName,
265
+ ParentNewVersion = packageVersions[rootPackageName],
266
+ });
267
+ }
261
268
  }
262
269
  break;
263
270
  case (true, false):
@@ -478,7 +478,7 @@ internal static partial class MSBuildHelper
478
478
  // Return as array
479
479
  var candidatePackagesArray = candidatePackages.ToImmutableArray();
480
480
 
481
- var targetFrameworks = new NuGetFramework[] { NuGetFramework.Parse(targetFramework) };
481
+ var targetFrameworks = ImmutableArray.Create<NuGetFramework>(NuGetFramework.Parse(targetFramework));
482
482
 
483
483
  var resolveProjectPath = projectPath;
484
484
 
@@ -492,15 +492,23 @@ internal static partial class MSBuildHelper
492
492
  // Target framework compatibility check
493
493
  foreach (var package in candidatePackages)
494
494
  {
495
- if (!NuGetVersion.TryParse(package.Version, out var nuGetVersion))
495
+ if (package.Version is null ||
496
+ !VersionRange.TryParse(package.Version, out var nuGetVersionRange))
496
497
  {
497
498
  // If version is not valid, return original packages and revert
498
499
  return packages;
499
500
  }
500
501
 
502
+ if (nuGetVersionRange.IsFloating)
503
+ {
504
+ // If a wildcard version, the original project specified it this way and we can count on restore to do the appropriate thing
505
+ continue;
506
+ }
507
+
508
+ var nuGetVersion = nuGetVersionRange.MinVersion; // not a wildcard, so `MinVersion` is just the version itself
501
509
  var packageIdentity = new NuGet.Packaging.Core.PackageIdentity(package.Name, nuGetVersion);
502
510
 
503
- bool isNewPackageCompatible = await CompatibilityChecker.CheckAsync(packageIdentity, targetFrameworks.ToImmutableArray(), nugetContext, logger, CancellationToken.None);
511
+ bool isNewPackageCompatible = await CompatibilityChecker.CheckAsync(packageIdentity, targetFrameworks, nugetContext, logger, CancellationToken.None);
504
512
  if (!isNewPackageCompatible)
505
513
  {
506
514
  // If the package target framework is not compatible, return original packages and revert
@@ -296,4 +296,43 @@ public class VersionFinderTests : TestBase
296
296
  var actualJson = JsonSerializer.Serialize(error, RunWorker.SerializerOptions);
297
297
  Assert.Equal(expectedJson, actualJson);
298
298
  }
299
+
300
+ [Theory]
301
+ [InlineData(null, "1.0.1", "1.1.0", "2.0.0")]
302
+ [InlineData(ConditionUpdateType.SemVerMajor, "1.0.1", "1.1.0")]
303
+ [InlineData(ConditionUpdateType.SemVerMinor, "1.0.1")]
304
+ [InlineData(ConditionUpdateType.SemVerPatch)]
305
+ public async Task VersionFinder_IgnoredUpdateTypesIsHonored(ConditionUpdateType? ignoredUpdateType, params string[] expectedVersions)
306
+ {
307
+ // arrange
308
+ using var tempDir = new TemporaryDirectory();
309
+ await UpdateWorkerTestBase.MockNuGetPackagesInDirectory([
310
+ MockNuGetPackage.CreateSimplePackage("Some.Dependency", "1.0.1", "net9.0"),
311
+ MockNuGetPackage.CreateSimplePackage("Some.Dependency", "1.1.0", "net9.0"),
312
+ MockNuGetPackage.CreateSimplePackage("Some.Dependency", "2.0.0", "net9.0"),
313
+ ], tempDir.DirectoryPath);
314
+ var tfm = NuGetFramework.Parse("net9.0");
315
+ var ignoredUpdateTypes = ignoredUpdateType is not null
316
+ ? new ConditionUpdateType[] { ignoredUpdateType.Value }
317
+ : [];
318
+ var dependencyInfo = new DependencyInfo()
319
+ {
320
+ Name = "Some.Dependency",
321
+ Version = "1.0.0",
322
+ IsVulnerable = false,
323
+ IgnoredVersions = [],
324
+ Vulnerabilities = [],
325
+ IgnoredUpdateTypes = [.. ignoredUpdateTypes],
326
+ };
327
+ var logger = new TestLogger();
328
+ var nugetContext = new NuGetContext(tempDir.DirectoryPath);
329
+
330
+ // act
331
+ var versionResult = await VersionFinder.GetVersionsAsync([tfm], dependencyInfo, nugetContext, logger, CancellationToken.None);
332
+ var versions = versionResult.GetVersions();
333
+
334
+ // assert
335
+ var actualVersions = versions.Select(v => v.ToString()).OrderBy(v => v).ToArray();
336
+ AssertEx.Equal(expectedVersions, actualVersions);
337
+ }
299
338
  }
@@ -1,10 +1,6 @@
1
1
  // Copyright (c) .NET Foundation. All rights reserved.
2
2
  // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
3
 
4
- using System;
5
- using System.Collections.Generic;
6
- using System.Linq;
7
-
8
4
  using NuGet.Frameworks;
9
5
 
10
6
  using NuGetUpdater.Core.FrameworkChecker;
@@ -64,17 +60,18 @@ public class FrameworkCompatibilityServiceFacts
64
60
  }
65
61
 
66
62
  [Theory]
67
- [InlineData("portable-net45+sl4+win8+wp7")]
68
- [InlineData("portable-net40+sl4")]
69
- [InlineData("portable-net45+sl5+win8+wpa81+wp8")]
70
- public void PCLPackageFrameworksReturnsEmptySet(string pclFrameworkName)
63
+ [InlineData("portable-net45+win8+wpa81", "net48", true)] // profile 111, compatible
64
+ [InlineData("portable-net45+win8+wpa81", "net40", false)] // profile 111, incompatible
65
+ [InlineData("portable-net45+win8+wp8+wpa81", "net48", true)] // profile 259, compatible
66
+ public void PCLPackageFrameworksReportCompatibility(string pclFrameworkName, string projectFrameworkName, bool expectedCompatible)
71
67
  {
72
68
  var portableFramework = NuGetFramework.Parse(pclFrameworkName);
69
+ var projectFramework = NuGetFramework.Parse(projectFrameworkName);
73
70
 
74
- var result = _service.GetCompatibleFrameworks([portableFramework]);
71
+ var compatible = _service.GetCompatibleFrameworks([portableFramework]);
75
72
 
76
- Assert.True(portableFramework.IsPCL);
77
- Assert.Empty(result);
73
+ var actualCompatible = compatible.Contains(projectFramework);
74
+ Assert.Equal(expectedCompatible, actualCompatible);
78
75
  }
79
76
 
80
77
  [Theory]
@@ -16,8 +16,8 @@ namespace NuGetUpdater.Core.Test.Run;
16
16
  public class MiscellaneousTests
17
17
  {
18
18
  [Theory]
19
- [MemberData(nameof(IsDependencyIgnoredTestData))]
20
- public void IsDependencyIgnored(Condition[] ignoreConditions, string dependencyName, string dependencyVersion, bool expectedIgnored)
19
+ [MemberData(nameof(IsDependencyIgnoredByNameOnlyTestData))]
20
+ public void IsDependencyIgnoredByNameOnly(Condition[] ignoreConditions, string dependencyName, bool expectedIgnored)
21
21
  {
22
22
  // arrange
23
23
  var job = new Job()
@@ -31,14 +31,15 @@ public class MiscellaneousTests
31
31
  };
32
32
 
33
33
  // act
34
- var actualIsIgnored = job.IsDependencyIgnored(dependencyName, dependencyVersion);
34
+ var actualIsIgnored = job.IsDependencyIgnoredByNameOnly(dependencyName);
35
35
 
36
36
  // assert
37
37
  Assert.Equal(expectedIgnored, actualIsIgnored);
38
38
  }
39
39
 
40
- public static IEnumerable<object[]> IsDependencyIgnoredTestData()
40
+ public static IEnumerable<object[]> IsDependencyIgnoredByNameOnlyTestData()
41
41
  {
42
+ // non-matching name
42
43
  yield return
43
44
  [
44
45
  // ignoreConditions
@@ -51,12 +52,11 @@ public class MiscellaneousTests
51
52
  },
52
53
  // dependencyName
53
54
  "Some.Dependency",
54
- // dependencyVersion
55
- "1.2.3",
56
55
  // expectedIgnored
57
56
  false,
58
57
  ];
59
58
 
59
+ // matching name, but has version requirement
60
60
  yield return
61
61
  [
62
62
  // ignoreConditions
@@ -70,12 +70,11 @@ public class MiscellaneousTests
70
70
  },
71
71
  // dependencyName
72
72
  "Some.Dependency",
73
- // dependencyVersion
74
- "1.2.3",
75
73
  // expectedIgnored
76
74
  false,
77
75
  ];
78
76
 
77
+ // wildcard matching name
79
78
  yield return
80
79
  [
81
80
  // ignoreConditions
@@ -83,18 +82,34 @@ public class MiscellaneousTests
83
82
  {
84
83
  new Condition()
85
84
  {
86
- DependencyName = "Some.Dependency",
87
- VersionRequirement = Requirement.Parse("> 1.0.0"),
85
+ DependencyName = "Some.*",
88
86
  }
89
87
  },
90
88
  // dependencyName
91
89
  "Some.Dependency",
92
- // dependencyVersion
93
- "1.2.3",
94
90
  // expectedIgnored
95
91
  true,
96
92
  ];
97
93
 
94
+ // matching name, but has update type restrictions
95
+ yield return
96
+ [
97
+ // ignoreConditions
98
+ new[]
99
+ {
100
+ new Condition()
101
+ {
102
+ DependencyName = "Some.*",
103
+ UpdateTypes = [ConditionUpdateType.SemVerMajor],
104
+ }
105
+ },
106
+ // dependencyName
107
+ "Some.Dependency",
108
+ // expectedIgnored
109
+ false,
110
+ ];
111
+
112
+ // explicitly null update types
98
113
  yield return
99
114
  [
100
115
  // ignoreConditions
@@ -103,17 +118,56 @@ public class MiscellaneousTests
103
118
  new Condition()
104
119
  {
105
120
  DependencyName = "Some.*",
121
+ UpdateTypes = null,
106
122
  }
107
123
  },
108
124
  // dependencyName
109
125
  "Some.Dependency",
110
- // dependencyVersion
111
- "1.2.3",
112
126
  // expectedIgnored
113
127
  true,
114
128
  ];
115
129
  }
116
130
 
131
+ [Fact]
132
+ public void DeserializeDependencyGroup()
133
+ {
134
+ var json = """
135
+ {
136
+ "name": "test-group",
137
+ "rules": {
138
+ "patterns": ["Test.*"],
139
+ "exclude-patterns": ["Dependency.*"]
140
+ }
141
+ }
142
+ """;
143
+ var group = JsonSerializer.Deserialize<DependencyGroup>(json, RunWorker.SerializerOptions);
144
+ Assert.NotNull(group);
145
+ Assert.Equal("test-group", group.Name);
146
+ var matcher = group.GetGroupMatcher();
147
+ Assert.Equal(["Test.*"], matcher.Patterns);
148
+ Assert.Equal(["Dependency.*"], matcher.ExcludePatterns);
149
+ }
150
+
151
+ [Fact]
152
+ public void DeserializeDependencyGroup_UnexpectedShape()
153
+ {
154
+ var json = """
155
+ {
156
+ "name": "test-group",
157
+ "rules": {
158
+ "patterns": { "unexpected": 1 },
159
+ "exclude-patterns": { "unexpected": 2 }
160
+ }
161
+ }
162
+ """;
163
+ var group = JsonSerializer.Deserialize<DependencyGroup>(json, RunWorker.SerializerOptions);
164
+ Assert.NotNull(group);
165
+ Assert.Equal("test-group", group.Name);
166
+ var matcher = group.GetGroupMatcher();
167
+ Assert.Equal([], matcher.Patterns);
168
+ Assert.Equal([], matcher.ExcludePatterns);
169
+ }
170
+
117
171
  [Theory]
118
172
  [MemberData(nameof(DependencyGroup_IsMatchTestData))]
119
173
  public void DependencyGroup_IsMatch(string[]? patterns, string[]? excludePatterns, string dependencyName, bool expectedMatch)
@@ -625,6 +679,7 @@ public class MiscellaneousTests
625
679
 
626
680
  public static IEnumerable<object[]> DependencyInfoFromJobData()
627
681
  {
682
+ // with security advisory
628
683
  yield return
629
684
  [
630
685
  // job
@@ -667,7 +722,45 @@ public class MiscellaneousTests
667
722
  VulnerableVersions = [Requirement.Parse(">= 1.0.0, < 1.1.0")],
668
723
  SafeVersions = [Requirement.Parse("= 1.1.0"), Requirement.Parse("= 1.2.0")],
669
724
  }
670
- ]
725
+ ],
726
+ IgnoredUpdateTypes = [],
727
+ }
728
+ ];
729
+
730
+ yield return
731
+ [
732
+ // job
733
+ new Job()
734
+ {
735
+ Source = new()
736
+ {
737
+ Provider = "github",
738
+ Repo = "some/repo",
739
+ },
740
+ IgnoreConditions = [
741
+ new Condition()
742
+ {
743
+ DependencyName = "Some.*",
744
+ UpdateTypes = [ConditionUpdateType.SemVerMajor],
745
+ },
746
+ new Condition()
747
+ {
748
+ DependencyName = "Unrelated.*",
749
+ UpdateTypes = [ConditionUpdateType.SemVerMinor],
750
+ },
751
+ ],
752
+ },
753
+ // dependency
754
+ new Dependency("Some.Dependency", "1.0.0", DependencyType.PackageReference),
755
+ // expectedDependencyInfo
756
+ new DependencyInfo()
757
+ {
758
+ Name = "Some.Dependency",
759
+ Version = "1.0.0",
760
+ IsVulnerable = false,
761
+ IgnoredVersions = [],
762
+ Vulnerabilities = [],
763
+ IgnoredUpdateTypes = [ConditionUpdateType.SemVerMajor],
671
764
  }
672
765
  ];
673
766
  }
@@ -316,13 +316,13 @@ public class SerializationTests : TestBase
316
316
 
317
317
  Assert.Equal("Package.1", jobWrapper.Job.IgnoreConditions[0].DependencyName);
318
318
  Assert.Equal("some-file", jobWrapper.Job.IgnoreConditions[0].Source);
319
- Assert.Equal("version-update:semver-major", jobWrapper.Job.IgnoreConditions[0].UpdateTypes.Single());
319
+ Assert.Equal(ConditionUpdateType.SemVerMajor, jobWrapper.Job.IgnoreConditions[0].UpdateTypes!.Single());
320
320
  Assert.Null(jobWrapper.Job.IgnoreConditions[0].UpdatedAt);
321
321
  Assert.Equal("> 1.2.3", jobWrapper.Job.IgnoreConditions[0].VersionRequirement?.ToString());
322
322
 
323
323
  Assert.Equal("Package.2", jobWrapper.Job.IgnoreConditions[1].DependencyName);
324
324
  Assert.Null(jobWrapper.Job.IgnoreConditions[1].Source);
325
- Assert.Empty(jobWrapper.Job.IgnoreConditions[1].UpdateTypes);
325
+ Assert.Null(jobWrapper.Job.IgnoreConditions[1].UpdateTypes);
326
326
  Assert.Equal(new DateTime(2024, 12, 5, 15, 47, 12), jobWrapper.Job.IgnoreConditions[1].UpdatedAt);
327
327
  Assert.Null(jobWrapper.Job.IgnoreConditions[1].VersionRequirement);
328
328
  }
@@ -795,4 +795,133 @@ public class GroupUpdateAllVersionsHandlerTests : UpdateHandlersTestsBase
795
795
  ]
796
796
  );
797
797
  }
798
+
799
+ [Fact]
800
+ public async Task IgnoredVersionUpdateTypesAreHonored()
801
+ {
802
+ await TestAsync(
803
+ job: new()
804
+ {
805
+ Source = CreateJobSource("/src"),
806
+ IgnoreConditions = [
807
+ new Condition()
808
+ {
809
+ DependencyName = "Some.Dependency",
810
+ UpdateTypes = [ConditionUpdateType.SemVerMajor],
811
+ }
812
+ ]
813
+ },
814
+ files: [("src/project.csproj", "initial contents")],
815
+ discoveryWorker: TestDiscoveryWorker.FromResults(
816
+ ("/src", new WorkspaceDiscoveryResult()
817
+ {
818
+ Path = "/src",
819
+ Projects = [
820
+ new()
821
+ {
822
+ FilePath = "project.csproj",
823
+ Dependencies = [
824
+ new("Some.Dependency", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net9.0"]),
825
+ ],
826
+ ImportedFiles = [],
827
+ AdditionalFiles = [],
828
+ }
829
+ ],
830
+ })
831
+ ),
832
+ analyzeWorker: new TestAnalyzeWorker(input =>
833
+ {
834
+ var repoRoot = input.Item1;
835
+ var discovery = input.Item2;
836
+ var dependencyInfo = input.Item3;
837
+ if (dependencyInfo.IgnoredUpdateTypes.Length != 1 || !dependencyInfo.IgnoredUpdateTypes.Contains(ConditionUpdateType.SemVerMajor))
838
+ {
839
+ throw new InvalidOperationException($"Expected to see ignored update type of {nameof(ConditionUpdateType.SemVerMajor)} but found [{string.Join(", ", dependencyInfo.IgnoredUpdateTypes)}]");
840
+ }
841
+ var newVersion = dependencyInfo.Name switch
842
+ {
843
+ "Some.Dependency" => "1.1.0",
844
+ _ => throw new NotImplementedException($"Test didn't expect to update dependency {dependencyInfo.Name}"),
845
+ };
846
+ return Task.FromResult(new AnalysisResult()
847
+ {
848
+ CanUpdate = true,
849
+ UpdatedVersion = newVersion,
850
+ UpdatedDependencies = [],
851
+ });
852
+ }),
853
+ updaterWorker: new TestUpdaterWorker(async input =>
854
+ {
855
+ var repoRoot = input.Item1;
856
+ var workspacePath = input.Item2;
857
+ var dependencyName = input.Item3;
858
+ var previousVersion = input.Item4;
859
+ var newVersion = input.Item5;
860
+ var isTransitive = input.Item6;
861
+
862
+ await File.WriteAllTextAsync(Path.Join(repoRoot, workspacePath), "updated contents");
863
+
864
+ return new UpdateOperationResult()
865
+ {
866
+ UpdateOperations = [new DirectUpdate() { DependencyName = dependencyName, NewVersion = NuGetVersion.Parse(newVersion), UpdatedFiles = [workspacePath] }],
867
+ };
868
+ }),
869
+ expectedUpdateHandler: GroupUpdateAllVersionsHandler.Instance,
870
+ expectedApiMessages: [
871
+ new IncrementMetric()
872
+ {
873
+ Metric = "updater.started",
874
+ Tags = new()
875
+ {
876
+ ["operation"] = "group_update_all_versions",
877
+ }
878
+ },
879
+ new UpdatedDependencyList()
880
+ {
881
+ Dependencies = [
882
+ new()
883
+ {
884
+ Name = "Some.Dependency",
885
+ Version = "1.0.0",
886
+ Requirements = [
887
+ new() { Requirement = "1.0.0", File = "/src/project.csproj", Groups = ["dependencies"] },
888
+ ],
889
+ },
890
+ ],
891
+ DependencyFiles = ["/src/project.csproj"],
892
+ },
893
+ new CreatePullRequest()
894
+ {
895
+ Dependencies = [
896
+ new()
897
+ {
898
+ Name = "Some.Dependency",
899
+ Version = "1.1.0",
900
+ Requirements = [
901
+ new() { Requirement = "1.1.0", File = "/src/project.csproj", Groups = ["dependencies"], Source = new() { SourceUrl = null } },
902
+ ],
903
+ PreviousVersion = "1.0.0",
904
+ PreviousRequirements = [
905
+ new() { Requirement = "1.0.0", File = "/src/project.csproj", Groups = ["dependencies"] },
906
+ ],
907
+ },
908
+ ],
909
+ UpdatedDependencyFiles = [
910
+ new()
911
+ {
912
+ Directory = "/src",
913
+ Name = "project.csproj",
914
+ Content = "updated contents",
915
+ },
916
+ ],
917
+ BaseCommitSha = "TEST-COMMIT-SHA",
918
+ CommitMessage = RunWorkerTests.TestPullRequestCommitMessage,
919
+ PrTitle = RunWorkerTests.TestPullRequestTitle,
920
+ PrBody = RunWorkerTests.TestPullRequestBody,
921
+ DependencyGroup = null,
922
+ },
923
+ new MarkAsProcessed("TEST-COMMIT-SHA"),
924
+ ]
925
+ );
926
+ }
798
927
  }
@@ -189,7 +189,8 @@ public class PackageReferenceUpdaterTests
189
189
  MockNuGetPackage.CreateSimplePackage("Transitive.Package", "1.0.0", "net9.0", [(null, [("Super.Transitive.Package", "1.0.0")])]),
190
190
  MockNuGetPackage.CreateSimplePackage("Transitive.Package", "2.0.0", "net9.0", [(null, [("Super.Transitive.Package", "2.0.0")])]),
191
191
  MockNuGetPackage.CreateSimplePackage("Super.Transitive.Package", "1.0.0", "net9.0"),
192
- MockNuGetPackage.CreateSimplePackage("Super.Transitive.Package", "2.0.0", "net9.0")
192
+ MockNuGetPackage.CreateSimplePackage("Super.Transitive.Package", "2.0.0", "net9.0"),
193
+ MockNuGetPackage.CreateSimplePackage("Unrelated.Package", "1.0.0", "net9.0"),
193
194
  ], repoRoot.DirectoryPath);
194
195
 
195
196
  // act
@@ -331,5 +332,54 @@ public class PackageReferenceUpdaterTests
331
332
  }
332
333
  )
333
334
  ];
335
+
336
+ // dependency was not updated
337
+ yield return
338
+ [
339
+ // topLevelDependencies
340
+ ImmutableArray.Create(
341
+ new Dependency("Parent.Package", "1.0.0", DependencyType.PackageReference)
342
+ ),
343
+ // requestedUpdates
344
+ ImmutableArray.Create(
345
+ new Dependency("Transitive.Package", "2.0.0", DependencyType.PackageReference)
346
+ ),
347
+ // resolvedDependencies
348
+ ImmutableArray.Create(
349
+ new Dependency("Parent.Package", "1.0.0", DependencyType.PackageReference)
350
+ ),
351
+ // expectedUpdateOperations
352
+ ImmutableArray<UpdateOperationBase>.Empty,
353
+ ];
354
+
355
+ // initial dependency has a wildcard
356
+ yield return
357
+ [
358
+ // topLevelDependencies
359
+ ImmutableArray.Create(
360
+ new Dependency("Parent.Package", "1.0.0", DependencyType.PackageReference),
361
+ new Dependency("Unrelated.Package", "1.0.*", DependencyType.PackageReference)
362
+ ),
363
+ // requestedUpdates
364
+ ImmutableArray.Create(
365
+ new Dependency("Transitive.Package", "2.0.0", DependencyType.PackageReference)
366
+ ),
367
+ // resolvedDependencies
368
+ ImmutableArray.Create(
369
+ new Dependency("Parent.Package", "2.0.0", DependencyType.PackageReference),
370
+ new Dependency("Unrelated.Package", "1.0.0", DependencyType.PackageReference)
371
+ ),
372
+ // expectedUpdateOperations
373
+ ImmutableArray.Create<UpdateOperationBase>(
374
+ new ParentUpdate()
375
+ {
376
+ DependencyName = "Transitive.Package",
377
+ NewVersion = NuGetVersion.Parse("2.0.0"),
378
+ UpdatedFiles = [],
379
+ ParentDependencyName = "Parent.Package",
380
+ ParentNewVersion = NuGetVersion.Parse("2.0.0"),
381
+ }
382
+ ),
383
+ ];
334
384
  }
335
385
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-nuget
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.317.0
4
+ version: 0.318.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.317.0
18
+ version: 0.318.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.317.0
25
+ version: 0.318.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rubyzip
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -580,7 +580,7 @@ licenses:
580
580
  - MIT
581
581
  metadata:
582
582
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
583
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.317.0
583
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.318.0
584
584
  rdoc_options: []
585
585
  require_paths:
586
586
  - lib