dependabot-nuget 0.315.0 → 0.316.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 +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Run.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs +6 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +3 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/ClosePullRequest.cs +15 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/CreatePullRequest.cs +47 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyGroup.cs +60 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +151 -23
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobErrorBase.cs +4 -18
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PullRequestExistsForSecurityUpdate.cs +15 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/SecurityUpdateDependencyNotFound.cs +9 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/SecurityUpdateIgnored.cs +10 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/SecurityUpdateNotFound.cs +11 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/SecurityUpdateNotPossible.cs +13 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/UpdatePullRequest.cs +6 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ModifiedFilesTracker.cs +151 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/PullRequestTextGenerator.cs +78 -32
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +99 -111
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs +169 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/GroupUpdateAllVersionsHandler.cs +271 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/IUpdateHandler.cs +22 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandler.cs +192 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshSecurityUpdatePullRequestHandler.cs +187 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshVersionUpdatePullRequestHandler.cs +175 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdateOperationBase.cs +43 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ILogger.cs +17 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +15 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MarkdownListBuilder.cs +65 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/ApiModel/JobTests.cs +405 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/EndToEndTests.cs +92 -82
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/HttpApiHandlerTests.cs +5 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MessageReportTests.cs +67 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +445 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestMessageTests.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/PullRequestTextTests.cs +260 -20
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +30 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +69 -10
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandlerTests.cs +766 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/GroupUpdateAllVersionsHandlerTests.cs +636 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandlerTests.cs +513 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/RefreshSecurityUpdatePullRequestHandlerTests.cs +806 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/RefreshVersionUpdatePullRequestHandlerTests.cs +589 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/UpdateHandlerSelectionTests.cs +183 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdateHandlers/UpdateHandlersTestsBase.cs +43 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdatedDependencyListTests.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateOperationBaseTests.cs +121 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +6 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +51 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MarkdownListBuilderTests.cs +42 -0
- metadata +26 -4
@@ -0,0 +1,169 @@
|
|
1
|
+
using NuGet.Versioning;
|
2
|
+
|
3
|
+
using NuGetUpdater.Core.Run.ApiModel;
|
4
|
+
using NuGetUpdater.Core.Updater;
|
5
|
+
|
6
|
+
namespace NuGetUpdater.Core.Run.UpdateHandlers;
|
7
|
+
|
8
|
+
internal class CreateSecurityUpdatePullRequestHandler : IUpdateHandler
|
9
|
+
{
|
10
|
+
public static IUpdateHandler Instance { get; } = new CreateSecurityUpdatePullRequestHandler();
|
11
|
+
|
12
|
+
public string TagName => "create_security_pr";
|
13
|
+
|
14
|
+
public bool CanHandle(Job job)
|
15
|
+
{
|
16
|
+
// only use this handler if we're creating a new security PR with an explicit list of dependencies
|
17
|
+
if (job.UpdatingAPullRequest)
|
18
|
+
{
|
19
|
+
return false;
|
20
|
+
}
|
21
|
+
|
22
|
+
if (job.Dependencies.Length == 0)
|
23
|
+
{
|
24
|
+
return false;
|
25
|
+
}
|
26
|
+
|
27
|
+
return job.SecurityUpdatesOnly;
|
28
|
+
}
|
29
|
+
|
30
|
+
public async Task HandleAsync(Job job, DirectoryInfo repoContentsPath, string baseCommitSha, IDiscoveryWorker discoveryWorker, IAnalyzeWorker analyzeWorker, IUpdaterWorker updaterWorker, IApiHandler apiHandler, ExperimentsManager experimentsManager, ILogger logger)
|
31
|
+
{
|
32
|
+
var jobDependencies = job.Dependencies.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
33
|
+
foreach (var directory in job.GetAllDirectories())
|
34
|
+
{
|
35
|
+
var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, directory);
|
36
|
+
logger.ReportDiscovery(discoveryResult);
|
37
|
+
if (discoveryResult.Error is not null)
|
38
|
+
{
|
39
|
+
await apiHandler.RecordUpdateJobError(discoveryResult.Error);
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
|
43
|
+
var updatedDependencyList = RunWorker.GetUpdatedDependencyListFromDiscovery(discoveryResult);
|
44
|
+
await apiHandler.UpdateDependencyList(updatedDependencyList);
|
45
|
+
await this.ReportUpdaterStarted(apiHandler);
|
46
|
+
|
47
|
+
var updateOperationsPerformed = new List<UpdateOperationBase>();
|
48
|
+
var updatedDependencies = new List<ReportedDependency>();
|
49
|
+
var updateOperationsToPerform = RunWorker.GetUpdateOperations(discoveryResult).ToArray();
|
50
|
+
var groupedUpdateOperationsToPerform = updateOperationsToPerform
|
51
|
+
.GroupBy(o => o.Dependency.Name, StringComparer.OrdinalIgnoreCase)
|
52
|
+
.Where(g => jobDependencies.Contains(g.Key))
|
53
|
+
.ToDictionary(g => g.Key, g => g.ToArray(), StringComparer.OrdinalIgnoreCase);
|
54
|
+
|
55
|
+
if (groupedUpdateOperationsToPerform.Count == 0)
|
56
|
+
{
|
57
|
+
await apiHandler.RecordUpdateJobError(new SecurityUpdateDependencyNotFound());
|
58
|
+
continue;
|
59
|
+
}
|
60
|
+
|
61
|
+
logger.Info($"Updating dependencies: {string.Join(", ", groupedUpdateOperationsToPerform.Select(g => g.Key).Distinct().OrderBy(d => d, StringComparer.OrdinalIgnoreCase))}");
|
62
|
+
|
63
|
+
var tracker = new ModifiedFilesTracker(repoContentsPath);
|
64
|
+
await tracker.StartTrackingAsync(discoveryResult);
|
65
|
+
foreach (var dependencyGroupToUpdate in groupedUpdateOperationsToPerform)
|
66
|
+
{
|
67
|
+
var dependencyName = dependencyGroupToUpdate.Key;
|
68
|
+
var vulnerableDependenciesToUpdate = dependencyGroupToUpdate.Value
|
69
|
+
.Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency)))
|
70
|
+
.Where(set => set.Item3.IsVulnerable)
|
71
|
+
.ToArray();
|
72
|
+
if (vulnerableDependenciesToUpdate.Length == 0)
|
73
|
+
{
|
74
|
+
await apiHandler.RecordUpdateJobError(new SecurityUpdateNotNeeded(dependencyName));
|
75
|
+
continue;
|
76
|
+
}
|
77
|
+
|
78
|
+
foreach (var (projectPath, dependency, dependencyInfo) in vulnerableDependenciesToUpdate)
|
79
|
+
{
|
80
|
+
var analysisResult = await analyzeWorker.RunAsync(repoContentsPath.FullName, discoveryResult, dependencyInfo);
|
81
|
+
if (analysisResult.Error is not null)
|
82
|
+
{
|
83
|
+
logger.Error($"Error analyzing {dependency.Name} in {projectPath}: {analysisResult.Error.GetReport()}");
|
84
|
+
await apiHandler.RecordUpdateJobError(analysisResult.Error);
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
|
88
|
+
if (!analysisResult.CanUpdate)
|
89
|
+
{
|
90
|
+
logger.Info($"No updatable version found for {dependency.Name} in {projectPath}.");
|
91
|
+
await apiHandler.RecordUpdateJobError(new SecurityUpdateNotFound(dependency.Name, dependency.Version!));
|
92
|
+
continue;
|
93
|
+
}
|
94
|
+
|
95
|
+
if (dependencyInfo.IgnoredVersions.Any(ignored => ignored.IsSatisfiedBy(NuGetVersion.Parse(analysisResult.UpdatedVersion))) ||
|
96
|
+
job.IsDependencyIgnored(dependency.Name, dependency.Version!))
|
97
|
+
{
|
98
|
+
logger.Error($"Cannot update {dependency.Name} for {projectPath} because all versions are ignored.");
|
99
|
+
await apiHandler.RecordUpdateJobError(new SecurityUpdateIgnored(dependencyName));
|
100
|
+
continue;
|
101
|
+
}
|
102
|
+
|
103
|
+
logger.Info($"Attempting update of {dependency.Name} from {dependency.Version} to {analysisResult.UpdatedVersion} for {projectPath}.");
|
104
|
+
var projectDiscovery = discoveryResult.GetProjectDiscoveryFromPath(projectPath);
|
105
|
+
var updaterResult = await updaterWorker.RunAsync(repoContentsPath.FullName, projectPath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, dependency.IsTransitive);
|
106
|
+
if (updaterResult.Error is not null)
|
107
|
+
{
|
108
|
+
logger.Error($"Error updating {dependency.Name} in {projectPath}: {updaterResult.Error.GetReport()}");
|
109
|
+
await apiHandler.RecordUpdateJobError(updaterResult.Error);
|
110
|
+
continue;
|
111
|
+
}
|
112
|
+
|
113
|
+
if (updaterResult.UpdateOperations.Length == 0)
|
114
|
+
{
|
115
|
+
// nothing was done, but we may have already handled it
|
116
|
+
var alreadyHandled = updatedDependencies.Where(updated => updated.Name == dependencyName && updated.Version == analysisResult.UpdatedVersion).Any();
|
117
|
+
if (!alreadyHandled)
|
118
|
+
{
|
119
|
+
logger.Error($"Update of {dependency.Name} in {projectPath} not possible.");
|
120
|
+
await apiHandler.RecordUpdateJobError(new SecurityUpdateNotPossible(dependencyName, analysisResult.UpdatedVersion, analysisResult.UpdatedVersion, []));
|
121
|
+
return;
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
var patchedUpdateOperations = RunWorker.PatchInOldVersions(updaterResult.UpdateOperations, projectDiscovery);
|
126
|
+
var updatedDependenciesForThis = patchedUpdateOperations
|
127
|
+
.Select(o => o.ToReportedDependency(projectPath, updatedDependencyList.Dependencies, analysisResult.UpdatedDependencies))
|
128
|
+
.ToArray();
|
129
|
+
|
130
|
+
updatedDependencies.AddRange(updatedDependenciesForThis);
|
131
|
+
updateOperationsPerformed.AddRange(patchedUpdateOperations);
|
132
|
+
foreach (var o in patchedUpdateOperations)
|
133
|
+
{
|
134
|
+
logger.Info($"Update operation performed: {o.GetReport()}");
|
135
|
+
}
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
var updatedDependencyFiles = await tracker.StopTrackingAsync();
|
140
|
+
var rawDependencies = updatedDependencies.Select(d => new Dependency(d.Name, d.Version, DependencyType.Unknown)).ToArray();
|
141
|
+
if (rawDependencies.Length > 0)
|
142
|
+
{
|
143
|
+
var existingPullRequest = job.GetExistingPullRequestForDependencies(rawDependencies, considerVersions: true);
|
144
|
+
if (existingPullRequest is not null)
|
145
|
+
{
|
146
|
+
await apiHandler.RecordUpdateJobError(new PullRequestExistsForSecurityUpdate(rawDependencies));
|
147
|
+
continue;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
if (updatedDependencyFiles.Length > 0)
|
152
|
+
{
|
153
|
+
var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], null);
|
154
|
+
var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], null);
|
155
|
+
var prBody = PullRequestTextGenerator.GetPullRequestBody(job, [.. updateOperationsPerformed], null);
|
156
|
+
await apiHandler.CreatePullRequest(new CreatePullRequest()
|
157
|
+
{
|
158
|
+
Dependencies = [.. updatedDependencies],
|
159
|
+
UpdatedDependencyFiles = [.. updatedDependencyFiles],
|
160
|
+
BaseCommitSha = baseCommitSha,
|
161
|
+
CommitMessage = commitMessage,
|
162
|
+
PrTitle = prTitle,
|
163
|
+
PrBody = prBody,
|
164
|
+
DependencyGroup = null,
|
165
|
+
});
|
166
|
+
}
|
167
|
+
}
|
168
|
+
}
|
169
|
+
}
|
data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/GroupUpdateAllVersionsHandler.cs
ADDED
@@ -0,0 +1,271 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
|
3
|
+
using NuGet.Versioning;
|
4
|
+
|
5
|
+
using NuGetUpdater.Core.Run.ApiModel;
|
6
|
+
using NuGetUpdater.Core.Updater;
|
7
|
+
|
8
|
+
namespace NuGetUpdater.Core.Run.UpdateHandlers;
|
9
|
+
|
10
|
+
internal class GroupUpdateAllVersionsHandler : IUpdateHandler
|
11
|
+
{
|
12
|
+
public static IUpdateHandler Instance { get; } = new GroupUpdateAllVersionsHandler();
|
13
|
+
|
14
|
+
public string TagName => "group_update_all_versions";
|
15
|
+
|
16
|
+
public bool CanHandle(Job job)
|
17
|
+
{
|
18
|
+
if (job.UpdatingAPullRequest)
|
19
|
+
{
|
20
|
+
return false;
|
21
|
+
}
|
22
|
+
|
23
|
+
if (job.SecurityUpdatesOnly)
|
24
|
+
{
|
25
|
+
if (job.Dependencies.Length > 1)
|
26
|
+
{
|
27
|
+
return true;
|
28
|
+
}
|
29
|
+
|
30
|
+
if (job.DependencyGroups.Any(g => g.IsSecurity()))
|
31
|
+
{
|
32
|
+
return true;
|
33
|
+
}
|
34
|
+
|
35
|
+
return false;
|
36
|
+
}
|
37
|
+
|
38
|
+
return true;
|
39
|
+
}
|
40
|
+
|
41
|
+
public async Task HandleAsync(Job job, DirectoryInfo repoContentsPath, string baseCommitSha, IDiscoveryWorker discoveryWorker, IAnalyzeWorker analyzeWorker, IUpdaterWorker updaterWorker, IApiHandler apiHandler, ExperimentsManager experimentsManager, ILogger logger)
|
42
|
+
{
|
43
|
+
// group update, do all directories and merge
|
44
|
+
// ungrouped update, do each dir separate
|
45
|
+
await this.ReportUpdaterStarted(apiHandler);
|
46
|
+
if (job.DependencyGroups.Length > 0)
|
47
|
+
{
|
48
|
+
await RunGroupedDependencyUpdates(job, repoContentsPath, baseCommitSha, discoveryWorker, analyzeWorker, updaterWorker, apiHandler, experimentsManager, logger);
|
49
|
+
}
|
50
|
+
else
|
51
|
+
{
|
52
|
+
await RunUngroupedDependencyUpdates(job, repoContentsPath, baseCommitSha, discoveryWorker, analyzeWorker, updaterWorker, apiHandler, experimentsManager, logger);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
private async Task RunGroupedDependencyUpdates(Job job, DirectoryInfo repoContentsPath, string baseCommitSha, IDiscoveryWorker discoveryWorker, IAnalyzeWorker analyzeWorker, IUpdaterWorker updaterWorker, IApiHandler apiHandler, ExperimentsManager experimentsManager, ILogger logger)
|
57
|
+
{
|
58
|
+
foreach (var group in job.DependencyGroups)
|
59
|
+
{
|
60
|
+
logger.Info($"Starting update for group {group.Name}");
|
61
|
+
var groupMatcher = group.GetGroupMatcher();
|
62
|
+
var updateOperationsPerformed = new List<UpdateOperationBase>();
|
63
|
+
var updatedDependencies = new List<ReportedDependency>();
|
64
|
+
var allUpdatedDependencyFiles = ImmutableArray.Create<DependencyFile>();
|
65
|
+
foreach (var directory in job.GetAllDirectories())
|
66
|
+
{
|
67
|
+
var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, directory);
|
68
|
+
logger.ReportDiscovery(discoveryResult);
|
69
|
+
if (discoveryResult.Error is not null)
|
70
|
+
{
|
71
|
+
await apiHandler.RecordUpdateJobError(discoveryResult.Error);
|
72
|
+
return;
|
73
|
+
}
|
74
|
+
|
75
|
+
var tracker = new ModifiedFilesTracker(repoContentsPath);
|
76
|
+
await tracker.StartTrackingAsync(discoveryResult);
|
77
|
+
|
78
|
+
var updatedDependencyList = RunWorker.GetUpdatedDependencyListFromDiscovery(discoveryResult);
|
79
|
+
await apiHandler.UpdateDependencyList(updatedDependencyList);
|
80
|
+
|
81
|
+
var updateOperationsToPerform = RunWorker.GetUpdateOperations(discoveryResult).ToArray();
|
82
|
+
foreach (var (projectPath, dependency) in updateOperationsToPerform)
|
83
|
+
{
|
84
|
+
if (!job.IsUpdatePermitted(dependency))
|
85
|
+
{
|
86
|
+
continue;
|
87
|
+
}
|
88
|
+
|
89
|
+
if (!groupMatcher.IsMatch(dependency.Name))
|
90
|
+
{
|
91
|
+
continue;
|
92
|
+
}
|
93
|
+
|
94
|
+
if (job.IsDependencyIgnored(dependency.Name, dependency.Version!))
|
95
|
+
{
|
96
|
+
logger.Info($"Skipping ignored dependency {dependency.Name}/{dependency.Version}.");
|
97
|
+
continue;
|
98
|
+
}
|
99
|
+
|
100
|
+
var dependencyInfo = RunWorker.GetDependencyInfo(job, dependency);
|
101
|
+
var analysisResult = await analyzeWorker.RunAsync(repoContentsPath.FullName, discoveryResult, dependencyInfo);
|
102
|
+
if (analysisResult.Error is not null)
|
103
|
+
{
|
104
|
+
logger.Error($"Error analyzing {dependency.Name} in {projectPath}: {analysisResult.Error.GetReport()}");
|
105
|
+
await apiHandler.RecordUpdateJobError(analysisResult.Error);
|
106
|
+
return;
|
107
|
+
}
|
108
|
+
|
109
|
+
if (!analysisResult.CanUpdate)
|
110
|
+
{
|
111
|
+
logger.Info($"No updatable version found for {dependency.Name} in {projectPath}.");
|
112
|
+
continue;
|
113
|
+
}
|
114
|
+
|
115
|
+
if (dependencyInfo.IgnoredVersions.Any(ignored => ignored.IsSatisfiedBy(NuGetVersion.Parse(analysisResult.UpdatedVersion))))
|
116
|
+
{
|
117
|
+
logger.Info($"Cannot update {dependency.Name} for {projectPath} because all versions are ignored.");
|
118
|
+
continue;
|
119
|
+
}
|
120
|
+
|
121
|
+
var projectDiscovery = discoveryResult.GetProjectDiscoveryFromPath(projectPath);
|
122
|
+
var updaterResult = await updaterWorker.RunAsync(repoContentsPath.FullName, projectPath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, dependency.IsTransitive);
|
123
|
+
if (updaterResult.Error is not null)
|
124
|
+
{
|
125
|
+
logger.Error($"Error updating {dependency.Name} in {projectPath}: {updaterResult.Error.GetReport()}");
|
126
|
+
await apiHandler.RecordUpdateJobError(updaterResult.Error);
|
127
|
+
continue;
|
128
|
+
}
|
129
|
+
|
130
|
+
if (updaterResult.UpdateOperations.Length == 0)
|
131
|
+
{
|
132
|
+
continue;
|
133
|
+
}
|
134
|
+
|
135
|
+
var patchedUpdateOperations = RunWorker.PatchInOldVersions(updaterResult.UpdateOperations, projectDiscovery);
|
136
|
+
var updatedDependenciesForThis = patchedUpdateOperations
|
137
|
+
.Select(o => o.ToReportedDependency(projectPath, updatedDependencyList.Dependencies, analysisResult.UpdatedDependencies))
|
138
|
+
.ToArray();
|
139
|
+
|
140
|
+
updatedDependencies.AddRange(updatedDependenciesForThis);
|
141
|
+
updateOperationsPerformed.AddRange(patchedUpdateOperations);
|
142
|
+
foreach (var o in patchedUpdateOperations)
|
143
|
+
{
|
144
|
+
logger.Info($"Update operation performed: {o.GetReport()}");
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
var updatedDependencyFiles = await tracker.StopTrackingAsync();
|
149
|
+
allUpdatedDependencyFiles = ModifiedFilesTracker.MergeUpdatedFileSet(allUpdatedDependencyFiles, updatedDependencyFiles);
|
150
|
+
}
|
151
|
+
|
152
|
+
if (updateOperationsPerformed.Count > 0)
|
153
|
+
{
|
154
|
+
var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], group.Name);
|
155
|
+
var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], group.Name);
|
156
|
+
var prBody = PullRequestTextGenerator.GetPullRequestBody(job, [.. updateOperationsPerformed], group.Name);
|
157
|
+
await apiHandler.CreatePullRequest(new CreatePullRequest()
|
158
|
+
{
|
159
|
+
Dependencies = [.. updatedDependencies],
|
160
|
+
UpdatedDependencyFiles = [.. allUpdatedDependencyFiles],
|
161
|
+
BaseCommitSha = baseCommitSha,
|
162
|
+
CommitMessage = commitMessage,
|
163
|
+
PrTitle = prTitle,
|
164
|
+
PrBody = prBody,
|
165
|
+
DependencyGroup = group.Name,
|
166
|
+
});
|
167
|
+
}
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
private async Task RunUngroupedDependencyUpdates(Job job, DirectoryInfo repoContentsPath, string baseCommitSha, IDiscoveryWorker discoveryWorker, IAnalyzeWorker analyzeWorker, IUpdaterWorker updaterWorker, IApiHandler apiHandler, ExperimentsManager experimentsManager, ILogger logger)
|
172
|
+
{
|
173
|
+
foreach (var directory in job.GetAllDirectories())
|
174
|
+
{
|
175
|
+
var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, directory);
|
176
|
+
logger.ReportDiscovery(discoveryResult);
|
177
|
+
if (discoveryResult.Error is not null)
|
178
|
+
{
|
179
|
+
await apiHandler.RecordUpdateJobError(discoveryResult.Error);
|
180
|
+
return;
|
181
|
+
}
|
182
|
+
|
183
|
+
var tracker = new ModifiedFilesTracker(repoContentsPath);
|
184
|
+
await tracker.StartTrackingAsync(discoveryResult);
|
185
|
+
|
186
|
+
var updatedDependencyList = RunWorker.GetUpdatedDependencyListFromDiscovery(discoveryResult);
|
187
|
+
await apiHandler.UpdateDependencyList(updatedDependencyList);
|
188
|
+
|
189
|
+
var updateOperationsPerformed = new List<UpdateOperationBase>();
|
190
|
+
var updatedDependencies = new List<ReportedDependency>();
|
191
|
+
var updateOperationsToPerform = RunWorker.GetUpdateOperations(discoveryResult).ToArray();
|
192
|
+
foreach (var (projectPath, dependency) in updateOperationsToPerform)
|
193
|
+
{
|
194
|
+
if (!job.IsUpdatePermitted(dependency))
|
195
|
+
{
|
196
|
+
continue;
|
197
|
+
}
|
198
|
+
|
199
|
+
if (job.IsDependencyIgnored(dependency.Name, dependency.Version!))
|
200
|
+
{
|
201
|
+
logger.Info($"Skipping ignored dependency {dependency.Name}/{dependency.Version}.");
|
202
|
+
continue;
|
203
|
+
}
|
204
|
+
|
205
|
+
var dependencyInfo = RunWorker.GetDependencyInfo(job, dependency);
|
206
|
+
var analysisResult = await analyzeWorker.RunAsync(repoContentsPath.FullName, discoveryResult, dependencyInfo);
|
207
|
+
if (analysisResult.Error is not null)
|
208
|
+
{
|
209
|
+
logger.Error($"Error analyzing {dependency.Name} in {projectPath}: {analysisResult.Error.GetReport()}");
|
210
|
+
await apiHandler.RecordUpdateJobError(analysisResult.Error);
|
211
|
+
return;
|
212
|
+
}
|
213
|
+
|
214
|
+
if (!analysisResult.CanUpdate)
|
215
|
+
{
|
216
|
+
logger.Info($"No updatable version found for {dependency.Name} in {projectPath}.");
|
217
|
+
continue;
|
218
|
+
}
|
219
|
+
|
220
|
+
if (dependencyInfo.IgnoredVersions.Any(ignored => ignored.IsSatisfiedBy(NuGetVersion.Parse(analysisResult.UpdatedVersion))))
|
221
|
+
{
|
222
|
+
logger.Info($"Cannot update {dependency.Name} for {projectPath} because all versions are ignored.");
|
223
|
+
continue;
|
224
|
+
}
|
225
|
+
|
226
|
+
var projectDiscovery = discoveryResult.GetProjectDiscoveryFromPath(projectPath);
|
227
|
+
var updaterResult = await updaterWorker.RunAsync(repoContentsPath.FullName, projectPath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, dependency.IsTransitive);
|
228
|
+
if (updaterResult.Error is not null)
|
229
|
+
{
|
230
|
+
await apiHandler.RecordUpdateJobError(updaterResult.Error);
|
231
|
+
continue;
|
232
|
+
}
|
233
|
+
|
234
|
+
if (updaterResult.UpdateOperations.Length == 0)
|
235
|
+
{
|
236
|
+
continue;
|
237
|
+
}
|
238
|
+
|
239
|
+
var patchedUpdateOperations = RunWorker.PatchInOldVersions(updaterResult.UpdateOperations, projectDiscovery);
|
240
|
+
var updatedDependenciesForThis = patchedUpdateOperations
|
241
|
+
.Select(o => o.ToReportedDependency(projectPath, updatedDependencyList.Dependencies, analysisResult.UpdatedDependencies))
|
242
|
+
.ToArray();
|
243
|
+
|
244
|
+
updatedDependencies.AddRange(updatedDependenciesForThis);
|
245
|
+
updateOperationsPerformed.AddRange(patchedUpdateOperations);
|
246
|
+
foreach (var o in patchedUpdateOperations)
|
247
|
+
{
|
248
|
+
logger.Info($"Update operation performed: {o.GetReport()}");
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
var updatedDependencyFiles = await tracker.StopTrackingAsync();
|
253
|
+
if (updateOperationsPerformed.Count > 0)
|
254
|
+
{
|
255
|
+
var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], null);
|
256
|
+
var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], null);
|
257
|
+
var prBody = PullRequestTextGenerator.GetPullRequestBody(job, [.. updateOperationsPerformed], null);
|
258
|
+
await apiHandler.CreatePullRequest(new CreatePullRequest()
|
259
|
+
{
|
260
|
+
Dependencies = [.. updatedDependencies],
|
261
|
+
UpdatedDependencyFiles = [.. updatedDependencyFiles],
|
262
|
+
BaseCommitSha = baseCommitSha,
|
263
|
+
CommitMessage = commitMessage,
|
264
|
+
PrTitle = prTitle,
|
265
|
+
PrBody = prBody,
|
266
|
+
DependencyGroup = null,
|
267
|
+
});
|
268
|
+
}
|
269
|
+
}
|
270
|
+
}
|
271
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
using NuGetUpdater.Core.Run.ApiModel;
|
2
|
+
|
3
|
+
namespace NuGetUpdater.Core.Run.UpdateHandlers;
|
4
|
+
|
5
|
+
public interface IUpdateHandler
|
6
|
+
{
|
7
|
+
string TagName { get; }
|
8
|
+
bool CanHandle(Job job);
|
9
|
+
Task HandleAsync(Job job, DirectoryInfo repoContentsPath, string baseCommitSha, IDiscoveryWorker discoveryWorker, IAnalyzeWorker analyzeWorker, IUpdaterWorker updaterWorker, IApiHandler apiHandler, ExperimentsManager experimentsManager, ILogger logger);
|
10
|
+
}
|
11
|
+
|
12
|
+
public static class IUpdateHandlerExtensions
|
13
|
+
{
|
14
|
+
public static Task ReportUpdaterStarted(this IUpdateHandler updateHandler, IApiHandler apiHandler) => apiHandler.IncrementMetric(new IncrementMetric()
|
15
|
+
{
|
16
|
+
Metric = "updater.started",
|
17
|
+
Tags = new()
|
18
|
+
{
|
19
|
+
["operation"] = updateHandler.TagName,
|
20
|
+
}
|
21
|
+
});
|
22
|
+
}
|
@@ -0,0 +1,192 @@
|
|
1
|
+
using NuGetUpdater.Core.Run.ApiModel;
|
2
|
+
using NuGetUpdater.Core.Updater;
|
3
|
+
|
4
|
+
namespace NuGetUpdater.Core.Run.UpdateHandlers;
|
5
|
+
|
6
|
+
internal class RefreshGroupUpdatePullRequestHandler : IUpdateHandler
|
7
|
+
{
|
8
|
+
public static IUpdateHandler Instance { get; } = new RefreshGroupUpdatePullRequestHandler();
|
9
|
+
|
10
|
+
public string TagName => "update_version_group_pr";
|
11
|
+
|
12
|
+
public bool CanHandle(Job job)
|
13
|
+
{
|
14
|
+
if (job.Dependencies.Length == 0)
|
15
|
+
{
|
16
|
+
return false;
|
17
|
+
}
|
18
|
+
|
19
|
+
if (job.DependencyGroupToRefresh is null)
|
20
|
+
{
|
21
|
+
return false;
|
22
|
+
}
|
23
|
+
|
24
|
+
if (job.GetAllDirectories().Length > 1)
|
25
|
+
{
|
26
|
+
return true;
|
27
|
+
}
|
28
|
+
|
29
|
+
if (job.SecurityUpdatesOnly)
|
30
|
+
{
|
31
|
+
if (job.Dependencies.Length > 1)
|
32
|
+
{
|
33
|
+
return true;
|
34
|
+
}
|
35
|
+
|
36
|
+
if (job.DependencyGroups.Any(g => g.IsSecurity()))
|
37
|
+
{
|
38
|
+
return true;
|
39
|
+
}
|
40
|
+
|
41
|
+
return false;
|
42
|
+
}
|
43
|
+
|
44
|
+
return job.UpdatingAPullRequest;
|
45
|
+
}
|
46
|
+
|
47
|
+
public async Task HandleAsync(Job job, DirectoryInfo repoContentsPath, string baseCommitSha, IDiscoveryWorker discoveryWorker, IAnalyzeWorker analyzeWorker, IUpdaterWorker updaterWorker, IApiHandler apiHandler, ExperimentsManager experimentsManager, ILogger logger)
|
48
|
+
{
|
49
|
+
if (job.DependencyGroupToRefresh is null)
|
50
|
+
{
|
51
|
+
throw new InvalidOperationException($"{nameof(job.DependencyGroupToRefresh)} must be non-null.");
|
52
|
+
}
|
53
|
+
|
54
|
+
var group = job.DependencyGroups.FirstOrDefault(g => g.Name == job.DependencyGroupToRefresh);
|
55
|
+
if (group is null)
|
56
|
+
{
|
57
|
+
throw new InvalidOperationException($"Dependency group {job.DependencyGroupToRefresh} not found.");
|
58
|
+
}
|
59
|
+
|
60
|
+
logger.Info($"Starting update for group {group.Name}");
|
61
|
+
|
62
|
+
var groupMatcher = group.GetGroupMatcher();
|
63
|
+
var jobDependencies = job.Dependencies.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
64
|
+
foreach (var directory in job.GetAllDirectories())
|
65
|
+
{
|
66
|
+
var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, directory);
|
67
|
+
logger.ReportDiscovery(discoveryResult);
|
68
|
+
if (discoveryResult.Error is not null)
|
69
|
+
{
|
70
|
+
await apiHandler.RecordUpdateJobError(discoveryResult.Error);
|
71
|
+
return;
|
72
|
+
}
|
73
|
+
|
74
|
+
var updatedDependencyList = RunWorker.GetUpdatedDependencyListFromDiscovery(discoveryResult);
|
75
|
+
await apiHandler.UpdateDependencyList(updatedDependencyList);
|
76
|
+
await this.ReportUpdaterStarted(apiHandler);
|
77
|
+
|
78
|
+
var updateOperationsPerformed = new List<UpdateOperationBase>();
|
79
|
+
var updatedDependencies = new List<ReportedDependency>();
|
80
|
+
var updateOperationsToPerform = RunWorker.GetUpdateOperations(discoveryResult).ToArray();
|
81
|
+
var groupedUpdateOperationsToPerform = updateOperationsToPerform
|
82
|
+
.GroupBy(o => o.Dependency.Name, StringComparer.OrdinalIgnoreCase)
|
83
|
+
.Where(g => jobDependencies.Contains(g.Key))
|
84
|
+
.Where(g => groupMatcher.IsMatch(g.Key))
|
85
|
+
.ToDictionary(g => g.Key, g => g.ToArray(), StringComparer.OrdinalIgnoreCase);
|
86
|
+
logger.Info($"Updating dependencies: {string.Join(", ", groupedUpdateOperationsToPerform.Select(g => g.Key).Distinct().OrderBy(d => d, StringComparer.OrdinalIgnoreCase))}");
|
87
|
+
|
88
|
+
var tracker = new ModifiedFilesTracker(repoContentsPath);
|
89
|
+
await tracker.StartTrackingAsync(discoveryResult);
|
90
|
+
foreach (var dependencyGroupToUpdate in groupedUpdateOperationsToPerform)
|
91
|
+
{
|
92
|
+
var dependencyName = dependencyGroupToUpdate.Key;
|
93
|
+
var relevantDependenciesToUpdate = dependencyGroupToUpdate.Value
|
94
|
+
.Select(o => (o.ProjectPath, o.Dependency, RunWorker.GetDependencyInfo(job, o.Dependency)))
|
95
|
+
.Where(set => !job.IsDependencyIgnored(set.Dependency.Name, set.Dependency.Version!))
|
96
|
+
.ToArray();
|
97
|
+
|
98
|
+
foreach (var (projectPath, dependency, dependencyInfo) in relevantDependenciesToUpdate)
|
99
|
+
{
|
100
|
+
var analysisResult = await analyzeWorker.RunAsync(repoContentsPath.FullName, discoveryResult, dependencyInfo);
|
101
|
+
if (analysisResult.Error is not null)
|
102
|
+
{
|
103
|
+
logger.Error($"Error analyzing {dependency.Name} in {projectPath}: {analysisResult.Error.GetReport()}");
|
104
|
+
await apiHandler.RecordUpdateJobError(analysisResult.Error);
|
105
|
+
return;
|
106
|
+
}
|
107
|
+
|
108
|
+
if (!analysisResult.CanUpdate)
|
109
|
+
{
|
110
|
+
logger.Info($"No updatable version found for {dependency.Name} in {projectPath}.");
|
111
|
+
continue;
|
112
|
+
}
|
113
|
+
|
114
|
+
logger.Info($"Attempting update of {dependency.Name} from {dependency.Version} to {analysisResult.UpdatedVersion} for {projectPath}.");
|
115
|
+
var projectDiscovery = discoveryResult.GetProjectDiscoveryFromPath(projectPath);
|
116
|
+
var updaterResult = await updaterWorker.RunAsync(repoContentsPath.FullName, projectPath, dependency.Name, dependency.Version!, analysisResult.UpdatedVersion, dependency.IsTransitive);
|
117
|
+
if (updaterResult.Error is not null)
|
118
|
+
{
|
119
|
+
logger.Error($"Error updating {dependency.Name} in {projectPath}: {updaterResult.Error.GetReport()}");
|
120
|
+
await apiHandler.RecordUpdateJobError(updaterResult.Error);
|
121
|
+
continue;
|
122
|
+
}
|
123
|
+
|
124
|
+
if (updaterResult.UpdateOperations.Length == 0)
|
125
|
+
{
|
126
|
+
logger.Info($"Performed no updates for {dependency.Name} in {projectPath}, but no error reported.");
|
127
|
+
continue;
|
128
|
+
}
|
129
|
+
|
130
|
+
var patchedUpdateOperations = RunWorker.PatchInOldVersions(updaterResult.UpdateOperations, projectDiscovery);
|
131
|
+
var updatedDependenciesForThis = patchedUpdateOperations
|
132
|
+
.Select(o => o.ToReportedDependency(projectPath, updatedDependencyList.Dependencies, analysisResult.UpdatedDependencies))
|
133
|
+
.ToArray();
|
134
|
+
|
135
|
+
updatedDependencies.AddRange(updatedDependenciesForThis);
|
136
|
+
updateOperationsPerformed.AddRange(patchedUpdateOperations);
|
137
|
+
foreach (var o in patchedUpdateOperations)
|
138
|
+
{
|
139
|
+
logger.Info($"Update operation performed: {o.GetReport()}");
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
var updatedDependencyFiles = await tracker.StopTrackingAsync();
|
145
|
+
var rawDependencies = updatedDependencies.Select(d => new Dependency(d.Name, d.Version, DependencyType.Unknown)).ToArray();
|
146
|
+
if (rawDependencies.Length == 0)
|
147
|
+
{
|
148
|
+
await apiHandler.ClosePullRequest(ClosePullRequest.WithUpdateNoLongerPossible(job));
|
149
|
+
continue;
|
150
|
+
}
|
151
|
+
|
152
|
+
var commitMessage = PullRequestTextGenerator.GetPullRequestCommitMessage(job, [.. updateOperationsPerformed], null);
|
153
|
+
var prTitle = PullRequestTextGenerator.GetPullRequestTitle(job, [.. updateOperationsPerformed], null);
|
154
|
+
var prBody = PullRequestTextGenerator.GetPullRequestBody(job, [.. updateOperationsPerformed], null);
|
155
|
+
var existingPullRequest = job.GetExistingPullRequestForDependencies(rawDependencies, considerVersions: true);
|
156
|
+
if (existingPullRequest is not null)
|
157
|
+
{
|
158
|
+
await apiHandler.UpdatePullRequest(new UpdatePullRequest()
|
159
|
+
{
|
160
|
+
DependencyNames = [.. jobDependencies.OrderBy(n => n, StringComparer.OrdinalIgnoreCase)],
|
161
|
+
DependencyGroup = group.Name,
|
162
|
+
UpdatedDependencyFiles = [.. updatedDependencyFiles],
|
163
|
+
BaseCommitSha = baseCommitSha,
|
164
|
+
CommitMessage = commitMessage,
|
165
|
+
PrTitle = prTitle,
|
166
|
+
PrBody = prBody,
|
167
|
+
});
|
168
|
+
continue;
|
169
|
+
}
|
170
|
+
else
|
171
|
+
{
|
172
|
+
var existingPrButDifferent = job.GetExistingPullRequestForDependencies(rawDependencies, considerVersions: false);
|
173
|
+
if (existingPrButDifferent is not null)
|
174
|
+
{
|
175
|
+
await apiHandler.ClosePullRequest(ClosePullRequest.WithDependenciesChanged(job));
|
176
|
+
}
|
177
|
+
|
178
|
+
await apiHandler.CreatePullRequest(new CreatePullRequest()
|
179
|
+
{
|
180
|
+
Dependencies = [.. updatedDependencies],
|
181
|
+
UpdatedDependencyFiles = [.. updatedDependencyFiles],
|
182
|
+
BaseCommitSha = baseCommitSha,
|
183
|
+
CommitMessage = commitMessage,
|
184
|
+
PrTitle = prTitle,
|
185
|
+
PrBody = prBody,
|
186
|
+
DependencyGroup = group.Name,
|
187
|
+
});
|
188
|
+
continue;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
}
|
192
|
+
}
|