dependabot-nuget 0.321.3 → 0.322.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/Directory.Packages.props +22 -22
  3. data/helpers/lib/NuGetUpdater/DotNetPackageCorrelation.Cli/Program.cs +21 -7
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +19 -11
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/CloneCommand.cs +19 -9
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs +21 -14
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/FrameworkCheckCommand.cs +8 -5
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +29 -16
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs +20 -19
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Program.cs +2 -1
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +1 -1
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +10 -23
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Run.cs +9 -0
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +15 -232
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +1 -154
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +3 -12
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/GlobalJsonBuildFile.cs +5 -13
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/PrivateSourceTimedOutException.cs +12 -0
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +4 -0
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PrivateSourceTimedOut.cs +10 -0
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestBodyGenerator/AzurePackageDetailFinder.cs +30 -0
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestBodyGenerator/DetailedPullRequestBodyGenerator.cs +237 -0
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestBodyGenerator/GitHubPackageDetailFinder.cs +101 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestBodyGenerator/GitLabPackageDetailFinder.cs +107 -0
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestBodyGenerator/HttpFetcher.cs +32 -0
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestBodyGenerator/IHttpFetcher.cs +30 -0
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestBodyGenerator/IPackageDetailFinder.cs +47 -0
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestBodyGenerator/IPullRequestBodyGenerator.cs +11 -0
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestBodyGenerator/SimplePullRequestBodyGenerator.cs +15 -0
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestTextGenerator.cs +7 -3
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +3 -525
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs +2 -2
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/GroupUpdateAllVersionsHandler.cs +4 -4
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandler.cs +2 -2
  35. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshSecurityUpdatePullRequestHandler.cs +2 -2
  36. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshVersionUpdatePullRequestHandler.cs +2 -2
  37. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/FileWriterWorker.cs +85 -35
  38. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/XmlFileWriter.cs +27 -8
  39. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +1 -856
  40. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdateOperationBase.cs +18 -7
  41. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +16 -200
  42. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +21 -556
  43. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +9 -73
  44. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Clone/CloneWorkerTests.cs +2 -2
  45. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/DependencySolver/MSBuildDependencySolverTests.cs +1 -1
  46. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +1 -20
  47. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.GlobalJson.cs +0 -2
  48. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs +3 -62
  49. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +13 -563
  50. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +20 -269
  51. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +2 -2
  52. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Files/GlobalJsonBuildFileTests.cs +0 -1
  53. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/EndToEndTests.cs +131 -131
  54. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/HttpApiHandlerTests.cs +1 -0
  55. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/JobErrorBaseTests.cs +7 -0
  56. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MessageReportTests.cs +11 -0
  57. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +0 -203
  58. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestBodyGenerator/DetailedPullRequestBodyGeneratorTests.cs +871 -0
  59. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestBodyGenerator/IPackageDetailFinderTests.cs +28 -0
  60. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestBodyGenerator/TestHttpFetcher.cs +23 -0
  61. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestTextTests.cs +24 -24
  62. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +14 -12
  63. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandlerTests.cs +6 -6
  64. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/GroupUpdateAllVersionsHandlerTests.cs +18 -18
  65. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandlerTests.cs +15 -15
  66. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/RefreshSecurityUpdatePullRequestHandlerTests.cs +21 -21
  67. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/RefreshVersionUpdatePullRequestHandlerTests.cs +15 -15
  68. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/UpdateHandlersTestsBase.cs +1 -8
  69. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/FileWriterWorkerTests.cs +2 -2
  70. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/FileWriterWorkerTests_MiscellaneousTests.cs +45 -0
  71. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/XmlFileWriterTests.cs +111 -0
  72. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackageReferenceUpdaterTests.cs +1 -159
  73. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +26 -660
  74. data/helpers/lib/NuGetUpdater/global.json +1 -1
  75. metadata +18 -10
  76. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunResult.cs +0 -13
  77. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestMessageTests.cs +0 -296
  78. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +0 -3592
  79. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdatePermittedAndMessageTests.cs +0 -457
  80. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs +0 -378
  81. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/SdkPackageUpdaterHelperTests.cs +0 -175
@@ -1,12 +1,8 @@
1
1
  using System.Collections.Immutable;
2
- using System.IO;
3
2
  using System.IO.Enumeration;
4
- using System.Text;
5
3
  using System.Text.Json;
6
4
  using System.Text.Json.Serialization;
7
5
 
8
- using Microsoft.Extensions.FileSystemGlobbing;
9
-
10
6
  using NuGet.Versioning;
11
7
 
12
8
  using NuGetUpdater.Core.Analyze;
