dependabot-nuget 0.285.0 → 0.286.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetProjects/Directory.Build.props +5 -1
  3. data/helpers/lib/NuGetUpdater/NuGetProjects/NuGet.CommandLine/NuGet.CommandLine.csproj +1 -0
  4. data/helpers/lib/NuGetUpdater/NuGetProjects/NuGet.Configuration/NuGet.Configuration.csproj +1 -0
  5. data/helpers/lib/NuGetUpdater/NuGetProjects/NuGet.LibraryModel/NuGet.LibraryModel.csproj +1 -0
  6. data/helpers/lib/NuGetUpdater/NuGetProjects/NuGet.Packaging/NuGet.Packaging.csproj +1 -1
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +8 -1
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs +7 -3
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +11 -0
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +1 -1
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +2 -2
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +52 -0
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/IAnalyzeWorker.cs +9 -0
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/IDiscoveryWorker.cs +8 -0
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/IUpdaterWorker.cs +9 -0
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +78 -61
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +6 -5
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +37 -5
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +5 -3
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +0 -5
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +2 -0
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +329 -45
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +168 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestAnalyzeWorker.cs +37 -0
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestDiscoveryWorker.cs +35 -0
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestUpdaterWorker.cs +39 -0
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackagesConfigUpdaterTests.cs +104 -3
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +51 -13
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs +4 -2
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +22 -17
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +1 -1
  32. data/lib/dependabot/nuget/file_updater.rb +8 -3
  33. data/lib/dependabot/nuget/native_helpers.rb +11 -12
  34. metadata +12 -6
  35. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/DependencySolverEnvironment.cs +0 -12
@@ -1,5 +1,6 @@
1
1
  using System.Diagnostics;
2
2
  using System.Text;
3
+ using System.Text.RegularExpressions;
3
4
  using System.Xml.Linq;
4
5
  using System.Xml.XPath;
5
6
 
@@ -213,8 +214,8 @@ internal static class PackagesConfigUpdater
213
214
  var hintPathSubString = $"{dependencyName}.{dependencyVersion}";
214
215
 
215
216
  string? partialPathMatch = null;
216
- var hintPathNodes = projectBuildFile.Contents.Descendants().Where(e => e.IsHintPathNodeForDependency(dependencyName));
217
- foreach (var hintPathNode in hintPathNodes)
217
+ var specificHintPathNodes = projectBuildFile.Contents.Descendants().Where(e => e.IsHintPathNodeForDependency(dependencyName)).ToArray();
218
+ foreach (var hintPathNode in specificHintPathNodes)
218
219
  {
219
220
  var hintPath = hintPathNode.GetContentValue();
220
221
  var hintPathSubStringLocation = hintPath.IndexOf(hintPathSubString, StringComparison.OrdinalIgnoreCase);
@@ -255,18 +256,49 @@ internal static class PackagesConfigUpdater
255
256
  if (hasPackage)
256
257
  {
257
258
  // the dependency exists in the packages.config file, so it must be the second case
258
- // the vast majority of projects found in the wild use this, and since we have nothing to look for, we'll just have to hope
259
- partialPathMatch = "../packages";
259
+ // at this point there's no perfect way to determine what the packages path is, but there's a really good chance that
260
+ // for any given package it looks something like this:
261
+ // ..\..\packages\Package.Name.[version]\lib\Tfm\Package.Name.dll
262
+ var genericHintPathNodes = projectBuildFile.Contents.Descendants().Where(IsHintPathNode).ToArray();
263
+ if (genericHintPathNodes.Length > 0)
264
+ {
265
+ foreach (var hintPathNode in genericHintPathNodes)
266
+ {
267
+ var hintPath = hintPathNode.GetContentValue();
268
+ var match = Regex.Match(hintPath, @"^(?<PackagesPath>.*)[/\\](?<PackageNameAndVersion>[^/\\]+)[/\\]lib[/\\](?<Tfm>[^/\\]+)[/\\](?<AssemblyName>[^/\\]+)$");
269
+ // e.g., ..\..\packages \ Some.Package.1.2.3 \ lib\ net45 \ Some.Package.dll
270
+ if (match.Success)
271
+ {
272
+ partialPathMatch = match.Groups["PackagesPath"].Value;
273
+ break;
274
+ }
275
+ }
276
+ }
277
+ else
278
+ {
279
+ // we know the dependency is used, but we have absolutely no idea where the packages path is, so we'll default to something reasonable
280
+ partialPathMatch = "../packages";
281
+ }
260
282
  }
261
283
  }
