dependabot-nuget 0.359.0 → 0.360.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37c8313017055e1840002707f6f97fbf09ed29c28df574327f188f33b5a5dfca
4
- data.tar.gz: 651030c7a22e6743b54a594f93b41973d4ffd288d95145b07e744b87885e0375
3
+ metadata.gz: d191440d66bca7937ff8f8012de3869cc337bc132a696c015d67452f427071e3
4
+ data.tar.gz: 83a204114a2cc66bb7d0a64e9d806a8c81ab99e3401100f7fb1a1ac547dc596b
5
5
  SHA512:
6
- metadata.gz: e5e9b92f11a473f8046b1925cf11a1fcae1cf3625d4510cf528a228615b18305f28fff320f9ce132de39ac7abb147f4234c8949a3ccb6841aa77e599e4ee54cc
7
- data.tar.gz: 8652832c636b18da24146671415f1e4f582e8998329f8d2e16c523a97c3d1e59b64db2065548b13aae0fe73a383b8817dd97111959a121901d012e8c07312712
6
+ metadata.gz: 41ef96cd974364883124a59c532c426c77be31c434774d318e59ef32267ae19c5fb610d7411d46d8d4f1ffa4fe28cbe6488139be33165d215b5204f4f9444a57
7
+ data.tar.gz: 2d940963ea21e8b776dc8797a445d6044dd3e59d311da89da06db39d8c656763037878e0c0418e4ed0f7700bf57b8ea8aacefa1d6da4629da4b59dd3c67e68d8
@@ -39,6 +39,6 @@
39
39
  <PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
40
40
  <PackageVersion Include="System.Threading.Tasks.Dataflow" Version="9.0.7" />
41
41
  <PackageVersion Include="xunit.v3" Version="3.0.0" />
42
- <PackageVersion Include="xunit.runner.visualstudio" Version="3.1.2" />
42
+ <PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
43
43
  </ItemGroup>
44
44
  </Project>
@@ -114,12 +114,24 @@ internal static class CompatibilityChecker
114
114
  }
115
115
  }
116
116
 
117
- var refItems = await readers.ContentReader.GetReferenceItemsAsync(cancellationToken);
117
+ var refItems = (await readers.ContentReader.GetReferenceItemsAsync(cancellationToken)).ToArray();
118
118
  foreach (var refItem in refItems)
119
119
  {
120
120
  tfms.Add(refItem.TargetFramework);
121
121
  }
122
122
 
123
+ var libItems = (await readers.ContentReader.GetLibItemsAsync(cancellationToken)).ToArray();
124
+ foreach (var libItem in libItems)
125
+ {
126
+ tfms.Add(libItem.TargetFramework);
127
+ }
128
+
129
+ // if a package contains no assemblies that need to be referenced, we can consider it compatible with all frameworks
130
+ if (refItems.Length == 0 && libItems.Length == 0)
131
+ {
132
+ tfms.Clear();
133
+ }
134
+
123
135
  if (!tfms.Any())
124
136
  {
125
137
  tfms.Add(NuGetFramework.AnyFramework);
@@ -63,6 +63,9 @@ internal static class SdkProjectDiscovery
63
63
  "GenerateBuildDependencyFile"
64
64
  ];
65
65
 
66
+ // this seems to be the maximum number of TFMs that can be restored in parallel without running into race conditions
67
+ private const int MaximumParallelTargetFrameworkRestores = 2;
68
+
66
69
  public static async Task<ImmutableArray<ProjectDiscoveryResult>> DiscoverAsync(string repoRootPath, string workspacePath, string startingProjectPath, ExperimentsManager experimentsManager, ILogger logger)