@@ -49,35 +45,12 @@ public class RunWorker
49
45
  var jobFileContent = await File.ReadAllTextAsync(jobFilePath.FullName);
50
46
  var jobWrapper = Deserialize(jobFileContent);
51
47
  var experimentsManager = ExperimentsManager.GetExperimentsManager(jobWrapper.Job.Experiments);
52
- var result = await RunAsync(jobWrapper.Job, repoContentsPath, caseInsensitiveRepoContentsPath, baseCommitSha, experimentsManager);
53
- if (experimentsManager.UseLegacyUpdateHandler)
54
- {
55
- // only the legacy handler writes this file
56
- var resultJson = JsonSerializer.Serialize(result, SerializerOptions);
57
- await File.WriteAllTextAsync(outputFilePath.FullName, resultJson);
58
- }
48
+ await RunAsync(jobWrapper.Job, repoContentsPath, caseInsensitiveRepoContentsPath, baseCommitSha, experimentsManager);
59
49
  }
60
50
 
61
- public async Task<RunResult> RunAsync(Job job, DirectoryInfo repoContentsPath, DirectoryInfo? caseInsensitiveRepoContentsPath, string baseCommitSha, ExperimentsManager experimentsManager)
51
+ public async Task RunAsync(Job job, DirectoryInfo repoContentsPath, DirectoryInfo? caseInsensitiveRepoContentsPath, string baseCommitSha, ExperimentsManager experimentsManager)
62
52
  {
63
- RunResult result;
64
- if (experimentsManager.UseLegacyUpdateHandler)
65
- {
66
- result = await RunWithErrorHandlingAsync(job, repoContentsPath, caseInsensitiveRepoContentsPath, baseCommitSha, experimentsManager);
67
- }
68
- else
69
- {
70
- await RunScenarioHandlersWithErrorHandlingAsync(job, repoContentsPath, caseInsensitiveRepoContentsPath, baseCommitSha, experimentsManager);
71
-
72
- // the group updater doesn't return this, so we provide an empty object
73
- result = new RunResult()
74
- {
75
- Base64DependencyFiles = [],
76
- BaseCommitSha = baseCommitSha,
77
- };
78
- }
79
-
80
- return result;
53
+ await RunScenarioHandlersWithErrorHandlingAsync(job, repoContentsPath, caseInsensitiveRepoContentsPath, baseCommitSha, experimentsManager);
81
54
  }
82
55
 
83
56
  private static readonly ImmutableArray<IUpdateHandler> UpdateHandlers =
@@ -115,252 +88,6 @@ public class RunWorker
115
88
  await _apiHandler.MarkAsProcessed(new(baseCommitSha));
116
89
  }
117
90
 
