dependabot-nuget 0.394.0 → 0.396.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/Directory.Packages.props +8 -8
- data/helpers/lib/NuGetUpdater/NuGetProjects/NuGet.Protocol/NuGet.Protocol.csproj +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +18 -10
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/HttpApiHandler.cs +10 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/IApiHandler.cs +14 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +164 -34
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/HttpApiHandlerTests.cs +29 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +73 -0
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c8d2c369fea3791d04cedce39111d000bc6d0052f48a6df16116b9c811b1f4c
|
|
4
|
+
data.tar.gz: '08c4cec0fef16173ca1d28eb497127064b4ecc5daeb2a2d84f3ab8ee72cc6852'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 220207aba4f007a902a08030847f865afad86e57de5dfcbfe81d9a6ef5bdaa5284ace3c4259f122778a69ad6401e42645858dd09516edf75055b14c48f3c4f59
|
|
7
|
+
data.tar.gz: c309c50fd55d24516bca819ff47c5b3981b867fe7d15a5990505c2ad0e527e999d0aa988fcb81c359e98291eb8da983edae2a7d803e7677530bf0dfef8fc85da
|
|
@@ -27,20 +27,20 @@
|
|
|
27
27
|
<PackageVersion Include="MSBuild.StructuredLogger" Version="2.3.246" />
|
|
28
28
|
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
|
29
29
|
<PackageVersion Include="OpenTelemetry" Version="1.18.0" />
|
|
30
|
-
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.
|
|
30
|
+
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.18.0" />
|
|
31
31
|
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.18.0" />
|
|
32
32
|
<PackageVersion Include="packageurl-dotnet" Version="2.0.1" />
|
|
33
33
|
<PackageVersion Include="Semver" Version="3.0.0" />
|
|
34
|
-
<PackageVersion Include="System.CommandLine" Version="2.0.
|
|
35
|
-
<PackageVersion Include="System.ComponentModel.Composition" Version="10.0.
|
|
34
|
+
<PackageVersion Include="System.CommandLine" Version="2.0.11" />
|
|
35
|
+
<PackageVersion Include="System.ComponentModel.Composition" Version="10.0.11" />
|
|
36
36
|
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
|
|
37
37
|
<PackageVersion Include="System.Formats.Asn1" Version="10.0.3" />
|
|
38
|
-
<PackageVersion Include="System.Security.Cryptography.Pkcs" Version="10.0.
|
|
39
|
-
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="10.0.
|
|
40
|
-
<PackageVersion Include="System.Text.Json" Version="10.0.
|
|
38
|
+
<PackageVersion Include="System.Security.Cryptography.Pkcs" Version="10.0.11" />
|
|
39
|
+
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="10.0.11" />
|
|
40
|
+
<PackageVersion Include="System.Text.Json" Version="10.0.11" />
|
|
41
41
|
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
|
|
42
|
-
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="10.0.
|
|
42
|
+
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="10.0.11" />
|
|
43
43
|
<PackageVersion Include="xunit.v3" Version="3.2.2" />
|
|
44
|
-
<PackageVersion Include="xunit.runner.visualstudio" Version="
|
|
44
|
+
<PackageVersion Include="xunit.runner.visualstudio" Version="4.0.0" />
|
|
45
45
|
</ItemGroup>
|
|
46
46
|
</Project>
|
|
@@ -65,6 +65,8 @@ internal static class SdkProjectDiscovery
|
|
|
65
65
|
// these targets are required to evaluate a legacy project with a single operation
|
|
66
66
|
private static readonly ImmutableArray<string> LegacyProjectSingleRestoreTargetNames = ["ResolveProjectReferences"];
|
|
67
67
|
|
|
68
|
+
private const string TargetFrameworksPropertyName = "TargetFrameworks";
|
|
69
|
+
|
|
68
70
|
// this property evaluates to a version number in an SDK-style project and is unset or empty otherwise
|
|
69
71
|
private const string NETCoreSdkVersionPropertyName = "NETCoreSdkVersion";
|
|
70
72
|
|
|
@@ -119,16 +121,30 @@ internal static class SdkProjectDiscovery
|
|
|
119
121
|
Dictionary<string, HashSet<string>> additionalFiles = new(PathComparer.Instance);
|
|
120
122
|
// projectPath additionalFiles
|
|
121
123
|
|
|
124
|
+
var startingProjectProperties = await MSBuildHelper.GetProjectPropertiesAsync(
|
|
125
|
+
startingProjectPath,
|
|
126
|
+
[TargetFrameworksPropertyName, NETCoreSdkVersionPropertyName],
|
|
127
|
+
logger
|
|
128
|
+
);
|
|
129
|
+
var projectTfms = MSBuildHelper.ParseProjectTargetFrameworks(startingProjectProperties?.GetValueOrDefault(TargetFrameworksPropertyName));
|
|
130
|
+
var netCoreSdkVersionValue = startingProjectProperties?.GetValueOrDefault(NETCoreSdkVersionPropertyName);
|
|
131
|
+
var isLegacyProject = string.IsNullOrEmpty(netCoreSdkVersionValue);
|
|
132
|
+
var requiredTargets = isLegacyProject
|
|
133
|
+
? LegacyProjectSingleRestoreTargetNames
|
|
134
|
+
: SingleRestoreTargetNames;
|
|
135
|
+
|
|
122
136
|
// due to how MSBuild handles multi-TFM projects with target platforms we may need to process each TFM separately
|
|
123
137
|
// we detect that by determining if there are multiple target frameworks specified and if any of them have a platform suffix (e.g., `-windows`, `-android`, etc)
|
|
124
138
|
// alternately, if there are too many target frameworks specified, they must be handled individually
|
|
125
|
-
var projectTfms = await MSBuildHelper.GetProjectTargetFrameworksAsync(startingProjectPath, logger);
|
|
126
139
|
var hasPlatformTfms = projectTfms.Any(tfm => tfm.Contains('-'));
|
|
127
140
|
var requiresIndividualRestores = hasPlatformTfms || projectTfms.Length > MaximumParallelTargetFrameworkRestores;
|
|
141
|
+
var useDirectRestore = requiresIndividualRestores;
|
|
128
142
|
if (!requiresIndividualRestores)
|
|
129
143
|
{
|
|
130
144
|
logger.Info($"Performing single restore for project {startingProjectPath}");
|
|
131
145
|
projectTfms = [string.Empty]; // a single restore can handle everything, but we need to loop at least once and an empty TFM is our signal to not specify anything
|
|
146
|
+
var actualTargets = await MSBuildHelper.GetProjectTargetsAsync(startingProjectPath, logger);
|
|
147
|
+
useDirectRestore = requiredTargets.All(actualTargets.Contains);
|
|
132
148
|
}
|
|
133
149
|
else
|
|
134
150
|
{
|
|
@@ -158,15 +174,7 @@ internal static class SdkProjectDiscovery
|
|
|
158
174
|
// `ResolveProjectReferences` to gather all `PackageReference` items and further down we re-build the transitive
|
|
159
175
|
// dependency set. Without the legacy project check, we could incorrectly invoke `Build` which eventually tries
|
|
160
176
|
// to call `csc.exe` which is unnecessary and can be slow.
|
|
161
|
-
|
|
162
|
-
var isLegacyProject = string.IsNullOrEmpty(netCoreSdkVersionValue);
|
|
163
|
-
var requiredTargets = isLegacyProject
|
|
164
|
-
? LegacyProjectSingleRestoreTargetNames
|
|
165
|
-
: SingleRestoreTargetNames;
|
|
166
|
-
|
|
167
|
-
var actualTargets = await MSBuildHelper.GetProjectTargetsAsync(startingProjectPath, logger);
|
|
168
|
-
var useDirectRestore = requiredTargets.All(actualTargets.Contains);
|
|
169
|
-
if (useDirectRestore || isIndividualTfmRestore)
|
|
177
|
+
if (useDirectRestore)
|
|
170
178
|
{
|
|
171
179
|
// directly call the required targets
|
|
172
180
|
args.Add($"/t:{string.Join(",", requiredTargets)}");
|
|
@@ -4,7 +4,7 @@ using System.Text.Json.Serialization;
|
|
|
4
4
|
|
|
5
5
|
namespace NuGetUpdater.Core.Run;
|
|
6
6
|
|
|
7
|
-
public class HttpApiHandler : IApiHandler
|
|
7
|
+
public class HttpApiHandler : IApiHandler, IApiRetryDelayProvider
|
|
8
8
|
{
|
|
9
9
|
private static readonly HttpClient HttpClient = new();
|
|
10
10
|
|
|
@@ -16,13 +16,22 @@ public class HttpApiHandler : IApiHandler
|
|
|
16
16
|
|
|
17
17
|
private readonly string _apiUrl;
|
|
18
18
|
private readonly string _jobId;
|
|
19
|
+
private readonly Func<TimeSpan, Task> _retryDelay;
|
|
19
20
|
|
|
20
21
|
public HttpApiHandler(string apiUrl, string jobId)
|
|
22
|
+
: this(apiUrl, jobId, Task.Delay)
|
|
23
|
+
{
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
internal HttpApiHandler(string apiUrl, string jobId, Func<TimeSpan, Task> retryDelay)
|
|
21
27
|
{
|
|
22
28
|
_apiUrl = apiUrl.TrimEnd('/');
|
|
23
29
|
_jobId = jobId;
|
|
30
|
+
_retryDelay = retryDelay;
|
|
24
31
|
}
|
|
25
32
|
|
|
33
|
+
Task IApiRetryDelayProvider.DelayAsync(TimeSpan delay) => _retryDelay(delay);
|
|
34
|
+
|
|
26
35
|
public async Task SendAsync(string endpoint, object body, string method)
|
|
27
36
|
{
|
|
28
37
|
var uri = $"{_apiUrl}/update_jobs/{_jobId}/{endpoint}";
|
|
@@ -7,6 +7,11 @@ public interface IApiHandler
|
|
|
7
7
|
Task SendAsync(string endpoint, object body, string method);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
internal interface IApiRetryDelayProvider
|
|
11
|
+
{
|
|
12
|
+
Task DelayAsync(TimeSpan delay);
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
public static class IApiHandlerExtensions
|
|
11
16
|
{
|
|
12
17
|
public static async Task RecordUpdateJobError(this IApiHandler handler, JobErrorBase error, ILogger logger)
|
|
@@ -70,7 +75,15 @@ public static class IApiHandlerExtensions
|
|
|
70
75
|
(ex.StatusCode is null || ((int)ex.StatusCode) / 100 == 5))
|
|
71
76
|
{
|
|
72
77
|
retryCount++;
|
|
73
|
-
|
|
78
|
+
var delay = TimeSpan.FromSeconds(Random.Shared.Next(MinRetryDelay, MaxRetryDelay));
|
|
79
|
+
if (handler is IApiRetryDelayProvider delayProvider)
|
|
80
|
+
{
|
|
81
|
+
await delayProvider.DelayAsync(delay);
|
|
82
|
+
}
|
|
83
|
+
else
|
|
84
|
+
{
|
|
85
|
+
await Task.Delay(delay);
|
|
86
|
+
}
|
|
74
87
|
}
|
|
75
88
|
}
|
|
76
89
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
using System.Collections.Immutable;
|
|
2
2
|
using System.Diagnostics.CodeAnalysis;
|
|
3
3
|
using System.Reflection;
|
|
4
|
+
using System.Text.Json;
|
|
4
5
|
using System.Text.Json.Nodes;
|
|
5
6
|
using System.Text.RegularExpressions;
|
|
6
7
|
using System.Xml.Linq;
|
|
@@ -563,7 +564,11 @@ internal static partial class MSBuildHelper
|
|
|
563
564
|
return targets;
|
|
564
565
|
}
|
|
565
566
|
|
|
566
|
-
internal static async Task<string
|
|
567
|
+
internal static async Task<ImmutableDictionary<string, string>?> GetProjectPropertiesAsync(
|
|
568
|
+
string projectPath,
|
|
569
|
+
IReadOnlyCollection<string> propertyNames,
|
|
570
|
+
ILogger logger
|
|
571
|
+
)
|
|
567
572
|
{
|
|
568
573
|
var extension = Path.GetExtension(projectPath)?.ToLowerInvariant();
|
|
569
574
|
if (extension == ".sln" || extension == ".slnx")
|
|
@@ -572,51 +577,128 @@ internal static partial class MSBuildHelper
|
|
|
572
577
|
return null;
|
|
573
578
|
}
|
|
574
579
|
|
|
575
|
-
var
|
|
576
|
-
|
|
580
|
+
var requestedPropertyNames = propertyNames
|
|
581
|
+
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
582
|
+
.ToImmutableArray();
|
|
583
|
+
if (requestedPropertyNames.Length == 0)
|
|
577
584
|
{
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
};
|
|
585
|
+
return ImmutableDictionary.Create<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
586
|
+
}
|
|
581
587
|
|
|
582
|
-
|
|
583
|
-
|
|
588
|
+
if (requestedPropertyNames.Length == 1)
|
|
589
|
+
{
|
|
590
|
+
var propertyName = requestedPropertyNames[0];
|
|
591
|
+
var propertyValue = await GetProjectPropertyAsync(projectPath, propertyName, logger);
|
|
592
|
+
return propertyValue is null
|
|
593
|
+
? null
|
|
594
|
+
: ImmutableDictionary.Create<string, string>(StringComparer.OrdinalIgnoreCase).Add(propertyName, propertyValue);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
var projectDirectory = Path.GetDirectoryName(projectPath)!;
|
|
598
|
+
var tempDir = Directory.CreateTempSubdirectory("__get_msbuild_properties_");
|
|
599
|
+
try
|
|
584
600
|
{
|
|
585
|
-
|
|
601
|
+
var resultOutputPath = Path.Combine(tempDir.FullName, "result.json");
|
|
602
|
+
var args = new[]
|
|
586
603
|
{
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
604
|
+
projectPath,
|
|
605
|
+
$"-getProperty:{string.Join(",", requestedPropertyNames)}",
|
|
606
|
+
$"-getResultOutputFile:{resultOutputPath}",
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetMSBuildSafelyAsync(args, projectDirectory);
|
|
610
|
+
if (exitCode != 0)
|
|
611
|
+
{
|
|
612
|
+
if (IsGetPropertyUnsupported(stdOut, stdErr))
|
|
591
613
|
{
|
|
592
|
-
|
|
593
|
-
var
|
|
594
|
-
var targetContents = targetsTemplateContents.Replace("%RequestedPropertyName%", $"$({propertyName})");
|
|
595
|
-
|
|
596
|
-
// write magic contents
|
|
597
|
-
var tempTargetsPath = Path.Combine(tempDir.FullName, $"GetProperty_{propertyName}.targets");
|
|
598
|
-
await File.WriteAllTextAsync(tempTargetsPath, targetContents);
|
|
599
|
-
|
|
600
|
-
// do it
|
|
601
|
-
args = [
|
|
602
|
-
projectPath,
|
|
603
|
-
$"/p:CustomAfterMicrosoftCommonTargets={tempTargetsPath}",
|
|
604
|
-
"/t:_Dependabot_GetProperty",
|
|
605
|
-
];
|
|
606
|
-
(exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetMSBuildSafelyAsync(args, projectDirectory);
|
|
607
|
-
if (exitCode == 0)
|
|
614
|
+
var fallbackProperties = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
615
|
+
foreach (var propertyName in requestedPropertyNames)
|
|
608
616
|
{
|
|
609
|
-
var
|
|
610
|
-
if (
|
|
617
|
+
var propertyValue = await GetProjectPropertyUsingCompatibilityTargetAsync(projectPath, propertyName, logger);
|
|
618
|
+
if (propertyValue is null)
|
|
611
619
|
{
|
|
612
|
-
return
|
|
620
|
+
return null;
|
|
613
621
|
}
|
|
622
|
+
|
|
623
|
+
fallbackProperties[propertyName] = propertyValue;
|
|
614
624
|
}
|
|
625
|
+
|
|
626
|
+
return fallbackProperties.ToImmutable();
|
|
615
627
|
}
|
|
616
|
-
|
|
628
|
+
|
|
629
|
+
logger.Warn($"Unable to determine properties '{string.Join("', '", requestedPropertyNames)}' for project [{projectPath}]:\nSTDOUT:\n{stdOut}\nSTDERR:\n{stdErr}\n");
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (!File.Exists(resultOutputPath))
|
|
634
|
+
{
|
|
635
|
+
logger.Warn($"Unable to determine properties '{string.Join("', '", requestedPropertyNames)}' for project [{projectPath}]: MSBuild did not produce a result output file.\nSTDOUT:\n{stdOut}\nSTDERR:\n{stdErr}\n");
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
var resultOutput = await File.ReadAllTextAsync(resultOutputPath);
|
|
640
|
+
try
|
|
641
|
+
{
|
|
642
|
+
using var resultDocument = JsonDocument.Parse(resultOutput);
|
|
643
|
+
var root = resultDocument.RootElement;
|
|
644
|
+
if (root.ValueKind != JsonValueKind.Object ||
|
|
645
|
+
!root.TryGetProperty("Properties", out var propertiesElement) ||
|
|
646
|
+
propertiesElement.ValueKind != JsonValueKind.Object)
|
|
617
647
|
{
|
|
618
|
-
|
|
648
|
+
logger.Warn($"Unable to determine properties '{string.Join("', '", requestedPropertyNames)}' for project [{projectPath}]: MSBuild result output did not contain a properties object.");
|
|
649
|
+
return null;
|
|
619
650
|
}
|
|
651
|
+
|
|
652
|
+
var properties = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
653
|
+
foreach (var propertyName in requestedPropertyNames)
|
|
654
|
+
{
|
|
655
|
+
if (!propertiesElement.TryGetProperty(propertyName, out var propertyElement) ||
|
|
656
|
+
propertyElement.ValueKind != JsonValueKind.String ||
|
|
657
|
+
propertyElement.GetString() is not string propertyValue)
|
|
658
|
+
{
|
|
659
|
+
logger.Warn($"Unable to determine property '{propertyName}' for project [{projectPath}]: MSBuild result output did not contain a string value for the property.");
|
|
660
|
+
return null;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
properties[propertyName] = propertyValue;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
return properties.ToImmutable();
|
|
667
|
+
}
|
|
668
|
+
catch (JsonException ex)
|
|
669
|
+
{
|
|
670
|
+
logger.Warn($"Unable to determine properties '{string.Join("', '", requestedPropertyNames)}' for project [{projectPath}]: MSBuild produced invalid JSON result output: {ex.Message}");
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
finally
|
|
675
|
+
{
|
|
676
|
+
tempDir.Delete(recursive: true);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
internal static async Task<string?> GetProjectPropertyAsync(string projectPath, string propertyName, ILogger logger)
|
|
681
|
+
{
|
|
682
|
+
var extension = Path.GetExtension(projectPath)?.ToLowerInvariant();
|
|
683
|
+
if (extension == ".sln" || extension == ".slnx")
|
|
684
|
+
{
|
|
685
|
+
// solution files don't specify properties, so we can skip the process invocation
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
var projectDirectory = Path.GetDirectoryName(projectPath)!;
|
|
690
|
+
var args = new[]
|
|
691
|
+
{
|
|
692
|
+
projectPath,
|
|
693
|
+
$"-getProperty:{propertyName}"
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetMSBuildSafelyAsync(args, projectDirectory);
|
|
697
|
+
if (exitCode != 0)
|
|
698
|
+
{
|
|
699
|
+
if (IsGetPropertyUnsupported(stdOut, stdErr))
|
|
700
|
+
{
|
|
701
|
+
return await GetProjectPropertyUsingCompatibilityTargetAsync(projectPath, propertyName, logger);
|
|
620
702
|
}
|
|
621
703
|
|
|
622
704
|
logger.Warn($"Unable to determine property '{propertyName}' for project [{projectPath}]:\nSTDOUT:\n{stdOut}\nSTDERR:\n{stdErr}\n");
|
|
@@ -629,6 +711,11 @@ internal static partial class MSBuildHelper
|
|
|
629
711
|
internal static async Task<ImmutableArray<string>> GetProjectTargetFrameworksAsync(string projectPath, ILogger logger)
|
|
630
712
|
{
|
|
631
713
|
var rawValue = await GetProjectPropertyAsync(projectPath, "TargetFrameworks", logger);
|
|
714
|
+
return ParseProjectTargetFrameworks(rawValue);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
internal static ImmutableArray<string> ParseProjectTargetFrameworks(string? rawValue)
|
|
718
|
+
{
|
|
632
719
|
if (rawValue is null)
|
|
633
720
|
{
|
|
634
721
|
return [];
|
|
@@ -641,6 +728,49 @@ internal static partial class MSBuildHelper
|
|
|
641
728
|
return tfms;
|
|
642
729
|
}
|
|
643
730
|
|
|
731
|
+
private static bool IsGetPropertyUnsupported(string stdOut, string stdErr)
|
|
732
|
+
{
|
|
733
|
+
return stdOut.Contains("error MSB1001: Unknown switch.", StringComparison.Ordinal) ||
|
|
734
|
+
stdErr.Contains("error MSB1001: Unknown switch.", StringComparison.Ordinal);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
private static async Task<string?> GetProjectPropertyUsingCompatibilityTargetAsync(string projectPath, string propertyName, ILogger logger)
|
|
738
|
+
{
|
|
739
|
+
// Older versions of MSBuild don't allow `-getProperty`, so import a custom target that reports the property.
|
|
740
|
+
var projectDirectory = Path.GetDirectoryName(projectPath)!;
|
|
741
|
+
var tempDir = Directory.CreateTempSubdirectory("__get_msbuild_property_");
|
|
742
|
+
try
|
|
743
|
+
{
|
|
744
|
+
var targetsTemplateContents = await File.ReadAllTextAsync(GetFileFromRuntimeDirectory("GetProperty.targets"));
|
|
745
|
+
var targetContents = targetsTemplateContents.Replace("%RequestedPropertyName%", $"$({propertyName})");
|
|
746
|
+
var tempTargetsPath = Path.Combine(tempDir.FullName, $"GetProperty_{propertyName}.targets");
|
|
747
|
+
await File.WriteAllTextAsync(tempTargetsPath, targetContents);
|
|
748
|
+
|
|
749
|
+
var args = new[]
|
|
750
|
+
{
|
|
751
|
+
projectPath,
|
|
752
|
+
$"/p:CustomAfterMicrosoftCommonTargets={tempTargetsPath}",
|
|
753
|
+
"/t:_Dependabot_GetProperty",
|
|
754
|
+
};
|
|
755
|
+
var (exitCode, stdOut, stdErr) = await ProcessEx.RunDotnetMSBuildSafelyAsync(args, projectDirectory);
|
|
756
|
+
if (exitCode == 0)
|
|
757
|
+
{
|
|
758
|
+
var match = Regex.Match(stdOut, "__PROPERTY_VALUE:(?<PropertyValue>[^$]*)$", RegexOptions.Multiline);
|
|
759
|
+
if (match.Success)
|
|
760
|
+
{
|
|
761
|
+
return match.Groups["PropertyValue"].Value.Trim();
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
logger.Warn($"Unable to determine property '{propertyName}' for project [{projectPath}]:\nSTDOUT:\n{stdOut}\nSTDERR:\n{stdErr}\n");
|
|
766
|
+
return null;
|
|
767
|
+
}
|
|
768
|
+
finally
|
|
769
|
+
{
|
|
770
|
+
tempDir.Delete(recursive: true);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
644
774
|
internal static string? GetMissingFile(string output)
|
|
645
775
|
{
|
|
646
776
|
var missingFilePatterns = new[]
|
|
@@ -332,6 +332,7 @@ public class SdkProjectDiscoveryTests : DiscoveryWorkerTestBase
|
|
|
332
332
|
[Theory]
|
|
333
333
|
[InlineData("net7.0")] // under the safe limit for parallel processing
|
|
334
334
|
[InlineData("net7.0", "net8.0")] // at the safe limit for parallel processing
|
|
335
|
+
[InlineData("net8.0", "net9.0-windows")] // platform-specific TFMs are processed individually
|
|
335
336
|
[InlineData("net7.0", "net8.0", "net9.0")] // above the safe limit for parallel processing
|
|
336
337
|
[InlineData("netstandard2.0", "netstandard2.1", "net6.0", "net7.0", "net8.0", "net9.0", "net10.0")] // well above the safe limit for parallel processing
|
|
337
338
|
public async Task DiscoverWithMultipleTargetFrameworks(params string[] targetFrameworks)
|
|
@@ -798,4 +799,3 @@ public class SdkProjectDiscoveryTests : DiscoveryWorkerTestBase
|
|
|
798
799
|
ValidateProjectResults(expectedProjects, projectDiscovery);
|
|
799
800
|
}
|
|
800
801
|
}
|
|
801
|
-
|
|
@@ -62,21 +62,24 @@ public class HttpApiHandlerTests
|
|
|
62
62
|
var requestCount = 0;
|
|
63
63
|
using var http = TestHttpServer.CreateTestServer((method, url) =>
|
|
64
64
|
{
|
|
65
|
-
|
|
65
|
+
requestCount++;
|
|
66
|
+
if (requestCount <= 2)
|
|
66
67
|
{
|
|
67
|
-
requestCount++;
|
|
68
68
|
return (500, Array.Empty<byte>());
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
return (200, Array.Empty<byte>());
|
|
72
72
|
});
|
|
73
|
-
var handler = new HttpApiHandler(http.BaseUrl, "TEST-ID");
|
|
73
|
+
var handler = new HttpApiHandler(http.BaseUrl, "TEST-ID", static _ => Task.CompletedTask);
|
|
74
74
|
|
|
75
75
|
// act
|
|
76
76
|
await handler.IncrementMetric(new()
|
|
77
77
|
{
|
|
78
78
|
Metric = "test",
|
|
79
79
|
});
|
|
80
|
+
|
|
81
|
+
// assert
|
|
82
|
+
Assert.Equal(3, requestCount);
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
[Fact]
|
|
@@ -93,7 +96,29 @@ public class HttpApiHandlerTests
|
|
|
93
96
|
|
|
94
97
|
// act
|
|
95
98
|
await Assert.ThrowsAsync<HttpRequestException>(() => handler.IncrementMetric(new() { Metric = "test" }));
|
|
96
|
-
|
|
99
|
+
|
|
100
|
+
// assert
|
|
101
|
+
Assert.Equal(1, requestCount);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
[Fact]
|
|
105
|
+
public async Task ApiCallsStopRetryingAfterTheMaximumNumberOfAttempts()
|
|
106
|
+
{
|
|
107
|
+
// arrange
|
|
108
|
+
var requestCount = 0;
|
|
109
|
+
using var http = TestHttpServer.CreateTestStringServer((method, url) =>
|
|
110
|
+
{
|
|
111
|
+
requestCount++;
|
|
112
|
+
return (500, $"attempt-{requestCount}");
|
|
113
|
+
});
|
|
114
|
+
var handler = new HttpApiHandler(http.BaseUrl, "TEST-ID", static _ => Task.CompletedTask);
|
|
115
|
+
|
|
116
|
+
// act
|
|
117
|
+
var exception = await Assert.ThrowsAsync<HttpRequestException>(() => handler.IncrementMetric(new() { Metric = "test" }));
|
|
118
|
+
|
|
119
|
+
// assert
|
|
120
|
+
Assert.Equal("500 (InternalServerError): attempt-4", exception.Message);
|
|
121
|
+
Assert.Equal(4, requestCount);
|
|
97
122
|
}
|
|
98
123
|
|
|
99
124
|
[Theory]
|
|
@@ -284,6 +284,79 @@ public class MSBuildHelperTests : TestBase
|
|
|
284
284
|
AssertEx.Equal(expectedDependencies, actualDependencies);
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
[Fact]
|
|
288
|
+
public async Task MultipleProjectPropertiesCanBeEvaluated()
|
|
289
|
+
{
|
|
290
|
+
using var tempDir = await TemporaryDirectory.CreateWithContentsAsync(
|
|
291
|
+
[
|
|
292
|
+
("project.csproj", """
|
|
293
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
|
294
|
+
<PropertyGroup>
|
|
295
|
+
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
|
|
296
|
+
</PropertyGroup>
|
|
297
|
+
</Project>
|
|
298
|
+
""")
|
|
299
|
+
]);
|
|
300
|
+
var projectPath = Path.Combine(tempDir.DirectoryPath, "project.csproj");
|
|
301
|
+
var properties = await MSBuildHelper.GetProjectPropertiesAsync(
|
|
302
|
+
projectPath,
|
|
303
|
+
["TargetFrameworks", "NETCoreSdkVersion"],
|
|
304
|
+
new TestLogger()
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
Assert.NotNull(properties);
|
|
308
|
+
Assert.Equal("net8.0;net9.0", properties["TargetFrameworks"]);
|
|
309
|
+
Assert.False(string.IsNullOrEmpty(properties["NETCoreSdkVersion"]));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
[Theory]
|
|
313
|
+
[InlineData("TargetFrameworks")]
|
|
314
|
+
[InlineData("TargetFrameworks", "targetframeworks")]
|
|
315
|
+
public async Task SingleDistinctProjectPropertyCanBeEvaluated(params string[] propertyNames)
|
|
316
|
+
{
|
|
317
|
+
using var tempDir = await TemporaryDirectory.CreateWithContentsAsync(
|
|
318
|
+
[
|
|
319
|
+
("project.csproj", """
|
|
320
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
|
321
|
+
<PropertyGroup>
|
|
322
|
+
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
|
|
323
|
+
</PropertyGroup>
|
|
324
|
+
</Project>
|
|
325
|
+
""")
|
|
326
|
+
]);
|
|
327
|
+
var projectPath = Path.Combine(tempDir.DirectoryPath, "project.csproj");
|
|
328
|
+
var properties = await MSBuildHelper.GetProjectPropertiesAsync(
|
|
329
|
+
projectPath,
|
|
330
|
+
propertyNames,
|
|
331
|
+
new TestLogger()
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
Assert.NotNull(properties);
|
|
335
|
+
Assert.Single(properties);
|
|
336
|
+
Assert.Equal("net8.0;net9.0", properties["TARGETFRAMEWORKS"]);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
[Theory]
|
|
340
|
+
[InlineData(".sln")]
|
|
341
|
+
[InlineData(".slnx")]
|
|
342
|
+
public async Task MultipleProjectPropertiesAreNotEvaluatedForSolutions(string extension)
|
|
343
|
+
{
|
|
344
|
+
using var tempDir = await TemporaryDirectory.CreateWithContentsAsync(
|
|
345
|
+
[
|
|
346
|
+
($"solution{extension}", string.Empty)
|
|
347
|
+
]);
|
|
348
|
+
var solutionPath = Path.Combine(tempDir.DirectoryPath, $"solution{extension}");
|
|
349
|
+
var logger = new StringLogger();
|
|
350
|
+
var properties = await MSBuildHelper.GetProjectPropertiesAsync(
|
|
351
|
+
solutionPath,
|
|
352
|
+
["TargetFrameworks", "NETCoreSdkVersion"],
|
|
353
|
+
logger
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
Assert.Null(properties);
|
|
357
|
+
Assert.Empty(logger.Messages);
|
|
358
|
+
}
|
|
359
|
+
|
|
287
360
|
[Theory]
|
|
288
361
|
[MemberData(nameof(GetTargetFrameworkValuesFromProjectData))]
|
|
289
362
|
public async Task GetTargetFrameworkValuesFromProject(string projectContents, string[] expectedTfms)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-nuget
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.396.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.396.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.396.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: debug
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -178,19 +178,19 @@ dependencies:
|
|
|
178
178
|
- !ruby/object:Gem::Version
|
|
179
179
|
version: '1.1'
|
|
180
180
|
- !ruby/object:Gem::Dependency
|
|
181
|
-
name:
|
|
181
|
+
name: turbo_tests2
|
|
182
182
|
requirement: !ruby/object:Gem::Requirement
|
|
183
183
|
requirements:
|
|
184
184
|
- - "~>"
|
|
185
185
|
- !ruby/object:Gem::Version
|
|
186
|
-
version:
|
|
186
|
+
version: 3.2.7
|
|
187
187
|
type: :development
|
|
188
188
|
prerelease: false
|
|
189
189
|
version_requirements: !ruby/object:Gem::Requirement
|
|
190
190
|
requirements:
|
|
191
191
|
- - "~>"
|
|
192
192
|
- !ruby/object:Gem::Version
|
|
193
|
-
version:
|
|
193
|
+
version: 3.2.7
|
|
194
194
|
- !ruby/object:Gem::Dependency
|
|
195
195
|
name: vcr
|
|
196
196
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -587,7 +587,7 @@ licenses:
|
|
|
587
587
|
- MIT
|
|
588
588
|
metadata:
|
|
589
589
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
590
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
590
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.396.0
|
|
591
591
|
rdoc_options: []
|
|
592
592
|
require_paths:
|
|
593
593
|
- lib
|