Skip to content

Commit

Permalink
Merge branch 'main' into jupinzer/otel_in_span
Browse files Browse the repository at this point in the history
  • Loading branch information
jpinz authored Mar 1, 2024
2 parents ed47fb8 + 8f5da96 commit 11f3f41
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1774,6 +1774,35 @@ await TestUpdateForProject("Microsoft.AspNetCore.Authentication.JwtBearer", "3.1
""");
}

[Fact]
public async Task UpdateVersionAttribute_InProjectFile_WhereTargetFrameworksIsSelfReferential()
{
// update Newtonsoft.Json from 9.0.1 to 13.0.1
await TestUpdateForProject("Newtonsoft.Json", "9.0.1", "13.0.1",
projectContents: """
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks Condition="!$(TargetFrameworks.Contains('net472'))">$(TargetFrameworks);net472</TargetFrameworks>
<TargetFrameworks Condition="!$(TargetFrameworks.Contains('netstandard2.0'))">$(TargetFrameworks);netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
</ItemGroup>
</Project>
""",
expectedProjectContents: """
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks Condition="!$(TargetFrameworks.Contains('net472'))">$(TargetFrameworks);net472</TargetFrameworks>
<TargetFrameworks Condition="!$(TargetFrameworks.Contains('netstandard2.0'))">$(TargetFrameworks);netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>
""");
}

[Fact]
public async Task UpdateOfNonExistantPackageDoesNothingEvenIfTransitiveDependencyIsPresent()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ public void GetRootedValue_FindsValue()
};

// Act
var rootValue = MSBuildHelper.GetRootedValue(projectContents, propertyInfo);
var (resultType, evaluatedValue, _) = MSBuildHelper.GetEvaluatedValue(projectContents, propertyInfo);

Assert.Equal(MSBuildHelper.EvaluationResultType.Success, resultType);

// Assert
Assert.Equal("""
Expand All @@ -48,7 +50,7 @@ public void GetRootedValue_FindsValue()
<PackageReference Include="Newtonsoft.Json" Version="1.1.1" />
</ItemGroup>
</Project>
""", rootValue);
""", evaluatedValue);
}

[Fact(Timeout = 1000)]
Expand All @@ -74,10 +76,11 @@ public async Task GetRootedValue_DoesNotRecurseAsync()
await Task.Delay(1);

// Act
var ex = Assert.Throws<InvalidDataException>(() => MSBuildHelper.GetRootedValue(projectContents, propertyInfo));
var (resultType, _, errorMessage) = MSBuildHelper.GetEvaluatedValue(projectContents, propertyInfo);

// Assert
Assert.Equal("Property 'PackageVersion1' has a circular reference.", ex.Message);
Assert.Equal(MSBuildHelper.EvaluationResultType.CircularReference, resultType);
Assert.Equal("Property 'PackageVersion1' has a circular reference.", errorMessage);
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

namespace NuGetUpdater.Core;

using EvaluationResult = (MSBuildHelper.EvaluationResultType ResultType, string EvaluatedValue, string? ErrorMessage);