118
- private async Task<RunResult> RunWithErrorHandlingAsync(Job job, DirectoryInfo repoContentsPath, DirectoryInfo? caseInsensitiveRepoContentsPath, string baseCommitSha, ExperimentsManager experimentsManager)
119
- {
120
- JobErrorBase? error = null;
121
- var currentDirectory = repoContentsPath.FullName; // used for error reporting below
122
- var runResult = new RunResult()
123
- {
124
- Base64DependencyFiles = [],
125
- BaseCommitSha = baseCommitSha,
126
- };
127
-
128
- try
129
- {
130
- MSBuildHelper.RegisterMSBuild(repoContentsPath.FullName, repoContentsPath.FullName, _logger);
131
-
132
- var allDependencyFiles = new Dictionary<string, DependencyFile>();
133
- foreach (var directory in job.GetAllDirectories())
134
- {
135
- var localPath = PathHelper.JoinPath(repoContentsPath.FullName, directory);
136
- currentDirectory = localPath;
137
- var result = await RunForDirectory(job, repoContentsPath, caseInsensitiveRepoContentsPath, directory, baseCommitSha, experimentsManager);
138
- foreach (var dependencyFile in result.Base64DependencyFiles)
139
- {
140
- var uniqueKey = Path.GetFullPath(Path.Join(dependencyFile.Directory, dependencyFile.Name)).NormalizePathToUnix().EnsurePrefix("/");
141
- allDependencyFiles[uniqueKey] = dependencyFile;
142
- }
143
- }
144
-
145
- runResult = new RunResult()
146
- {
147
- Base64DependencyFiles = allDependencyFiles.Values.ToArray(),
148
- BaseCommitSha = baseCommitSha,
149
- };
150
- }
151
- catch (Exception ex)
152
- {
153
- error = JobErrorBase.ErrorFromException(ex, _jobId, currentDirectory);
154
- }
155
-
156
- if (error is not null)
157
- {
158
- await _apiHandler.RecordUpdateJobError(error, _logger);
159
- }
160
-
161
- await _apiHandler.MarkAsProcessed(new(baseCommitSha));
162
-
163
- return runResult;
164
- }
165
-
166
- private async Task<RunResult> RunForDirectory(Job job, DirectoryInfo originalRepoContentsPath, DirectoryInfo? caseInsensitiveRepoContentsPath, string repoDirectory, string baseCommitSha, ExperimentsManager experimentsManager)
167
- {
168
- var repoContentsPath = caseInsensitiveRepoContentsPath ?? originalRepoContentsPath;
169
- var discoveryResult = await _discoveryWorker.RunAsync(repoContentsPath.FullName, repoDirectory);
170
- _logger.ReportDiscovery(discoveryResult);
171
-
172
- if (discoveryResult.Error is not null)
173
- {
174
- // this is unrecoverable
175
- await _apiHandler.RecordUpdateJobError(discoveryResult.Error, _logger);
176
- return new()
177
- {
178
- Base64DependencyFiles = [],
179
- BaseCommitSha = baseCommitSha,
180
- };
181
- }
182
-
183
- // report dependencies
184
- var discoveredUpdatedDependencies = GetUpdatedDependencyListFromDiscovery(discoveryResult, originalRepoContentsPath.FullName, _logger);
185
- await _apiHandler.UpdateDependencyList(discoveredUpdatedDependencies);
186
-
187
- var incrementMetric = GetIncrementMetric(job);
188
- await _apiHandler.IncrementMetric(incrementMetric);
189
-
190
- // TODO: pull out relevant dependencies, then check each for updates and track the changes
191
- var actualUpdatedDependencies = new List<ReportedDependency>();
192
-
193
- // track original contents for later handling
194
- var tracker = new ModifiedFilesTracker(originalRepoContentsPath, _logger);
195
- await tracker.StartTrackingAsync(discoveryResult);
196
-
197
- // do update
198
- var updateOperationsPerformed = new List<UpdateOperationBase>();
199
- var existingPullRequests = job.GetAllExistingPullRequests();
200
- var unhandledPullRequestDependenciesSet = existingPullRequests
201
- .Select(pr => pr.Item2.Select(d => d.DependencyName).ToHashSet(StringComparer.OrdinalIgnoreCase))
202
- .ToHashSet();
203
- var remainingSecurityIssues = job.SecurityAdvisories
204
- .Select(s => s.DependencyName)
205
- .ToHashSet(StringComparer.OrdinalIgnoreCase);
206
- var updateOperations = GetUpdateOperations(discoveryResult).ToArray();
207
-
208
- foreach (var updateOperation in updateOperations)
209
- {
210
- var dependency = updateOperation.Dependency;
211
- var (isAllowed, message) = UpdatePermittedAndMessage(job, updateOperation.Dependency);
212
- if (message is SecurityUpdateNotNeeded sec)
213
- {
214
- // flag this update operation as having been handled
215
- remainingSecurityIssues.RemoveWhere(r => r.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase));
216
-
217
- // we only want to send this message if we're in the only update operation for this dependency, otherwise it's ambiguous
218
- var updateOperationsWithSameName = updateOperations.Where(u => u.Dependency.Name.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase))
219
- .ToArray();
220
- if (updateOperationsWithSameName.Length > 1)
221
- {
222
- // suppress the message
223
- message = null;
224
- }
225
- }
226
-
227
- await SendApiMessage(message);
228
- if (!isAllowed)
229
- {
230
- continue;
231
- }
232
-
233
- _logger.Info($"Updating [{dependency.Name}] in [{updateOperation.ProjectPath}]");
234
-
235
- var dependencyInfo = GetDependencyInfo(job, dependency);
236
- var analysisResult = await _analyzeWorker.RunAsync(repoContentsPath.FullName, discoveryResult, dependencyInfo);
237
- _logger.ReportAnalysis(analysisResult);
238
-
239
- if (analysisResult.Error is not null)
240
- {
241
- await _apiHandler.RecordUpdateJobError(analysisResult.Error, _logger);
242
- continue;
243
- }
244
-
245
- if (analysisResult.CanUpdate)
246
- {
247
- if (!job.UpdatingAPullRequest)
248
- {
249
- var updatedDependencyFromAnalysis = analysisResult.UpdatedDependencies
250
- .FirstOrDefault(d => d.Name.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase));
251
- if (updatedDependencyFromAnalysis is not null)
252
- {
253
- var existingPullRequest = job.GetExistingPullRequestForDependencies([updatedDependencyFromAnalysis], considerVersions: true);
254
- if (existingPullRequest is not null)
255
- {
256
- await SendApiMessage(new PullRequestExistsForLatestVersion(dependency.Name, analysisResult.UpdatedVersion));
257
- unhandledPullRequestDependenciesSet.RemoveWhere(handled => handled.Count == 1 && handled.Contains(dependency.Name));
258
- continue;
259
- }
260
- }
261
- }
262
-
263
- // TODO: this is inefficient, but not likely causing a bottleneck
264
- var previousDependency = discoveredUpdatedDependencies.Dependencies
265
- .Single(d => d.Name == dependency.Name && d.Requirements.Single().File == updateOperation.ProjectPath);
266
- var updatedDependency = new ReportedDependency()
267
- {
268
- Name = dependency.Name,
269
- Version = analysisResult.UpdatedVersion,
270
- Requirements =
271
- [
272
- new ReportedRequirement()
273
- {
274
- File = updateOperation.ProjectPath,
275
- Requirement = analysisResult.UpdatedVersion,
276
- Groups = previousDependency.Requirements.Single().Groups,
277
- Source = new RequirementSource()
278
- {
279
- SourceUrl = analysisResult.UpdatedDependencies.FirstOrDefault(d => d.Name == dependency.Name)?.InfoUrl,
280
- },
281
- }
282
- ],
283
- PreviousVersion = dependency.Version,
284
- PreviousRequirements = previousDependency.Requirements,
285
- };
286
-
287
- var projectDiscovery = discoveryResult.GetProjectDiscoveryFromPath(updateOperation.ProjectPath);
288
- var updateResult = await _updaterWorker.RunAsync(repoContentsPath.FullName, updateOperation.ProjectPath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, isTransitive: dependency.IsTransitive);
289
- if (updateResult.Error is not null)
290
- {
291
- await _apiHandler.RecordUpdateJobError(updateResult.Error, _logger);
292
- }
293
- else
294
- {
295
- actualUpdatedDependencies.Add(updatedDependency);
296
- }
297
-
298
- var patchedUpdateOperations = PatchInOldVersions(updateResult.UpdateOperations, projectDiscovery);
299
- updateOperationsPerformed.AddRange(patchedUpdateOperations);
300
- }
301
- }
302
-
303
- // create PR - we need to manually check file contents; we can't easily use `git status` in tests
304
- var updatedDependencyFiles = await tracker.StopTrackingAsync();
305
- var normalizedUpdateOperationsPerformed = UpdateOperationBase.NormalizeUpdateOperationCollection(repoContentsPath.FullName, updateOperationsPerformed);
306
- var report = UpdateOperationBase.GenerateUpdateOperationReport(normalizedUpdateOperationsPerformed);
307
- _logger.Info(report);
308
-
309
- var sortedUpdatedDependencies = actualUpdatedDependencies.OrderBy(d => d.Name, StringComparer.OrdinalIgnoreCase).ToArray();
310
- var resultMessage = GetPullRequestApiMessage(job, [.. updatedDependencyFiles], sortedUpdatedDependencies, normalizedUpdateOperationsPerformed, baseCommitSha);
311
- switch (resultMessage)
312
- {
313
- case ClosePullRequest close:
314
- var closePrDependencies = close.DependencyNames.ToHashSet(StringComparer.OrdinalIgnoreCase);
315
- remainingSecurityIssues.RemoveWhere(closePrDependencies.Contains);
316
- if (!unhandledPullRequestDependenciesSet.Remove(closePrDependencies))
317
- {
318
- // this PR was handled earlier, we don't want to now close it; suppress the message
319
- resultMessage = null;
320
- }
321
- break;
322
- case CreatePullRequest create:
323
- var createPrDependencies = create.Dependencies.Select(d => d.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
324
- remainingSecurityIssues.RemoveWhere(createPrDependencies.Contains);
325
- break;
326
- case UpdatePullRequest update:
327
- var updatePrDependencies = update.DependencyNames.ToHashSet(StringComparer.OrdinalIgnoreCase);
328
- remainingSecurityIssues.RemoveWhere(updatePrDependencies.Contains);
329
- break;
330
- }
331
-
332
- await SendApiMessage(resultMessage);
333
-
334
- // for each security advisory that _didn't_ result in a pr, report it
335
- foreach (var depName in remainingSecurityIssues)
336
- {
337
- await SendApiMessage(new SecurityUpdateNotNeeded(depName));
338
- }
339
-
340
- var result = new RunResult()
341
- {
342
- Base64DependencyFiles = tracker.OriginalDependencyFileContents.OrderBy(kvp => kvp.Key).Select(kvp =>
343
- {
344
- var fullPath = kvp.Key.FullyNormalizedRootedPath();
345
- var rawContent = Encoding.UTF8.GetBytes(kvp.Value);
346
- if (tracker.OriginalDependencyFileBOMs[kvp.Key])
347
- {
348
- rawContent = Encoding.UTF8.GetPreamble().Concat(rawContent).ToArray();
349
- }
350
-
351
- return new DependencyFile()
352
- {
353
- Name = Path.GetFileName(fullPath),
354
- Content = Convert.ToBase64String(rawContent),
355
- ContentEncoding = "base64",
356
- Directory = Path.GetDirectoryName(fullPath)!.NormalizePathToUnix(),
357
- };
358
- }).ToArray(),
359
- BaseCommitSha = baseCommitSha,
360
- };
361
- return result;
362
- }
363
-
364
91
  internal static ImmutableArray<UpdateOperationBase> PatchInOldVersions(ImmutableArray<UpdateOperationBase> updateOperations, ProjectDiscoveryResult? projectDiscovery)
