Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[automated] Merge branch 'release/9.0.3xx' => 'main' #46908

Merged
merged 105 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
81bcbf3
fix e2e test after checking option 'Use containerd for pulling and st…
Jan 28, 2025
01a9c07
refactor BuiltImage
Jan 29, 2025
d973c0e
refactor single-arch oci tarball publishing
Jan 29, 2025
2363f94
implement loading multi-arch image as a tarball and to a local registry
Jan 31, 2025
068d073
implement publishing to tarball/local daemon/remote registry in Creat…
Jan 31, 2025
8d52899
move Telemetry into a seperate file
Jan 31, 2025
0399310
move Telemetry class to another folder
Jan 31, 2025
ec26765
extract publishing image logic into a seperate class
Jan 31, 2025
7acc5e9
refactor ImagePublisher
Jan 31, 2025
181b6fa
skip publishing individual images in case of tarball and local daemon…
Feb 1, 2025
ec09d05
update public api
Feb 1, 2025
5e38e73
skip CreateImageIndex task in case of local damon podman publishing a…
Feb 1, 2025
88c613a
refactor CreateImageIndex task; improve logging; log tip for enabling…
Feb 1, 2025
6b147e1
add support for multi tagoci tarball
Feb 1, 2025
999368f
fix test EndToEndMultiArch_LocalRegistry
Feb 2, 2025
0c9bdd1
check docker availability before arch support in tests
surayya-MS Dec 4, 2024
7b09eb9
refactoring
Feb 2, 2025
6e1035b
fixed multi-arch e2e tests
Feb 2, 2025
9b3fd7e
cleanup
Feb 2, 2025
fb04982
refactoring: make BuiltImage a class instead of a struct
Feb 2, 2025
73b120d
rearrange functions order in DockerCli for easier review
Feb 2, 2025
c8d4e09
rearrange functions again
Feb 2, 2025
f4f1754
add back log message about building image index
Feb 2, 2025
fc80348
extract error messages into Strings
Feb 2, 2025
f2909c1
fix typo in log message
Feb 3, 2025
a61aad5
extract image index creation from DockerCli into ImageIndexGenerator
Feb 3, 2025
51d9cc8
cleanup
Feb 3, 2025
a0c3a56
add more ImageIndexGenertorTests
Feb 3, 2025
3078ea8
check if containerd store is enabled before loading
Feb 3, 2025
adadcc2
Delete spurious error
Forgind Feb 5, 2025
af3a548
cleanup targets
Feb 5, 2025
69026ea
add docker.io/library prefix to image name annotation; fix json seria…
Feb 5, 2025
a821ac2
delete empty lines
Feb 5, 2025
8bea2ec
fix EndToEndMultiArch_ArchivePublishing test
Feb 5, 2025
2e6adab
update EndToEndMultiArch_RemoteRegistry test since containerd store i…
Feb 5, 2025
929c2b3
go back to running containers by image and not imageId for multi-arch…
Feb 5, 2025
e46389b
implement skipping tests if containerd image store is not enabled
Feb 5, 2025
299e6d1
remove using
Feb 5, 2025
2c1705b
Merge branch 'release/8.0.4xx' into multi-arch-tarballs
surayya-MS Feb 5, 2025
674ee0e
refactor to bring back GeneratedImageIndex; fix ImageIndexGeneratorTests
Feb 5, 2025
adaffdd
small fix
Feb 5, 2025
757a0ef
Merge remote-tracking branch 'origin/multi-arch-tarballs' into multi-…
Feb 5, 2025
c6c0826
Update dependencies from https://github.com/dotnet/templating build 2…
dotnet-maestro[bot] Feb 6, 2025
3285270
make BuiltImage and MultiArchImage readonly structs
Feb 6, 2025
aef3546
Merge branch 'release/8.0.4xx' into multi-arch-tarballs
surayya-MS Feb 6, 2025
9cea231
if ArchiveOutputPath does't have file extension then treat it as dire…
Feb 6, 2025
d998510
trim BaseRegistry before checking null or empty
Feb 6, 2025
5094a41
BaseRegistry shouldn't be required parameter
Feb 6, 2025
74b793a
Merge branch 'release/8.0.4xx' of https://github.com/dotnet/sdk into …
v-wuzhai Feb 7, 2025
b9a63ca
Update dependencies from https://github.com/dotnet/templating build 2…
dotnet-maestro[bot] Feb 7, 2025
8631aec
Merge branch 'release/8.0.4xx' of https://github.com/dotnet/sdk into …
v-wuzhai Feb 8, 2025
e9f4af3
address comments
Feb 8, 2025
65837f6
refactor ImagePublisher
Feb 8, 2025
960bb7d
remove BuildEngine null check before logging
Feb 8, 2025
16b98ae
Merge branch 'release/8.0.4xx' into multi-arch-tarballs
surayya-MS Feb 8, 2025
63847ba
register task resources for CreateImageIndex
Feb 8, 2025
72b4bf0
optimize ParseImages in CreateImageIndex
Feb 10, 2025
0f5e6c8
fix setting annotation image name prefix: set to 'docker.io/' when re…
Feb 10, 2025
f09c5c4
move DockerIsAvailableAndSupportsArchTheoryAttribute to its own file;…
Feb 10, 2025
8103a1c
[release/8.0.4xx] Update dependencies from dotnet/templating (#46590)
nagilson Feb 11, 2025
e78c097
[release/8.0.4xx] Multi-arch OCI images export as tarballs (#46467)
marcpopMSFT Feb 11, 2025
ca5f4da
Handle bad upgrade state without blocking the SDK (#46540)
marcpopMSFT Feb 11, 2025
bca34b9
[release/8.0.4xx] Manual Backport of #40611 to 8.0.4xx - Allow users …
baronfel Feb 11, 2025
6b995c0
Update dependencies from https://github.com/dotnet/msbuild build 2025…
dotnet-maestro[bot] Feb 12, 2025
fbe3b31
Update dependencies from https://github.com/dotnet/arcade build 20250…
dotnet-maestro[bot] Feb 12, 2025
d4b3ed3
Merge branch 'release/9.0.1xx' of https://github.com/dotnet/sdk into …
v-wuzhai Feb 12, 2025
97260ce
Update dependencies from https://github.com/dotnet/templating build 2…
dotnet-maestro[bot] Feb 12, 2025
affb751
Update dependencies from https://github.com/dotnet/templating build 2…
dotnet-maestro[bot] Feb 12, 2025
a77f8db
Update dependencies from https://github.com/dotnet/templating build 2…
dotnet-maestro[bot] Feb 12, 2025
da94f40
add BaseImageDigest param to CreateImageIndex task
surayya-MS Feb 12, 2025
e796fde
Update dependencies from https://github.com/dotnet/msbuild build 2025…
dotnet-maestro[bot] Feb 12, 2025
70393ec
.NET Source-Build 9.0.103 February 2025 Updates (#46729)
dotnet-sb-bot Feb 12, 2025
5c29eb7
delete file that was renamed
surayya-MS Feb 12, 2025
1c46976
Merge branch 'release/9.0.1xx' into merge/release/8.0.4xx-to-release/…
surayya-MS Feb 12, 2025
702936d
Update dependencies from https://github.com/dotnet/scenario-tests bui…
dotnet-maestro[bot] Feb 12, 2025
6728bc4
Update dependencies from https://github.com/dotnet/scenario-tests bui…
dotnet-maestro[bot] Feb 12, 2025
e2db10d
delete file that was renamed
surayya-MS Feb 12, 2025
b016cd0
Merge remote-tracking branch 'dotnet-sdk/merge/release/8.0.4xx-to-rel…
surayya-MS Feb 12, 2025
07e7dfe
Revert "delete file that was renamed"
surayya-MS Feb 12, 2025
426c92d
remove ConfigureAwait in ArchiveFileRegistryTests
surayya-MS Feb 12, 2025
22d8996
[release/9.0.1xx] Update dependencies from dotnet/msbuild (#46757)
nagilson Feb 12, 2025
8662c02
Merge branch 'release/9.0.1xx' into darc-release/9.0.1xx-1833fc1b-009…
nagilson Feb 12, 2025
511ed1f
[release/9.0.2xx] Update dependencies from dotnet/templating (#46775)
nagilson Feb 12, 2025
8c6f43b
[release/9.0.2xx] Update dependencies from dotnet/msbuild (#46777)
nagilson Feb 12, 2025
e81bc47
[release/9.0.2xx] Update dependencies from dotnet/scenario-tests (#46…
nagilson Feb 12, 2025
60ae371
[release/9.0.1xx] Update dependencies from dotnet/scenario-tests (#46…
nagilson Feb 12, 2025
eac887c
Merge remote-tracking branch 'upstream/release/9.0.1xx' into darc-rel…
nagilson Feb 12, 2025
47683da
Merge branch 'release/9.0.1xx' into merge/release/8.0.4xx-to-release/…
nagilson Feb 12, 2025
60bfe7c
[release/9.0.1xx] Update dependencies from dotnet/templating (#46766)
nagilson Feb 13, 2025
54e82b9
[automated] Merge branch 'release/8.0.4xx' => 'release/9.0.1xx' (#46744)
surayya-MS Feb 13, 2025
08f9eb5
Update dependencies from https://github.com/dotnet/roslyn build 20250…
dotnet-maestro[bot] Feb 13, 2025
14158f8
[release/9.0.1xx] Update dependencies from dotnet/arcade (#46760)
v-wuzhai Feb 13, 2025
ffe4458
[release/9.0.2xx] Update dependencies from dotnet/roslyn (#46806)
v-wuzhai Feb 13, 2025
530c54c
Merge branch 'release/9.0.2xx' of https://github.com/dotnet/sdk into …
v-wuzhai Feb 13, 2025
c82cd2e
[automated] Merge branch 'release/9.0.1xx' => 'release/9.0.2xx' (#46781)
surayya-MS Feb 13, 2025
4e9565d
Add test case for adding projects outside solution dir descendants (#…
edvilme Feb 14, 2025
3079516
Merge branch 'release/9.0.3xx' of https://github.com/dotnet/sdk into …
v-wuzhai Feb 17, 2025
56ce44b
[automated] Merge branch 'release/9.0.2xx' => 'release/9.0.3xx' (#46870)
v-wuzhai Feb 17, 2025
c3f86d6
Update dependencies from https://github.com/microsoft/vstest build 20…
dotnet-maestro[bot] Feb 18, 2025
857d454
Update dependencies from https://github.com/dotnet/roslyn build 20250…
dotnet-maestro[bot] Feb 18, 2025
25b4940
[release/9.0.3xx] Update dependencies from microsoft/vstest (#46903)
v-wuzhai Feb 18, 2025
dab660e
[release/9.0.3xx] Update dependencies from dotnet/roslyn (#46904)
v-wuzhai Feb 18, 2025
7aa3163
Merge branch 'main' of https://github.com/dotnet/sdk into merge/relea…
v-wuzhai Feb 18, 2025
cbb033c
Remove duplicate node
v-wuzhai Feb 18, 2025
8f39695
fix Microsoft.NET.Build.Containers.targets
surayya-MS Feb 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Cli/dotnet/commands/InstallingWorkloadCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ private IEnumerable<ManifestVersionUpdate> InstallWorkloadSet(ITransactionContex
Reporter.WriteLine(string.Format(Strings.NewWorkloadSet, workloadSetVersion));
var workloadSet = _workloadInstaller.InstallWorkloadSet(context, workloadSetVersion);

return _workloadManifestUpdater.CalculateManifestUpdatesForWorkloadSet(workloadSet);
return workloadSet is null ? Enumerable.Empty<ManifestVersionUpdate>() : _workloadManifestUpdater.CalculateManifestUpdatesForWorkloadSet(workloadSet);
}

protected async Task<List<WorkloadDownload>> GetDownloads(IEnumerable<WorkloadId> workloadIds, bool skipManifestUpdate, bool includePreview, string downloadFolder = null,
Expand Down
29 changes: 22 additions & 7 deletions src/Containers/Microsoft.NET.Build.Containers/BuiltImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,51 @@ internal readonly struct BuiltImage
/// <summary>
/// Gets image digest.
/// </summary>
internal required string ImageDigest { get; init; }
internal string? ImageDigest { get; init; }

/// <summary>
/// Gets image SHA.
/// </summary>
internal required string ImageSha { get; init; }
internal string? ImageSha { get; init; }

/// <summary>
/// Gets image size.
/// Gets image manifest.
/// </summary>
internal required long ImageSize { get; init; }
internal required string Manifest { get; init; }

/// <summary>
/// Gets image manifest.
/// Gets manifest digest.
/// </summary>
internal required ManifestV2 Manifest { get; init; }
internal required string ManifestDigest { get; init; }

/// <summary>
/// Gets manifest mediaType.
/// </summary>
internal required string ManifestMediaType { get; init; }

/// <summary>
/// Gets image layers.
/// </summary>
internal List<ManifestLayer>? Layers { get; init; }

/// <summary>
/// Gets image OS.
/// </summary>
internal string? OS { get; init; }

/// <summary>
/// Gets image architecture.
/// </summary>
internal string? Architecture { get; init; }

/// <summary>
/// Gets layers descriptors.
/// </summary>
internal IEnumerable<Descriptor> LayerDescriptors
{
get
{
List<ManifestLayer> layersNode = Manifest.Layers ?? throw new NotImplementedException("Tried to get layer information but there is no layer node?");
List<ManifestLayer> layersNode = Layers ?? throw new NotImplementedException("Tried to get layer information but there is no layer node?");
foreach (ManifestLayer layer in layersNode)
{
yield return new(layer.mediaType, layer.digest, layer.size);
Expand Down
10 changes: 10 additions & 0 deletions src/Containers/Microsoft.NET.Build.Containers/DigestUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ internal sealed class DigestUtils
/// </summary>
internal static string GetDigestFromSha(string sha) => $"sha256:{sha}";

internal static string GetShaFromDigest(string digest)
{
if (!digest.StartsWith("sha256:", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException($"Invalid digest '{digest}'. Digest must start with 'sha256:'.");
}

return digest.Substring("sha256:".Length);
}

/// <summary>
/// Gets the SHA of <paramref name="str"/>.
/// </summary>
Expand Down
9 changes: 5 additions & 4 deletions src/Containers/Microsoft.NET.Build.Containers/ImageBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

using System.Text;
using System.Text.RegularExpressions;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.NET.Build.Containers.Resources;

namespace Microsoft.NET.Build.Containers;


/// <summary>
/// The class builds new image based on the base image.
/// </summary>
Expand Down Expand Up @@ -91,9 +91,10 @@ internal BuiltImage Build()
Config = imageJsonStr,
ImageDigest = imageDigest,
ImageSha = imageSha,
ImageSize = imageSize,
Manifest = newManifest,
ManifestMediaType = ManifestMediaType
Manifest = JsonSerializer.SerializeToNode(newManifest)?.ToJsonString() ?? "",
ManifestDigest = newManifest.GetDigest(),
ManifestMediaType = ManifestMediaType,
Layers = _manifest.Layers
};
}

Expand Down
116 changes: 77 additions & 39 deletions src/Containers/Microsoft.NET.Build.Containers/ImageIndexGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,100 +1,138 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using Microsoft.NET.Build.Containers.Resources;
using Microsoft.NET.Build.Containers.Tasks;

namespace Microsoft.NET.Build.Containers;

internal readonly struct ImageInfo
{
internal string Config { get; init; }
internal string ManifestDigest { get; init; }
internal string Manifest { get; init; }
internal string ManifestMediaType { get; init; }

public override string ToString() => ManifestDigest;
}

internal static class ImageIndexGenerator
{
/// <summary>
/// Generates an image index from the given images.
/// </summary>
/// <param name="imageInfos"></param>
/// <param name="images">Images to generate image index from.</param>
/// <returns>Returns json string of image index and image index mediaType.</returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="NotSupportedException"></exception>
internal static (string, string) GenerateImageIndex(ImageInfo[] imageInfos)
internal static (string, string) GenerateImageIndex(BuiltImage[] images)
{
if (imageInfos.Length == 0)
if (images.Length == 0)
{
throw new ArgumentException(string.Format(Strings.ImagesEmpty));
throw new ArgumentException(Strings.ImagesEmpty);
}

string manifestMediaType = imageInfos[0].ManifestMediaType;
string manifestMediaType = images[0].ManifestMediaType;

if (!imageInfos.All(image => string.Equals(image.ManifestMediaType, manifestMediaType, StringComparison.OrdinalIgnoreCase)))
if (!images.All(image => string.Equals(image.ManifestMediaType, manifestMediaType, StringComparison.OrdinalIgnoreCase)))
{
throw new ArgumentException(Strings.MixedMediaTypes);
}

if (manifestMediaType == SchemaTypes.DockerManifestV2)
{
return GenerateImageIndex(imageInfos, SchemaTypes.DockerManifestV2, SchemaTypes.DockerManifestListV2);
return (GenerateImageIndex(images, SchemaTypes.DockerManifestV2, SchemaTypes.DockerManifestListV2), SchemaTypes.DockerManifestListV2);
}
else if (manifestMediaType == SchemaTypes.OciManifestV1)
{
return GenerateImageIndex(imageInfos, SchemaTypes.OciManifestV1, SchemaTypes.OciImageIndexV1);
return (GenerateImageIndex(images, SchemaTypes.OciManifestV1, SchemaTypes.OciImageIndexV1), SchemaTypes.OciImageIndexV1);
}
else
{
throw new NotSupportedException(string.Format(Strings.UnsupportedMediaType, manifestMediaType));
}
}

private static (string, string) GenerateImageIndex(ImageInfo[] images, string manifestMediaType, string imageIndexMediaType)
/// <summary>
/// Generates an image index from the given images.
/// </summary>
/// <param name="images">Images to generate image index from.</param>
/// <param name="manifestMediaType">Media type of the manifest.</param>
/// <param name="imageIndexMediaType">Media type of the produced image index.</param>
/// <returns>Returns json string of image index and image index mediaType.</returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="NotSupportedException"></exception>
internal static string GenerateImageIndex(BuiltImage[] images, string manifestMediaType, string imageIndexMediaType)
{
if (images.Length == 0)
{
throw new ArgumentException(Strings.ImagesEmpty);
}

// Here we are using ManifestListV2 struct, but we could use ImageIndexV1 struct as well.
// We are filling the same fiels, so we can use the same struct.
// We are filling the same fields, so we can use the same struct.
var manifests = new PlatformSpecificManifest[images.Length];

for (int i = 0; i < images.Length; i++)
{
var image = images[i];

var manifest = new PlatformSpecificManifest
manifests[i] = new PlatformSpecificManifest
{
mediaType = manifestMediaType,
size = image.Manifest.Length,
digest = image.ManifestDigest,
platform = GetArchitectureAndOsFromConfig(image)
size = images[i].Manifest.Length,
digest = images[i].ManifestDigest,
platform = new PlatformInformation
{
architecture = images[i].Architecture!,
os = images[i].OS!
}
};
manifests[i] = manifest;
}

var dockerManifestList = new ManifestListV2
var imageIndex = new ManifestListV2
{
schemaVersion = 2,
mediaType = imageIndexMediaType,
manifests = manifests
};

return (JsonSerializer.SerializeToNode(dockerManifestList)?.ToJsonString() ?? "", dockerManifestList.mediaType);
return GetJsonStringFromImageIndex(imageIndex);
}

private static PlatformInformation GetArchitectureAndOsFromConfig(ImageInfo image)
internal static string GenerateImageIndexWithAnnotations(string manifestMediaType, string manifestDigest, long manifestSize, string repository, string[] tags)
{
var configJson = JsonNode.Parse(image.Config) as JsonObject ??
throw new ArgumentException($"{nameof(image.Config)} should be a JSON object.", nameof(image.Config));
string containerdImageNamePrefix = repository.Contains('/') ? "docker.io/" : "docker.io/library/";

var manifests = new PlatformSpecificOciManifest[tags.Length];
for (int i = 0; i < tags.Length; i++)
{
var tag = tags[i];
manifests[i] = new PlatformSpecificOciManifest
{
mediaType = manifestMediaType,
size = manifestSize,
digest = manifestDigest,
annotations = new Dictionary<string, string>
{
{ "io.containerd.image.name", $"{containerdImageNamePrefix}{repository}:{tag}" },
{ "org.opencontainers.image.ref.name", tag }
}
};
}

var architecture = configJson["architecture"]?.ToString() ??
throw new ArgumentException($"{nameof(image.Config)} should contain 'architecture'.", nameof(image.Config));
var index = new ImageIndexV1
{
schemaVersion = 2,
mediaType = SchemaTypes.OciImageIndexV1,
manifests = manifests
};

var os = configJson["os"]?.ToString() ??
throw new ArgumentException($"{nameof(image.Config)} should contain 'os'.", nameof(image.Config));
return GetJsonStringFromImageIndex(index);
}

private static string GetJsonStringFromImageIndex<T>(T imageIndex)
{
var nullIgnoreOptions = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
// To avoid things like \u002B for '+' especially in media types ("application/vnd.oci.image.manifest.v1\u002Bjson"), we use UnsafeRelaxedJsonEscaping.
var escapeOptions = new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};

return new PlatformInformation { architecture = architecture, os = os };
return JsonSerializer.SerializeToNode(imageIndex, nullIgnoreOptions)?.ToJsonString(escapeOptions) ?? "";
}
}
Loading
Loading