67
70
  {
68
71
  var extension = Path.GetExtension(startingProjectPath)?.ToLowerInvariant();
@@ -113,8 +116,10 @@ internal static class SdkProjectDiscovery
113
116
 
114
117
  // due to how MSBuild handles multi-TFM projects with target platforms we may need to process each TFM separately
115
118
  // we detect that by determining if there are multiple target frameworks specified and if any of them have a platform suffix (e.g., `-windows`, `-android`, etc)
119
+ // alternately, if there are too many target frameworks specified, they must be handled individually
116
120
  var projectTfms = await MSBuildHelper.GetProjectTargetFrameworksAsync(startingProjectPath, logger);
117
- var requiresIndividualRestores = projectTfms.Any(tfm => tfm.Contains('-'));
121
+ var hasPlatformTfms = projectTfms.Any(tfm => tfm.Contains('-'));
122
+ var requiresIndividualRestores = hasPlatformTfms || projectTfms.Length > MaximumParallelTargetFrameworkRestores;
118
123
  if (!requiresIndividualRestores)
119
124
  {
120
125
  projectTfms = [string.Empty]; // a single restore can handle everything, but we need to loop at least once and an empty TFM is our signal to not specify anything
@@ -122,7 +127,7 @@ internal static class SdkProjectDiscovery
122
127
 
123
128
  foreach (var tfm in projectTfms)
124
129
  {
125
- var isSingleTfmRestore = !string.IsNullOrEmpty(tfm);
130
+ var isIndividualTfmRestore = !string.IsNullOrEmpty(tfm);
126
131
 
127
132
  // create a binlog
128
133
  var binLogPath = Path.Combine(Path.GetTempPath(), $"msbuild_{Guid.NewGuid():d}.binlog");
@@ -132,7 +137,7 @@ internal static class SdkProjectDiscovery
132
137
  var args = new List<string>() { "msbuild", startingProjectPath };
133
138
  var targets = await MSBuildHelper.GetProjectTargetsAsync(startingProjectPath, logger);
134
139
  var useDirectRestore = SingleRestoreTargetNames.All(targets.Contains);
135
- if (useDirectRestore || isSingleTfmRestore)
140
+ if (useDirectRestore || isIndividualTfmRestore)
136
141
  {
137
142
  // directly call the required targets
138
143
  args.Add($"/t:{string.Join(",", SingleRestoreTargetNames)}");
@@ -151,7 +156,7 @@ internal static class SdkProjectDiscovery
151
156
  args.Add($"/p:CustomAfterMicrosoftCommonCrossTargetingTargets={dependencyDiscoveryTargetsPath}");
152
157
  args.Add($"/p:CustomAfterMicrosoftCommonTargets={dependencyDiscoveryTargetsPath}");
153
158
 
154
- if (isSingleTfmRestore)
159
+ if (isIndividualTfmRestore)
155
160
  {
156
161
  args.Add($"/p:TargetFramework={tfm}");
157
162
  }
@@ -257,8 +257,8 @@ public class XmlFileWriter : IFileWriter
257
257
  var (matchingPackageVersionElement, filePath) = matchingPackageVersionElementsAndPaths.First();
258
258
  var versionAttribute = matchingPackageVersionElement.GetAttributeCaseInsensitive(VersionMetadataName);
259
259
  if (versionAttribute is not null &&
260
- NuGetVersion.TryParse(versionAttribute.Value, out var existingVersion) &&
261
- existingVersion == requiredVersion)
260
+ VersionRange.TryParse(versionAttribute.Value, out var existingVersionRange) &&
261
+ existingVersionRange.MinVersion == requiredVersion)
262
262
  {
263
263
  // version matches; no update needed
264
264
  _logger.Info($"Dependency {requiredPackageVersion.Name} already set to {requiredVersion}; no override needed.");
@@ -5,6 +5,7 @@ using NuGet.Packaging.Core;
5
5
  using NuGet.Versioning;
6
6
 
7
7
  using NuGetUpdater.Core.Analyze;
8
+ using NuGetUpdater.Core.Test.Update;
8
9
 
9
10
  using Xunit;
10
11
 
@@ -143,6 +144,30 @@ public class CompatibilityCheckerTests
143
144
  Assert.False(result);
144
145
  }
145
146
 
147
+ [Fact]
148
+ public async Task CheckAsync_PackageWithFrameworkDependencyGroupButNoAssemblies_ReportsAsCompatible()
149
+ {
150
+ // package has an explicit dependency group that is incompatible with the project framework, but lib and ref directories are empty
151
+ // a real-world example is a project targeting `net9.0` and referencing `Microsoft.VisualStudio.Azure.Containers.Tools.Targets/1.22.1`
152
+ // depending on the project's properties, it's entirely possible for this to be a supported scenario
153
+
154
+ // arrange
155
+ using var tempDir = new TemporaryDirectory();
156
+ var package = new MockNuGetPackage("Some.Package", "1.0.0", DependencyGroups: [(".NETFramework4.7.2", [])]);
157
+ await UpdateWorkerTestBase.MockNuGetPackagesInDirectory([package], tempDir.DirectoryPath, includeCommonPackages: false);
158
+
159
+ var packageId = new PackageIdentity(package.Id, NuGetVersion.Parse(package.Version));
160
+ var projectFramework = NuGetFramework.Parse("net9.0");
161
+ var context = new NuGetContext(tempDir.DirectoryPath, NuGet.Common.NullLogger.Instance);
162
+ var logger = new TestLogger();
163
+
164
+ // act
165
+ var isCompatible = await CompatibilityChecker.CheckAsync(packageId, [projectFramework], context, logger, CancellationToken.None);
166
+
167
+ //assert
168
+ Assert.True(isCompatible);
169
+ }
170
+
146
171
  [Theory]
147
172
  [InlineData("netstandard2.0")]
148
173
  [InlineData("net472")]
@@ -268,22 +268,28 @@ public class SdkProjectDiscoveryTests : DiscoveryWorkerTestBase
268
268
  );
269
269
  }
270
270
 
271
- [Fact]
272
- public async Task DiscoverWithMultipleTargetFrameworks()
271
+ [Theory]
272
+ [InlineData("net7.0")] // under the safe limit for parallel processing
273
+ [InlineData("net7.0", "net8.0")] // at the safe limit for parallel processing
274
+ [InlineData("net7.0", "net8.0", "net9.0")] // above the safe limit for parallel processing
275
+ [InlineData("netstandard2.0", "netstandard2.1", "net6.0", "net7.0", "net8.0", "net9.0", "net10.0")] // well above the safe limit for parallel processing
276
+ public async Task DiscoverWithMultipleTargetFrameworks(params string[] targetFrameworks)
273
277
  {
278
+ // tfms are sorted for reporting purposes
279
+ var sortedTargetFrameworks = targetFrameworks.OrderBy(t => t, StringComparer.Ordinal).ToArray();
274
280
  await TestDiscoverAsync(
275
281
  packages:
276
282
  [
277
- MockNuGetPackage.CreateSimplePackage("Some.Dependency", "1.2.3", "net7.0"),
283
+ MockNuGetPackage.CreateSimplePackage("Some.Dependency", "1.2.3", "netstandard2.0"), // the lowest TFM this test uses
278
284
  ],
279
285
  startingDirectory: "src",
280
286
  projectPath: "src/library.csproj",
281
287
  files:
282
288
  [
283
- ("src/library.csproj", """
289
+ ("src/library.csproj", $"""
284
290
  <Project Sdk="Microsoft.NET.Sdk">
285
291
  <PropertyGroup>
286
- <TargetFrameworks>net7.0;net8.0</TargetFrameworks>
292
+ <TargetFrameworks>{string.Join(";", targetFrameworks)}</TargetFrameworks>
287
293
  </PropertyGroup>
288
294
  <ItemGroup>
289
295
  <PackageReference Include="Some.Dependency" Version="1.2.3" />
@@ -298,14 +304,14 @@ public class SdkProjectDiscoveryTests : DiscoveryWorkerTestBase
298
304
  FilePath = "library.csproj",
299
305
  Dependencies =
300
306
  [
301
- new("Some.Dependency", "1.2.3", DependencyType.PackageReference, TargetFrameworks: ["net7.0", "net8.0"], IsDirect: true),
307
+ new("Some.Dependency", "1.2.3", DependencyType.PackageReference, TargetFrameworks: [.. sortedTargetFrameworks], IsDirect: true),
302
308
  ],
303
309
  ImportedFiles = [],
304
310
  Properties =
305
311
  [
306
- new("TargetFrameworks", "net7.0;net8.0", "src/library.csproj"),
312
+ new("TargetFrameworks", string.Join(";", targetFrameworks), "src/library.csproj"),
307
313
  ],
308
- TargetFrameworks = ["net7.0", "net8.0"],
314
+ TargetFrameworks = [.. sortedTargetFrameworks],
309
315
  ReferencedProjectPaths = [],
310
316
  AdditionalFiles = [],
311
317
  },
@@ -1137,6 +1137,116 @@ public class EndToEndTests
1137
1137
  );
1138
1138
  }
1139
1139
 
1140
+ [Fact]
1141
+ public async Task LockFilesAreRegeneratedThroughProjectReferences()
1142
+ {
1143
+ // this test needs to do some dynamic checks so we have to set it up manually
1144
+ // job is started in `src/client` directory but ultimately the updater navigates through a `<ProjectReference>` element to make
1145
+ // the update in `src/library` and both lock files are updated along the way _and_ included in the final PR
1146
+
1147
+ // arrange
1148
+ using var tempDirectory = await TemporaryDirectory.CreateWithContentsAsync(
1149
+ ("src/client/client.csproj", """
1150
+ <Project Sdk="Microsoft.NET.Sdk">
1151
+ <PropertyGroup>
1152
+ <TargetFramework>net9.0</TargetFramework>
1153
+ </PropertyGroup>
1154
+ <ItemGroup>
1155
+ <ProjectReference Include="..\library\library.csproj" />
1156
+ </ItemGroup>
1157
+ </Project>
1158
+ """),
1159
+ ("src/client/packages.lock.json", "{}"),
1160
+ ("src/library/library.csproj", """
1161
+ <Project Sdk="Microsoft.NET.Sdk">
1162
+ <PropertyGroup>
1163
+ <TargetFramework>net9.0</TargetFramework>
1164
+ </PropertyGroup>
1165
+ <ItemGroup>
1166
+ <PackageReference Include="Some.Package" Version="1.0.0" />
1167
+ </ItemGroup>
1168
+ </Project>
1169
+ """),
1170
+ ("src/library/packages.lock.json", "{}")
1171
+ );
1172
+ var repoContentsPath = tempDirectory.DirectoryPath;
1173
+ await UpdateWorkerTestBase.MockNuGetPackagesInDirectory([
1174
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net9.0", [(null, [("Transitive.Package", "2.0.0")])]),
1175
+ MockNuGetPackage.CreateSimplePackage("Transitive.Package", "2.0.0", "net9.0"),
1176
+ MockNuGetPackage.CreateSimplePackage("Transitive.Package", "2.1.0", "net9.0"),
1177
+ ], repoContentsPath);
1178
+ var jobId = "TEST-JOB-ID";
1179
+ var experimentsManager = new ExperimentsManager();
1180
+ var logger = new TestLogger();
1181
+ var apiHandler = new TestApiHandler();
1182
+ var discoveryWorker = new DiscoveryWorker(jobId, experimentsManager, logger);
1183
+ var analyzeWorker = new AnalyzeWorker(jobId, experimentsManager, logger);
1184
+ var updaterWorker = new UpdaterWorker(jobId, experimentsManager, logger);
1185
+ var worker = new RunWorker(jobId, apiHandler, discoveryWorker, analyzeWorker, updaterWorker, logger);
1186
+ var job = new Job()
1187
+ {
1188
+ Dependencies = ["Transitive.Package"],
1189
+ SecurityAdvisories = [
1190
+ new()
1191
+ {
1192
+ DependencyName = "Transitive.Package",
1193
+ AffectedVersions = [Requirement.Parse("= 2.0.0")],
1194
+ PatchedVersions = [Requirement.Parse(">= 2.1.0")],
1195
+ }
1196
+ ],
1197
+ SecurityUpdatesOnly = true,
1198
+ Source = new()
1199
+ {
1200
+ Provider = "github",
1201
+ Repo = "test/repo",
1202
+ Directory = "src/client",
1203
+ }
1204
+ };
1205
+
1206
+ // act
1207
+ await worker.RunAsync(job, new DirectoryInfo(repoContentsPath), null, "TEST-COMMIT-SHA", experimentsManager);
1208
+
1209
+ // assert
1210
+ var createPr = (CreatePullRequest)apiHandler.ReceivedMessages.Single(m => m.Type == typeof(CreatePullRequest)).Object;
1211
+ var updatedFiles = createPr.UpdatedDependencyFiles.ToDictionary(df => Path.Join(df.Directory, df.Name).NormalizePathToUnix(), df => df.Content.Replace("\r", ""));
1212
+
1213
+ // original project is unchanged
1214
+ Assert.False(updatedFiles.ContainsKey("/src/client/client.csproj"));
1215
+
1216
+ // transitive project was updated
1217
+ Assert.Equal("""
1218
+ <Project Sdk="Microsoft.NET.Sdk">
1219
+ <PropertyGroup>
1220
+ <TargetFramework>net9.0</TargetFramework>
1221
+ </PropertyGroup>
1222
+ <ItemGroup>
1223
+ <PackageReference Include="Some.Package" Version="1.0.0" />
1224
+ <PackageReference Include="Transitive.Package" Version="2.1.0" />
1225
+ </ItemGroup>
1226
+ </Project>
1227
+ """.Replace("\r", ""), updatedFiles["/src/library/library.csproj"]);
1228
+
1229
+ // client lock file reflects updated transitive dependency
1230
+ var clientLockFileJson = JsonDocument.Parse(updatedFiles["/src/client/packages.lock.json"]);
1231
+ var resolvedInClient = clientLockFileJson.RootElement
1232
+ .GetProperty("dependencies")
1233
+ .GetProperty("net9.0")
1234
+ .GetProperty("Transitive.Package")
1235
+ .GetProperty("resolved")
1236
+ .GetString();
1237
+ Assert.Equal("2.1.0", resolvedInClient);
1238
+
1239
+ // library lock file reflects updated transitive dependency
1240
+ var libraryLockFileJson = JsonDocument.Parse(updatedFiles["/src/library/packages.lock.json"]);
1241
+ var resolvedInLibrary = libraryLockFileJson.RootElement
1242
+ .GetProperty("dependencies")
1243
+ .GetProperty("net9.0")
1244
+ .GetProperty("Transitive.Package")
1245
+ .GetProperty("resolved")
1246
+ .GetString();
1247
+ Assert.Equal("2.1.0", resolvedInLibrary);
1248
+ }
1249
+
1140
1250
  public const string TestPullRequestCommitMessage = "test-pull-request-commit-message";
1141
1251
  public const string TestPullRequestTitle = "test-pull-request-title";
1142
1252
  public const string TestPullRequestBody = "test-pull-request-body";
@@ -260,6 +260,48 @@ public class XmlFileWriterTests : FileWriterTestsBase
260
260
  );
261
261
  }