365
92
  {
366
93
  if (projectDiscovery is null)
@@ -377,115 +104,6 @@ public class RunWorker
377
104
  return patchedUpdateOperations;
378
105
  }
379
106
 
380
- private async Task SendApiMessage(MessageBase? message)
381
- {
382
- if (message is null)
383
- {
384
- return;
385
- }
386
-
387
- var report = message.GetReport();
388
- _logger.Info(report);
389
- switch (message)
390
- {
391
- case JobErrorBase error:
392
- await _apiHandler.RecordUpdateJobError(error, _logger);
393
- break;
394
- case CreatePullRequest create:
395
- await _apiHandler.CreatePullRequest(create);
396
- break;
397
- case ClosePullRequest close:
398
- await _apiHandler.ClosePullRequest(close);
399
- break;
400
- case UpdatePullRequest update:
401
- await _apiHandler.UpdatePullRequest(update);
402
- break;
403
- default:
404
- throw new NotSupportedException($"unsupported api message: {message.GetType().Name}");
405
- }
406
- }
407
-
408
- internal static MessageBase? GetPullRequestApiMessage(
409
- Job job,
410
- DependencyFile[] updatedFiles,
411
- ReportedDependency[] updatedDependencies,
412
- ImmutableArray<UpdateOperationBase> updateOperationsPerformed,
413
- string baseCommitSha
414
- )
415
- {
416
- var updatedDependencyNames = updateOperationsPerformed.Select(u => u.DependencyName).OrderBy(d => d, StringComparer.OrdinalIgnoreCase).ToArray();
417
- var updatedDependenciesSet = updatedDependencyNames.ToHashSet(StringComparer.OrdinalIgnoreCase);
418
-
419
- // all pull request dependencies with optional group name
420
- var existingPullRequests = job.GetAllExistingPullRequests();
421
- var existingPullRequest = existingPullRequests.FirstOrDefault(pr => pr.Item2.Select(d => d.DependencyName).All(updatedDependenciesSet.Contains));
422
- if (existingPullRequest is null && updatedFiles.Length == 0)
423
- {
424
- // it's possible that we were asked to update a specific package, but it's no longer there; in that case find _that_ specific PR
425
- var requestedUpdates = job.Dependencies.ToHashSet(StringComparer.OrdinalIgnoreCase);
426
- existingPullRequest = existingPullRequests.FirstOrDefault(pr => pr.Item2.Select(d => d.DependencyName).All(requestedUpdates.Contains));
427
- }
428
-
429
- var expectedSecurityUpdateDependencyNames = job.SecurityAdvisories.Select(sa => sa.DependencyName).ToHashSet(StringComparer.OrdinalIgnoreCase);
430
- var isExpectedSecurityUpdate = updatedDependenciesSet.All(expectedSecurityUpdateDependencyNames.Contains);
431
-
432
- if (existingPullRequest is { })
433
- {
434
- if (job.UpdatingAPullRequest)
435
- {
436
- return new UpdatePullRequest()
437
- {
438
- DependencyGroup = existingPullRequest.Item1,
439
- DependencyNames = [.. updatedDependencyNames],
440
- UpdatedDependencyFiles = updatedFiles,
441
- BaseCommitSha = baseCommitSha,
442
- CommitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, updateOperationsPerformed, existingPullRequest.Item1),
443
- PrTitle = PullRequestTextGenerator.GetPullRequestTitle(job, updateOperationsPerformed, existingPullRequest.Item1),
444
- PrBody = PullRequestTextGenerator.GetPullRequestBody(job, updateOperationsPerformed, existingPullRequest.Item1),
445
- };
446
- }
447
- else
448
- {
449
- if (updatedDependenciesSet.Count == 0)
450
- {
451
- // nothing found, close current
452
- return new ClosePullRequest()
453
- {
454
- DependencyNames = [.. existingPullRequest.Item2.Select(d => d.DependencyName)],
455
- Reason = "dependency_removed",
456
- };
457
- }
458
- else
459
- {
460
- // found but no longer required
461
- return new ClosePullRequest()
462
- {
463
- DependencyNames = [.. updatedDependenciesSet],
464
- Reason = "up_to_date",
465
- };
466
- }
467
- }
468
- }
469
- else
470
- {
471
- if (updatedDependencyNames.Any())
472
- {
473
- return new CreatePullRequest()
474
- {
475
- Dependencies = updatedDependencies,
476
- UpdatedDependencyFiles = updatedFiles,
477
- BaseCommitSha = baseCommitSha,
478
- CommitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, updateOperationsPerformed, dependencyGroupName: null),
479
- PrTitle = PullRequestTextGenerator.GetPullRequestTitle(job, updateOperationsPerformed, dependencyGroupName: null),
480
- PrBody = PullRequestTextGenerator.GetPullRequestBody(job, updateOperationsPerformed, dependencyGroupName: null),
481
- DependencyGroup = null,
482
- };
483
- }
484
- }
485
-
486
- return null;
487
- }
488
-
489
107
  internal static IEnumerable<(string ProjectPath, Dependency Dependency)> GetUpdateOperations(WorkspaceDiscoveryResult discovery)
