Skip to content

Commit 3dfe17a

Browse files
committed
fix: Add Platform type
1 parent c1b76c5 commit 3dfe17a

File tree

7 files changed

+65
-29
lines changed

7 files changed

+65
-29
lines changed

docs/api/create_docker_container.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Testcontainers' generic container support offers the greatest flexibility and ma
44

55
## Configure container image
66

7-
Use `WithImage(...)` to specify the container image.
7+
To specify the container image, use `WithImage(...)`.
88

99
The simplest overload accepts a `string`:
1010

@@ -13,13 +13,19 @@ _ = new ContainerBuilder()
1313
.WithImage("postgres:15.1");
1414
```
1515

16-
For platform-specific scenarios, `WithImage` also accepts an `IImage`. Using the `DockerImage` implementation, you can explicitly set the platform:
16+
For more advanced scenarios, `WithImage` also supports `IImage`, giving you more control over how the image is represented and its properties are resolved.
17+
18+
If you need to target a specific platform, the `DockerImage` implementation provides an overload that lets you explicitly set the platform, such as `linux/amd64`.
1719

1820
```csharp
1921
_ = new ContainerBuilder()
20-
.WithImage(new DockerImage("postgres:15.1", "linux/amd64"));
22+
.WithImage(new DockerImage("postgres:15.1", new Platform("linux/amd64")));
2123
```
2224

25+
!!!tip
26+
27+
A specifier has the format `<os>|<arch>|<os>/<arch>[/<variant>]`. The user can provide either the operating system or the architecture or both. For more details, [see containerd/platforms](https://github.com/containerd/platforms).
28+
2329
## Configure container start
2430

2531
Both `ENTRYPOINT` and `CMD` allows you to configure an executable and parameters, that a container runs at the start. By default, a container will run whatever `ENTRYPOINT` or `CMD` is specified in the Docker container image. At least one of both configurations is necessary. The container builder implementation supports `WithEntrypoint(params string[])` and `WithCommand(params string[])` to set or override the executable. Ideally, the `ENTRYPOINT` should set the container's executable, whereas the `CMD` sets the default arguments for the `ENTRYPOINT`.

src/Testcontainers/Clients/DockerContainerOperations.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ public async Task<string> RunAsync(IContainerConfiguration configuration, Cancel
202202
var createParameters = new CreateContainerParameters
203203
{
204204
Image = configuration.Image.FullName,
205+
Platform = configuration.Image.Platform,
205206
Name = configuration.Name,
206207
Hostname = configuration.Hostname,
207208
WorkingDir = configuration.WorkingDirectory,

src/Testcontainers/Images/DockerImage.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,15 @@ public DockerImage(string image)
5656
/// <summary>
5757
/// Initializes a new instance of the <see cref="DockerImage" /> class.
5858
/// </summary>
59-
/// <remarks>
60-
/// The supported format for <paramref name="platform" /> is <c>&lt;os&gt;|&lt;arch&gt;|&lt;os&gt;/&lt;arch&gt;[/&lt;variant&gt;]</c>.
61-
/// You can provide the operating system, the architecture, or both.
62-
/// For more details and examples, see <see href="https://github.com/containerd/platforms">containerd/platforms</see>.
63-
/// </remarks>
6459
/// <param name="image">The image.</param>
6560
/// <param name="platform">The platform.</param>
6661
/// <example><c>fedora/httpd:version1.0</c> where <c>fedora/httpd</c> is the repository and <c>version1.0</c> the tag.</example>
6762
public DockerImage(
6863
string image,
69-
string platform)
64+
Platform platform)
7065
: this(GetDockerImage(image))
7166
{
72-
_platform = TrimOrDefault(platform);
67+
_platform = platform.Value;
7368
}
7469

7570
/// <summary>

src/Testcontainers/Images/DockerfileArchive.cs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public IEnumerable<IImage> GetBaseImages()
170170
{
171171
var fromArgs = ParseFromArgs(item.Arg).ToDictionary(arg => arg.Name, arg => arg.Value);
172172
_ = fromArgs.TryGetValue("platform", out var platform);
173-
return new DockerImage(item.Image, platform);
173+
return new DockerImage(item.Image, new Platform(platform));
174174
})
175175
.ToArray();
176176

@@ -339,11 +339,8 @@ private static string ReplaceVariables(string line, IDictionary<string, string>
339339
/// quotes (<c>'</c>) are supported. Whitespaces outside of quotes are
340340
/// treated as separators.
341341
///
342-
/// For example, the line:
343-
/// <code>
344-
/// --pull=always --platform="linux/amd64"
345-
/// </code>
346-
/// becomes:
342+
/// E.g., the line <c>--pull=always --platform="linux/amd64"</c> becomes:
343+
///
347344
/// <list type="bullet">
348345
/// <item>
349346
/// <description>
@@ -393,7 +390,7 @@ private static string ReplaceVariables(string line, IDictionary<string, string>
393390

394391
if (i > start)
395392
{
396-
yield return ParseFlag(line.Substring(start, i - start));
393+
yield return ParseArg(line.Substring(start, i - start));
397394
}
398395

399396
start = i + 1;
@@ -406,18 +403,18 @@ private static string ReplaceVariables(string line, IDictionary<string, string>
406403

407404
if (line.Length > start)
408405
{
409-
yield return ParseFlag(line.Substring(start));
406+
yield return ParseArg(line.Substring(start));
410407
}
411408
}
412409

413410
/// <summary>
414-
/// Splits a single flag token into a flag name and an optional value.
411+
/// Splits a single arg into flag name and an optional value.
415412
/// </summary>
416-
/// <param name="flag">A single flag token, optionally containing an equals sign and value.</param>
413+
/// <param name="arg">A single arg, optionally containing an equals sign and value.</param>
417414
/// <returns>A tuple containing the flag name and its value, or <c>null</c> if no value is specified.</returns>
418-
private static (string Name, string Value) ParseFlag(string flag)
415+
private static (string Name, string Value) ParseArg(string arg)
419416
{
420-
var trimmed = flag.TrimStart('-');
417+
var trimmed = arg.TrimStart('-');
421418
var eqIndex = trimmed.IndexOf('=');
422419
if (eqIndex == -1)
423420
{

src/Testcontainers/Images/IImage.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,8 @@ public interface IImage
3737
/// Gets the platform.
3838
/// </summary>
3939
/// <remarks>
40-
/// The supported format is <c>&lt;os&gt;|&lt;arch&gt;|&lt;os&gt;/&lt;arch&gt;[/&lt;variant&gt;]</c>.
41-
/// You can provide the operating system, the architecture, or both.
42-
/// For more details and examples, see <see href="https://github.com/containerd/platforms">containerd/platforms</see>.
40+
/// The supported format for a platform value is:
41+
/// <c>&lt;os&gt;|&lt;arch&gt;|&lt;os&gt;/&lt;arch&gt;[/&lt;variant&gt;]</c>.
4342
/// </remarks>
4443
[CanBeNull]
4544
string Platform { get; }
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
namespace DotNet.Testcontainers.Images
2+
{
3+
using JetBrains.Annotations;
4+
5+
/// <summary>
6+
/// Represents a container platform identifier.
7+
/// </summary>
8+
/// <remarks>
9+
/// The supported format for a platform value is:
10+
/// <c>&lt;os&gt;|&lt;arch&gt;|&lt;os&gt;/&lt;arch&gt;[/&lt;variant&gt;]</c>.
11+
///
12+
/// You can provide either the operating system or the architecture or both.
13+
/// For more details, see <see href="https://github.com/containerd/platforms">containerd/platforms</see>.
14+
/// </remarks>
15+
[PublicAPI]
16+
public readonly struct Platform
17+
{
18+
/// <summary>
19+
/// Initializes a new instance of the <see cref="Platform" /> struct.
20+
/// </summary>
21+
/// <param name="value">The platform identifier.</param>
22+
[PublicAPI]
23+
public Platform(string value)
24+
{
25+
}
26+
27+
/// <summary>
28+
/// Gets the platform identifier.
29+
/// </summary>
30+
/// <remarks>
31+
/// A string representing the container platform in <c>containerd/platforms</c> format, or
32+
/// <c>null</c> if no platform was specified.
33+
/// </remarks>
34+
[PublicAPI]
35+
[CanBeNull]
36+
public string Value { get; }
37+
}
38+
}

tests/Testcontainers.Tests/Unit/Images/ImageFromDockerfileTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ public void DockerfileArchiveGetBaseImages()
2727
new DockerImage("mcr.microsoft.com/dotnet/aspnet:8.0-jammy"),
2828
new DockerImage("mcr.microsoft.com/dotnet/aspnet:8.0-noble"),
2929
new DockerImage("mcr.microsoft.com/dotnet/aspnet:8.0-alpine"),
30-
new DockerImage("mcr.microsoft.com/dotnet/aspnet:8.0-azurelinux3.0", "linux/amd64"),
31-
new DockerImage("mcr.microsoft.com/dotnet/aspnet:8.0-azurelinux3.0", "linux/arm64"),
32-
new DockerImage("mcr.microsoft.com/dotnet/aspnet:8.0-azurelinux3.0", "linux/arm/v6"),
33-
new DockerImage("mcr.microsoft.com/dotnet/aspnet:8.0-azurelinux3.0", "linux/arm/v7"),
30+
new DockerImage("mcr.microsoft.com/dotnet/aspnet:8.0-azurelinux3.0", new Platform("linux/amd64")),
31+
new DockerImage("mcr.microsoft.com/dotnet/aspnet:8.0-azurelinux3.0", new Platform("linux/arm64")),
32+
new DockerImage("mcr.microsoft.com/dotnet/aspnet:8.0-azurelinux3.0", new Platform("linux/arm/v6")),
33+
new DockerImage("mcr.microsoft.com/dotnet/aspnet:8.0-azurelinux3.0", new Platform("linux/arm/v7")),
3434
new DockerImage("mcr.microsoft.com/dotnet/sdk:8.0.414"),
3535
};
3636

0 commit comments

Comments
 (0)