diff --git a/src/Containers/Microsoft.NET.Build.Containers/KnownStrings.cs b/src/Containers/Microsoft.NET.Build.Containers/KnownStrings.cs index bc68b412d7e4..a81d91cea00b 100644 --- a/src/Containers/Microsoft.NET.Build.Containers/KnownStrings.cs +++ b/src/Containers/Microsoft.NET.Build.Containers/KnownStrings.cs @@ -8,6 +8,8 @@ internal static class KnownStrings public static class Properties { public static readonly string ContainerBaseImage = nameof(ContainerBaseImage); + public static readonly string ContainerFamily = nameof(ContainerFamily); + public static readonly string _ContainerBaseImageTag = nameof(_ContainerBaseImageTag); public static readonly string ContainerRegistry = nameof(ContainerRegistry); /// Note that this is deprecated in favor of public static readonly string ContainerImageName = nameof(ContainerImageName); @@ -22,6 +24,8 @@ public static class Properties public static readonly string ContainerPort = nameof(ContainerPort); public static readonly string ContainerEnvironmentVariable = nameof(ContainerEnvironmentVariable); + public static readonly string ComputeContainerBaseImage = nameof(ComputeContainerBaseImage); + public static readonly string _ComputeContainerBaseImageTag = nameof(_ComputeContainerBaseImageTag); public static readonly string ComputeContainerConfig = nameof(ComputeContainerConfig); public static readonly string AssemblyName = nameof(AssemblyName); public static readonly string ContainerBaseRegistry = nameof(ContainerBaseRegistry); diff --git a/src/Containers/Microsoft.NET.Build.Containers/PublicAPI/net472/PublicAPI.Unshipped.txt b/src/Containers/Microsoft.NET.Build.Containers/PublicAPI/net472/PublicAPI.Unshipped.txt index abc399bee64e..e6a9eae984b5 100644 --- a/src/Containers/Microsoft.NET.Build.Containers/PublicAPI/net472/PublicAPI.Unshipped.txt +++ b/src/Containers/Microsoft.NET.Build.Containers/PublicAPI/net472/PublicAPI.Unshipped.txt @@ -24,6 +24,8 @@ Microsoft.NET.Build.Containers.PortType.udp = 1 -> Microsoft.NET.Build.Container Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.ComputedBaseImageTag.get -> string? Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.ComputeDotnetBaseImageTag() -> void +Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.ContainerFamily.get -> string! +Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.ContainerFamily.set -> void Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.SdkVersion.get -> string! Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.SdkVersion.set -> void Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.TargetFrameworkVersion.get -> string! diff --git a/src/Containers/Microsoft.NET.Build.Containers/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/src/Containers/Microsoft.NET.Build.Containers/PublicAPI/net8.0/PublicAPI.Unshipped.txt index d51a607c56b9..77d32872c72e 100644 --- a/src/Containers/Microsoft.NET.Build.Containers/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ b/src/Containers/Microsoft.NET.Build.Containers/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -112,6 +112,8 @@ Microsoft.NET.Build.Containers.PortType Microsoft.NET.Build.Containers.PortType.tcp = 0 -> Microsoft.NET.Build.Containers.PortType Microsoft.NET.Build.Containers.PortType.udp = 1 -> Microsoft.NET.Build.Containers.PortType Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag +Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.ContainerFamily.get -> string! +Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.ContainerFamily.set -> void Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.SdkVersion.get -> string! Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.SdkVersion.set -> void Microsoft.NET.Build.Containers.Tasks.ComputeDotnetBaseImageTag.TargetFrameworkVersion.get -> string! diff --git a/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageTag.cs b/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageTag.cs index d0fdde5b930d..448daec0845b 100644 --- a/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageTag.cs +++ b/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageTag.cs @@ -25,6 +25,8 @@ public sealed class ComputeDotnetBaseImageTag : Microsoft.Build.Utilities.Task [Required] public string TargetFrameworkVersion { get; set; } + public string ContainerFamily { get; set; } + [Output] public string? ComputedBaseImageTag { get; private set; } @@ -32,6 +34,7 @@ public ComputeDotnetBaseImageTag() { SdkVersion = ""; TargetFrameworkVersion = ""; + ContainerFamily = ""; } public override bool Execute() @@ -39,19 +42,24 @@ public override bool Execute() if (SemanticVersion.TryParse(TargetFrameworkVersion, out var tfm) && tfm.Major < FirstVersionWithNewTaggingScheme) { ComputedBaseImageTag = $"{tfm.Major}.{tfm.Minor}"; - return true; } - - if (SemanticVersion.TryParse(SdkVersion, out var version)) + else if (SemanticVersion.TryParse(SdkVersion, out var version)) { ComputedBaseImageTag = ComputeVersionInternal(version, tfm); - return true; } else { Log.LogError(Resources.Strings.InvalidSdkVersion, SdkVersion); - return false; + return !Log.HasLoggedErrors; + } + + if (!string.IsNullOrWhiteSpace(ContainerFamily)) + { + // for the inferred image tags, 'family' aka 'flavor' comes after the 'version' portion (including any preview/rc segments). + // so it's safe to just append here + ComputedBaseImageTag += $"-{ContainerFamily}"; } + return true; } diff --git a/src/Containers/packaging/build/Microsoft.NET.Build.Containers.targets b/src/Containers/packaging/build/Microsoft.NET.Build.Containers.targets index 9c3d0b17e8d3..8a47d6795d5d 100644 --- a/src/Containers/packaging/build/Microsoft.NET.Build.Containers.targets +++ b/src/Containers/packaging/build/Microsoft.NET.Build.Containers.targets @@ -32,7 +32,8 @@ + TargetFrameworkVersion="$(_TargetFrameworkVersionWithoutV).0" + ContainerFamily="$(ContainerFamily)"> diff --git a/src/Tests/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs b/src/Tests/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs index 7ed58d4a0df2..30f132f077f2 100644 --- a/src/Tests/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs +++ b/src/Tests/Microsoft.NET.Build.Containers.IntegrationTests/TargetsTests.cs @@ -222,4 +222,26 @@ public void WindowsUsersGetLinuxContainers(string sdkPortableRid, string expecte var computedRid = instance.GetProperty(KnownStrings.Properties.ContainerRuntimeIdentifier)?.EvaluatedValue; computedRid.Should().Be(expectedRid); } + + [InlineData("8.0.100", "v7.0", "", "7.0")] + [InlineData("8.0.100-preview.2", "v8.0", "", "8.0.0-preview.2")] + [InlineData("8.0.100-preview.2", "v8.0", "jammy", "8.0.0-preview.2-jammy")] + [InlineData("8.0.100-preview.2", "v8.0", "jammy-chiseled", "8.0.0-preview.2-jammy-chiseled")] + [InlineData("8.0.100-rc.2", "v8.0", "jammy-chiseled", "8.0.0-rc.2-jammy-chiseled")] + [InlineData("8.0.100", "v8.0", "jammy-chiseled", "8.0-jammy-chiseled")] + [Theory] + public void CanTakeContainerBaseFamilyIntoAccount(string sdkVersion, string tfmMajMin, string containerFamily, string expectedTag) + { + var (project, logger, d) = ProjectInitializer.InitProject(new() + { + ["NetCoreSdkVersion"] = sdkVersion, + ["TargetFrameworkVersion"] = tfmMajMin, + [KnownStrings.Properties.ContainerFamily] = containerFamily, + }, projectName: $"{nameof(CanTakeContainerBaseFamilyIntoAccount)}_{sdkVersion}_{tfmMajMin}_{containerFamily}_{expectedTag}"); + using var _ = d; + var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None); + instance.Build(new[]{ _ComputeContainerBaseImageTag }, null, null, out var outputs).Should().BeTrue(String.Join(Environment.NewLine, logger.Errors)); + var computedBaseImageTag = instance.GetProperty(KnownStrings.Properties._ContainerBaseImageTag)?.EvaluatedValue; + computedBaseImageTag.Should().Be(expectedTag); + } }