490
108
  {
491
109
  // discovery is grouped by project/file then dependency, but we want to pivot and return a list of update operations sorted by dependency name then file path
@@ -534,146 +152,6 @@ public class RunWorker
534
152
  }
535
153
  }
536
154
 
537
- internal static IncrementMetric GetIncrementMetric(Job job)
538
- {
539
- var isSecurityUpdate = job.AllowedUpdates.Any(a => a.UpdateType == UpdateType.Security) || job.SecurityUpdatesOnly;
540
- var metricOperation = isSecurityUpdate ?
541
- (job.UpdatingAPullRequest ? "update_security_pr" : "create_security_pr")
542
- : (job.UpdatingAPullRequest ? "update_version_pr" : "group_update_all_versions");
543
- var increment = new IncrementMetric()
544
- {
545
- Metric = "updater.started",
546
- Tags = { ["operation"] = metricOperation },
547
- };
548
- return increment;
549
- }
550
-
551
- internal static (bool, MessageBase?) UpdatePermittedAndMessage(Job job, Dependency dependency)
552
- {
553
- if (dependency.Name.Equals("Microsoft.NET.Sdk", StringComparison.OrdinalIgnoreCase))
554
- {
555
- // this can't be updated
556
- // TODO: pull this out of discovery?
557
- return (false, null);
558
- }
559
-
560
- if (dependency.Version is null)
561
- {
562
- // if we don't know the version, there's nothing we can do
563
- // TODO: pull this out of discovery?
564
- return (false, null);
565
- }
566
-
567
- var version = NuGetVersion.Parse(dependency.Version);
568
- var dependencyInfo = GetDependencyInfo(job, dependency);
569
- var isVulnerable = dependencyInfo.Vulnerabilities.Any(v => v.IsVulnerable(version));
570
- MessageBase? message = null;
571
- var allowed = job.AllowedUpdates.Any(allowedUpdate =>
572
- {
573
- // check name restriction, if any
574
- if (allowedUpdate.DependencyName is not null)
575
- {
576
- var matcher = new Matcher(StringComparison.OrdinalIgnoreCase)
577
- .AddInclude(allowedUpdate.DependencyName);
578
- var result = matcher.Match(dependency.Name);
579
- if (!result.HasMatches)
580
- {
581
- return false;
582
- }
583
- }
584
-
585
- var isSecurityUpdate = allowedUpdate.UpdateType == UpdateType.Security || job.SecurityUpdatesOnly;
586
- if (isSecurityUpdate)
587
- {
588
- if (isVulnerable)
589
- {
590
- // try to match to existing PR
591
- var dependencyVersion = NuGetVersion.Parse(dependency.Version);
592
- var existingPullRequests = job.GetAllExistingPullRequests()
593
- .Where(pr => pr.Item2.Any(d => d.DependencyName.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase) && d.DependencyVersion >= dependencyVersion))
594
- .ToArray();
595
- if (existingPullRequests.Length > 0)
596
- {
597
- // found a matching pr...
598
- if (job.UpdatingAPullRequest)
599
- {
600
- // ...and we've been asked to update it
601
- return true;
602
- }
603
- else
604
- {
605
- // ...but no update requested => don't perform any update and report error
606
- var existingPrVersion = existingPullRequests[0].Item2.First(d => d.DependencyName.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase)).DependencyVersion;
607
- message = new PullRequestExistsForLatestVersion(dependency.Name, existingPrVersion.ToString());
608
- return false;
609
- }
610
- }
611
- else
612
- {
613
- // no matching pr...
614
- if (job.UpdatingAPullRequest)
615
- {
616
- // ...but we've been asked to perform an update => no update possible, nothing to report
617
- return false;
618
- }
619
- else
620
- {
621
- // ...and no update specifically requested => create new
622
- return true;
623
- }
624
- }
625
- }
626
- else
627
- {
628
- // not vulnerable => no longer needed
629
- var specificJobDependencies = job.SecurityAdvisories
630
- .Select(a => a.DependencyName)
631
- .Concat(job.Dependencies)
632
- .ToHashSet(StringComparer.OrdinalIgnoreCase);
633
- if (specificJobDependencies.Contains(dependency.Name))
634
- {
635
- message = new SecurityUpdateNotNeeded(dependency.Name);
636
- }
637
- }
638
-
639
- return false;
640
- }
641
- else
642
- {
643
- // not a security update, so only update if...
644
- // ...we've been explicitly asked to update this
645
- if (job.Dependencies.Any(d => d.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase)))
646
- {
647
- return true;
648
- }
649
-
650
- // ...no specific update being performed, do it if it's not transitive
651
- return !dependency.IsTransitive;
652
- }
653
- });
654
-
655
- return (allowed, message);
656
- }
657
-
658
- internal static ImmutableArray<Requirement> GetIgnoredRequirementsForDependency(Job job, string dependencyName)
659
- {
660
- var ignoreConditions = job.IgnoreConditions
661
- .Where(c => c.DependencyName.Equals(dependencyName, StringComparison.OrdinalIgnoreCase))
662
- .ToArray();
663
- if (ignoreConditions.Length == 1 && ignoreConditions[0].VersionRequirement is null)
664
- {
665
- // if only one match with no version requirement, ignore all versions
666
- return [Requirement.Parse("> 0.0.0")];
667
- }
668
-
669
- var ignoredVersions = ignoreConditions
670
- .Select(c => c.VersionRequirement)
671
- .Where(r => r is not null)
672
- .Cast<Requirement>()
673
- .ToImmutableArray();
674
- return ignoredVersions;
675
- }
676
-
677
155
  internal static DependencyInfo GetDependencyInfo(Job job, Dependency dependency)
