Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
10c08ac
Create ImageBuilder manifest library
lbussell Sep 15, 2025
123d971
Rename project to ImageBuilder.Models and move Manifest model out of …
lbussell Sep 15, 2025
4880c1e
Remove unused imports
lbussell Sep 15, 2025
bc4c1ba
Use file scoped namespaces
lbussell Sep 15, 2025
94a3993
Remove unused class
lbussell Sep 15, 2025
5e920f2
Enable nullable annotations in Models project
lbussell Sep 15, 2025
417d9af
Upgrade ImageBuilder to .NET 10
lbussell Sep 16, 2025
d98761c
WIP add templating library and CLI
lbussell Sep 16, 2025
1bed2d0
WIP: Add read model / view model to models library
lbussell Sep 16, 2025
6f63594
Add some backreferences to RepoInfo
lbussell Sep 17, 2025
5b12450
WIP on variable store
lbussell Sep 17, 2025
644de11
Fix warnings from manifest model
lbussell Sep 17, 2025
e56bdbe
Read manifest from file and correctly resolve variables and includes
lbussell Sep 17, 2025
25d20a2
Disassociate Templating projects from ImageBuilder namespace
lbussell Sep 18, 2025
da4d45a
Add benchmark for round-trip serialization
lbussell Sep 18, 2025
156394a
Add simple templating abstractions and cottle implementation
lbussell Sep 18, 2025
07f4243
Separate context based variables and predefined variables
lbussell Sep 18, 2025
6d03594
Move ManifestInfo serialization to separate namespace
lbussell Sep 18, 2025
004a1bc
Remove unused usings
lbussell Sep 18, 2025
f8d3e47
Get template generation working
lbussell Sep 18, 2025
c4d2ecb
Get sub-templates working without crashing
lbussell Sep 19, 2025
4e18e9a
Fix ARGS and VARIABLES in templates
lbussell Sep 19, 2025
5137b44
Add sub-template trimming
lbussell Sep 19, 2025
055ec80
Reorder fields
lbussell Sep 19, 2025
1c143f0
Apply trimming and indent after document render
lbussell Sep 19, 2025
e43c326
Add replace function
lbussell Sep 19, 2025
2dd1d3e
Fix OS_VERSION_BASE variable
lbussell Sep 19, 2025
0f09cb4
Add file system and template caches
lbussell Sep 19, 2025
6dc10e7
Use source generated JSON serialization
lbussell Sep 19, 2025
d389a53
Move JsonHelper to Serialization namespace
lbussell Sep 19, 2025
900c9ba
Add GenerateDockerfiles benchmark
lbussell Sep 19, 2025
c62c23d
Enable Native AOT
lbussell Sep 19, 2025
f92de74
Use fully synchronous manifest loading
lbussell Sep 19, 2025
3bf11f5
Get readme generation working
lbussell Sep 21, 2025
4bf5c40
Fix nullable warnings in ImageBuilder
lbussell Sep 21, 2025
b340808
Add benchmark for GenerateReadmes and GenerateAll
lbussell Sep 21, 2025
473c72d
Implement rudimentary tags table generation
lbussell Sep 21, 2025
cd4fba9
Improve template engine abstraction
lbussell Sep 21, 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 .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"image": "mcr.microsoft.com/dotnet/sdk:9.0-noble",
"image": "mcr.microsoft.com/dotnet/sdk:10.0-noble",
"features": {
"ghcr.io/devcontainers/features/common-utils": {
"username": "app",
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@

# Test files
*.trx

# BenchmarkDotNet Artifacts
BenchmarkDotNet.Artifacts/
9 changes: 9 additions & 0 deletions Microsoft.DotNet.DockerTools.slnx
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
<Solution>

<Configurations>
<Platform Name="Any CPU" />
<Platform Name="x64" />
<Platform Name="x86" />
</Configurations>

<Project Path="eng/src/file-pusher/file-pusher.csproj" />
<Project Path="eng/src/yaml-updater/yaml-updater.csproj" />

<Project Path="src/ImageBuilder/Microsoft.DotNet.ImageBuilder.csproj" />
<Project Path="src/ImageBuilder.Models/Microsoft.DotNet.ImageBuilder.Models.csproj" />
<Project Path="src/ImageBuilder.Tests/Microsoft.DotNet.ImageBuilder.Tests.csproj" />

<Project Path="src/Templating/Templating.csproj" />
<Project Path="src/TemplateGenerator/TemplateGenerator.csproj" />
<Project Path="src/TemplateGenerator.Benchmarks/TemplateGenerator.Benchmarks.csproj" />

</Solution>
2 changes: 1 addition & 1 deletion eng/common/Install-DotNetSdk.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ param(
[string]
$InstallPath,
[string]
$Channel = "9.0"
$Channel = "10.0"
)

Set-StrictMode -Version Latest
Expand Down
2 changes: 1 addition & 1 deletion eng/common/templates/jobs/cg-build-projects.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ parameters:
# See https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script#options for possible Channel values
- name: dotnetVersionChannel
type: string
default: '9.0'
default: '10.0'
displayName: .NET Version

jobs:
Expand Down
5 changes: 3 additions & 2 deletions src/Dockerfile.linux
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v <local path to build>:/repo -w /repo image-builder <image-build args>

# build Microsoft.DotNet.ImageBuilder
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0-azurelinux3.0 AS build-env
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-azurelinux3.0 AS build-env
ARG TARGETARCH

# download oras package tarball
Expand All @@ -19,6 +19,7 @@ WORKDIR /image-builder
# restore packages before copying entire source - provides optimizations when rebuilding
COPY NuGet.config ./
COPY ImageBuilder/Microsoft.DotNet.ImageBuilder.csproj ./ImageBuilder/
COPY ImageBuilder.Models/Microsoft.DotNet.ImageBuilder.Models.csproj ./ImageBuilder.Models/
RUN dotnet restore -r linux-$TARGETARCH ./ImageBuilder/Microsoft.DotNet.ImageBuilder.csproj

# copy everything else and publish
Expand All @@ -27,7 +28,7 @@ RUN dotnet publish -r linux-$TARGETARCH ./ImageBuilder/Microsoft.DotNet.ImageBui


# build runtime image
FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-azurelinux3.0
FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-azurelinux3.0

# install tooling
RUN tdnf install -y \
Expand Down
3 changes: 2 additions & 1 deletion src/Dockerfile.windows
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ ARG WINDOWS_BASE
ARG WINDOWS_SDK

# build Microsoft.DotNet.ImageBuilder
FROM mcr.microsoft.com/dotnet/sdk:9.0-$WINDOWS_SDK AS build-env
FROM mcr.microsoft.com/dotnet/sdk:10.0-$WINDOWS_SDK AS build-env
WORKDIR /image-builder

# restore packages before copying entire source - provides optimizations when rebuilding
COPY NuGet.config ./
COPY ImageBuilder/Microsoft.DotNet.ImageBuilder.csproj ./ImageBuilder/
COPY ImageBuilder.Models/Microsoft.DotNet.ImageBuilder.Models.csproj ./ImageBuilder.Models/
RUN dotnet restore -r win-x64 ./ImageBuilder/Microsoft.DotNet.ImageBuilder.csproj

# copy everything else and publish
Expand Down
13 changes: 13 additions & 0 deletions src/ImageBuilder.Models/Manifest/Architecture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace Microsoft.DotNet.ImageBuilder.Models.Manifest;

// Enum values must align with the $GOARCH values specified at https://golang.org/doc/install/source#environment
public enum Architecture
{
ARM,
ARM64,
AMD64,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.ComponentModel;

namespace Microsoft.DotNet.ImageBuilder.Models.Manifest;

[Description(
"The type of dependency an image has for a specific scenario."
)]
public enum CustomBuildLegDependencyType
{
[Description(
"Indicates the dependency is considered to be integral to the depending image." +
"This means the dependent image will not have its own dependency graph considered for build leg " +
"generation. An example of this is when a custom build leg dependency is defined from sdk to " +
"aspnet; in that case, aspnet and sdk will be included in a leg together but the sdk will not " +
"have its own leg generated."
)]
Integral,

[Description(
"Indicates the dependency is considered to be a supplemental companion to the depending image." +
"This means the dependent image will have its own dependency graph considered for build leg " +
"generation. An example of this is when a custom build leg dependency is defined to " +
"include an SDK image supported on a particular architecture in order to test a runtime OS " +
"that doesn't its own SDK on that architecture (Trixie ARM SDK to test Alpine ARM runtime); " +
"in that case, the SDK will be included in a leg together with the runtime and the SDK will " +
"still have have its own leg."
)]
Supplemental
}
37 changes: 37 additions & 0 deletions src/ImageBuilder.Models/Manifest/CustomBuildLegGroup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.ComponentModel;
using Newtonsoft.Json;

namespace Microsoft.DotNet.ImageBuilder.Models.Manifest;

[Description(
"This object describes the tag dependencies of the image for a specific named scenario. This is " +
"for advanced cases only. It allows tooling to modify the build matrix that would normally be " +
"generated for the image by including the customizations described in this metadata. An example " +
"usage of this is in PR builds where it is necessary to build and test in the same job. In such " +
"a scenario, some images are part of a test matrix that require images to be available on the " +
"build machine that aren't part of that images dependency graph in normal scenarios. By " +
"specifying a customBuildLegGroup for this scenario, those additional image dependencies can " +
"be specified and the build pipeline can make use of them when constructing its build graph when " +
"specified to do so."
)]
public class CustomBuildLegGroup
{
[Description(
"Name of the group describing the scenario in which it's relevant. This is just a " +
" custom label that can then be used by tooling to lookup the group when necessary."
)]
[JsonProperty(Required = Required.Always)]
public required string Name { get; set; }

[Description("The type of the dependency which impacts how it's used during the build.")]
[JsonProperty(Required = Required.Always)]
public required CustomBuildLegDependencyType Type { get; set; }

[Description("The set of dependencies the image has for this scenario.")]
[JsonProperty(Required = Required.Always)]
public required string[] Dependencies { get; set; }
}
32 changes: 32 additions & 0 deletions src/ImageBuilder.Models/Manifest/Image.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.ComponentModel;
using Newtonsoft.Json;

namespace Microsoft.DotNet.ImageBuilder.Models.Manifest;

[Description("An image object contains metadata about a specific Docker image.")]
public class Image
{
[Description(
"The set of platforms that describe the platform-specific variations of the Docker image.")]
[JsonProperty(Required = Required.Always)]
public Platform[] Platforms { get; set; } = [];

[Description(
"The set of tags that are shared amongst all platform-specific versions of the image. An " +
"example of a shared tag, including its repo name, is dotnet/core/runtime:2.2; running " +
"`docker pull mcr.microsoft.com/dotnet/core/runtime:2.2` on Windows will get the " +
"default Windows-based tag whereas running it on Linux will get the default " +
"Linux-based tag.")]
public IDictionary<string, Tag>? SharedTags { get; set; }

[Description("The full version of the product that the Docker image contains.")]
public string? ProductVersion { get; set; }

public Image()
{
}
}
52 changes: 52 additions & 0 deletions src/ImageBuilder.Models/Manifest/Manifest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.ComponentModel;

namespace Microsoft.DotNet.ImageBuilder.Models.Manifest;

[Description(
"The manifest file is the primary source of metadata that drives the production " +
"of all .NET Docker images. It describes various attributes of the Docker images " +
"that are to be produced by a given GitHub repo. .NET Docker's engineering system " +
"consumes this file in various ways as part of the automated build pipelines and " +
"other tools. It's intended to be product-agnostic meaning that it could be used " +
"to describe metadata for Docker image production of any product, not just .NET.")]
public class Manifest
{
[Description(
"Additional json files to be loaded with this manifest. This is a convienent" +
"way to split the manifest apart into logical parts."
)]
public string[] Includes { get; set; } = [];

[Description(
"Info about the readme that documents the product family."
)]
public Readme? Readme { get; set; }

[Description(
"The location of the Docker registry where the images are to be published."
)]
public string? Registry { get; set; }

[Description(
"The set of Docker repositories described by this manifest."
)]
public Repo[] Repos { get; set; } = [];

[Description(
"A set of custom variables that can be referenced in various parts of the " +
"manifest. This provides a few benefits: 1) allows a commmonly used value " +
"to be defined only once and referenced by its variable name many times" +
"2) allows tools that consume the manifest file to provide a mechanism to " +
"dynamically override the value of these variables. Variables may be " +
"referenced in other parts of the manifest by using the following syntax: " +
"$(_VariableName_).")]
public IDictionary<string, string> Variables { get; set; } = new Dictionary<string, string>();

public Manifest()
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace Microsoft.DotNet.ImageBuilder.Models.Manifest
namespace Microsoft.DotNet.ImageBuilder.Models.Manifest;

public enum OS
{
public enum OS
{
Linux,
Windows,
}
Linux,
Windows,
}
76 changes: 76 additions & 0 deletions src/ImageBuilder.Models/Manifest/Platform.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.ComponentModel;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace Microsoft.DotNet.ImageBuilder.Models.Manifest;

[Description(
"A platform object contains metadata about a platform-specific version of an " +
"image and refers to the actual Dockerfile used to build the image.")]
public class Platform
{
[Description(
"The processor architecture associated with the image."
)]
[DefaultValue(Architecture.AMD64)]
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)]
public Architecture Architecture { get; set; } = Architecture.AMD64;

[Description(
"A set of values that will passed to the `docker build` command " +
"to override variables defined in the Dockerfile.")]
public IDictionary<string, string> BuildArgs { get; set; } = new Dictionary<string, string>();

[Description(
"Relative path to the associated Dockerfile. This can be a file or a " +
"directory. If it is a directory, the file name defaults to Dockerfile."
)]
[JsonProperty(Required = Required.Always)]
public string Dockerfile { get; set; } = string.Empty;

[Description(
"Relative path to the template the Dockerfile is generated from."
)]
public string? DockerfileTemplate { get; set; }

[Description(
"The generic name of the operating system associated with the image."
)]
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty(Required = Required.Always)]
public OS OS { get; set; }

[Description(
"The specific version of the operating system associated with the image. " +
"Examples: alpine3.9, bionic, nanoserver-1903."
)]
[JsonProperty(Required = Required.Always)]
public string OsVersion { get; set; } = string.Empty;

[Description(
"The set of platform-specific tags associated with the image."
)]
[JsonProperty(Required = Required.Always)]
public IDictionary<string, Tag> Tags { get; set; } = new Dictionary<string, Tag>();

[Description(
"The custom build leg groups associated with the platform."
)]
public CustomBuildLegGroup[] CustomBuildLegGroups { get; set; } = Array.Empty<CustomBuildLegGroup>();

[Description(
"A label which further distinguishes the architecture when it " +
"contains variants. For example, the ARM architecture has variants " +
"named v6, v7, etc."
)]
public string? Variant { get; set; }

public Platform()
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

namespace Microsoft.DotNet.ImageBuilder.Models.Manifest;

#nullable enable
public class Readme
{
[Description(
Expand All @@ -32,4 +31,3 @@ public Readme(string path, string? templatePath)
TemplatePath = templatePath;
}
}
#nullable disable
Loading
Loading