262
284
 
263
285
  return partialPathMatch?.NormalizePathToUnix();
264
286
  }
265
287
 
266
- private static bool IsHintPathNodeForDependency(this IXmlElementSyntax element, string dependencyName)
288
+ private static bool IsHintPathNode(this IXmlElementSyntax element)
267
289
  {
268
290
  if (element.Name.Equals("HintPath", StringComparison.OrdinalIgnoreCase) &&
269
291
  element.Parent.Name.Equals("Reference", StringComparison.OrdinalIgnoreCase))
292
+ {
293
+ return true;
294
+ }
295
+
296
+ return false;
297
+ }
298
+
299
+ private static bool IsHintPathNodeForDependency(this IXmlElementSyntax element, string dependencyName)
300
+ {
301
+ if (element.IsHintPathNode())
270
302
  {
271
303
  // the include attribute will look like one of the following:
272
304
  // <Reference Include="Some.Dependency, Version=1.0.0.0, Culture=neutral, PublicKeyToken=abcd">
@@ -7,8 +7,9 @@ using NuGetUpdater.Core.Updater;
7
7
 
8
8
  namespace NuGetUpdater.Core;
9
9
 
10
- public class UpdaterWorker
10
+ public class UpdaterWorker : IUpdaterWorker
11
11
  {
12
+ private readonly ExperimentsManager _experimentsManager;
12
13
  private readonly ILogger _logger;
13
14
  private readonly HashSet<string> _processedProjectPaths = new(StringComparer.OrdinalIgnoreCase);
14
15
 
@@ -18,8 +19,9 @@ public class UpdaterWorker
18
19
  Converters = { new JsonStringEnumConverter() },
19
20
  };
20
21
 
21
- public UpdaterWorker(ILogger logger)
22
+ public UpdaterWorker(ExperimentsManager experimentsManager, ILogger logger)
22
23
  {
24
+ _experimentsManager = experimentsManager;
23
25
  _logger = logger;
24
26
  }
25
27
 
@@ -221,7 +223,7 @@ public class UpdaterWorker
221
223
  }
222
224
 
223
225
  // Some repos use a mix of packages.config and PackageReference
224
- await PackageReferenceUpdater.UpdateDependencyAsync(repoRootPath, projectPath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive, _logger);
226
+ await PackageReferenceUpdater.UpdateDependencyAsync(repoRootPath, projectPath, dependencyName, previousDependencyVersion, newDependencyVersion, isTransitive, _experimentsManager, _logger);
225
227
 
226
228
  // Update lock file if exists
227
229
  if (File.Exists(Path.Combine(Path.GetDirectoryName(projectPath), "packages.lock.json")))
@@ -335,11 +335,6 @@ internal static partial class MSBuildHelper
335
335
  }
336
336
  }
337
337
 
338
- internal static bool UseNewDependencySolver()
339
- {
340
- return Environment.GetEnvironmentVariable("UseNewNugetPackageResolver") == "true";
341
- }
342
-
343
338
  internal static async Task<Dependency[]?> ResolveDependencyConflicts(string repoRoot, string projectPath, string targetFramework, Dependency[] packages, Dependency[] update, ILogger logger)
344
339
  {
345
340
  var tempDirectory = Directory.CreateTempSubdirectory("package-dependency-coherence_");
@@ -63,6 +63,8 @@ internal static class PathHelper
63
63
  return result;
64
64
  }
65
65
 
66
+ public static string FullyNormalizedRootedPath(this string path) => path.NormalizePathToUnix().NormalizeUnixPathParts().EnsurePrefix("/");
67
+
66
68
  public static string GetFullPathFromRelative(string rootPath, string relativePath)
