Skip to content

Commit 268b85b

Browse files
author
v-wuzhai
authored
[automated] Merge branch 'release/9.0.1xx' => 'release/9.0.2xx' (#48271)
2 parents 870942b + 9e7e438 commit 268b85b

File tree

4 files changed

+134
-10
lines changed

4 files changed

+134
-10
lines changed

.github/workflows/pr-analysis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
name: PR Analysis
22
on:
33
pull_request:
4-
types: [opened, synchronize, labeled, unlabeled]
4+
types: [opened, labeled, unlabeled]
55
permissions:
66
contents: read
77
pull-requests: read
88
jobs:
99
allowed-labels:
1010
runs-on: ubuntu-latest
1111
steps:
12-
- name: Return error if branch is in lockdown or 'do not merge' label is present
12+
- name: Return error if blocking labels are present in PR
1313
run: echo "Labels on this PR prevent it from being merged. Please contact the repo owners for more information." && exit 1
14-
if: ${{ contains(github.event.pull_request.labels.*.name, 'Branch Lockdown') || contains(github.event.pull_request.labels.*.name, 'DO NOT MERGE') }}
14+
if: ${{ contains(github.event.pull_request.labels.*.name, 'Branch Lockdown') || contains(github.event.pull_request.labels.*.name, 'DO NOT MERGE') || contains(github.event.pull_request.labels.*.name, 'Servicing-consider') || contains(github.event.pull_request.labels.*.name, 'Servicing-more-info') || contains(github.event.pull_request.labels.*.name, 'Servicing-rejected') }}

src/Containers/packaging/build/Microsoft.NET.Build.Containers.targets

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,16 @@
305305
<!--We don't want to skip publishing individual images in case of local daemon podman because podman loads multi-arch tarball differently - only individual image for the current platform.-->
306306
<_SkipContainerPublishing>false</_SkipContainerPublishing>
307307
<_SkipContainerPublishing Condition="$(ContainerArchiveOutputPath) != '' or ( $(ContainerRegistry) == '' and ( $(LocalRegistry) == '' or $(LocalRegistry) == 'Docker' ) )">true</_SkipContainerPublishing>
308-
308+
309309
<!--We want to skip CreateImageIndex task in case of local daemon podman because it is not supported.-->
310310
<_SkipCreateImageIndex>false</_SkipCreateImageIndex>
311311
<_SkipCreateImageIndex Condition="$(ContainerArchiveOutputPath) == '' and $(ContainerRegistry) == '' and $(LocalRegistry) == 'Podman'">true</_SkipCreateImageIndex>
312+
313+
<!-- Figure out what format the inner images should be coerced to -->
314+
<!-- If a user had an opinion, use that -->
315+
<_SingleImageContainerFormat Condition="'$(ContainerImageFormat)' != ''">$(ContainerImageFormat)</_SingleImageContainerFormat>
316+
<!-- If we are publishing to local tarball or to local Docker, force OCI to prevent mismatches between inner images and the outer manifest -->
317+
<_SingleImageContainerFormat Condition="$(_SkipContainerPublishing) == 'true' ">OCI</_SingleImageContainerFormat>
312318
</PropertyGroup>
313319

314320
<ItemGroup>
@@ -339,15 +345,16 @@
339345
ContainerUser=$(ContainerUser);
340346
ContainerGenerateLabels=$(ContainerGenerateLabels);
341347
ContainerGenerateLabelsImageBaseDigest=$(ContainerGenerateLabelsImageBaseDigest);
342-
_SkipContainerPublishing=$(_SkipContainerPublishing)
348+
_SkipContainerPublishing=$(_SkipContainerPublishing);
349+
ContainerImageFormat=$(_SingleImageContainerFormat)
343350
"/>
344351
<_rids Remove ="$(_rids)" />
345352
</ItemGroup>
346353

347354
<MSBuild
348355
Projects="@(_InnerBuild)"
349356
Targets="Publish;_ParseItemsForPublishingSingleContainer;_PublishSingleContainer"
350-
BuildInParallel="true">
357+
BuildInParallel="$([MSBuild]::ValueOrDefault('$(ContainerPublishInParallel)', 'true'))">
351358
<Output TaskParameter="TargetOutputs" ItemName="GeneratedContainers" />
352359
</MSBuild>
353360

src/Tasks/Microsoft.NET.Build.Tasks/sdk/Sdk.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,5 @@ Copyright (c) .NET Foundation. All rights reserved.
6565
Condition="Exists('$(MSBuildThisFileDirectory)..\..\..\Containers\build\Microsoft.NET.Build.Containers.props')" />
6666

6767
<Import Project="$(_ContainersTargetsDir)Microsoft.NET.Build.Containers.targets"
68-
Condition="$(_IsNotSetContainersTargetsDir) AND Exists('$(_ContainersTargetsDir)Microsoft.NET.Build.Containers.targets') AND '$(TargetFramework)' != ''" />
68+
Condition="$(_IsNotSetContainersTargetsDir) AND Exists('$(_ContainersTargetsDir)Microsoft.NET.Build.Containers.targets')" />
6969
</Project>

test/Microsoft.NET.Build.Containers.IntegrationTests/EndToEndTests.cs

Lines changed: 120 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ private string BuildLocalApp([CallerMemberName] string testName = "TestName", st
353353
public async Task EndToEnd_MultiProjectSolution()
354354
{
355355
ILogger logger = _loggerFactory.CreateLogger(nameof(EndToEnd_MultiProjectSolution));
356-
DirectoryInfo newSolutionDir = new(Path.Combine(TestSettings.TestArtifactsDirectory, $"CreateNewImageTest_EndToEnd_MultiProjectSolution"));
356+
DirectoryInfo newSolutionDir = new(Path.Combine(TestSettings.TestArtifactsDirectory, nameof(EndToEnd_MultiProjectSolution)));
357357

358358
if (newSolutionDir.Exists)
359359
{
@@ -431,6 +431,82 @@ public async Task EndToEnd_MultiProjectSolution()
431431
commandResult.Should().HaveStdOutContaining("Pushed image 'consoleapp:latest'");
432432
}
433433

434+
/// <summary>
435+
/// Tests that a multi-project solution with a library that targets multiple frameworks can be published.
436+
/// This is interesting because before https://github.com/dotnet/sdk/pull/47693 the container targets
437+
/// wouldn't be loaded for multi-TFM project evaluations, so any calls to the PublishContainer target
438+
/// for libraries (which may be multi-targeted even when referenced from a single-target published app project) would fail.
439+
/// It's safe to load the target for libraries in a multi-targeted context because libraries don't have EnableSdkContainerSupport
440+
/// enabled by default, so the target will be skipped.
441+
/// </summary>
442+
[DockerAvailableFact]
443+
public async Task EndToEnd_MultiProjectSolution_with_multitargeted_library()
444+
{
445+
ILogger logger = _loggerFactory.CreateLogger(nameof(EndToEnd_MultiProjectSolution_with_multitargeted_library));
446+
DirectoryInfo newSolutionDir = new(Path.Combine(TestSettings.TestArtifactsDirectory, nameof(EndToEnd_MultiProjectSolution_with_multitargeted_library)));
447+
448+
if (newSolutionDir.Exists)
449+
{
450+
newSolutionDir.Delete(recursive: true);
451+
}
452+
453+
newSolutionDir.Create();
454+
455+
// Create solution with projects
456+
new DotnetNewCommand(_testOutput, "sln", "-n", nameof(EndToEnd_MultiProjectSolution_with_multitargeted_library))
457+
.WithVirtualHive()
458+
.WithWorkingDirectory(newSolutionDir.FullName)
459+
.Execute()
460+
.Should().Pass();
461+
462+
new DotnetNewCommand(_testOutput, "web", "-n", "WebApp")
463+
.WithVirtualHive()
464+
.WithWorkingDirectory(newSolutionDir.FullName)
465+
.Execute()
466+
.Should().Pass();
467+
468+
new DotnetCommand(_testOutput, "sln", "add", Path.Combine("WebApp", "WebApp.csproj"))
469+
.WithWorkingDirectory(newSolutionDir.FullName)
470+
.Execute()
471+
.Should().Pass();
472+
473+
new DotnetNewCommand(_testOutput, "classlib", "-n", "Library")
474+
.WithVirtualHive()
475+
.WithWorkingDirectory(newSolutionDir.FullName)
476+
.Execute()
477+
.Should().Pass();
478+
479+
new DotnetCommand(_testOutput, "sln", "add", Path.Combine("Library", "Library.csproj"))
480+
.WithWorkingDirectory(newSolutionDir.FullName)
481+
.Execute()
482+
.Should().Pass();
483+
484+
// Set TFMs for Library - use current toolset + NS2.0 for compatibility
485+
// also set IsPublishable to false
486+
using (FileStream stream = File.Open(Path.Join(newSolutionDir.FullName, "Library", "Library.csproj"), FileMode.Open, FileAccess.ReadWrite))
487+
{
488+
XDocument document = await XDocument.LoadAsync(stream, LoadOptions.None, CancellationToken.None);
489+
var tfmNode =
490+
document
491+
.Descendants()
492+
.First(e => e.Name.LocalName == "TargetFramework");
493+
var propertyGroupNode = tfmNode.Parent!;
494+
tfmNode.Remove();
495+
propertyGroupNode.Add(new XElement("TargetFrameworks", $"{ToolsetInfo.CurrentTargetFramework};netstandard2.0"));
496+
propertyGroupNode.Add(new XElement("IsPublishable", "false"));
497+
stream.SetLength(0);
498+
await document.SaveAsync(stream, SaveOptions.None, CancellationToken.None);
499+
}
500+
501+
// Publish
502+
CommandResult commandResult = new DotnetCommand(_testOutput, "publish", "/t:PublishContainer")
503+
.WithWorkingDirectory(newSolutionDir.FullName)
504+
.Execute();
505+
506+
commandResult.Should().Pass();
507+
commandResult.Should().HaveStdOutContaining("Pushed image 'webapp:latest'");
508+
}
509+
434510
[DockerAvailableTheory()]
435511
[InlineData("webapi", false)]
436512
[InlineData("webapi", true)]
@@ -1014,7 +1090,7 @@ public void EndToEndMultiArch_RemoteRegistry()
10141090
.And.HaveStdOutContaining($"Pushed image '{imageX64}' to registry '{registry}'.")
10151091
.And.HaveStdOutContaining($"Pushed image '{imageArm64}' to registry '{registry}'.")
10161092
.And.HaveStdOutContaining($"Pushed image index '{imageIndex}' to registry '{registry}'.");
1017-
1093+
10181094
// Check that the containers can be run
10191095
// First pull the image from the registry for each platform
10201096
ContainerCli.PullCommand(
@@ -1031,7 +1107,7 @@ public void EndToEndMultiArch_RemoteRegistry()
10311107
imageFromRegistry)
10321108
.Execute()
10331109
.Should().Pass();
1034-
1110+
10351111
// Run the containers
10361112
ContainerCli.RunCommand(
10371113
_testOutput,
@@ -1353,4 +1429,45 @@ static string[] DecideEntrypoint(string rid, string appName, string workingDir)
13531429
return new[] { $"{workingDir}/{binary}" };
13541430
}
13551431
}
1432+
1433+
[DockerAvailableFact(checkContainerdStoreAvailability: true)]
1434+
public void EnforcesOciSchemaForMultiRIDTarballOutput()
1435+
{
1436+
string imageName = NewImageName();
1437+
string tag = "1.0";
1438+
1439+
// Create new console app
1440+
DirectoryInfo newProjectDir = CreateNewProject("webapp");
1441+
1442+
// Run PublishContainer for multi-arch with ContainerGenerateLabels
1443+
var publishResult = new DotnetCommand(
1444+
_testOutput,
1445+
"publish",
1446+
"/t:PublishContainer",
1447+
"/p:RuntimeIdentifiers=\"linux-x64;linux-arm64\"",
1448+
$"/p:ContainerBaseImage={DockerRegistryManager.FullyQualifiedBaseImageAspNet}",
1449+
$"/p:ContainerRepository={imageName}",
1450+
$"/p:ContainerImageTag={tag}",
1451+
"/p:EnableSdkContainerSupport=true",
1452+
"/p:ContainerArchiveOutputPath=archive.tar.gz",
1453+
"-getProperty:GeneratedImageIndex",
1454+
"-getItem:GeneratedContainers",
1455+
"/bl")
1456+
.WithWorkingDirectory(newProjectDir.FullName)
1457+
.Execute();
1458+
1459+
publishResult.Should().Pass();
1460+
var jsonDump = JsonDocument.Parse(publishResult.StdOut);
1461+
var index = JsonDocument.Parse(jsonDump.RootElement.GetProperty("Properties").GetProperty("GeneratedImageIndex").ToString());
1462+
var containers = jsonDump.RootElement.GetProperty("Items").GetProperty("GeneratedContainers").EnumerateArray().ToArray();
1463+
1464+
index.RootElement.GetProperty("mediaType").GetString().Should().Be("application/vnd.oci.image.index.v1+json");
1465+
containers.Should().HaveCount(2);
1466+
foreach (var container in containers)
1467+
{
1468+
container.GetProperty("ManifestMediaType").GetString().Should().Be("application/vnd.oci.image.manifest.v1+json");
1469+
}
1470+
// Cleanup
1471+
newProjectDir.Delete(true);
1472+
}
13561473
}

0 commit comments

Comments
 (0)