Skip to content

Commit 5744fd6

Browse files
github-actions[bot]Copilotmitchdenny
authored
[release/9.5] Allow .NET 10 prerelease versions for single-file apphost scenarios (#11616)
* Initial plan * Implement .NET 10 prerelease support for single-file apphost Co-authored-by: mitchdenny <513398+mitchdenny@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mitchdenny <513398+mitchdenny@users.noreply.github.com>
1 parent e44dc82 commit 5744fd6

File tree

2 files changed

+87
-1
lines changed

2 files changed

+87
-1
lines changed

src/Aspire.Cli/DotNet/DotNetSdkInstaller.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ internal sealed class DotNetSdkInstaller(IFeatures features, IConfiguration conf
9090
}
9191

9292
// Check if this version meets the minimum requirement
93-
if (SemVersion.ComparePrecedence(sdkVersion, minVersion) >= 0)
93+
if (MeetsMinimumRequirement(sdkVersion, minVersion, minimumVersion))
9494
{
9595
meetsMinimum = true;
9696
}
@@ -152,4 +152,25 @@ public string GetEffectiveMinimumSdkVersion()
152152
return MinimumSdkVersion;
153153
}
154154
}
155+
156+
/// <summary>
157+
/// Checks if an installed SDK version meets the minimum requirement.
158+
/// For .NET 10.x requirements, allows any .NET 10.x version including prereleases.
159+
/// </summary>
160+
/// <param name="installedVersion">The installed SDK version.</param>
161+
/// <param name="requiredVersion">The required minimum version (parsed).</param>
162+
/// <param name="requiredVersionString">The required version string.</param>
163+
/// <returns>True if the installed version meets the requirement.</returns>
164+
private static bool MeetsMinimumRequirement(SemVersion installedVersion, SemVersion requiredVersion, string requiredVersionString)
165+
{
166+
// Special handling for .NET 10.0.100 requirement - allow any .NET 10.x version
167+
if (requiredVersionString == MinimumSdkVersionSingleFileAppHost)
168+
{
169+
// If we require 10.0.100, accept any version that is >= 10.0.0
170+
return installedVersion.Major >= 10;
171+
}
172+
173+
// For all other requirements, use strict version comparison
174+
return SemVersion.ComparePrecedence(installedVersion, requiredVersion) >= 0;
175+
}
155176
}

tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Aspire.Cli.DotNet;
77
using Aspire.Cli.Resources;
88
using Microsoft.Extensions.Configuration;
9+
using Semver;
910

1011
namespace Aspire.Cli.Tests;
1112

@@ -238,6 +239,70 @@ public void ErrorMessage_Format_IsCorrect()
238239
Assert.Equal("The Aspire CLI requires .NET SDK version 9.0.302 or later. Detected: (not found).", message);
239240
}
240241

242+
[Fact]
243+
public void MeetsMinimumRequirement_AllowsDotNet10Prereleases_ForSingleFileAppHost()
244+
{
245+
// Test the logic we added for allowing .NET 10 prereleases
246+
var installedVersion = SemVersion.Parse("10.0.100-preview.1.25463.5", SemVersionStyles.Strict);
247+
var requiredVersion = SemVersion.Parse("10.0.100", SemVersionStyles.Strict);
248+
var requiredVersionString = "10.0.100";
249+
250+
// Use reflection to access the private method
251+
var method = typeof(DotNetSdkInstaller).GetMethod("MeetsMinimumRequirement",
252+
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
253+
var result = (bool)method!.Invoke(null, new object[] { installedVersion, requiredVersion, requiredVersionString })!;
254+
255+
Assert.True(result);
256+
}
257+
258+
[Fact]
259+
public void MeetsMinimumRequirement_AllowsDotNet10LatestPrerelease_ForSingleFileAppHost()
260+
{
261+
// Test with a more recent .NET 10 prerelease
262+
var installedVersion = SemVersion.Parse("10.1.0-preview.2.25999.99", SemVersionStyles.Strict);
263+
var requiredVersion = SemVersion.Parse("10.0.100", SemVersionStyles.Strict);
264+
var requiredVersionString = "10.0.100";
265+
266+
// Use reflection to access the private method
267+
var method = typeof(DotNetSdkInstaller).GetMethod("MeetsMinimumRequirement",
268+
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
269+
var result = (bool)method!.Invoke(null, new object[] { installedVersion, requiredVersion, requiredVersionString })!;
270+
271+
Assert.True(result);
272+
}
273+
274+
[Fact]
275+
public void MeetsMinimumRequirement_RejectsDotNet9_ForSingleFileAppHost()
276+
{
277+
// Test that .NET 9 is still rejected for single file apphost requirements
278+
var installedVersion = SemVersion.Parse("9.0.999", SemVersionStyles.Strict);
279+
var requiredVersion = SemVersion.Parse("10.0.100", SemVersionStyles.Strict);
280+
var requiredVersionString = "10.0.100";
281+
282+
// Use reflection to access the private method
283+
var method = typeof(DotNetSdkInstaller).GetMethod("MeetsMinimumRequirement",
284+
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
285+
var result = (bool)method!.Invoke(null, new object[] { installedVersion, requiredVersion, requiredVersionString })!;
286+
287+
Assert.False(result);
288+
}
289+
290+
[Fact]
291+
public void MeetsMinimumRequirement_UsesStrictComparison_ForNonSingleFileAppHost()
292+
{
293+
// Test that other version requirements still use strict comparison
294+
var installedVersion = SemVersion.Parse("9.0.301", SemVersionStyles.Strict);
295+
var requiredVersion = SemVersion.Parse("9.0.302", SemVersionStyles.Strict);
296+
var requiredVersionString = "9.0.302";
297+
298+
// Use reflection to access the private method
299+
var method = typeof(DotNetSdkInstaller).GetMethod("MeetsMinimumRequirement",
300+
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
301+
var result = (bool)method!.Invoke(null, new object[] { installedVersion, requiredVersion, requiredVersionString })!;
302+
303+
Assert.False(result);
304+
}
305+
241306
private static IConfiguration CreateEmptyConfiguration()
242307
{
243308
return new ConfigurationBuilder().Build();

0 commit comments

Comments
 (0)