internal static partial class MSBuildHelper
{
public static string MSBuildPath { get; private set; } = string.Empty;
Expand Down Expand Up @@ -57,7 +59,10 @@ public static string[] GetTargetFrameworkMonikers(ImmutableArray<ProjectBuildFil
if (property.Name.Equals("TargetFramework", StringComparison.OrdinalIgnoreCase) ||
property.Name.Equals("TargetFrameworks", StringComparison.OrdinalIgnoreCase))
{
targetFrameworkValues.Add(property.Value);
foreach (var tfm in property.Value.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
targetFrameworkValues.Add(tfm);
}
}
else if (property.Name.Equals("TargetFrameworkVersion", StringComparison.OrdinalIgnoreCase))
{
Expand All @@ -75,8 +80,16 @@ public static string[] GetTargetFrameworkMonikers(ImmutableArray<ProjectBuildFil

foreach (var targetFrameworkValue in targetFrameworkValues)
{
var tfms = targetFrameworkValue;
tfms = GetRootedValue(tfms, propertyInfo);
var (resultType, tfms, errorMessage) =
GetEvaluatedValue(targetFrameworkValue, propertyInfo, propertiesToIgnore: ["TargetFramework", "TargetFrameworks"]);
if (resultType == EvaluationResultType.PropertyIgnored)
{
continue;
}
else if (resultType != EvaluationResultType.Success)
{
throw new InvalidDataException(errorMessage);
}

if (string.IsNullOrEmpty(tfms))
{
Expand Down Expand Up @@ -230,9 +243,13 @@ public static IEnumerable<Dependency> GetTopLevelPackageDependencyInfos(Immutabl
}

// Walk the property replacements until we don't find another one.
packageVersion = GetRootedValue(packageVersion, propertyInfo);
var evaluationResult = GetEvaluatedValue(packageVersion, propertyInfo);
if (evaluationResult.ResultType != EvaluationResultType.Success)
{
throw new InvalidDataException(evaluationResult.ErrorMessage);
}

packageVersion = packageVersion.TrimStart('[', '(').TrimEnd(']', ')');
packageVersion = evaluationResult.EvaluatedValue.TrimStart('[', '(').TrimEnd(']', ')');

// We don't know the version for range requirements or wildcard
// requirements, so return "" for these.
Expand All @@ -245,25 +262,32 @@ public static IEnumerable<Dependency> GetTopLevelPackageDependencyInfos(Immutabl
/// <summary>
/// Given an MSBuild string and a set of properties, returns our best guess at the final value MSBuild will evaluate to.
/// </summary>
/// <param name="msbuildString"></param>
/// <param name="propertyInfo"></param>
/// <returns></returns>
public static string GetRootedValue(string msbuildString, Dictionary<string, string> propertyInfo)
public static EvaluationResult GetEvaluatedValue(string msbuildString, Dictionary<string, string> propertyInfo, params string[] propertiesToIgnore)
{
var ignoredProperties = new HashSet<string>(propertiesToIgnore, StringComparer.OrdinalIgnoreCase);
var seenProperties = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

while (TryGetPropertyName(msbuildString, out var propertyName))
{
if (ignoredProperties.Contains(propertyName))
{
return (EvaluationResultType.PropertyIgnored, msbuildString, $"Property '{propertyName}' is ignored.");
}

if (!seenProperties.Add(propertyName))
{
throw new InvalidDataException($"Property '{propertyName}' has a circular reference.");
return (EvaluationResultType.CircularReference, msbuildString, $"Property '{propertyName}' has a circular reference.");
}

if (!propertyInfo.TryGetValue(propertyName, out var propertyValue))
{
return (EvaluationResultType.PropertyNotFound, msbuildString, $"Property '{propertyName}' was not found.");
}

msbuildString = propertyInfo.TryGetValue(propertyName, out var propertyValue)
? msbuildString.Replace($"$({propertyName})", propertyValue)
: throw new InvalidDataException($"Property '{propertyName}' was not found.");
msbuildString = msbuildString.Replace($"$({propertyName})", propertyValue);
}

return msbuildString;
return (EvaluationResultType.Success, msbuildString, null);
}

public static bool TryGetPropertyName(string versionContent, [NotNullWhen(true)] out string? propertyName)
Expand Down Expand Up @@ -500,4 +524,12 @@ internal static async Task<ImmutableArray<ProjectBuildFile>> LoadBuildFiles(stri

[GeneratedRegex("^\\s*NuGetData::Package=(?<PackageName>[^,]+), Version=(?<PackageVersion>.+)$")]
private static partial Regex PackagePattern();

internal enum EvaluationResultType
{
Success,
PropertyIgnored,
CircularReference,
PropertyNotFound,
}
}

0 comments on commit 11f3f41

Please sign in to comment.