dependabot-nuget 0.383.0 → 0.384.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.Core/Clone/CloneWorker.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +35 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +13 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs +4 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Graph/GraphWorker.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +3 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobCommand.cs +11 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/JobCommandConverter.cs +61 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ModifiedFilesTracker.cs +83 -16
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +51 -26
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/CreateSecurityUpdatePullRequestHandler.cs +3 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/GroupUpdateAllVersionsHandler.cs +6 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshGroupUpdatePullRequestHandler.cs +3 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshSecurityUpdatePullRequestHandler.cs +3 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/UpdateHandlers/RefreshVersionUpdatePullRequestHandler.cs +3 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/FileWriterWorker.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/IFileWriter.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/FileWriters/XmlFileWriter.cs +254 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +22 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +60 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +90 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/ApiModel/JobTests.cs +116 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/ModifiedFilesTrackerTests.cs +378 -10
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdatedDependencyListTests.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/FileWriterTestsBase.cs +6 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/TestFileWriterReturnsConstantResult.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/FileWriters/XmlFileWriterTests.cs +714 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +24 -0
- metadata +7 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b77dedc63031536f0a500698857e46afbc14f3f5ea80a0e8300a52e27d4d3d46
|
|
4
|
+
data.tar.gz: 5794be271db14c64c9d3e72adb259bbd52e78fa79ed796943595598395fe3ed6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bf66e0d54541539ac5fe228db99426b8f15b8a7e7253e2a62b61d25cee3ddf6a86c9ce1a51a2206f01b4ba3559ed69191bcf8ca7e81eb9b71950576c79002b5b
|
|
7
|
+
data.tar.gz: 5227b2387092e94a359eff0c3a0f08608d6a559b007b59caeb6c9016ff760712c6ab684dbc455ced2211835000ed2d8a2fc3b4f53f4638828d1ee01b705c66a0
|
|
@@ -34,7 +34,7 @@ public class CloneWorker
|
|
|
34
34
|
JobErrorBase? parseError = null;
|
|
35
35
|
try
|
|
36
36
|
{
|
|
37
|
-
jobFile = RunWorker.Deserialize(jobFileContent);
|
|
37
|
+
jobFile = RunWorker.Deserialize(jobFileContent, _logger);
|
|
38
38
|
if (jobFile is null)
|
|
39
39
|
{
|
|
40
40
|
parseError = new UnknownError(new Exception("Job file could not be deserialized"), _jobId);
|
|
@@ -88,10 +88,20 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
|
88
88
|
ImmutableArray<ProjectDiscoveryResult> projectResults = [];
|
|
89
89
|
WorkspaceDiscoveryResult result;
|
|
90
90
|
|
|
91
|
+
// if the workspace directory directly contains a solution file, capture its directory so that the MSBuild
|
|
92
|
+
// `SolutionDir` property can be faked during discovery; this allows project files that reference
|
|
93
|
+
// `$(SolutionDir)` to be evaluated correctly
|
|
94
|
+
string? solutionDir = null;
|
|
95
|
+
|
|
91
96
|
if (Directory.Exists(workspacePath))
|
|
92
97
|
{
|
|
93
98
|
_logger.Info($"Discovering build files in workspace [{workspacePath}].");
|
|
94
99
|
|
|
100
|
+
if (DirectoryContainsSolutionFile(workspacePath))
|
|
101
|
+
{
|
|
102
|
+
solutionDir = workspacePath;
|
|
103
|
+
}
|
|
104
|
+
|
|
95
105
|
dotNetToolsJsonDiscovery = DotNetToolsJsonDiscovery.Discover(repoRootPath, workspacePath, _logger);
|
|
96
106
|
globalJsonDiscovery = GlobalJsonDiscovery.Discover(repoRootPath, workspacePath, _logger);
|
|
97
107
|
|
|
@@ -101,7 +111,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
|
101
111
|
}
|
|
102
112
|
|
|
103
113
|
// this next line should throw or something
|
|
104
|
-
projectResults = await RunForDirectoryAsync(repoRootPath, workspacePath);
|
|
114
|
+
projectResults = await RunForDirectoryAsync(repoRootPath, workspacePath, solutionDir);
|
|
105
115
|
}
|
|
106
116
|
else
|
|
107
117
|
{
|
|
@@ -149,6 +159,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
|
149
159
|
DotNetToolsJson = null,
|
|
150
160
|
GlobalJson = null,
|
|
151
161
|
Projects = projectResults.Where(p => p.IsSuccess).OrderBy(p => p.FilePath).ToImmutableArray(),
|
|
162
|
+
SolutionDirectory = GetRelativeSolutionDirectory(repoRootPath, solutionDir),
|
|
152
163
|
Error = failedProjectResult.Error,
|
|
153
164
|
IsSuccess = false,
|
|
154
165
|
};
|
|
@@ -162,6 +173,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
|
162
173
|
DotNetToolsJson = dotNetToolsJsonDiscovery,
|
|
163
174
|
GlobalJson = globalJsonDiscovery,
|
|
164
175
|
Projects = projectResults.OrderBy(p => p.FilePath).ToImmutableArray(),
|
|
176
|
+
SolutionDirectory = GetRelativeSolutionDirectory(repoRootPath, solutionDir),
|
|
165
177
|
};
|
|
166
178
|
|
|
167
179
|
_logger.Info("Discovery complete.");
|
|
@@ -196,7 +208,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
|
196
208
|
return await NuGetHelper.DownloadNuGetPackagesAsync(repoRootPath, workspacePath, msbuildSdks, logger);
|
|
197
209
|
}
|
|
198
210
|
|
|
199
|
-
private async Task<ImmutableArray<ProjectDiscoveryResult>> RunForDirectoryAsync(string repoRootPath, string workspacePath)
|
|
211
|
+
private async Task<ImmutableArray<ProjectDiscoveryResult>> RunForDirectoryAsync(string repoRootPath, string workspacePath, string? solutionDir)
|
|
200
212
|
{
|
|
201
213
|
_logger.Info($" Discovering projects beneath [{Path.GetRelativePath(repoRootPath, workspacePath)}].");
|
|
202
214
|
var entryPoints = FindEntryPoints(workspacePath);
|
|
@@ -227,7 +239,24 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
|
227
239
|
return [];
|
|
228
240
|
}
|
|
229
241
|
|
|
230
|
-
return await RunForProjectPathsAsync(repoRootPath, workspacePath, projects);
|
|
242
|
+
return await RunForProjectPathsAsync(repoRootPath, workspacePath, projects, solutionDir);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private static bool DirectoryContainsSolutionFile(string directoryPath)
|
|
246
|
+
{
|
|
247
|
+
return Directory.EnumerateFiles(directoryPath)
|
|
248
|
+
.Any(path =>
|
|
249
|
+
{
|
|
250
|
+
string extension = Path.GetExtension(path).ToLowerInvariant();
|
|
251
|
+
return extension is ".sln" or ".slnx";
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private static string? GetRelativeSolutionDirectory(string repoRootPath, string? solutionDir)
|
|
256
|
+
{
|
|
257
|
+
return solutionDir is null
|
|
258
|
+
? null
|
|
259
|
+
: Path.GetRelativePath(repoRootPath, solutionDir).NormalizePathToUnix();
|
|
231
260
|
}
|
|
232
261
|
|
|
233
262
|
private static ImmutableArray<string> FindEntryPoints(string workspacePath)
|
|
@@ -378,7 +407,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
|
378
407
|
return foundItems;
|
|
379
408
|
}
|
|
380
409
|
|
|
381
|
-
private async Task<ImmutableArray<ProjectDiscoveryResult>> RunForProjectPathsAsync(string repoRootPath, string workspacePath, IEnumerable<string> projectPaths)
|
|
410
|
+
private async Task<ImmutableArray<ProjectDiscoveryResult>> RunForProjectPathsAsync(string repoRootPath, string workspacePath, IEnumerable<string> projectPaths, string? solutionDir)
|
|
382
411
|
{
|
|
383
412
|
var normalizedProjectPaths = projectPaths.SelectMany(p => PathHelper.ResolveCaseInsensitivePathsInsideRepoRoot(p, repoRootPath) ?? []).Distinct().ToImmutableArray();
|
|
384
413
|
|
|
@@ -437,7 +466,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
|
437
466
|
_processedProjectPaths.Add(projectPath);
|
|
438
467
|
|
|
439
468
|
var relativeProjectPath = Path.GetRelativePath(workspacePath, projectPath).NormalizePathToUnix();
|
|
440
|
-
var projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath, projectPath, _experimentsManager, _logger);
|
|
469
|
+
var projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath, projectPath, _experimentsManager, solutionDir, _logger);
|
|
441
470
|
|
|
442
471
|
// Determine if there were unrestored MSBuildSdks
|
|
443
472
|
var msbuildSdks = projectResults.SelectMany(p => p.Dependencies.Where(d => d.Type == DependencyType.MSBuildSdk)).ToImmutableArray();
|
|
@@ -446,7 +475,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
|
|
|
446
475
|
// If new SDKs were restored, then we need to rerun SdkProjectDiscovery.
|
|
447
476
|
if (await TryRestoreMSBuildSdksAsync(repoRootPath, workspacePath, msbuildSdks, _logger))
|
|
448
477
|
{
|
|
449
|
-
projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath, projectPath, _experimentsManager, _logger);
|
|
478
|
+
projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath, projectPath, _experimentsManager, solutionDir, _logger);
|
|
450
479
|
}
|
|
451
480
|
}
|
|
452
481
|
|
|
@@ -71,7 +71,7 @@ internal static class SdkProjectDiscovery
|
|
|
71
71
|
// this seems to be the maximum number of TFMs that can be restored in parallel without running into race conditions
|
|
72
72
|
private const int MaximumParallelTargetFrameworkRestores = 2;
|
|
73
73
|
|
|
74
|
-
public static async Task<ImmutableArray<ProjectDiscoveryResult>> DiscoverAsync(string repoRootPath, string workspacePath, string startingProjectPath, ExperimentsManager experimentsManager, ILogger logger)
|
|
74
|
+
public static async Task<ImmutableArray<ProjectDiscoveryResult>> DiscoverAsync(string repoRootPath, string workspacePath, string startingProjectPath, ExperimentsManager experimentsManager, string? solutionDir, ILogger logger)
|
|
75
75
|
{
|
|
76
76
|
var extension = Path.GetExtension(startingProjectPath)?.ToLowerInvariant();
|
|
77
77
|
switch (extension)
|
|
@@ -190,6 +190,15 @@ internal static class SdkProjectDiscovery
|
|
|
190
190
|
args.Add($"/p:TargetFramework={tfm}");
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
// if the project lives alongside a solution file, fake the MSBuild `SolutionDir` property so that
|
|
194
|
+
// project files referencing `$(SolutionDir)` can be evaluated correctly; MSBuild expects this value
|
|
195
|
+
// to end with a directory separator so that `$(SolutionDir)foo` concatenations form valid paths
|
|
196
|
+
if (solutionDir is not null)
|
|
197
|
+
{
|
|
198
|
+
var normalizedSolutionDir = $"{solutionDir.TrimEnd('/', Path.DirectorySeparatorChar)}/";
|
|
199
|
+
args.Add($"/p:SolutionDir={normalizedSolutionDir}");
|
|
200
|
+
}
|
|
201
|
+
|
|
193
202
|
// if using CPM and a project also sets TreatWarningsAsErrors to true, this can cause discovery to fail; explicitly don't allow that
|
|
194
203
|
args.Add("/p:TreatWarningsAsErrors=false");
|
|
195
204
|
args.Add("/p:MSBuildTreatWarningsAsErrors=false");
|
|
@@ -446,6 +455,7 @@ internal static class SdkProjectDiscovery
|
|
|
446
455
|
packagesPerProject,
|
|
447
456
|
explicitPackageVersionsPerProject,
|
|
448
457
|
experimentsManager,
|
|
458
|
+
solutionDir,
|
|
449
459
|
logger
|
|
450
460
|
);
|
|
451
461
|
}
|
|
@@ -809,6 +819,7 @@ internal static class SdkProjectDiscovery
|
|
|
809
819
|
Dictionary<string, Dictionary<string, Dictionary<string, string>>> packagesPerProject,
|
|
810
820
|
Dictionary<string, Dictionary<string, Dictionary<string, string>>> explicitPackageVersionsPerProject,
|
|
811
821
|
ExperimentsManager experimentsManager,
|
|
822
|
+
string? solutionDir,
|
|
812
823
|
ILogger logger
|
|
813
824
|
)
|
|
814
825
|
{
|
|
@@ -831,7 +842,7 @@ internal static class SdkProjectDiscovery
|
|
|
831
842
|
|
|
832
843
|
var tempProjectPath = await MSBuildHelper.CreateTempProjectAsync(tempDirectory, repoRootPath, projectPath, targetFrameworks, topLevelDependencies, logger);
|
|
833
844
|
var tempProjectDirectory = Path.GetDirectoryName(tempProjectPath)!;
|
|
834
|
-
var rediscoveredDependencies = await DiscoverAsync(tempProjectDirectory, tempProjectDirectory, tempProjectPath, experimentsManager, logger);
|
|
845
|
+
var rediscoveredDependencies = await DiscoverAsync(tempProjectDirectory, tempProjectDirectory, tempProjectPath, experimentsManager, solutionDir, logger);
|
|
835
846
|
var tempProjectFileName = Path.GetFileName(tempProjectPath);
|
|
836
847
|
var rediscoveredDependenciesForThisProject = rediscoveredDependencies.FirstOrDefault(r => PathComparer.Instance.Equals(r.FilePath, tempProjectFileName));
|
|
837
848
|
if (rediscoveredDependenciesForThisProject is null)
|
|
@@ -10,6 +10,10 @@ public sealed record WorkspaceDiscoveryResult : NativeResult
|
|
|
10
10
|
public GlobalJsonDiscoveryResult? GlobalJson { get; init; }
|
|
11
11
|
public DotNetToolsJsonDiscoveryResult? DotNetToolsJson { get; init; }
|
|
12
12
|
|
|
13
|
+
// when the workspace directly contains a solution file, this is the directory that was used to fake the MSBuild
|
|
14
|
+
// `SolutionDir` property during discovery; it is `null` when no solution file was present
|
|
15
|
+
public string? SolutionDirectory { get; init; }
|
|
16
|
+
|
|
13
17
|
public ProjectDiscoveryResult? GetProjectDiscoveryFromPath(string repoPath)
|
|
14
18
|
{
|
|
15
19
|
var projectDiscovery = Projects.FirstOrDefault(p => System.IO.Path.Join(Path, p.FilePath).FullyNormalizedRootedPath().Equals(repoPath, StringComparison.OrdinalIgnoreCase));
|
|
@@ -28,7 +28,7 @@ public class GraphWorker : IGraphWorker
|
|
|
28
28
|
{
|
|
29
29
|
// Deserialize the job file
|
|
30
30
|
var jobFileContent = await File.ReadAllTextAsync(jobFilePath.FullName);
|
|
31
|
-
var jobWrapper = RunWorker.Deserialize(jobFileContent);
|
|
31
|
+
var jobWrapper = RunWorker.Deserialize(jobFileContent, _logger);
|
|
32
32
|
var job = jobWrapper.Job;
|
|
33
33
|
|
|
34
34
|
// Use the case-insensitive repo contents path if provided, otherwise use the original
|
|
@@ -14,6 +14,9 @@ namespace NuGetUpdater.Core.Run.ApiModel;
|
|
|
14
14
|
public sealed record Job
|
|
15
15
|
{
|
|
16
16
|
public string PackageManager { get; init; } = "nuget";
|
|
17
|
+
|
|
18
|
+
public JobCommand Command { get; init; } = JobCommand.None;
|
|
19
|
+
|
|
17
20
|
public ImmutableArray<AllowedUpdate> AllowedUpdates { get; init; } = [new AllowedUpdate()];
|
|
18
21
|
|
|
19
22
|
[JsonConverter(typeof(NullAsBoolConverter))]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
using System.Text.Json;
|
|
2
|
+
using System.Text.Json.Serialization;
|
|
3
|
+
|
|
4
|
+
namespace NuGetUpdater.Core.Run.ApiModel;
|
|
5
|
+
|
|
6
|
+
public class JobCommandConverter : JsonConverter<JobCommand>
|
|
7
|
+
{
|
|
8
|
+
private readonly ILogger _logger;
|
|
9
|
+
|
|
10
|
+
public JobCommandConverter(ILogger logger)
|
|
11
|
+
{
|
|
12
|
+
_logger = logger;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public override JobCommand Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
16
|
+
{
|
|
17
|
+
if (reader.TokenType == JsonTokenType.Null)
|
|
18
|
+
{
|
|
19
|
+
return JobCommand.None;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (reader.TokenType != JsonTokenType.String)
|
|
23
|
+
{
|
|
24
|
+
_logger.Warn($"Unexpected JSON token type for job command: {reader.TokenType}; defaulting to None.");
|
|
25
|
+
reader.Skip();
|
|
26
|
+
return JobCommand.None;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var value = reader.GetString();
|
|
30
|
+
return value switch
|
|
31
|
+
{
|
|
32
|
+
"" => JobCommand.None,
|
|
33
|
+
"version" => JobCommand.Version,
|
|
34
|
+
"update" => JobCommand.Update,
|
|
35
|
+
"recreate" => JobCommand.Recreate,
|
|
36
|
+
"security" => JobCommand.Security,
|
|
37
|
+
"graph" => JobCommand.Graph,
|
|
38
|
+
_ => LogAndDefault(value),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private JobCommand LogAndDefault(string? value)
|
|
43
|
+
{
|
|
44
|
+
_logger.Warn($"Unknown job command value: \"{value}\"; defaulting to None.");
|
|
45
|
+
return JobCommand.None;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public override void Write(Utf8JsonWriter writer, JobCommand value, JsonSerializerOptions options)
|
|
49
|
+
{
|
|
50
|
+
var str = value switch
|
|
51
|
+
{
|
|
52
|
+
JobCommand.Version => "version",
|
|
53
|
+
JobCommand.Update => "update",
|
|
54
|
+
JobCommand.Recreate => "recreate",
|
|
55
|
+
JobCommand.Security => "security",
|
|
56
|
+
JobCommand.Graph => "graph",
|
|
57
|
+
_ => "",
|
|
58
|
+
};
|
|
59
|
+
writer.WriteStringValue(str);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -18,27 +18,56 @@ public class ModifiedFilesTracker
|
|
|
18
18
|
private readonly Dictionary<string, EOLType> _originalDependencyFileEOFs = [];
|
|
19
19
|
private readonly Dictionary<string, bool> _originalDependencyFileBOMs = [];
|
|
20
20
|
private string[] _nonProjectFiles = [];
|
|
21
|
-
private readonly HashSet<string>
|
|
21
|
+
private readonly HashSet<string> _initiallyExistingFiles;
|
|
22
|
+
|
|
23
|
+
/// <summary>
|
|
24
|
+
/// The set of file name patterns (case-insensitive) that are allowed to be edited during an update run.
|
|
25
|
+
/// Files matching these patterns are tracked for pre-existence; any file not present before discovery
|
|
26
|
+
/// will not be reported as modified.
|
|
27
|
+
/// </summary>
|
|
28
|
+
internal static readonly string[] AllowedEditableFilePatterns =
|
|
29
|
+
[
|
|
30
|
+
"global.json",
|
|
31
|
+
"dotnet-tools.json",
|
|
32
|
+
"*.csproj",
|
|
33
|
+
"*.fsproj",
|
|
34
|
+
"*.vbproj",
|
|
35
|
+
"*.props",
|
|
36
|
+
"*.targets",
|
|
37
|
+
"app.config",
|
|
38
|
+
"web.config",
|
|
39
|
+
"packages.config",
|
|
40
|
+
"packages.lock.json",
|
|
41
|
+
];
|
|
22
42
|
|
|
23
43
|
public IReadOnlyDictionary<string, string> OriginalDependencyFileContents => _originalDependencyFileContents;
|
|
24
44
|
//public IReadOnlyDictionary<string, EOLType> OriginalDependencyFileEOFs => _originalDependencyFileEOFs;
|
|
25
45
|
public IReadOnlyDictionary<string, bool> OriginalDependencyFileBOMs => _originalDependencyFileBOMs;
|
|
26
46
|
|
|
27
|
-
public ModifiedFilesTracker(DirectoryInfo repoContentsPath, HashSet<string>
|
|
47
|
+
public ModifiedFilesTracker(DirectoryInfo repoContentsPath, HashSet<string> initiallyExistingFiles, ILogger logger)
|
|
28
48
|
{
|
|
29
49
|
RepoContentsPath = repoContentsPath;
|
|
30
|
-
|
|
50
|
+
_initiallyExistingFiles = initiallyExistingFiles;
|
|
31
51
|
_logger = logger;
|
|
32
52
|
}
|
|
33
53
|
|
|
34
54
|
/// <summary>
|
|
35
|
-
/// Returns the set of
|
|
55
|
+
/// Returns the set of editable file paths (relative to repo root, unix-style) that currently exist on disk
|
|
56
|
+
/// and match the allowed editable file patterns.
|
|
36
57
|
/// </summary>
|
|
37
|
-
public static HashSet<string>
|
|
58
|
+
public static HashSet<string> GetInitiallyExistingFiles(DirectoryInfo repoContentsPath)
|
|
38
59
|
{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
60
|
+
var result = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
61
|
+
foreach (var file in Directory.EnumerateFiles(repoContentsPath.FullName, "*", SearchOption.AllDirectories))
|
|
62
|
+
{
|
|
63
|
+
var fileName = Path.GetFileName(file);
|
|
64
|
+
if (MatchesAllowedEditablePattern(fileName))
|
|
65
|
+
{
|
|
66
|
+
result.Add(Path.GetRelativePath(repoContentsPath.FullName, file).NormalizePathToUnix());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return result;
|
|
42
71
|
}
|
|
43
72
|
|
|
44
73
|
public async Task StartTrackingAsync(WorkspaceDiscoveryResult discoveryResult)
|
|
@@ -65,11 +94,16 @@ public class ModifiedFilesTracker
|
|
|
65
94
|
foreach (var project in _currentDiscoveryResult.Projects)
|
|
66
95
|
{
|
|
67
96
|
var projectDirectory = Path.GetDirectoryName(project.FilePath);
|
|
97
|
+
if (IsFileNotInitiallyPresent(Path.Join(_currentDiscoveryResult.Path, project.FilePath).NormalizePathToUnix()))
|
|
98
|
+
{
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
68
102
|
await TrackOriginalContentsAsync(_currentDiscoveryResult.Path, project.FilePath);
|
|
69
103
|
foreach (var extraFile in project.ImportedFiles.Concat(project.AdditionalFiles))
|
|
70
104
|
{
|
|
71
105
|
var extraFilePath = Path.Join(projectDirectory, extraFile);
|
|
72
|
-
if (
|
|
106
|
+
if (IsFileNotInitiallyPresent(Path.Join(_currentDiscoveryResult.Path, extraFilePath).NormalizePathToUnix()))
|
|
73
107
|
{
|
|
74
108
|
continue;
|
|
75
109
|
}
|
|
@@ -82,7 +116,9 @@ public class ModifiedFilesTracker
|
|
|
82
116
|
{
|
|
83
117
|
_currentDiscoveryResult.GlobalJson?.FilePath,
|
|
84
118
|
_currentDiscoveryResult.DotNetToolsJson?.FilePath,
|
|
85
|
-
}.Where(f => f is not null).Cast<string>()
|
|
119
|
+
}.Where(f => f is not null).Cast<string>()
|
|
120
|
+
.Where(f => !IsFileNotInitiallyPresent(Path.Join(_currentDiscoveryResult.Path, f).NormalizePathToUnix()))
|
|
121
|
+
.ToArray();
|
|
86
122
|
foreach (var nonProjectFile in _nonProjectFiles)
|
|
87
123
|
{
|
|
88
124
|
await TrackOriginalContentsAsync(_currentDiscoveryResult.Path, nonProjectFile);
|
|
@@ -138,12 +174,17 @@ public class ModifiedFilesTracker
|
|
|
138
174
|
|
|
139
175
|
foreach (var project in _currentDiscoveryResult.Projects)
|
|
140
176
|
{
|
|
177
|
+
if (IsFileNotInitiallyPresent(Path.Join(_currentDiscoveryResult.Path, project.FilePath).NormalizePathToUnix()))
|
|
178
|
+
{
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
141
182
|
await AddUpdatedFileIfDifferentAsync(_currentDiscoveryResult.Path, project.FilePath);
|
|
142
183
|
var projectDirectory = Path.GetDirectoryName(project.FilePath);
|
|
143
184
|
foreach (var extraFile in project.ImportedFiles.Concat(project.AdditionalFiles))
|
|
144
185
|
{
|
|
145
186
|
var extraFilePath = Path.Join(projectDirectory, extraFile);
|
|
146
|
-
if (
|
|
187
|
+
if (IsFileNotInitiallyPresent(Path.Join(_currentDiscoveryResult.Path, extraFilePath).NormalizePathToUnix()))
|
|
147
188
|
{
|
|
148
189
|
continue;
|
|
149
190
|
}
|
|
@@ -173,20 +214,46 @@ public class ModifiedFilesTracker
|
|
|
173
214
|
return correctedRepoFullPath;
|
|
174
215
|
}
|
|
175
216
|
|
|
176
|
-
private bool
|
|
217
|
+
private bool IsFileNotInitiallyPresent(string repoRelativePath)
|
|
177
218
|
{
|
|
178
|
-
return
|
|
219
|
+
return IsFileNotInitiallyPresent(repoRelativePath, _initiallyExistingFiles);
|
|
179
220
|
}
|
|
180
221
|
|
|
181
|
-
public static bool
|
|
222
|
+
public static bool IsFileNotInitiallyPresent(string repoRelativePath, HashSet<string> initiallyExistingFiles)
|
|
182
223
|
{
|
|
183
224
|
var normalizedPath = repoRelativePath.NormalizePathToUnix().NormalizeUnixPathParts().TrimStart('/');
|
|
184
|
-
|
|
225
|
+
var fileName = Path.GetFileName(normalizedPath);
|
|
226
|
+
|
|
227
|
+
if (!MatchesAllowedEditablePattern(fileName))
|
|
185
228
|
{
|
|
186
229
|
return false;
|
|
187
230
|
}
|
|
188
231
|
|
|
189
|
-
return !
|
|
232
|
+
return !initiallyExistingFiles.Contains(normalizedPath);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
internal static bool MatchesAllowedEditablePattern(string fileName)
|
|
236
|
+
{
|
|
237
|
+
foreach (var pattern in AllowedEditableFilePatterns)
|
|
238
|
+
{
|
|
239
|
+
if (pattern.StartsWith("*"))
|
|
240
|
+
{
|
|
241
|
+
var extension = pattern[1..]; // e.g., ".csproj"
|
|
242
|
+
if (fileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
|
|
243
|
+
{
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
else
|
|
248
|
+
{
|
|
249
|
+
if (fileName.Equals(pattern, StringComparison.OrdinalIgnoreCase))
|
|
250
|
+
{
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return false;
|
|
190
257
|
}
|
|
191
258
|
|
|
192
259
|
public static ImmutableArray<DependencyFile> MergeUpdatedFileSet(ImmutableArray<DependencyFile> setA, ImmutableArray<DependencyFile> setB)
|
|
@@ -44,7 +44,7 @@ public class RunWorker
|
|
|
44
44
|
public async Task<int> RunAsync(FileInfo jobFilePath, DirectoryInfo repoContentsPath, DirectoryInfo? caseInsensitiveRepoContentsPath, string baseCommitSha)
|
|
45
45
|
{
|
|
46
46
|
var jobFileContent = await File.ReadAllTextAsync(jobFilePath.FullName);
|
|
47
|
-
var jobWrapper = Deserialize(jobFileContent);
|
|
47
|
+
var jobWrapper = Deserialize(jobFileContent, _logger);
|
|
48
48
|
var experimentsManager = ExperimentsManager.GetExperimentsManager(jobWrapper.Job.Experiments);
|
|
49
49
|
var result = await RunAsync(jobWrapper.Job, repoContentsPath, caseInsensitiveRepoContentsPath, baseCommitSha, experimentsManager);
|
|
50
50
|
return result;
|
|
@@ -96,6 +96,13 @@ public class RunWorker
|
|
|
96
96
|
|
|
97
97
|
try
|
|
98
98
|
{
|
|
99
|
+
// Register MSBuild up front so that the `Microsoft.Build` assembly is loadable for
|
|
100
|
+
// the rest of the job. This is required even on the error-handling path:
|
|
101
|
+
// `JobErrorBase.ErrorFromException` references `Microsoft.Build` exception types, so
|
|
102
|
+
// if a failure occurs before MSBuild is registered, JIT-compiling the error handler
|
|
103
|
+
// would itself throw `FileNotFoundException` for `Microsoft.Build` and mask the real
|
|
104
|
+
// error.
|
|
105
|
+
MSBuildHelper.RegisterMSBuild(repoContentsPath.FullName, repoContentsPath.FullName, _logger);
|
|
99
106
|
await PatchNuGetConfigFilesAsync(repoContentsPath);
|
|
100
107
|
var handler = GetUpdateHandler(job);
|
|
101
108
|
_logger.Info($"Starting update job of type {handler.TagName}");
|
|
@@ -264,7 +271,7 @@ public class RunWorker
|
|
|
264
271
|
return relativeResolvedName;
|
|
265
272
|
}
|
|
266
273
|
|
|
267
|
-
internal static UpdatedDependencyList GetUpdatedDependencyListFromDiscovery(WorkspaceDiscoveryResult discoveryResult, string repoRoot, ILogger logger, HashSet<string>
|
|
274
|
+
internal static UpdatedDependencyList GetUpdatedDependencyListFromDiscovery(WorkspaceDiscoveryResult discoveryResult, string repoRoot, ILogger logger, HashSet<string> initiallyExistingFiles)
|
|
268
275
|
{
|
|
269
276
|
string GetFullRepoPath(string path)
|
|
270
277
|
{
|
|
@@ -272,12 +279,17 @@ public class RunWorker
|
|
|
272
279
|
return Path.Join(discoveryResult.Path, path).FullyNormalizedRootedPath();
|
|
273
280
|
}
|
|
274
281
|
|
|
282
|
+
bool IsInitiallyPresent(string filePath)
|
|
283
|
+
{
|
|
284
|
+
return !ModifiedFilesTracker.IsFileNotInitiallyPresent(Path.Join(discoveryResult.Path, filePath).NormalizePathToUnix(), initiallyExistingFiles);
|
|
285
|
+
}
|
|
286
|
+
|
|
275
287
|
var auxiliaryFiles = new List<string>();
|
|
276
|
-
if (discoveryResult.GlobalJson is not null)
|
|
288
|
+
if (discoveryResult.GlobalJson is not null && IsInitiallyPresent(discoveryResult.GlobalJson.FilePath))
|
|
277
289
|
{
|
|
278
290
|
auxiliaryFiles.Add(GetFullRepoPath(discoveryResult.GlobalJson.FilePath));
|
|
279
291
|
}
|
|
280
|
-
if (discoveryResult.DotNetToolsJson is not null)
|
|
292
|
+
if (discoveryResult.DotNetToolsJson is not null && IsInitiallyPresent(discoveryResult.DotNetToolsJson.FilePath))
|
|
281
293
|
{
|
|
282
294
|
auxiliaryFiles.Add(GetFullRepoPath(discoveryResult.DotNetToolsJson.FilePath));
|
|
283
295
|
}
|
|
@@ -288,7 +300,7 @@ public class RunWorker
|
|
|
288
300
|
foreach (var extraFile in project.ImportedFiles.Concat(project.AdditionalFiles))
|
|
289
301
|
{
|
|
290
302
|
var extraFileFullPath = Path.Join(projectDirectory, extraFile);
|
|
291
|
-
if (
|
|
303
|
+
if (!IsInitiallyPresent(extraFileFullPath))
|
|
292
304
|
{
|
|
293
305
|
continue;
|
|
294
306
|
}
|
|
@@ -298,28 +310,30 @@ public class RunWorker
|
|
|
298
310
|
}
|
|
299
311
|
}
|
|
300
312
|
|
|
301
|
-
var allDependenciesWithFilePath = discoveryResult.Projects
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
.
|
|
306
|
-
(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
313
|
+
var allDependenciesWithFilePath = discoveryResult.Projects
|
|
314
|
+
.Where(p => IsInitiallyPresent(p.FilePath))
|
|
315
|
+
.SelectMany(p =>
|
|
316
|
+
{
|
|
317
|
+
return p.Dependencies
|
|
318
|
+
.Where(d => d.Version is not null)
|
|
319
|
+
.Select(d =>
|
|
320
|
+
(p.FilePath, new ReportedDependency()
|
|
321
|
+
{
|
|
322
|
+
Name = d.Name,
|
|
323
|
+
Requirements = [new ReportedRequirement()
|
|
324
|
+
{
|
|
325
|
+
File = GetFullRepoPath(p.FilePath),
|
|
326
|
+
Requirement = d.Version!,
|
|
327
|
+
Groups = ["dependencies"],
|
|
328
|
+
}],
|
|
329
|
+
Version = d.Version,
|
|
330
|
+
}));
|
|
331
|
+
}).ToList();
|
|
318
332
|
|
|
319
333
|
var nonProjectDependencySet = new (string?, IEnumerable<Dependency>)[]
|
|
320
334
|
{
|
|
321
|
-
(discoveryResult.GlobalJson
|
|
322
|
-
(discoveryResult.DotNetToolsJson
|
|
335
|
+
(discoveryResult.GlobalJson is not null && IsInitiallyPresent(discoveryResult.GlobalJson.FilePath) ? discoveryResult.GlobalJson.FilePath : null, discoveryResult.GlobalJson?.Dependencies ?? []),
|
|
336
|
+
(discoveryResult.DotNetToolsJson is not null && IsInitiallyPresent(discoveryResult.DotNetToolsJson.FilePath) ? discoveryResult.DotNetToolsJson.FilePath : null, discoveryResult.DotNetToolsJson?.Dependencies ?? []),
|
|
323
337
|
};
|
|
324
338
|
|
|
325
339
|
foreach (var (filePath, dependencies) in nonProjectDependencySet)
|
|
@@ -352,6 +366,7 @@ public class RunWorker
|
|
|
352
366
|
.ToArray();
|
|
353
367
|
|
|
354
368
|
var dependencyFiles = discoveryResult.Projects
|
|
369
|
+
.Where(p => IsInitiallyPresent(p.FilePath))
|
|
355
370
|
.Select(p => GetFullRepoPath(p.FilePath))
|
|
356
371
|
.Concat(auxiliaryFiles)
|
|
357
372
|
.Select(p => EnsureCorrectFileCasing(p, repoRoot, logger))
|
|
@@ -367,9 +382,12 @@ public class RunWorker
|
|
|
367
382
|
return updatedDependencyList;
|
|
368
383
|
}
|
|
369
384
|
|
|
370
|
-
public static JobFile Deserialize(string json)
|
|
385
|
+
public static JobFile Deserialize(string json) => Deserialize(json, new ConsoleLogger());
|
|
386
|
+
|
|
387
|
+
public static JobFile Deserialize(string json, ILogger logger)
|
|
371
388
|
{
|
|
372
|
-
var
|
|
389
|
+
var options = GetDeserializerOptions(logger);
|
|
390
|
+
var jobFile = JsonSerializer.Deserialize<JobFile>(json, options);
|
|
373
391
|
if (jobFile is null)
|
|
374
392
|
{
|
|
375
393
|
throw new InvalidOperationException("Unable to deserialize job wrapper.");
|
|
@@ -383,6 +401,13 @@ public class RunWorker
|
|
|
383
401
|
return jobFile;
|
|
384
402
|
}
|
|
385
403
|
|
|
404
|
+
internal static JsonSerializerOptions GetDeserializerOptions(ILogger logger)
|
|
405
|
+
{
|
|
406
|
+
var options = new JsonSerializerOptions(SerializerOptions);
|
|
407
|
+
options.Converters.Insert(0, new JobCommandConverter(logger));
|
|
408
|
+
return options;
|
|
409
|
+
}
|
|
410
|
+
|
|
386
411
|
internal static string AddInsecureConnectionsAttribute(string nugetConfigContents)
|
|
387
412
|
{
|
|
388
413
|
try
|
|
@@ -31,7 +31,7 @@ internal class CreateSecurityUpdatePullRequestHandler : IUpdateHandler
|
|
|
31
31
|
{
|
|
32
32
|
var repoContentsPath = caseInsensitiveRepoContentsPath ?? originalRepoContentsPath;
|
|
33
33
|
var jobDependencies = job.Dependencies.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
34
|
-
var
|
|
34
|
+
var initialFiles = ModifiedFilesTracker.GetInitiallyExistingFiles(repoContentsPath);
|
|
35
35
|
foreach (var directory in job.GetAllDirectories(repoContentsPath.FullName))
|
|
36
36
|
{
|
|
37
37
|
var discoveryResult = await discoveryWorker.RunAsync(repoContentsPath.FullName, directory);
|
|
@@ -42,7 +42,7 @@ internal class CreateSecurityUpdatePullRequestHandler : IUpdateHandler
|
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
var updatedDependencyList = RunWorker.GetUpdatedDependencyListFromDiscovery(discoveryResult, originalRepoContentsPath.FullName, logger,
|
|
45
|
+
var updatedDependencyList = RunWorker.GetUpdatedDependencyListFromDiscovery(discoveryResult, originalRepoContentsPath.FullName, logger, initialFiles);
|
|
46
46
|
await apiHandler.UpdateDependencyList(updatedDependencyList);
|
|
47
47
|
await this.ReportUpdaterStarted(apiHandler);
|
|
48
48
|
|
|
@@ -62,7 +62,7 @@ internal class CreateSecurityUpdatePullRequestHandler : IUpdateHandler
|
|
|
62
62
|
|
|
63
63
|
logger.Info($"Updating dependencies: {string.Join(", ", groupedUpdateOperationsToPerform.Select(g => g.Key).Distinct().OrderBy(d => d, StringComparer.OrdinalIgnoreCase))}");
|
|
64
64
|
|
|
65
|
-
var tracker = new ModifiedFilesTracker(originalRepoContentsPath,
|
|
65
|
+
var tracker = new ModifiedFilesTracker(originalRepoContentsPath, initialFiles, logger);
|
|
66
66
|
await tracker.StartTrackingAsync(discoveryResult);
|
|
67
67
|
foreach (var dependencyGroupToUpdate in groupedUpdateOperationsToPerform)
|
|
68
68
|
{
|