diff --git a/src/Containers/packaging/build/Microsoft.NET.Build.Containers.targets b/src/Containers/packaging/build/Microsoft.NET.Build.Containers.targets index 50458adc2a37..2ec6d1664af5 100644 --- a/src/Containers/packaging/build/Microsoft.NET.Build.Containers.targets +++ b/src/Containers/packaging/build/Microsoft.NET.Build.Containers.targets @@ -34,10 +34,10 @@ - $(RuntimeIdentifiers) - $(RuntimeIdentifier) + $(RuntimeIdentifier) + $(RuntimeIdentifiers) linux-$(NETCoreSdkPortableRuntimeIdentifier.Split('-')[1]) <_ContainerIsUsingMicrosoftDefaultImages Condition="'$(ContainerBaseImage)' == ''">true @@ -45,8 +45,8 @@ - <_TargetRuntimeIdentifiers Include="$(ContainerRuntimeIdentifiers)" Condition="'$(ContainerRuntimeIdentifiers)' != ''" /> - <_TargetRuntimeIdentifiers Include="$(ContainerRuntimeIdentifier)" Condition="'$(ContainerRuntimeIdentifiers)' == ''" /> + <_TargetRuntimeIdentifiers Include="$(ContainerRuntimeIdentifier)" Condition="'$(ContainerRuntimeIdentifier)' != ''" /> + <_TargetRuntimeIdentifiers Include="$(ContainerRuntimeIdentifiers)" Condition="@(_TargetRuntimeIdentifiers->Count()) == 0" /> @@ -400,7 +400,14 @@ Condition="'$(IsPublishable)' == 'true' AND '$(EnableSdkContainerSupport)' == 'true'"> <_IsMultiTFMBuild Condition="'$(TargetFrameworks)' != '' and '$(TargetFramework)' == ''">true - <_IsMultiRIDBuild Condition="'$(BuildingInsideVisualStudio)' != 'true' and (('$(RuntimeIdentifiers)' != '' and '$(RuntimeIdentifier)' == '') or ('$(ContainerRuntimeIdentifiers)' != '' and '$(ContainerRuntimeIdentfier)' == ''))">true + + <_HasCRIDsAndNoCRID Condition="'$(ContainerRuntimeIdentifiers)' != '' and '$(ContainerRuntimeIdentifier)' == ''">true + <_HasRIDs Condition="'$(RuntimeIdentifiers)' != ''">true + <_NoCRIDsOrCRIDorRID Condition="'$(ContainerRuntimeIdentifiers)' == '' and '$(ContainerRuntimeIdentifier)' == '' and '$(RuntimeIdentifier)' == ''">true + <_IsMultiRIDBuild Condition="'$(BuildingInsideVisualStudio)' != 'true' and ('$(_HasCRIDsAndNoCRID)' == true or ('$(_HasRIDs)' == 'true' and '$(_NoCRIDsOrCRIDorRID)' == 'true'))">true <_IsSingleRIDBuild Condition="'$(_IsMultiRIDBuild)' == ''">true diff --git a/test/Microsoft.NET.Build.Containers.IntegrationTests/EndToEndTests.cs b/test/Microsoft.NET.Build.Containers.IntegrationTests/EndToEndTests.cs index 3d9e24147556..82c7bfabec72 100644 --- a/test/Microsoft.NET.Build.Containers.IntegrationTests/EndToEndTests.cs +++ b/test/Microsoft.NET.Build.Containers.IntegrationTests/EndToEndTests.cs @@ -780,6 +780,108 @@ public void EndToEndMultiArch_LocalRegistry() newProjectDir.Delete(true); } + [DockerAvailableFact] + public void MultiArchStillAllowsSingleRID() + { + string imageName = NewImageName(); + string imageTag = "1.0"; + string qualifiedImageName = $"{imageName}:{imageTag}"; + + // Create a new console project + DirectoryInfo newProjectDir = CreateNewProject("console"); + + // Run PublishContainer for multi-arch-capable, but single-arch actual + CommandResult commandResult = new DotnetCommand( + _testOutput, + "publish", + "/t:PublishContainer", + // make it so the app is _able_ to target both linux TFMs + "/p:RuntimeIdentifiers=\"linux-x64;linux-arm64\"", + // and that it opts into to multi-targeting containers for both of those linux TFMs + "/p:ContainerRuntimeIdentifiers=\"linux-x64;linux-arm64\"", + // but then only actually publishes for one of them + "/p:ContainerRuntimeIdentifier=linux-x64", + $"/p:ContainerBaseImage={DockerRegistryManager.FullyQualifiedBaseImageAspNet}", + $"/p:ContainerRepository={imageName}", + $"/p:ContainerImageTag={imageTag}", + "/p:EnableSdkContainerSupport=true", + "/bl") + .WithWorkingDirectory(newProjectDir.FullName) + .Execute(); + + // Check that the app was published for each RID, + // images were created locally for each RID + // and image index was NOT created + commandResult.Should().Pass() + // no rid-specific path because we didn't pass RuntimeIdentifier + .And.NotHaveStdOutContaining(GetPublishArtifactsPath(newProjectDir.FullName, "linux-x64")) + .And.HaveStdOutContaining($"Pushed image '{qualifiedImageName}' to local registry") + .And.NotHaveStdOutContaining("Pushed image index"); + + // Check that the containers can be run + CommandResult processResultX64 = ContainerCli.RunCommand( + _testOutput, + "--rm", + "--name", + $"test-container-{imageName}", + qualifiedImageName) + .Execute(); + processResultX64.Should().Pass().And.HaveStdOut("Hello, World!"); + + // Cleanup + newProjectDir.Delete(true); + } + + [DockerAvailableFact] + public void MultiArchStillAllowsSingleRIDUsingJustRIDProperties() + { + string imageName = NewImageName(); + string imageTag = "1.0"; + string qualifiedImageName = $"{imageName}:{imageTag}"; + + // Create a new console project + DirectoryInfo newProjectDir = CreateNewProject("console"); + + // Run PublishContainer for multi-arch-capable, but single-arch actual + CommandResult commandResult = new DotnetCommand( + _testOutput, + "publish", + "/t:PublishContainer", + // make it so the app is _able_ to target both linux TFMs + "/p:RuntimeIdentifiers=\"linux-x64;linux-arm64\"", + // but then only actually publishes for one of them + "-r", "linux-x64", + $"/p:ContainerBaseImage={DockerRegistryManager.FullyQualifiedBaseImageAspNet}", + $"/p:ContainerRepository={imageName}", + $"/p:ContainerImageTag={imageTag}", + "/p:EnableSdkContainerSupport=true", + "/bl") + .WithWorkingDirectory(newProjectDir.FullName) + .Execute(); + + // Check that the app was published for each RID, + // images were created locally for each RID + // and image index was NOT created + commandResult.Should().Pass() + .And.HaveStdOutContaining(GetPublishArtifactsPath(newProjectDir.FullName, "linux-x64", configuration: "Release")) + .And.NotHaveStdOutContaining(GetPublishArtifactsPath(newProjectDir.FullName, "linux-arm64", configuration: "Release")) + .And.HaveStdOutContaining($"Pushed image '{qualifiedImageName}' to local registry") + .And.NotHaveStdOutContaining("Pushed image index"); + + // Check that the containers can be run + CommandResult processResultX64 = ContainerCli.RunCommand( + _testOutput, + "--rm", + "--name", + $"test-container-{imageName}-x64", + qualifiedImageName) + .Execute(); + processResultX64.Should().Pass().And.HaveStdOut("Hello, World!"); + + // Cleanup + newProjectDir.Delete(true); + } + private DirectoryInfo CreateNewProject(string template, [CallerMemberName] string callerMemberName = "") { DirectoryInfo newProjectDir = new DirectoryInfo(Path.Combine(TestSettings.TestArtifactsDirectory, callerMemberName)); @@ -800,8 +902,8 @@ private DirectoryInfo CreateNewProject(string template, [CallerMemberName] strin return newProjectDir; } - private string GetPublishArtifactsPath(string projectDir, string rid) - => Path.Combine(projectDir, "bin", "Debug", ToolsetInfo.CurrentTargetFramework, rid, "publish"); + private string GetPublishArtifactsPath(string projectDir, string rid, string configuration = "Debug") + => Path.Combine(projectDir, "bin", configuration, ToolsetInfo.CurrentTargetFramework, rid, "publish"); [DockerIsAvailableAndSupportsArchFact("linux/arm64")] public void EndToEndMultiArch_ArchivePublishing() @@ -1176,7 +1278,7 @@ public void EndToEndMultiArch_Labels() // Run PublishContainer for multi-arch with ContainerGenerateLabels new DotnetCommand( _testOutput, - "build", + "publish", "/t:PublishContainer", "/p:RuntimeIdentifiers=\"linux-x64;linux-arm64\"", $"/p:ContainerBaseImage={DockerRegistryManager.FullyQualifiedBaseImageAspNet}",