262
262
 
263
+ [Fact]
264
+ public async Task SingleDependency_CentralPackageManagement_RangeContainsNewVersion()
265
+ {
266
+ // in this scenario, a prior pass updated `[1.0.0]` to `[1.1.0]` for a direct dependency and now in a higher
267
+ // level project we need to ensure the version matches when pinning a transitive dependency
268
+ await TestAsync(
269
+ files: [
270
+ ("project.csproj", """
271
+ <Project Sdk="Microsoft.NET.Sdk">
272
+ <ItemGroup>
273
+ </ItemGroup>
274
+ </Project>
275
+ """),
276
+ ("Directory.Packages.props", """
277
+ <Project>
278
+ <ItemGroup>
279
+ <PackageVersion Include="Some.Dependency" Version="[1.1.0]" />
280
+ </ItemGroup>
281
+ </Project>
282
+ """),
283
+ ],
284
+ initialProjectDependencyStrings: ["Some.Dependency/1.0.0"],
285
+ requiredDependencyStrings: ["Some.Dependency/1.1.0"],
286
+ expectedFiles: [
287
+ ("project.csproj", """
288
+ <Project Sdk="Microsoft.NET.Sdk">
289
+ <ItemGroup>
290
+ <PackageReference Include="Some.Dependency" />
291
+ </ItemGroup>
292
+ </Project>
293
+ """),
294
+ ("Directory.Packages.props", """
295
+ <Project>
296
+ <ItemGroup>
297
+ <PackageVersion Include="Some.Dependency" Version="[1.1.0]" />
298
+ </ItemGroup>
299
+ </Project>
300
+ """),
301
+ ]
302
+ );
303
+ }
304
+
263
305
  [Fact]
264
306
  public async Task SingleDependency_SingleFile_AttributeDirectUpdate_ExactMatchVersionRangeFromPropertyValue()
265
307
  {
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.359.0
4
+ version: 0.360.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.359.0
18
+ version: 0.360.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.359.0
25
+ version: 0.360.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -553,7 +553,7 @@ licenses:
553
553
  - MIT
554
554
  metadata:
555
555
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
556
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.359.0
556
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.360.0
557
557
  rdoc_options: []
558
558
  require_paths:
559
559
  - lib