678
156
  {
679
157
  var dependencyVersion = NuGetVersion.Parse(dependency.Version!);
@@ -140,7 +140,7 @@ internal class CreateSecurityUpdatePullRequestHandler : IUpdateHandler
140
140
  updateOperationsPerformed.AddRange(patchedUpdateOperations);
141
141
  foreach (var o in patchedUpdateOperations)
142
142
  {
143
- logger.Info($"Update operation performed: {o.GetReport()}");
143
+ logger.Info($"Update operation performed: {o.GetReport(includeFileNames: true)}");
144
144
  }
145
145
  }
146
146
  }
@@ -161,7 +161,7 @@ internal class CreateSecurityUpdatePullRequestHandler : IUpdateHandler
161
161
  {
162
162
  var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], null);
163
163
  var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], null);
164
- var prBody = PullRequestTextGenerator.GetPullRequestBody(job, [.. updateOperationsPerformed], null);
164
+ var prBody = await PullRequestTextGenerator.GetPullRequestBodyAsync(job, [.. updateOperationsPerformed], [.. updatedDependencies], experimentsManager);
165
165
  await apiHandler.CreatePullRequest(new CreatePullRequest()
166
166
  {
167
167
  Dependencies = [.. updatedDependencies],
@@ -143,7 +143,7 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
143
143
  updateOperationsPerformed.AddRange(patchedUpdateOperations);
144
144
  foreach (var o in patchedUpdateOperations)
145
145
  {
146
- logger.Info($"Update operation performed: {o.GetReport()}");
146
+ logger.Info($"Update operation performed: {o.GetReport(includeFileNames: true)}");
147
147
  }
148
148
  }
149
149
 
@@ -155,7 +155,7 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
155
155
  {
156
156
  var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], group.Name);
