From aee00c5cc58af3d0360bf954f8c9c464db79e082 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:44:18 +0000 Subject: [PATCH 1/5] Initial plan From 8c06e5a011ee509ca2634654d36770488b262293 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:53:45 +0000 Subject: [PATCH 2/5] Fix comparison to use >= for -extra variant support and add tests for .NET 9/10 Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com> --- .../Tasks/ComputeDotnetBaseImageAndTag.cs | 2 +- .../TargetsTests.cs | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs b/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs index 92cd3f5a5c85..fd27b740ad33 100644 --- a/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs +++ b/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs @@ -191,7 +191,7 @@ private bool ComputeRepositoryAndTag([NotNullWhen(true)] out string? repository, && !UsesInvariantGlobalization && versionAllowsUsingAOTAndExtrasImages // the extras only became available on the stable tags of the FirstVersionWithNewTaggingScheme - && (!parsedVersion.IsPrerelease && parsedVersion.Major == FirstVersionWithNewTaggingScheme)) + && (!parsedVersion.IsPrerelease && parsedVersion.Major >= FirstVersionWithNewTaggingScheme)) { Log.LogMessage("Using extra variant because the application needs globalization"); tag += "-extra"; diff --git a/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs b/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs index d0cb12539451..1c96207458a4 100644 --- a/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs +++ b/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs @@ -614,6 +614,49 @@ public void AOTAppsLessThan8WithCulturesDoNotGetExtraImages(string rid, string e computedBaseImageTag.Should().BeEquivalentTo(expectedImage); } + [InlineData("9.0.100", "v9.0", "noble-chiseled", "mcr.microsoft.com/dotnet/runtime:9.0-noble-chiseled-extra")] + [InlineData("10.0.100", "v10.0", "noble-chiseled", "mcr.microsoft.com/dotnet/runtime:10.0-noble-chiseled-extra")] + [Theory] + public void FDDConsoleAppWithCulturesAndOptingIntoChiseledGetsExtrasForNet9AndLater(string sdkVersion, string tfm, string containerFamily, string expectedImage) + { + var (project, logger, d) = ProjectInitializer.InitProject(new() + { + ["NetCoreSdkVersion"] = sdkVersion, + ["TargetFrameworkVersion"] = tfm, + [KnownStrings.Properties.ContainerRuntimeIdentifier] = "linux-x64", + [KnownStrings.Properties.ContainerFamily] = containerFamily, + [KnownStrings.Properties.InvariantGlobalization] = false.ToString(), + }, projectName: $"{nameof(FDDConsoleAppWithCulturesAndOptingIntoChiseledGetsExtrasForNet9AndLater)}_{sdkVersion}_{tfm}_{containerFamily}"); + using var _ = d; + var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None); + instance.Build(new[] { ComputeContainerBaseImage }, null, null, out var outputs).Should().BeTrue(String.Join(Environment.NewLine, logger.Errors)); + var computedBaseImageTag = instance.GetProperty(ContainerBaseImage)?.EvaluatedValue; + computedBaseImageTag.Should().BeEquivalentTo(expectedImage); + } + + [InlineData("9.0.100", "v9.0", "noble-chiseled", "mcr.microsoft.com/dotnet/aspnet:9.0-noble-chiseled-extra")] + [InlineData("10.0.100", "v10.0", "noble-chiseled", "mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled-extra")] + [Theory] + public void FDDAspNetAppWithCulturesAndOptingIntoChiseledGetsExtrasForNet9AndLater(string sdkVersion, string tfm, string containerFamily, string expectedImage) + { + var (project, logger, d) = ProjectInitializer.InitProject(new() + { + ["NetCoreSdkVersion"] = sdkVersion, + ["TargetFrameworkVersion"] = tfm, + [KnownStrings.Properties.ContainerRuntimeIdentifier] = "linux-x64", + [KnownStrings.Properties.ContainerFamily] = containerFamily, + [KnownStrings.Properties.InvariantGlobalization] = false.ToString(), + }, bonusItems: new() + { + [KnownStrings.Items.FrameworkReference] = KnownFrameworkReferences.WebApp + }, projectName: $"{nameof(FDDAspNetAppWithCulturesAndOptingIntoChiseledGetsExtrasForNet9AndLater)}_{sdkVersion}_{tfm}_{containerFamily}"); + using var _ = d; + var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None); + instance.Build(new[] { ComputeContainerBaseImage }, null, null, out var outputs).Should().BeTrue(String.Join(Environment.NewLine, logger.Errors)); + var computedBaseImageTag = instance.GetProperty(ContainerBaseImage)?.EvaluatedValue; + computedBaseImageTag.Should().BeEquivalentTo(expectedImage); + } + [Fact] public void AspNetFDDAppsGetAspNetBaseImage() { From 07dda7b67a62b0d945f8d43d1dd2af1fe7da1ac5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:01:21 +0000 Subject: [PATCH 3/5] Apply code formatting with dotnet format Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com> --- .../Tasks/ComputeDotnetBaseImageAndTag.cs | 5 +++-- .../TargetsTests.cs | 11 +++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs b/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs index fd27b740ad33..898767817493 100644 --- a/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs +++ b/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs @@ -130,7 +130,7 @@ private bool TargetRuntimeIdentiriersAreValid() { if (muslRidsCount == TargetRuntimeIdentifiers.Length) { - IsMuslRid = true; + IsMuslRid = true; } else { @@ -311,7 +311,8 @@ private bool ComputeRepositoryAndTag([NotNullWhen(true)] out string? repository, default: Log.LogError(Resources.Strings.InvalidSdkPrereleaseVersion, channel); return null; - }; + } + ; } private bool UserImageIsMicrosoftBaseImage => UserBaseImage?.StartsWith("mcr.microsoft.com/") ?? false; diff --git a/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs b/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs index 1c96207458a4..0596d96bbed4 100644 --- a/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs +++ b/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs @@ -26,7 +26,7 @@ public void CanDeferContainerAppCommand( }, projectName: $"{nameof(CanDeferContainerAppCommand)}_{prop}_{value}_{string.Join("_", expectedAppCommandArgs)}"); using var _ = d; var instance = project.CreateProjectInstance(ProjectInstanceSettings.None); - instance.Build([ ComputeContainerConfig ], []); + instance.Build([ComputeContainerConfig], []); var computedAppCommand = instance.GetItems(ContainerAppCommand).Select(i => i.EvaluatedInclude); // The test was not testing anything previously, as the list returned was zero length, @@ -169,7 +169,8 @@ public void ShouldNotIncludeSourceControlLabelsUnlessUserOptsIn(bool includeSour labels.Should().NotBeEmpty("Should have evaluated some labels by default") .And.NotContain(label => LabelMatch("org.opencontainers.image.source", repoUrl, label)) .And.NotContain(label => LabelMatch("org.opencontainers.image.revision", commitHash, label)); ; - }; + } + ; } [InlineData("https://git.cosmere.com/shard/whimsy.git", "https://git.cosmere.com/shard/whimsy")] @@ -222,7 +223,8 @@ public void ShouldIncludeBaseImageLabelsUnlessUserOptsOut(bool includeBaseImageL { labels.Should().NotBeEmpty("Should have evaluated some labels by default") .And.NotContain(label => LabelMatch("org.opencontainers.image.base.name", expectedBaseImage, label)); - }; + } + ; } [InlineData(true)] @@ -255,7 +257,8 @@ public void ShouldIncludeSDKAndRuntimeVersionLabelsUnlessUserOptsOut(bool includ labels.Should().NotBeEmpty("Should have evaluated some labels by default") .And.NotContain(label => LabelMatch("net.dot.runtime.majorminor", runtimeMajorMinor, label)) .And.NotContain(label => LabelMatch("net.dot.sdk.version", randomSdkVersion, label)); - }; + } + ; } [InlineData("7.0.100", "v7.0", "7.0")] From 77c1e620673dfe4fbdb410540e17bcee43eeb585 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:03:33 +0000 Subject: [PATCH 4/5] Fix semicolon placement to match repo style Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com> --- .../Tasks/ComputeDotnetBaseImageAndTag.cs | 3 +-- .../TargetsTests.cs | 9 +++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs b/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs index 898767817493..69ced08eae1e 100644 --- a/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs +++ b/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs @@ -311,8 +311,7 @@ private bool ComputeRepositoryAndTag([NotNullWhen(true)] out string? repository, default: Log.LogError(Resources.Strings.InvalidSdkPrereleaseVersion, channel); return null; - } - ; + }; } private bool UserImageIsMicrosoftBaseImage => UserBaseImage?.StartsWith("mcr.microsoft.com/") ?? false; diff --git a/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs b/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs index 0596d96bbed4..e2f88f362aaa 100644 --- a/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs +++ b/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs @@ -169,8 +169,7 @@ public void ShouldNotIncludeSourceControlLabelsUnlessUserOptsIn(bool includeSour labels.Should().NotBeEmpty("Should have evaluated some labels by default") .And.NotContain(label => LabelMatch("org.opencontainers.image.source", repoUrl, label)) .And.NotContain(label => LabelMatch("org.opencontainers.image.revision", commitHash, label)); ; - } - ; + }; } [InlineData("https://git.cosmere.com/shard/whimsy.git", "https://git.cosmere.com/shard/whimsy")] @@ -223,8 +222,7 @@ public void ShouldIncludeBaseImageLabelsUnlessUserOptsOut(bool includeBaseImageL { labels.Should().NotBeEmpty("Should have evaluated some labels by default") .And.NotContain(label => LabelMatch("org.opencontainers.image.base.name", expectedBaseImage, label)); - } - ; + }; } [InlineData(true)] @@ -257,8 +255,7 @@ public void ShouldIncludeSDKAndRuntimeVersionLabelsUnlessUserOptsOut(bool includ labels.Should().NotBeEmpty("Should have evaluated some labels by default") .And.NotContain(label => LabelMatch("net.dot.runtime.majorminor", runtimeMajorMinor, label)) .And.NotContain(label => LabelMatch("net.dot.sdk.version", randomSdkVersion, label)); - } - ; + }; } [InlineData("7.0.100", "v7.0", "7.0")] From 2397fde5ff63a5e703117f54d5f4933b107ab61a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 00:52:13 +0000 Subject: [PATCH 5/5] Add .NET 8.0 test coverage to extra variant tests Co-authored-by: mthalman <15789599+mthalman@users.noreply.github.com> --- .../TargetsTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs b/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs index e2f88f362aaa..2c6b80ace493 100644 --- a/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs +++ b/test/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs @@ -614,6 +614,7 @@ public void AOTAppsLessThan8WithCulturesDoNotGetExtraImages(string rid, string e computedBaseImageTag.Should().BeEquivalentTo(expectedImage); } + [InlineData("8.0.100", "v8.0", "jammy-chiseled", "mcr.microsoft.com/dotnet/runtime:8.0-jammy-chiseled-extra")] [InlineData("9.0.100", "v9.0", "noble-chiseled", "mcr.microsoft.com/dotnet/runtime:9.0-noble-chiseled-extra")] [InlineData("10.0.100", "v10.0", "noble-chiseled", "mcr.microsoft.com/dotnet/runtime:10.0-noble-chiseled-extra")] [Theory] @@ -634,6 +635,7 @@ public void FDDConsoleAppWithCulturesAndOptingIntoChiseledGetsExtrasForNet9AndLa computedBaseImageTag.Should().BeEquivalentTo(expectedImage); } + [InlineData("8.0.100", "v8.0", "jammy-chiseled", "mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled-extra")] [InlineData("9.0.100", "v9.0", "noble-chiseled", "mcr.microsoft.com/dotnet/aspnet:9.0-noble-chiseled-extra")] [InlineData("10.0.100", "v10.0", "noble-chiseled", "mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled-extra")] [Theory]