dependabot-nuget 0.285.0 → 0.286.0

Sign up to get free protection for your applications and to get access to all the features.
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