157
157
  var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], group.Name);
158
- var prBody = PullRequestTextGenerator.GetPullRequestBody(job, [.. updateOperationsPerformed], group.Name);
158
+ var prBody = await PullRequestTextGenerator.GetPullRequestBodyAsync(job, [.. updateOperationsPerformed], [.. updatedDependencies], experimentsManager);
159
159
  await apiHandler.CreatePullRequest(new CreatePullRequest()
160
160
  {
161
161
  Dependencies = [.. updatedDependencies],
@@ -242,7 +242,7 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
242
242
  updateOperationsPerformed.AddRange(patchedUpdateOperations);
243
243
  foreach (var o in patchedUpdateOperations)
244
244
  {
245
- logger.Info($"Update operation performed: {o.GetReport()}");
245
+ logger.Info($"Update operation performed: {o.GetReport(includeFileNames: true)}");
246
246
  }
247
247
  }
248
248
 
@@ -251,7 +251,7 @@ internal class GroupUpdateAllVersionsHandler : IUpdateHandler
251
251
  {
252
252
  var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], null);
253
253
  var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], null);
254
- var prBody = PullRequestTextGenerator.GetPullRequestBody(job, [.. updateOperationsPerformed], null);
254
+ var prBody = await PullRequestTextGenerator.GetPullRequestBodyAsync(job, [.. updateOperationsPerformed], [.. updatedDependencies], experimentsManager);
255
255
  await apiHandler.CreatePullRequest(new CreatePullRequest()
256
256
  {
257
257
  Dependencies = [.. updatedDependencies],
@@ -137,7 +137,7 @@ internal class RefreshGroupUpdatePullRequestHandler : IUpdateHandler
137
137
  updateOperationsPerformed.AddRange(patchedUpdateOperations);
138
138
  foreach (var o in patchedUpdateOperations)
139
139
  {
140
- logger.Info($"Update operation performed: {o.GetReport()}");
140
+ logger.Info($"Update operation performed: {o.GetReport(includeFileNames: true)}");
141
141
  }
142
142
  }
143
143
  }
