From 0d49124757ed8f29068f4c98af78a54177668e25 Mon Sep 17 00:00:00 2001 From: Premek Vysoky Date: Mon, 10 Aug 2026 16:59:21 +0200 Subject: [PATCH] Allow steps to be injected before ImageBuilder runs Backport of https://github.com/dotnet/dotnet-buildtools-prereqs-docker/pull/1729 where we needed to copy `eng/common` in the right time but there was no hook for it yet --- src/Infrastructure/Content/CHANGELOG.md | 9 +++++++++ src/Infrastructure/Content/DEV-GUIDE.md | 16 ++++++++++++++++ .../Content/templates/jobs/build-images.yml | 3 +++ .../Content/templates/stages/build-and-test.yml | 9 +++++++++ .../templates/stages/dotnet/build-and-test.yml | 2 ++ .../stages/dotnet/build-test-publish-repo.yml | 2 ++ .../Content/templates/steps/init-common.yml | 6 ++++++ .../templates/steps/init-imagebuilder.yml | 5 +++++ 8 files changed, 52 insertions(+) diff --git a/src/Infrastructure/Content/CHANGELOG.md b/src/Infrastructure/Content/CHANGELOG.md index 0936f6feb..09e796d6f 100644 --- a/src/Infrastructure/Content/CHANGELOG.md +++ b/src/Infrastructure/Content/CHANGELOG.md @@ -4,6 +4,15 @@ All breaking changes and new features in `eng/docker-tools` will be documented i --- +## 2026-08-10: Pre-ImageBuilder build customization + +Build pipeline templates now accept `customPreImageBuilderBuildSteps`. These steps run after +ImageBuilder is available but before repository content is copied into the Linux ImageBuilder +image. Repositories can use the hook to stage files into Docker build contexts, such as shared +`eng/common` content required by Dockerfiles. + +--- + ## 2026-06-11: Configurable per-registry referrer-lookup rate limit - Issue: [#2141](https://github.com/dotnet/docker-tools/issues/2141) diff --git a/src/Infrastructure/Content/DEV-GUIDE.md b/src/Infrastructure/Content/DEV-GUIDE.md index 9d4eaee7c..ba45f3077 100644 --- a/src/Infrastructure/Content/DEV-GUIDE.md +++ b/src/Infrastructure/Content/DEV-GUIDE.md @@ -389,6 +389,22 @@ To force a rebuild regardless of cache state, set the `noCache` parameter to `tr ## Common Customization Patterns +### Pattern: Staging Files into Docker Build Contexts + +Use `customPreImageBuilderBuildSteps` to modify repository content immediately before the +repository is copied into the Linux ImageBuilder image. For example, a repository can stage +shared `eng/common` files next to Dockerfiles whose build contexts cannot access the repository +root: + +```yaml +customPreImageBuilderBuildSteps: +- powershell: ./eng/Stage-EngCommon.ps1 + displayName: Stage eng/common in Docker Build Contexts +``` + +The steps run once per Linux build job, after ImageBuilder is available and before the +`Dockerfile.WithRepo` image is built. + ### Pattern: Adding Build Arguments Pass Dockerfile `ARG` values via ImageBuilder: diff --git a/src/Infrastructure/Content/templates/jobs/build-images.yml b/src/Infrastructure/Content/templates/jobs/build-images.yml index 7327b6d69..a77c02cb7 100644 --- a/src/Infrastructure/Content/templates/jobs/build-images.yml +++ b/src/Infrastructure/Content/templates/jobs/build-images.yml @@ -10,6 +10,8 @@ parameters: # Custom steps that run after ImageBuilder is set up but before the build starts. # Use for build-specific initialization (e.g., setting variables, additional setup). customBuildInitSteps: [] + # Custom steps that modify repository content before it is copied into the ImageBuilder image. + customPreImageBuilderBuildSteps: [] publishConfig: null versionsRepoRef: "" noCache: false @@ -41,6 +43,7 @@ jobs: versionsRepoRef: ${{ parameters.versionsRepoRef }} cleanupDocker: true customInitSteps: ${{ parameters.customInitSteps }} + customPreImageBuilderBuildSteps: ${{ parameters.customPreImageBuilderBuildSteps }} - ${{ parameters.customBuildInitSteps }} - template: /eng/docker-tools/templates/steps/reference-service-connections.yml@self parameters: diff --git a/src/Infrastructure/Content/templates/stages/build-and-test.yml b/src/Infrastructure/Content/templates/stages/build-and-test.yml index a03804aa8..6d602fe40 100644 --- a/src/Infrastructure/Content/templates/stages/build-and-test.yml +++ b/src/Infrastructure/Content/templates/stages/build-and-test.yml @@ -13,6 +13,8 @@ parameters: # Custom steps that run after ImageBuilder is set up but before the build starts. # Use for build-specific initialization (e.g., setting variables, additional setup). customBuildInitSteps: [] + # Custom steps that modify repository content before it is copied into the ImageBuilder image. + customPreImageBuilderBuildSteps: [] customTestInitSteps: [] sourceBuildPipelineRunId: "" # When true, the Post-Build stage runs even if the Build stage failed (succeededOrFailed). @@ -113,6 +115,7 @@ stages: versionsRepoRef: ${{ parameters.versionsRepoRef }} customInitSteps: ${{ parameters.customInitSteps }} customBuildInitSteps: ${{ parameters.customBuildInitSteps }} + customPreImageBuilderBuildSteps: ${{ parameters.customPreImageBuilderBuildSteps }} noCache: ${{ parameters.noCache }} publishConfig: ${{ parameters.publishConfig }} internalProjectName: ${{ parameters.internalProjectName }} @@ -128,6 +131,7 @@ stages: versionsRepoRef: ${{ parameters.versionsRepoRef }} customInitSteps: ${{ parameters.customInitSteps }} customBuildInitSteps: ${{ parameters.customBuildInitSteps }} + customPreImageBuilderBuildSteps: ${{ parameters.customPreImageBuilderBuildSteps }} noCache: ${{ parameters.noCache }} publishConfig: ${{ parameters.publishConfig }} internalProjectName: ${{ parameters.internalProjectName }} @@ -143,6 +147,7 @@ stages: versionsRepoRef: ${{ parameters.versionsRepoRef }} customInitSteps: ${{ parameters.customInitSteps }} customBuildInitSteps: ${{ parameters.customBuildInitSteps }} + customPreImageBuilderBuildSteps: ${{ parameters.customPreImageBuilderBuildSteps }} noCache: ${{ parameters.noCache }} publishConfig: ${{ parameters.publishConfig }} internalProjectName: ${{ parameters.internalProjectName }} @@ -158,6 +163,7 @@ stages: versionsRepoRef: ${{ parameters.versionsRepoRef }} customInitSteps: ${{ parameters.customInitSteps }} customBuildInitSteps: ${{ parameters.customBuildInitSteps }} + customPreImageBuilderBuildSteps: ${{ parameters.customPreImageBuilderBuildSteps }} noCache: ${{ parameters.noCache }} publishConfig: ${{ parameters.publishConfig }} internalProjectName: ${{ parameters.internalProjectName }} @@ -173,6 +179,7 @@ stages: versionsRepoRef: ${{ parameters.versionsRepoRef }} customInitSteps: ${{ parameters.customInitSteps }} customBuildInitSteps: ${{ parameters.customBuildInitSteps }} + customPreImageBuilderBuildSteps: ${{ parameters.customPreImageBuilderBuildSteps }} noCache: ${{ parameters.noCache }} publishConfig: ${{ parameters.publishConfig }} internalProjectName: ${{ parameters.internalProjectName }} @@ -188,6 +195,7 @@ stages: versionsRepoRef: ${{ parameters.versionsRepoRef }} customInitSteps: ${{ parameters.customInitSteps }} customBuildInitSteps: ${{ parameters.customBuildInitSteps }} + customPreImageBuilderBuildSteps: ${{ parameters.customPreImageBuilderBuildSteps }} noCache: ${{ parameters.noCache }} publishConfig: ${{ parameters.publishConfig }} internalProjectName: ${{ parameters.internalProjectName }} @@ -203,6 +211,7 @@ stages: versionsRepoRef: ${{ parameters.versionsRepoRef }} customInitSteps: ${{ parameters.customInitSteps }} customBuildInitSteps: ${{ parameters.customBuildInitSteps }} + customPreImageBuilderBuildSteps: ${{ parameters.customPreImageBuilderBuildSteps }} noCache: ${{ parameters.noCache }} publishConfig: ${{ parameters.publishConfig }} internalProjectName: ${{ parameters.internalProjectName }} diff --git a/src/Infrastructure/Content/templates/stages/dotnet/build-and-test.yml b/src/Infrastructure/Content/templates/stages/dotnet/build-and-test.yml index 5b7e23379..81eee2c9e 100644 --- a/src/Infrastructure/Content/templates/stages/dotnet/build-and-test.yml +++ b/src/Infrastructure/Content/templates/stages/dotnet/build-and-test.yml @@ -29,6 +29,7 @@ parameters: linuxArmBuildJobTimeout: 60 windowsAmdBuildJobTimeout: 60 customBuildInitSteps: [] + customPreImageBuilderBuildSteps: [] # Test parameters testMatrixType: platformVersionedOs @@ -58,6 +59,7 @@ stages: testMatrixCustomBuildLegGroupArgs: ${{ parameters.testMatrixCustomBuildLegGroupArgs }} customCopyBaseImagesInitSteps: ${{ parameters.customCopyBaseImagesInitSteps}} customBuildInitSteps: ${{ parameters.customBuildInitSteps }} + customPreImageBuilderBuildSteps: ${{ parameters.customPreImageBuilderBuildSteps }} customInitSteps: ${{ parameters.customInitSteps }} customTestInitSteps: ${{ parameters.customTestInitSteps }} windowsAmdBuildJobTimeout: ${{ parameters.windowsAmdBuildJobTimeout }} diff --git a/src/Infrastructure/Content/templates/stages/dotnet/build-test-publish-repo.yml b/src/Infrastructure/Content/templates/stages/dotnet/build-test-publish-repo.yml index 2c924ef0d..9102d994c 100644 --- a/src/Infrastructure/Content/templates/stages/dotnet/build-test-publish-repo.yml +++ b/src/Infrastructure/Content/templates/stages/dotnet/build-test-publish-repo.yml @@ -21,6 +21,7 @@ parameters: linuxArmBuildJobTimeout: 60 windowsAmdBuildJobTimeout: 60 customBuildInitSteps: [] + customPreImageBuilderBuildSteps: [] # Test parameters testMatrixType: platformVersionedOs @@ -60,6 +61,7 @@ stages: linuxArmBuildJobTimeout: ${{ parameters.linuxArmBuildJobTimeout }} windowsAmdBuildJobTimeout: ${{ parameters.windowsAmdBuildJobTimeout }} customBuildInitSteps: ${{ parameters.customBuildInitSteps }} + customPreImageBuilderBuildSteps: ${{ parameters.customPreImageBuilderBuildSteps }} customInitSteps: ${{ parameters.customInitSteps }} # Test sourceBuildPipelineRunId: ${{ parameters.sourceBuildPipelineRunId }} diff --git a/src/Infrastructure/Content/templates/steps/init-common.yml b/src/Infrastructure/Content/templates/steps/init-common.yml index eda572618..25d22a7b1 100644 --- a/src/Infrastructure/Content/templates/steps/init-common.yml +++ b/src/Infrastructure/Content/templates/steps/init-common.yml @@ -34,6 +34,11 @@ parameters: type: stepList default: [] +# Custom steps that modify repository content before it is copied into the ImageBuilder image. +- name: customPreImageBuilderBuildSteps + type: stepList + default: [] + # Registry and authentication configuration for publishing images. # Contains server URLs, repo prefixes, subscriptions, and resource groups. # When null, build/publish steps that require registry access will be skipped. @@ -245,3 +250,4 @@ steps: publishConfig: ${{ parameters.publishConfig }} condition: ${{ parameters.condition }} customInitSteps: ${{ parameters.customInitSteps }} + customPreImageBuilderBuildSteps: ${{ parameters.customPreImageBuilderBuildSteps }} diff --git a/src/Infrastructure/Content/templates/steps/init-imagebuilder.yml b/src/Infrastructure/Content/templates/steps/init-imagebuilder.yml index b85c62b6c..1e4f57a1f 100644 --- a/src/Infrastructure/Content/templates/steps/init-imagebuilder.yml +++ b/src/Infrastructure/Content/templates/steps/init-imagebuilder.yml @@ -21,6 +21,10 @@ parameters: type: stepList default: [] +- name: customPreImageBuilderBuildSteps + type: stepList + default: [] + steps: # Custom ImageBuilder setup (e.g., bootstrap from source) - ${{ if gt(length(parameters.customInitSteps), 0) }}: @@ -67,6 +71,7 @@ steps: # The withrepo image layers the checked-out repository into the ImageBuilder # container at /repo, so ImageBuilder can access manifests and Dockerfiles - ${{ if eq(parameters.dockerClientOS, 'linux') }}: + - ${{ parameters.customPreImageBuilderBuildSteps }} - script: >- docker build -t $(imageNames.imageBuilder.withrepo)