67
69
  => Path.GetFullPath(JoinPath(rootPath, relativePath.NormalizePathToUnix()));
68
70
 
@@ -1,10 +1,14 @@
1
+ using System.Net;
1
2
  using System.Text;
2
3
  using System.Text.Json;
3
4
  using System.Xml.Linq;
4
5
 
6
+ using NuGetUpdater.Core.Analyze;
7
+ using NuGetUpdater.Core.Discover;
5
8
  using NuGetUpdater.Core.Run;
6
9
  using NuGetUpdater.Core.Run.ApiModel;
7
10
  using NuGetUpdater.Core.Test.Update;
11
+ using NuGetUpdater.Core.Updater;
8
12
 
9
13
  using Xunit;
10
14
 
@@ -17,13 +21,8 @@ public class RunWorkerTests
17
21
  [Fact]
18
22
  public async Task UpdateSinglePackageProducedExpectedAPIMessages()
19
23
  {
20
- var repoMetadata = XElement.Parse("""<repository type="git" url="https://nuget.example.com/some-package" />""");
21
24
  await RunAsync(
22
- packages:
23
- [
24
- MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0", additionalMetadata: [repoMetadata]),
25
- MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.1", "net8.0", additionalMetadata: [repoMetadata]),
26
- ],
25
+ packages: [],
27
26
  job: new Job()
28
27
  {
29
28
  Source = new()
@@ -50,6 +49,55 @@ public class RunWorkerTests
50
49
  </Project>
51
50
  """)
52
51
  ],
52
+ discoveryWorker: new TestDiscoveryWorker(_input =>
53
+ {
54
+ return Task.FromResult(new WorkspaceDiscoveryResult()
55
+ {
56
+ Path = "some-dir",
57
+ Projects =
58
+ [
59
+ new()
60
+ {
61
+ FilePath = "project.csproj",
62
+ TargetFrameworks = ["net8.0"],
63
+ Dependencies =
64
+ [
65
+ new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"]),
66
+ ]
67
+ }
68
+ ]
69
+ });
70
+ }),
71
+ analyzeWorker: new TestAnalyzeWorker(input =>
72
+ {
73
+ return Task.FromResult(new AnalysisResult()
74
+ {
75
+ UpdatedVersion = "1.0.1",
76
+ CanUpdate = true,
77
+ UpdatedDependencies =
78
+ [
79
+ new("Some.Package", "1.0.2", DependencyType.Unknown, TargetFrameworks: ["net8.0"], InfoUrl: "https://nuget.example.com/some-package"),
80
+ ]
81
+ });
82
+ }),
83
+ updaterWorker: new TestUpdaterWorker(async input =>
84
+ {
85
+ Assert.Equal("Some.Package", input.Item3);
86
+ Assert.Equal("1.0.0", input.Item4);
87
+ Assert.Equal("1.0.1", input.Item5);
88
+ var projectPath = input.Item1 + input.Item2;
89
+ await File.WriteAllTextAsync(projectPath, """
90
+ <Project Sdk="Microsoft.NET.Sdk">
91
+ <PropertyGroup>
92
+ <TargetFramework>net8.0</TargetFramework>
93
+ </PropertyGroup>
94
+ <ItemGroup>
95
+ <PackageReference Include="Some.Package" Version="1.0.1" />
96
+ </ItemGroup>
97
+ </Project>
98
+ """);
99
+ return new UpdateOperationResult();
100
+ }),
53
101
  expectedResult: new RunResult()
54
102
  {
55
103
  Base64DependencyFiles =
@@ -168,37 +216,6 @@ public class RunWorkerTests
168
216
  [Fact]
169
217
  public async Task PrivateSourceAuthenticationFailureIsForwaredToApiHandler()
170
218
  {
171
- static (int, string) TestHttpHandler(string uriString)
172
- {
173
- var uri = new Uri(uriString, UriKind.Absolute);
174
- var baseUrl = $"{uri.Scheme}://{uri.Host}:{uri.Port}";
175
- return uri.PathAndQuery switch
176
- {
177
- // initial request is good
178
- "/index.json" => (200, $$"""
179
- {
180
- "version": "3.0.0",
181
- "resources": [
182
- {
183
- "@id": "{{baseUrl}}/download",
184
- "@type": "PackageBaseAddress/3.0.0"
185
- },
186
- {
187
- "@id": "{{baseUrl}}/query",
188
- "@type": "SearchQueryService"
189
- },
190
- {
191
- "@id": "{{baseUrl}}/registrations",
192
- "@type": "RegistrationsBaseUrl"
193
- }
194
- ]
195
- }
196
- """),
197
- // all other requests are unauthorized
198
- _ => (401, "{}"),
199
- };
200
- }
201
- using var http = TestHttpServer.CreateTestStringServer(TestHttpHandler);
202
219
  await RunAsync(
203
220
  packages:
204
221
  [
@@ -218,11 +235,11 @@ public class RunWorkerTests
218
235
  },
219
236
  files:
220
237
  [
221
- ("NuGet.Config", $"""
238
+ ("NuGet.Config", """
222
239
  <configuration>
223
240
  <packageSources>
224
241
  <clear />
225
- <add key="private_feed" value="{http.BaseUrl.TrimEnd('/')}/index.json" allowInsecureConnections="true" />
242
+ <add key="private_feed" value="http://example.com/nuget/index.json" allowInsecureConnections="true" />
226
243
  </packageSources>
227
244
  </configuration>
228
245
  """),
@@ -237,6 +254,12 @@ public class RunWorkerTests
237
254
  </Project>
238
255
  """)
239
256
  ],
257
+ discoveryWorker: new TestDiscoveryWorker((_input) =>
258
+ {
259
+ throw new HttpRequestException(message: null, inner: null, statusCode: HttpStatusCode.Unauthorized);
260
+ }),
261
+ analyzeWorker: TestAnalyzeWorker.FromResults(),
262
+ updaterWorker: TestUpdaterWorker.FromResults(),
240
263
  expectedResult: new RunResult()
241
264
  {
242
265
  Base64DependencyFiles = [],
@@ -244,7 +267,7 @@ public class RunWorkerTests
244
267
  },
245
268
  expectedApiMessages:
246
269
  [
247
- new PrivateSourceAuthenticationFailure([$"{http.BaseUrl.TrimEnd('/')}/index.json"]),
270
+ new PrivateSourceAuthenticationFailure(["http://example.com/nuget/index.json"]),
248
271
  new MarkAsProcessed("TEST-COMMIT-SHA")
249
272
  ]
250
273
  );
@@ -296,6 +319,107 @@ public class RunWorkerTests
296
319
  </packages>
297
320
  """),
298
321
  ],
322
+ discoveryWorker: new TestDiscoveryWorker(_input =>
323
+ {
324
+ return Task.FromResult(new WorkspaceDiscoveryResult()
325
+ {
326
+ Path = "some-dir",
327
+ Projects =
328
+ [
329
+ new()
330
+ {
331
+ FilePath = "project.csproj",
332
+ TargetFrameworks = ["net8.0"],
333
+ Dependencies =
334
+ [
335
+ new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"]),
336
+ new("Some.Package2", "2.0.0", DependencyType.PackagesConfig, TargetFrameworks: ["net8.0"]),
337
+ ]
338
+ }
339
+ ]
340
+ });
341
+ }),
342
+ analyzeWorker: new TestAnalyzeWorker(input =>
343
+ {
344
+ var result = input.Item3.Name switch
345
+ {
346
+ "Some.Package" => new AnalysisResult()
347
+ {
348
+ CanUpdate = true,
349
+ UpdatedVersion = "1.0.1",
350
+ UpdatedDependencies =
351
+ [
352
+ new("Some.Package", "1.0.1", DependencyType.Unknown, TargetFrameworks: ["net8.0"], InfoUrl: "https://nuget.example.com/some-package"),
353
+ ]
354
+ },
355
+ "Some.Package2" => new AnalysisResult()
356
+ {
357
+ CanUpdate = true,
358
+ UpdatedVersion = "2.0.1",
359
+ UpdatedDependencies =
360
+ [
361
+ new("Some.Package2", "2.0.1", DependencyType.Unknown, TargetFrameworks: ["net8.0"], InfoUrl: "https://nuget.example.com/some-package2"),
362
+ ]
363
+ },
364
+ _ => throw new NotSupportedException(),
365
+ };
366
+ return Task.FromResult(result);
367
+ }),
368
+ updaterWorker: new TestUpdaterWorker(async input =>
369
+ {
370
+ var repoRootPath = input.Item1;
371
+ var filePath = input.Item2;
372
+ var packageName = input.Item3;
373
+ var previousVersion = input.Item4;
374
+ var newVersion = input.Item5;
375
+ var _isTransitive = input.Item6;
376
+
377
+ var projectPath = Path.Join(repoRootPath, filePath);
378
+ switch (packageName)
379
+ {
380
+ case "Some.Package":
381
+ await File.WriteAllTextAsync(projectPath, """
382
+ <Project Sdk="Microsoft.NET.Sdk">
383
+ <PropertyGroup>
384
+ <TargetFramework>net8.0</TargetFramework>
385
+ </PropertyGroup>
386
+ <ItemGroup>
387
+ <PackageReference Include="Some.Package" Version="1.0.1" />
388
+ </ItemGroup>
389
+ </Project>
390
+ """);
391
+ break;
392
+ case "Some.Package2":
393
+ await File.WriteAllTextAsync(projectPath, """
394
+ <Project Sdk="Microsoft.NET.Sdk">
395
+ <PropertyGroup>
396
+ <TargetFramework>net8.0</TargetFramework>
397
+ </PropertyGroup>
398
+ <ItemGroup>
399
+ <PackageReference Include="Some.Package" Version="1.0.1" />
400
+ </ItemGroup>
401
+ <ItemGroup>
402
+ <Reference Include="Some.Package2">
403
+ <HintPath>..\packages\Some.Package2.2.0.1\lib\net8.0\Some.Package2.dll</HintPath>
404
+ <Private>True</Private>
405
+ </Reference>
406
+ </ItemGroup>
407
+ </Project>
408
+ """);
409
+ var packagesConfigPath = Path.Join(Path.GetDirectoryName(projectPath)!, "packages.config");
410
+ await File.WriteAllTextAsync(packagesConfigPath, """
411
+ <?xml version="1.0" encoding="utf-8"?>
412
+ <packages>
413
+ <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
414
+ </packages>
415
+ """);
416
+ break;
417
+ default:
418
+ throw new NotSupportedException();
419
+ }
420
+
421
+ return new UpdateOperationResult();
422
+ }),
299
423
  expectedResult: new RunResult()
300
424
  {
301
425
  Base64DependencyFiles =
@@ -547,6 +671,160 @@ public class RunWorkerTests
547
671
  </packages>
548
672
  """),
549
673
  ],
674
+ discoveryWorker: new TestDiscoveryWorker(_input =>
675
+ {
676
+ return Task.FromResult(new WorkspaceDiscoveryResult()
677
+ {
678
+ Path = "some-dir/ProjectA",
679
+ Projects =
680
+ [
681
+ new()
682
+ {
683
+ FilePath = "../ProjectB/ProjectB.csproj",
684
+ TargetFrameworks = ["net8.0"],
685
+ Dependencies =
686
+ [
687
+ new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"]),
688
+ new("Some.Package2", "2.0.0", DependencyType.PackagesConfig, TargetFrameworks: ["net8.0"]),
689
+ ]
690
+ },
691
+ new()
692
+ {
693
+ FilePath = "ProjectA.csproj",
694
+ TargetFrameworks = ["net8.0"],
695
+ Dependencies =
696
+ [
697
+ new("Some.Package", "1.0.0", DependencyType.PackageReference, TargetFrameworks: ["net8.0"]),
698
+ new("Some.Package2", "2.0.0", DependencyType.PackagesConfig, TargetFrameworks: ["net8.0"]),
699
+ ]
700
+ }
701
+ ]
702
+ });
703
+ }),
704
+ analyzeWorker: new TestAnalyzeWorker(input =>
705
+ {
706
+ var result = input.Item3.Name switch
707
+ {
708
+ "Some.Package" => new AnalysisResult()
709
+ {
710
+ CanUpdate = true,
711
+ UpdatedVersion = "1.0.1",
712
+ UpdatedDependencies =
713
+ [
714
+ new("Some.Package", "1.0.1", DependencyType.Unknown, TargetFrameworks: ["net8.0"], InfoUrl: "https://nuget.example.com/some-package"),
715
+ ]
716
+ },
717
+ "Some.Package2" => new AnalysisResult()
718
+ {
719
+ CanUpdate = true,
720
+ UpdatedVersion = "2.0.1",
721
+ UpdatedDependencies =
722
+ [
723
+ new("Some.Package2", "2.0.1", DependencyType.Unknown, TargetFrameworks: ["net8.0"], InfoUrl: "https://nuget.example.com/some-package2"),
724
+ ]
725
+ },
726
+ _ => throw new NotSupportedException(),
727
+ };
728
+ return Task.FromResult(result);
729
+ }),
730
+ updaterWorker: new TestUpdaterWorker(async input =>
731
+ {
732
+ var repoRootPath = input.Item1;
733
+ var filePath = input.Item2;
734
+ var packageName = input.Item3;
735
+ var previousVersion = input.Item4;
736
+ var newVersion = input.Item5;
737
+ var _isTransitive = input.Item6;
738
+
739
+ var projectPath = Path.Join(repoRootPath, filePath);
740
+ var projectName = Path.GetFileName(projectPath);
741
+ var packagesConfigPath = Path.Join(Path.GetDirectoryName(projectPath)!, "packages.config");
742
+ switch ((projectName, packageName))
743
+ {
744
+ case ("ProjectA.csproj", "Some.Package"):
745
+ await File.WriteAllTextAsync(projectPath, """
746
+ <Project Sdk="Microsoft.NET.Sdk">
747
+ <PropertyGroup>
748
+ <TargetFramework>net8.0</TargetFramework>
749
+ </PropertyGroup>
750
+ <ItemGroup>
751
+ <PackageReference Include="Some.Package" Version="1.0.1" />
752
+ </ItemGroup>
753
+ <ItemGroup>
754
+ <ProjectReference Include="../ProjectB/ProjectB.csproj" />
755
+ </ItemGroup>
756
+ </Project>
757
+ """);
758
+ break;
759
+ case ("ProjectA.csproj", "Some.Package2"):
760
+ await File.WriteAllTextAsync(projectPath, """
761
+ <Project Sdk="Microsoft.NET.Sdk">
762
+ <PropertyGroup>
763
+ <TargetFramework>net8.0</TargetFramework>
764
+ </PropertyGroup>
765
+ <ItemGroup>
766
+ <PackageReference Include="Some.Package" Version="1.0.1" />
767
+ </ItemGroup>
768
+ <ItemGroup>
769
+ <ProjectReference Include="../ProjectB/ProjectB.csproj" />
770
+ </ItemGroup>
771
+ <ItemGroup>
772
+ <Reference Include="Some.Package2">
773
+ <HintPath>..\packages\Some.Package2.2.0.1\lib\net8.0\Some.Package2.dll</HintPath>
774
+ <Private>True</Private>
775
+ </Reference>
776
+ </ItemGroup>
777
+ </Project>
778
+ """);
779
+ await File.WriteAllTextAsync(packagesConfigPath, """
780
+ <?xml version="1.0" encoding="utf-8"?>
781
+ <packages>
782
+ <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
783
+ </packages>
784
+ """);
785
+ break;
786
+ case ("ProjectB.csproj", "Some.Package"):
787
+ await File.WriteAllTextAsync(projectPath, """
788
+ <Project Sdk="Microsoft.NET.Sdk">
789
+ <PropertyGroup>
790
+ <TargetFramework>net8.0</TargetFramework>
791
+ </PropertyGroup>
792
+ <ItemGroup>
793
+ <PackageReference Include="Some.Package" Version="1.0.1" />
794
+ </ItemGroup>
795
+ </Project>
796
+ """);
797
+ break;
798
+ case ("ProjectB.csproj", "Some.Package2"):
799
+ await File.WriteAllTextAsync(projectPath, """
800
+ <Project Sdk="Microsoft.NET.Sdk">
801
+ <PropertyGroup>
802
+ <TargetFramework>net8.0</TargetFramework>
803
+ </PropertyGroup>
804
+ <ItemGroup>
805
+ <PackageReference Include="Some.Package" Version="1.0.1" />
806
+ </ItemGroup>
807
+ <ItemGroup>
808
+ <Reference Include="Some.Package2">
809
+ <HintPath>..\packages\Some.Package2.2.0.1\lib\net8.0\Some.Package2.dll</HintPath>
810
+ <Private>True</Private>
811
+ </Reference>
812
+ </ItemGroup>
813
+ </Project>
814
+ """);
815
+ await File.WriteAllTextAsync(packagesConfigPath, """
816
+ <?xml version="1.0" encoding="utf-8"?>
817
+ <packages>
818
+ <package id="Some.Package2" version="2.0.1" targetFramework="net8.0" />
819
+ </packages>
820
+ """);
821
+ break;
822
+ default:
823
+ throw new NotSupportedException();
824
+ }
825
+
826
+ return new UpdateOperationResult();
827
+ }),
550
828
  expectedResult: new RunResult()
551
829
  {
552
830
  Base64DependencyFiles =
@@ -807,7 +1085,7 @@ public class RunWorkerTests
807
1085
  [
808
1086
  new DependencyFile()
809
1087
  {
810
- Name = "../ProjectB/ProjectB.csproj",
1088
+ Name = "ProjectB.csproj",
811
1089
  Directory = "/some-dir/ProjectB",
812
1090
  Content = """
813
1091
  <Project Sdk="Microsoft.NET.Sdk">
@@ -828,7 +1106,7 @@ public class RunWorkerTests
828
1106
  },
829
1107
  new DependencyFile()
830
1108
  {
831
- Name = "../ProjectB/packages.config",
1109
+ Name = "packages.config",
832
1110
  Directory = "/some-dir/ProjectB",
833
1111
  Content = """
834
1112
  <?xml version="1.0" encoding="utf-8"?>
@@ -883,7 +1161,7 @@ public class RunWorkerTests
883
1161
  );
884
1162
  }
885
1163
 
886
- private static async Task RunAsync(Job job, TestFile[] files, RunResult? expectedResult, object[] expectedApiMessages, MockNuGetPackage[]? packages = null, string? repoContentsPath = null)
1164
+ private static async Task RunAsync(Job job, TestFile[] files, IDiscoveryWorker? discoveryWorker, IAnalyzeWorker? analyzeWorker, IUpdaterWorker? updaterWorker, RunResult expectedResult, object[] expectedApiMessages, MockNuGetPackage[]? packages = null, ExperimentsManager? experimentsManager = null, string? repoContentsPath = null)
887
1165
  {
888
1166
  // arrange
889
1167
  using var tempDirectory = new TemporaryDirectory();
@@ -898,9 +1176,15 @@ public class RunWorkerTests
898
1176
  }
899
1177
 
900
1178
  // act
1179
+ experimentsManager ??= new ExperimentsManager();
901
1180
  var testApiHandler = new TestApiHandler();
902
- var worker = new RunWorker(testApiHandler, new TestLogger());
903
- var repoContentsPathDirectoryInfo = new DirectoryInfo(repoContentsPath);
1181
+ var logger = new TestLogger();
1182
+ discoveryWorker ??= new DiscoveryWorker(logger);
1183
+ analyzeWorker ??= new AnalyzeWorker(logger);
1184
+ updaterWorker ??= new UpdaterWorker(experimentsManager, logger);
1185
+
1186
+ var worker = new RunWorker(testApiHandler, discoveryWorker, analyzeWorker, updaterWorker, logger);
1187
+ var repoContentsPathDirectoryInfo = new DirectoryInfo(tempDirectory.DirectoryPath);
904
1188
  var actualResult = await worker.RunAsync(job, repoContentsPathDirectoryInfo, "TEST-COMMIT-SHA");
905
1189
  var actualApiMessages = testApiHandler.ReceivedMessages.ToArray();
906
1190