@@ -154,7 +154,7 @@ internal class RefreshGroupUpdatePullRequestHandler : IUpdateHandler
154
154
 
155
155
  var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], null);
156
156
  var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], null);
157
- var prBody = PullRequestTextGenerator.GetPullRequestBody(job, [.. updateOperationsPerformed], null);
157
+ var prBody = await PullRequestTextGenerator.GetPullRequestBodyAsync(job, [.. updateOperationsPerformed], [.. updatedDependencies], experimentsManager);
158
158
  var existingPullRequest = job.GetExistingPullRequestForDependencies(rawDependencies, considerVersions: true);
159
159
  if (existingPullRequest is not null)
160
160
  {
@@ -135,7 +135,7 @@ internal class RefreshSecurityUpdatePullRequestHandler : IUpdateHandler
135
135
  updateOperationsPerformed.AddRange(patchedUpdateOperations);
136
136
  foreach (var o in patchedUpdateOperations)
137
137
  {
138
- logger.Info($"Update operation performed: {o.GetReport()}");
138
+ logger.Info($"Update operation performed: {o.GetReport(includeFileNames: true)}");
139
139
  }
140
140
  }
141
141
  }
@@ -161,7 +161,7 @@ internal class RefreshSecurityUpdatePullRequestHandler : IUpdateHandler
161
161
  {
162
162
  var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], null);
163
163
  var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], null);
164
- var prBody = PullRequestTextGenerator.GetPullRequestBody(job, [.. updateOperationsPerformed], null);
164
+ var prBody = await PullRequestTextGenerator.GetPullRequestBodyAsync(job, [.. updateOperationsPerformed], [.. updatedDependencies], experimentsManager);
165
165
 
166
166
  var existingPullRequest = job.GetExistingPullRequestForDependencies(rawDependencies, considerVersions: true);
167
167
  if (existingPullRequest is not null)
@@ -125,7 +125,7 @@ internal class RefreshVersionUpdatePullRequestHandler : IUpdateHandler
125
125
  updateOperationsPerformed.AddRange(patchedUpdateOperations);
126
126
  foreach (var o in patchedUpdateOperations)
127
127
  {
128
- logger.Info($"Update operation performed: {o.GetReport()}");
128
+ logger.Info($"Update operation performed: {o.GetReport(includeFileNames: true)}");
129
129
  }
130
130
  }
131
131
  }
@@ -151,7 +151,7 @@ internal class RefreshVersionUpdatePullRequestHandler : IUpdateHandler
151
151
  {
152
152
  var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], null);
153
153
  var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], null);
154
- var prBody = PullRequestTextGenerator.GetPullRequestBody(job, [.. updateOperationsPerformed], null);
154
+ var prBody = await PullRequestTextGenerator.GetPullRequestBodyAsync(job, [.. updateOperationsPerformed], [.. updatedDependencies], experimentsManager);
155
155
 
156
156
  var existingPullRequest = job.GetExistingPullRequestForDependencies(rawDependencies, considerVersions: true);
157
157
  if (existingPullRequest is not null)