├── .config
├── dotnet-tools.json
└── tsaoptions.json
├── .devcontainer
└── devcontainer.json
├── .dockerignore
├── .editorconfig
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── releases
│ │ └── new-windows-release.md
├── dependabot.yml
├── labeler.yml
└── workflows
│ └── labeler.yml
├── .gitignore
├── .vault-config
└── secrets.yaml
├── CODE-OF-CONDUCT.md
├── CODEOWNERS
├── LICENSE
├── Microsoft.DotNet.DockerTools.sln
├── NuGet.config
├── README.md
├── documentation
├── assets
│ └── Base Image Dependency Flow.drawio
├── base-image-dependency-flow.md
├── images
│ └── base-image-dependency-flow-diagram.png
└── manifest-file.md
├── eng
├── check-base-image-subscriptions-buildtools.json
├── check-base-image-subscriptions.json
├── common
│ ├── Dockerfile.WithRepo
│ ├── Get-BaseImageStatus.ps1
│ ├── Get-ImageBuilder.ps1
│ ├── Get-ImageNameVars.ps1
│ ├── Install-DotNetSdk.ps1
│ ├── Invoke-CleanupDocker.ps1
│ ├── Invoke-ImageBuilder.ps1
│ ├── Invoke-WithRetry.ps1
│ ├── Retain-Build.ps1
│ ├── build.ps1
│ ├── pull-image.sh
│ ├── readme.md
│ └── templates
│ │ ├── 1es-official.yml
│ │ ├── 1es-unofficial.yml
│ │ ├── jobs
│ │ ├── build-images.yml
│ │ ├── cg-build-projects.yml
│ │ ├── copy-base-images-staging.yml
│ │ ├── copy-base-images.yml
│ │ ├── generate-matrix.yml
│ │ ├── post-build.yml
│ │ ├── publish.yml
│ │ ├── test-images-linux-client.yml
│ │ └── test-images-windows-client.yml
│ │ ├── stages
│ │ ├── build-and-test.yml
│ │ ├── dotnet
│ │ │ ├── build-and-test.yml
│ │ │ ├── build-test-publish-repo.yml
│ │ │ └── publish.yml
│ │ ├── publish.yml
│ │ └── setup-service-connections.yml
│ │ ├── steps
│ │ ├── annotate-eol-digests.yml
│ │ ├── clean-acr-images.yml
│ │ ├── cleanup-docker-linux.yml
│ │ ├── cleanup-docker-windows.yml
│ │ ├── common-init-for-matrix-and-build.yml
│ │ ├── copy-base-images.yml
│ │ ├── download-build-artifact.yml
│ │ ├── init-common.yml
│ │ ├── init-docker-linux.yml
│ │ ├── init-docker-windows.yml
│ │ ├── parse-test-arg-arrays.yml
│ │ ├── publish-artifact.yml
│ │ ├── publish-readmes.yml
│ │ ├── retain-build.yml
│ │ ├── run-imagebuilder.yml
│ │ ├── run-pwsh-with-auth.yml
│ │ ├── set-dry-run.yml
│ │ ├── set-image-info-path-var.yml
│ │ ├── test-images-linux-client.yml
│ │ ├── test-images-windows-client.yml
│ │ ├── validate-branch.yml
│ │ ├── wait-for-mcr-doc-ingestion.yml
│ │ └── wait-for-mcr-image-ingestion.yml
│ │ ├── task-prefix-decorator.yml
│ │ └── variables
│ │ ├── common-paths.yml
│ │ ├── common.yml
│ │ ├── docker-images.yml
│ │ └── dotnet
│ │ ├── build-test-publish.yml
│ │ └── common.yml
├── eng-common-file-pusher-config.json
├── image-builder-tag-update-config.json
├── pipelines
│ ├── annotate-eol-digests.yml
│ ├── cg-detection.yml
│ ├── check-base-image-updates.yml
│ ├── cleanup-acr-images-custom.yml
│ ├── cleanup-acr-images.yml
│ ├── dotnet-buildtools-image-builder-official.yml
│ ├── dotnet-buildtools-image-builder-pr.yml
│ ├── dotnet-docker-tools-eng-validation-pr.yml
│ ├── dotnet-docker-tools-eng-validation.yml
│ ├── import-image.yml
│ ├── mirror-base-images.yml
│ ├── push-common-updates.yml
│ ├── secret-management-weekly.yml
│ ├── templates
│ │ ├── jobs
│ │ │ ├── check-base-image-updates.yml
│ │ │ └── copy-base-images-public-mirror.yml
│ │ └── variables
│ │ │ ├── build-test-publish.yml
│ │ │ ├── common.yml
│ │ │ ├── eng-validation.yml
│ │ │ └── image-builder.yml
│ ├── update-image-builder-tag.yml
│ └── upload-file.yml
├── src
│ ├── file-pusher
│ │ ├── AzDoSafeTraceListenerWrapper.cs
│ │ ├── Dockerfile
│ │ ├── FilePusher.cs
│ │ ├── Models
│ │ │ ├── Config.cs
│ │ │ └── GitRepo.cs
│ │ ├── Options.cs
│ │ └── file-pusher.csproj
│ └── yaml-updater
│ │ ├── Dockerfile
│ │ ├── Options.cs
│ │ ├── YamlUpdater.cs
│ │ └── yaml-updater.csproj
└── tests
│ └── pipeline-validation
│ ├── 1.0
│ ├── nanoserver-1809
│ │ └── amd64
│ │ │ └── Dockerfile
│ └── noble
│ │ ├── amd64
│ │ └── Dockerfile
│ │ └── arm64v8
│ │ └── Dockerfile
│ ├── README.placeholder.md
│ ├── run-tests.ps1
│ ├── templates
│ ├── README.md
│ └── test-tags.yml
│ └── test-manifest.json
└── src
└── Microsoft.DotNet.ImageBuilder
├── .dockerignore
├── Dockerfile.linux
├── Dockerfile.windows
├── NuGet.config
├── README.md
├── build.ps1
├── manifest.json
├── run-tests.ps1
├── src
├── AsyncLockedValue.cs
├── AuthHelper.cs
├── AzureScopes.cs
├── AzureTokenCredentialProvider.cs
├── AzureTokenCredentialProviderExtensions.cs
├── BlobsClientExtensions.cs
├── Commands
│ ├── AnnotateEolDigestsCommand.cs
│ ├── AnnotateEolDigestsOptions.cs
│ ├── AzdoOptions.cs
│ ├── AzdoTags.cs
│ ├── BaseImageOverrideOptions.cs
│ ├── BuildCommand.cs
│ ├── BuildLegInfo.cs
│ ├── BuildMatrixInfo.cs
│ ├── BuildOptions.cs
│ ├── CleanAcrImagesCommand.cs
│ ├── CleanAcrImagesOptions.cs
│ ├── CliHelper.cs
│ ├── Command.TOptions.cs
│ ├── CommandExtensions.cs
│ ├── CopyAcrImagesCommand.cs
│ ├── CopyAcrImagesOptions.cs
│ ├── CopyBaseImagesCommand.cs
│ ├── CopyBaseImagesOptions.cs
│ ├── CopyImagesCommand.cs
│ ├── CopyImagesOptions.cs
│ ├── DockerfileFilterOptions.cs
│ ├── GenerateArtifactsCommand.cs
│ ├── GenerateArtifactsOptions.cs
│ ├── GenerateBuildMatrixCommand.cs
│ ├── GenerateBuildMatrixOptions.cs
│ ├── GenerateDockerfilesCommand.cs
│ ├── GenerateDockerfilesOptions.cs
│ ├── GenerateEolAnnotationDataCommand.cs
│ ├── GenerateEolAnnotationDataOptions.cs
│ ├── GenerateReadmesCommand.cs
│ ├── GenerateReadmesOptions.cs
│ ├── GetBaseImageStatusCommand.cs
│ ├── GetBaseImageStatusOptions.cs
│ ├── GetStaleImagesCommand.cs
│ ├── GetStaleImagesOptions.cs
│ ├── GitOptions.cs
│ ├── ICommand.cs
│ ├── IFilterableOptions.cs
│ ├── IGitOptionsHost.cs
│ ├── IManifestCommand.cs
│ ├── IOptions.cs
│ ├── ImageInfoOptions.cs
│ ├── IngestKustoImageInfoCommand.cs
│ ├── IngestKustoImageInfoOptions.cs
│ ├── ManifestCommand.cs
│ ├── ManifestFilterOptions.cs
│ ├── ManifestOptions.cs
│ ├── MarIngestionOptions.cs
│ ├── MatrixType.cs
│ ├── MergeImageInfoCommand.cs
│ ├── MergeImageInfoOptions.cs
│ ├── NotificationLabels.cs
│ ├── Options.cs
│ ├── PlatformFilterOptions.cs
│ ├── PostPublishNotificationCommand.cs
│ ├── PostPublishNotificationOptions.cs
│ ├── PublishImageInfoCommand.cs
│ ├── PublishImageInfoOptions.cs
│ ├── PublishManifestCommand.cs
│ ├── PublishManifestOptions.cs
│ ├── PublishMcrDocsCommand.cs
│ ├── PublishMcrDocsOptions.cs
│ ├── PullImagesCommand.cs
│ ├── PullImagesOptions.cs
│ ├── QueueBuildCommand.cs
│ ├── QueueBuildOptions.cs
│ ├── RegistryCredentialsOptions.cs
│ ├── RegistryOptions.cs
│ ├── ServiceConnectionOptions.cs
│ ├── ShowImageStatsCommand.cs
│ ├── ShowImageStatsOptions.cs
│ ├── ShowManifestSchemaCommand.cs
│ ├── Signing
│ │ ├── GenerateSigningPayloadsCommand.cs
│ │ └── GenerateSigningPayloadsOptions.cs
│ ├── SubscriptionImagePaths.cs
│ ├── SubscriptionOptions.cs
│ ├── TrimUnchangedPlatformsCommand.cs
│ ├── TrimUnchangedPlatformsOptions.cs
│ ├── WaitForMarAnnotationIngestionCommand.cs
│ ├── WaitForMarAnnotationIngestionOptions.cs
│ ├── WaitForMcrDocIngestionCommand.cs
│ ├── WaitForMcrDocIngestionOptions.cs
│ ├── WaitForMcrImageIngestionCommand.cs
│ └── WaitForMcrImageIngestionOptions.cs
├── ContainerRegistryClientFactory.cs
├── ContainerRegistryClientWrapper.cs
├── ContainerRegistryContentClientFactory.cs
├── ContainerRegistryContentClientWrapper.cs
├── CopyImageService.cs
├── CopyImageServiceFactory.cs
├── DateTimeService.cs
├── DockerHelper.cs
├── DockerService.cs
├── DockerServiceCache.cs
├── EnumHelper.cs
├── EnumerableExtensions.cs
├── EnvironmentService.cs
├── ExecuteHelper.cs
├── FileHelper.cs
├── GitHelper.cs
├── GitHubClientFactory.cs
├── GitService.cs
├── GitServiceExtensions.cs
├── GraphExtensions.cs
├── Helpers
│ └── JwtHelper.cs
├── HttpClientProvider.cs
├── HttpHelper.cs
├── HttpPolicyBuilder.cs
├── IAzureTokenCredentialProvider.cs
├── IContainerRegistryClient.cs
├── IContainerRegistryClientFactory.cs
├── IContainerRegistryContentClient.cs
├── IContainerRegistryContentClientFactory.cs
├── IDateTimeService.cs
├── IDockerService.cs
├── IEnvironmentService.cs
├── IGitHubBranchRef.cs
├── IGitHubClientFactory.cs
├── IGitHubFileRef.cs
├── IGitHubRepoRef.cs
├── IGitService.cs
├── IHttpClientProvider.cs
├── ILifecycleMetadataService.cs
├── ILoggerService.cs
├── IManifestService.cs
├── IManifestServiceFactory.cs
├── IMcrStatusClient.cs
├── INotificationService.cs
├── IOctokitClientFactory.cs
├── IProcessService.cs
├── IRegistryContentClient.cs
├── IRegistryContentClientFactory.cs
├── IRegistryCredentialsHost.cs
├── IRegistryCredentialsProvider.cs
├── IServiceConnection.cs
├── ImageBuilder.cs
├── ImageCacheService.cs
├── ImageDigestCache.cs
├── ImageInfoHelper.cs
├── ImageInfoMergeOptions.cs
├── ImageName.cs
├── ImageNameResolver.cs
├── JsonHelper.cs
├── LifecycleMetadataService.cs
├── LockHelper.cs
├── Logger.cs
├── LoggerService.cs
├── ManifestQueryResult.cs
├── ManifestService.cs
├── ManifestServiceFactory.cs
├── MarImageIngestionReporter.cs
├── McrStatusClient.cs
├── McrStatusClientFactory.cs
├── McrTagsMetadataGenerator.cs
├── Microsoft.DotNet.ImageBuilder.csproj
├── Models
│ ├── Annotations
│ │ ├── EolAnnotationsData.cs
│ │ └── EolDigestData.cs
│ ├── Image
│ │ ├── ImageArtifactDetails.cs
│ │ ├── ImageData.cs
│ │ ├── ManifestData.cs
│ │ ├── PlatformData.cs
│ │ └── RepoData.cs
│ ├── Manifest
│ │ ├── Architecture.cs
│ │ ├── CustomBuildLegDependencyType.cs
│ │ ├── CustomBuildLegGroup.cs
│ │ ├── Image.cs
│ │ ├── Manifest.cs
│ │ ├── OS.cs
│ │ ├── PackageQueryInfo.cs
│ │ ├── Platform.cs
│ │ ├── Readme.cs
│ │ ├── Repo.cs
│ │ ├── Tag.cs
│ │ ├── TagDocumentationType.cs
│ │ └── TagSyndication.cs
│ ├── MarBulkDeletion
│ │ └── BulkDeletionDescription.cs
│ ├── McrStatus
│ │ ├── CommitResult.cs
│ │ ├── CommitResultDetailed.cs
│ │ ├── CommitStatus.cs
│ │ ├── ContentSubstatus.cs
│ │ ├── ImageResult.cs
│ │ ├── ImageResultDetailed.cs
│ │ ├── ImageStatus.cs
│ │ ├── ImageSubstatus.cs
│ │ └── StageStatus.cs
│ ├── McrTags
│ │ ├── Repo.cs
│ │ ├── TagGroup.cs
│ │ └── TagsMetadata.cs
│ ├── Notary
│ │ └── Payload.cs
│ ├── Oci
│ │ ├── Descriptor.cs
│ │ └── Manifest.cs
│ ├── Oras
│ │ └── OrasDiscoverData.cs
│ ├── QueueNotification
│ │ └── QueueInfo.cs
│ └── Subscription
│ │ ├── GitFile.cs
│ │ ├── PipelineTrigger.cs
│ │ ├── Subscription.cs
│ │ └── SubscriptionManifest.cs
├── NotificationHelper.cs
├── NotificationService.cs
├── OAuthHelper.cs
├── OctokitClientFactory.cs
├── OrasClient.cs
├── PathHelper.cs
├── PipelineHelper.cs
├── ProcessService.cs
├── ReadmeHelper.cs
├── RegistryContentClientFactory.cs
├── RegistryCredentials.cs
├── RegistryCredentialsHostExtensions.cs
├── RegistryCredentialsProvider.cs
├── RegistryCredentialsProviderExtensions.cs
├── RegistryHttpClient.cs
├── RegistryServiceClient.cs
├── RetryHelper.cs
├── Services
│ ├── AzdoGitHttpClientExtensions.cs
│ ├── AzdoGitHttpClientFactory.cs
│ ├── BuildExtensions.cs
│ ├── IAzdoGitHttpClient.cs
│ ├── IAzdoGitHttpClientFactory.cs
│ ├── IBuildHttpClient.cs
│ ├── IKustoClient.cs
│ ├── IProjectHttpClient.cs
│ ├── IVssConnection.cs
│ ├── IVssConnectionFactory.cs
│ ├── KustoClientWrapper.cs
│ └── VssConnectionFactory.cs
├── StringExtensions.cs
├── SubscriptionHelper.cs
├── SystemCommandLineExtensions.cs
├── TaskHelper.cs
├── TreesClientExtensions.cs
├── ValidationException.cs
└── ViewModel
│ ├── IManifestOptionsInfo.cs
│ ├── ImageDigestInfo.cs
│ ├── ImageInfo.cs
│ ├── ManifestFilter.cs
│ ├── ManifestInfo.cs
│ ├── ModelExtensions.cs
│ ├── PlatformInfo.cs
│ ├── RepoInfo.cs
│ ├── TagInfo.cs
│ └── VariableHelper.cs
└── tests
├── AnnotateEolDigestsCommandTests.cs
├── BuildCommandTests.cs
├── CleanAcrImagesCommandTest.cs
├── CopyAcrImagesCommandTests.cs
├── CopyBaseImagesCommandTests.cs
├── DependencyInjectionTests.cs
├── GenerateBuildMatrixCommandTests.cs
├── GenerateDockerfilesCommandTests.cs
├── GenerateEolAnnotationDataCommandTests.cs
├── GenerateReadmesCommandTests.cs
├── GenerateSigningPayloadsCommandTests.cs
├── GetStaleImagesCommandTests.cs
├── Helpers
├── AsyncPageableMock.cs
├── ContainerRegistryHelper.cs
├── CopyImageHelper.cs
├── DigestInfoEqualityComparer.cs
├── DockerfileHelper.cs
├── ImageInfoHelper.cs
├── ManifestHelper.cs
├── ManifestServiceHelper.cs
├── MarStatusHelper.cs
├── ReturnsExtensions.cs
├── TestHelper.cs
└── TestHttpMessageHandler.cs
├── ImageArtifactDetailsTests.cs
├── ImageInfoHelperTests.cs
├── IngestKustoImageInfoCommandTests.cs
├── ManifestInfoTests.cs
├── ManifestServiceDefaultImplementationTests.cs
├── MarImageIngestionReporterTests.cs
├── McrTagsMetadataGeneratorTests.cs
├── MergeImageInfoFilesCommandTests.cs
├── Microsoft.DotNet.ImageBuilder.Tests.csproj
├── ModelExtensionsTests.cs
├── PlatformDataTests.cs
├── PlatformInfoTests.cs
├── PublishImageInfoCommandTests.cs
├── PublishManifestCommandTests.cs
├── PublishMcrDocsCommandTests.cs
├── QueueBuildCommandTests.cs
├── RegistryContentClientFactoryTests.cs
├── ShowManifestSchemaCommandTests.cs
├── TrimUnchangedPlatformsCommandTests.cs
├── VariableHelperTests.cs
├── WaitForMarAnnotationIngestionCommandTests.cs
├── WaitForMcrDocIngestionCommandTests.cs
└── WaitForMcrImageIngestionCommandTests.cs
/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "microsoft.dnceng.secretmanager": {
6 | "version": "1.1.0-beta.25257.1",
7 | "commands": [
8 | "secret-manager"
9 | ],
10 | "rollForward": false
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/.config/tsaoptions.json:
--------------------------------------------------------------------------------
1 | {
2 | "instanceUrl": "https://devdiv.visualstudio.com/",
3 | "template": "TFSDEVDIV",
4 | "projectName": "DEVDIV",
5 | "areaPath": "DevDiv\\NET Fundamentals\\.NET Acquisition\\Docker",
6 | "iterationPath": "DevDiv",
7 | "notificationAliases": [ "dotnetADTeam@microsoft.com" ],
8 | "repositoryName":"dotnet-docker-tools",
9 | "codebaseName": "dotnet-docker-tools"
10 | }
11 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "image": "mcr.microsoft.com/dotnet/sdk:9.0-noble",
3 | "features": {
4 | "ghcr.io/devcontainers/features/common-utils": {
5 | "username": "app",
6 | "userUid": 1654,
7 | "userGid": 1654
8 | },
9 | "ghcr.io/devcontainers/features/docker-in-docker:2": {}
10 | },
11 | "customizations": {
12 | "vscode": {
13 | "extensions": [
14 | "ms-dotnettools.csdevkit",
15 | "GitHub.copilot"
16 | ],
17 | "settings": {
18 | "dotnet.defaultSolution": "Microsoft.DotNet.DockerTools.sln",
19 | "remote.autoForwardPorts": true,
20 | "remote.autoForwardPortsSource": "hybrid",
21 | "remote.otherPortsAttributes": {
22 | "onAutoForward": "ignore"
23 | }
24 | }
25 | }
26 | },
27 | "remoteUser": "app",
28 | "onCreateCommand": "sudo chsh -s /bin/bash app"
29 | }
30 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | **/bin
2 | **/obj
3 | **/out
4 | **/.vscode
5 | **/.vs
6 | .Microsoft.DotNet.ImageBuilder
7 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "Bug Report"
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | ## Steps to reproduce the issue
8 | 1.
9 | 2.
10 | 3.
11 |
12 | ## Expected behavior
13 |
14 |
15 | ## Actual behavior
16 |
17 |
18 | ## Additional information (e.g. issue happens only occasionally)
19 |
20 |
21 | ## Output of `docker version`
22 |
23 | ```
24 | (paste your output here)
25 | ```
26 |
27 | ## Output of `docker info`
28 |
29 | ```
30 | (paste your output here)
31 | ```
32 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Please see the documentation for all configuration options:
2 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
3 |
4 | version: 2
5 | updates:
6 | - package-ecosystem: "nuget"
7 | directory: "/"
8 | schedule:
9 | interval: "weekly"
10 | day: "monday"
11 | time: "00:00"
12 | timezone: "America/Los_Angeles"
13 | commit-message:
14 | prefix: "[dependabot]"
15 | - package-ecosystem: "github-actions"
16 | directory: "/"
17 | schedule:
18 | interval: "weekly"
19 | day: "monday"
20 | time: "00:00"
21 | timezone: "America/Los_Angeles"
22 |
--------------------------------------------------------------------------------
/.github/labeler.yml:
--------------------------------------------------------------------------------
1 | # Add 'untriaged' label to any issue that gets opened
2 | untriaged:
3 | - '/.*/'
4 |
--------------------------------------------------------------------------------
/.github/workflows/labeler.yml:
--------------------------------------------------------------------------------
1 | name: "Issue Labeler"
2 | on:
3 | issues:
4 | types: [opened]
5 |
6 | permissions:
7 | issues: write
8 | contents: read
9 |
10 | jobs:
11 | triage:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: github/issue-labeler@v3.4
15 | with:
16 | configuration-path: .github/labeler.yml
17 | enable-versioned-regex: 0
18 | repo-token: ${{ github.token }}
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build output
2 | [Bb]in/
3 | [Oo]bj/
4 | [Oo]ut/
5 |
6 | # Visual Studio Code cache/options directory
7 | .vscode/
8 | .vs
9 |
10 | # Visual Studio user-specific files
11 | **/launchSettings.json
12 | **/*.user
13 |
14 | # ImageBuilder directory
15 | .Microsoft.DotNet.ImageBuilder
16 |
17 | # dotnet install directory
18 | .dotnet/
19 |
20 | # Test files
21 | *.trx
22 |
--------------------------------------------------------------------------------
/.vault-config/secrets.yaml:
--------------------------------------------------------------------------------
1 | # Partially copied from https://github.com/dotnet/arcade/blob/dfc6882da43decb37f12e0d9011ce82b25225578/.vault-config/product-builds-dnceng-pipeline-secrets.yaml
2 |
3 | storageLocation:
4 | type: azure-key-vault
5 | parameters:
6 | name: DotnetDockerKeyVault
7 | subscription: 941d4baa-5ef2-462e-b4b1-505791294610
8 |
9 | secrets:
10 | BotAccount-dotnet-docker-bot:
11 | type: github-account
12 | parameters:
13 | Name: dotnet-docker-bot
14 |
15 | BotAccount-dotnet-docker-bot-PAT:
16 | type: github-access-token
17 | parameters:
18 | gitHubBotAccountSecret: BotAccount-dotnet-docker-bot
19 | gitHubBotAccountName: dotnet-docker-bot
20 |
--------------------------------------------------------------------------------
/CODE-OF-CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | This project has adopted the code of conduct defined by the Contributor Covenant
4 | to clarify expected behavior in our community.
5 |
6 | For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
7 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Users referenced in this file will automatically be requested as reviewers for PRs that modify the given paths.
2 | # See https://help.github.com/articles/about-code-owners/
3 |
4 | * @dotnet/dotnet-docker-reviewers
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 .NET Foundation
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NuGet.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Docker Tools
2 |
3 | This is a repo to house some common tools for use in the various .NET Docker repos.
4 |
5 | ## Image Builder
6 |
7 | A tool used to build and publish Docker images.
8 |
9 | The Image Builder tool can be acquired via a Docker image available at [mcr.microsoft.com/dotnet-buildtools/image-builder](https://mcr.microsoft.com/v2/dotnet-buildtools/image-builder/tags/list) or built from source via the [build script](./src/Microsoft.DotNet.ImageBuilder/build.ps1).
10 |
11 | The Image Builder tool relies on metadata which defines various information needed to build and tag Docker images. The metadata is stored in a manifest.json file ([sample](https://github.com/dotnet/dotnet-docker/blob/main/manifest.json)). The metadata schema is defined in [source](./src/Microsoft.DotNet.ImageBuilder/src/Model).
12 |
13 | The full list of supported commands can be seen by running the tool.
14 |
15 | - Linux container environment: `docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock mcr.microsoft.com/dotnet-buildtools/image-builder:debian-20190223173930 -h`
16 |
17 | The list of support command options can be seen by specifying the `-h` command option. The following illustrates how to list the build options.
18 |
19 | - Linux container environment: `docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock mcr.microsoft.com/dotnet-buildtools/image-builder:debian-20190223173930 build -h`
20 |
--------------------------------------------------------------------------------
/documentation/images/base-image-dependency-flow-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet/docker-tools/22707be9c359f3d8fe2d3a90b96f33cc78df2595/documentation/images/base-image-dependency-flow-diagram.png
--------------------------------------------------------------------------------
/documentation/manifest-file.md:
--------------------------------------------------------------------------------
1 | # Manifest File
2 |
3 | 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.
4 |
5 | For a description of the schema, see the source location at https://github.com/dotnet/docker-tools/tree/main/src/Microsoft.DotNet.ImageBuilder/src/Models/Manifest. Alternatively, you can generate a JSON schema of the manifest by using the ImageBuilder tool:
6 | ```
7 | Microsoft.DotNet.ImageBuilder.exe showManifestSchema
8 | ```
9 |
--------------------------------------------------------------------------------
/eng/check-base-image-subscriptions-buildtools.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "manifest": {
4 | "owner": "dotnet",
5 | "repo": "dotnet-buildtools-prereqs-docker",
6 | "branch": "main",
7 | "path": "manifest.json",
8 | "variables": {
9 | "UniqueId": ""
10 | }
11 | },
12 | "imageInfo": {
13 | "owner": "dotnet",
14 | "repo": "versions",
15 | "branch": "main",
16 | "path": "build-info/docker/image-info.dotnet-dotnet-buildtools-prereqs-docker-main.json"
17 | },
18 | "pipelineTrigger": {
19 | "id": 1183,
20 | "pathVariable": "imageBuilder.pathArgs"
21 | }
22 | }
23 | ]
24 |
--------------------------------------------------------------------------------
/eng/common/Dockerfile.WithRepo:
--------------------------------------------------------------------------------
1 | # Use this Dockerfile to create an ImageBuilder image
2 | ARG IMAGE
3 | FROM $IMAGE
4 |
5 | WORKDIR /repo
6 | COPY . .
7 |
--------------------------------------------------------------------------------
/eng/common/Get-BaseImageStatus.ps1:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env pwsh
2 |
3 | <#
4 | .SYNOPSIS
5 | Outputs the status of external base images referenced in the Dockerfiles.
6 | #>
7 | [cmdletbinding()]
8 | param(
9 | # Path to the manifest file to use
10 | [string]
11 | $Manifest = "manifest.json",
12 |
13 | # Architecture to filter Dockerfiles to
14 | [string]
15 | $Architecture = "*",
16 |
17 | # A value indicating whether to run the script continously
18 | [switch]
19 | $Continuous,
20 |
21 | # Number of seconds to wait between each iteration
22 | [int]
23 | $ContinuousDelay = 10
24 | )
25 |
26 | Set-StrictMode -Version Latest
27 |
28 | $imageBuilderArgs = "getBaseImageStatus --manifest $Manifest --architecture $Architecture"
29 | if ($Continuous) {
30 | $imageBuilderArgs += " --continuous --continuous-delay $ContinuousDelay"
31 | }
32 |
33 | & "$PSScriptRoot/Invoke-ImageBuilder.ps1" -ImageBuilderArgs $imageBuilderArgs
34 |
--------------------------------------------------------------------------------
/eng/common/Get-ImageBuilder.ps1:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env pwsh
2 |
3 | # Load common image names
4 | $imageNameVars = & $PSScriptRoot/Get-ImageNameVars.ps1
5 | foreach ($varName in $imageNameVars.Keys) {
6 | Set-Variable -Name $varName -Value $imageNameVars[$varName] -Scope Global
7 | }
8 |
9 | & docker inspect ${imageNames.imagebuilderName} | Out-Null
10 | if (-not $?) {
11 | Write-Output "Pulling"
12 | & $PSScriptRoot/Invoke-WithRetry.ps1 "docker pull ${imageNames.imagebuilderName}"
13 | }
14 |
--------------------------------------------------------------------------------
/eng/common/Get-ImageNameVars.ps1:
--------------------------------------------------------------------------------
1 | # Returns a hashtable of variable name-to-value mapping representing the image name variables
2 | # used by the common build infrastructure.
3 |
4 | $vars = @{}
5 | Get-Content $PSScriptRoot/templates/variables/docker-images.yml |
6 | Where-Object { $_.Trim().Length -gt 0 -and $_.Trim() -notlike 'variables:' -and $_.Trim() -notlike '# *' } |
7 | ForEach-Object {
8 | $parts = $_.Split(':', 2)
9 | $vars[$parts[0].Trim()] = $parts[1].Trim()
10 | }
11 |
12 | return $vars
13 |
--------------------------------------------------------------------------------
/eng/common/Invoke-CleanupDocker.ps1:
--------------------------------------------------------------------------------
1 | Set-StrictMode -Version Latest
2 | $ErrorActionPreference = 'Stop'
3 |
4 | docker ps -a -q | ForEach-Object { docker rm -f $_ }
5 |
6 | docker volume prune -f
7 |
8 | # Preserve the tagged Windows base images and the common eng infra images (e.g. ImageBuilder)
9 | # to avoid the expense of having to repull continuously.
10 | $imageNameVars = & $PSScriptRoot/Get-ImageNameVars.ps1
11 |
12 | docker images --format "{{.Repository}}:{{.Tag}} {{.ID}}" |
13 | Where-Object {
14 | $localImage = $_
15 | $localImage.Contains(": ")`
16 | -Or -Not ($localImage.StartsWith("mcr.microsoft.com/windows")`
17 | -Or ($imageNameVars.Values.Where({ $localImage.StartsWith($_) }, 'First').Count -gt 0)) } |
18 | ForEach-Object { $_.Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)[1] } |
19 | Select-Object -Unique |
20 | ForEach-Object { docker rmi -f $_ }
21 |
--------------------------------------------------------------------------------
/eng/common/Invoke-WithRetry.ps1:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env pwsh
2 |
3 | # Executes a command and retries if it fails.
4 | [cmdletbinding()]
5 | param (
6 | [Parameter(Mandatory = $true)][string]$Cmd,
7 | [int]$Retries = 2,
8 | [int]$WaitFactor = 6
9 | )
10 |
11 | Set-StrictMode -Version Latest
12 | $ErrorActionPreference = 'Stop'
13 |
14 | $count = 0
15 | $completed = $false
16 |
17 | Write-Output "Executing '$Cmd'"
18 |
19 | while (-not $completed) {
20 | try {
21 | Invoke-Expression $Cmd
22 | if (-not $(Test-Path variable:LASTEXITCODE) -or $LASTEXITCODE -eq 0) {
23 | $completed = $true
24 | continue
25 | }
26 | }
27 | catch {
28 | }
29 |
30 | $count++
31 |
32 | if ($count -lt $Retries) {
33 | $wait = [Math]::Pow($WaitFactor, $count - 1)
34 | Write-Output "Retry $count/$Retries, retrying in $wait seconds..."
35 | Start-Sleep $wait
36 | }
37 | else {
38 | Write-Output "Retry $count/$Retries, no more retries left."
39 | throw "Failed to execute '$Cmd'"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/eng/common/Retain-Build.ps1:
--------------------------------------------------------------------------------
1 | # Adapted from https://github.com/dotnet/arcade/blob/main/eng/common/retain-build.ps1
2 | Param(
3 | [Parameter(Mandatory = $true)][int] $BuildId,
4 | [Parameter(Mandatory = $true)][string] $AzdoOrgUri,
5 | [Parameter(Mandatory = $true)][string] $AzdoProject,
6 | [Parameter(Mandatory = $true)][string] $Token
7 | )
8 |
9 | $ErrorActionPreference = 'Stop'
10 | Set-StrictMode -Version 2.0
11 |
12 | function Get-AzDOHeaders(
13 | [string] $Token) {
14 | $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":${Token}"))
15 | $headers = @{"Authorization" = "Basic $base64AuthInfo" }
16 | return $headers
17 | }
18 |
19 | function Update-BuildRetention(
20 | [string] $AzdoOrgUri,
21 | [string] $AzdoProject,
22 | [int] $BuildId,
23 | [string] $Token) {
24 | $headers = Get-AzDOHeaders -Token $Token
25 | $requestBody = "{
26 | `"keepForever`": `"true`"
27 | }"
28 |
29 | $requestUri = "${AzdoOrgUri}/${AzdoProject}/_apis/build/builds/${BuildId}?api-version=6.0"
30 | Write-Host "Attempting to retain build using the following URI: ${requestUri} ..."
31 |
32 | try {
33 | Invoke-RestMethod -Uri $requestUri -Method Patch -Body $requestBody -Header $headers -contentType "application/json"
34 | Write-Host "Updated retention settings for build ${BuildId}."
35 | }
36 | catch {
37 | Write-Host "##[error] Failed to update retention settings for build: $($_.Exception.Response.StatusDescription)"
38 | exit 1
39 | }
40 | }
41 |
42 | Update-BuildRetention -AzdoOrgUri $AzdoOrgUri -AzdoProject $AzdoProject -BuildId $BuildId -Token $Token
43 | exit 0
44 |
--------------------------------------------------------------------------------
/eng/common/build.ps1:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env pwsh
2 |
3 | <#
4 | .SYNOPSIS
5 | Builds the Dockerfiles
6 | #>
7 |
8 | [cmdletbinding()]
9 | param(
10 | # Product versions to filter by
11 | [string[]]$Version = "*",
12 |
13 | # Names of OS to filter by
14 | [string[]]$OS,
15 |
16 | # Type of architecture to filter by
17 | [string]$Architecture,
18 |
19 | # Additional custom path filters
20 | [string[]]$Paths,
21 |
22 | # Path to manifest file
23 | [string]$Manifest = "manifest.json",
24 |
25 | # Additional args to pass to ImageBuilder
26 | [string]$OptionalImageBuilderArgs
27 | )
28 |
29 | Set-StrictMode -Version Latest
30 | $ErrorActionPreference = 'Stop'
31 |
32 | function Log {
33 | param ([string] $Message)
34 |
35 | Write-Output $Message
36 | }
37 |
38 | function Exec {
39 | param ([string] $Cmd)
40 |
41 | Log "Executing: '$Cmd'"
42 | Invoke-Expression $Cmd
43 | if ($LASTEXITCODE -ne 0) {
44 | throw "Failed: '$Cmd'"
45 | }
46 | }
47 |
48 | pushd $PSScriptRoot/../..
49 | try {
50 | $args = $OptionalImageBuilderArgs
51 |
52 | if ($Version) {
53 | $args += ($Version | foreach { ' --version "{0}"' -f $_ })
54 | }
55 |
56 | if ($OS) {
57 | $args += ($OS | foreach { ' --os-version "{0}"' -f $_ })
58 | }
59 |
60 | if ($Architecture) {
61 | $args += ' --architecture "{0}"' -f $Architecture
62 | }
63 |
64 | if ($Paths) {
65 | $args += ($Paths | foreach { ' --path "{0}"' -f $_ })
66 | }
67 |
68 | if ($Manifest) {
69 | $args += ' --manifest "{0}"' -f $Manifest
70 | }
71 |
72 | ./eng/common/Invoke-ImageBuilder.ps1 "build $args"
73 | }
74 | finally {
75 | popd
76 | }
77 |
--------------------------------------------------------------------------------
/eng/common/pull-image.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Stop script on NZEC
4 | set -e
5 | # Stop script if unbound variable found (use ${var:-} if intentional)
6 | set -u
7 |
8 | say_err() {
9 | printf "%b\n" "Error: $1" >&2
10 | }
11 |
12 | # Executes a command and retries if it fails.
13 | execute() {
14 | local count=0
15 | until "$@"; do
16 | local exit=$?
17 | count=$(( $count + 1 ))
18 | if [ $count -lt $retries ]; then
19 | local wait=$(( waitFactor ** (( count - 1 )) ))
20 | echo "Retry $count/$retries exited $exit, retrying in $wait seconds..."
21 | sleep $wait
22 | else
23 | say_err "Retry $count/$retries exited $exit, no more retries left."
24 | return $exit
25 | fi
26 | done
27 |
28 | return 0
29 | }
30 |
31 | scriptName=$0
32 | retries=5
33 | waitFactor=6
34 | image=$1
35 |
36 | echo "Pulling Docker image $image"
37 | execute docker pull $image
38 |
--------------------------------------------------------------------------------
/eng/common/readme.md:
--------------------------------------------------------------------------------
1 | # Don't touch this folder
2 |
3 | uuuuuuuuuuuuuuuuuuuu
4 | u" uuuuuuuuuuuuuuuuuu "u
5 | u" u$$$$$$$$$$$$$$$$$$$$u "u
6 | u" u$$$$$$$$$$$$$$$$$$$$$$$$u "u
7 | u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u
8 | u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u
9 | u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u
10 | $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $
11 | $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $
12 | $ $$$" ... "$... ...$" ... "$$$ ... "$$$ $
13 | $ $$$u `"$$$$$$$ $$$ $$$$$ $$ $$$ $$$ $
14 | $ $$$$$$uu "$$$$ $$$ $$$$$ $$ """ u$$$ $
15 | $ $$$""$$$ $$$$ $$$u "$$$" u$$ $$$$$$$$ $
16 | $ $$$$....,$$$$$..$$$$$....,$$$$..$$$$$$$$ $
17 | $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $
18 | "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u"
19 | "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u"
20 | "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u"
21 | "u "$$$$$$$$$$$$$$$$$$$$$$$$" u"
22 | "u "$$$$$$$$$$$$$$$$$$$$" u"
23 | "u """""""""""""""""" u"
24 | """"""""""""""""""""
25 |
26 | !!! Changes made in this directory are subject to being overwritten by automation !!!
27 |
28 | The files in this directory are shared by all .NET Docker repos. If you need to make changes to these files, open an issue or submit a pull request in https://github.com/dotnet/docker-tools.
--------------------------------------------------------------------------------
/eng/common/templates/jobs/copy-base-images-staging.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: name
3 | type: string
4 | default: null
5 | - name: pool
6 | type: object
7 | default: {}
8 | - name: customInitSteps
9 | type: stepList
10 | default: []
11 | - name: additionalOptions
12 | type: string
13 | default: ''
14 | - name: continueOnError
15 | type: string
16 | default: false
17 |
18 | jobs:
19 | - template: /eng/common/templates/jobs/copy-base-images.yml@self
20 | parameters:
21 | name: ${{ parameters.name }}
22 | pool: ${{ parameters.pool }}
23 | customInitSteps: ${{ parameters.customInitSteps }}
24 | additionalOptions: ${{ parameters.additionalOptions }}
25 | acr:
26 | server: $(acr-staging.server)
27 | serviceConnection:
28 | tenantId: $(internal-mirror.serviceConnection.tenantId)
29 | clientId: $(internal-mirror.serviceConnection.clientId)
30 | id: $(internal-mirror.serviceConnection.id)
31 | subscription: $(acr-staging.subscription)
32 | resourceGroup: $(acr-staging.resourceGroup)
33 | repoPrefix: $(mirrorRepoPrefix)
34 |
--------------------------------------------------------------------------------
/eng/common/templates/jobs/copy-base-images.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: name
3 | type: string
4 | default: null
5 | - name: pool
6 | type: object
7 | default: {}
8 | - name: acr
9 | type: object
10 | default: null
11 | - name: repoPrefix
12 | type: string
13 | default: null
14 | - name: customInitSteps
15 | type: stepList
16 | default: []
17 | - name: additionalOptions
18 | type: string
19 | default: ''
20 | - name: continueOnError
21 | type: string
22 | default: false
23 | - name: forceDryRun
24 | type: boolean
25 | default: false
26 |
27 | jobs:
28 | - job: ${{ parameters.name }}
29 | pool: ${{ parameters.pool }}
30 | steps:
31 | - template: /eng/common/templates/steps/init-docker-linux.yml@self
32 | - ${{ parameters.customInitSteps }}
33 | - template: /eng/common/templates/steps/copy-base-images.yml@self
34 | parameters:
35 | acr: ${{ parameters.acr }}
36 | repoPrefix: ${{ parameters.repoPrefix }}
37 | additionalOptions: ${{ parameters.additionalOptions }}
38 | continueOnError: ${{ parameters.continueOnError }}
39 | forceDryRun: ${{ parameters.forceDryRun }}
40 |
--------------------------------------------------------------------------------
/eng/common/templates/jobs/test-images-linux-client.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | name: null
3 | pool: {}
4 | matrix: {}
5 | testJobTimeout: 60
6 | preBuildValidation: false
7 | internalProjectName: null
8 | customInitSteps: []
9 | sourceBuildPipelineRunId: ""
10 |
11 | jobs:
12 | - job: ${{ parameters.name }}
13 | ${{ if eq(parameters.preBuildValidation, 'false') }}:
14 | condition: and(succeeded(), ${{ parameters.matrix }})
15 | dependsOn: GenerateTestMatrix
16 | strategy:
17 | matrix: $[ ${{ parameters.matrix }} ]
18 | ${{ if eq(parameters.preBuildValidation, 'true') }}:
19 | condition: and(succeeded(), ne(variables.testScriptPath, ''))
20 | pool: ${{ parameters.pool }}
21 | timeoutInMinutes: ${{ parameters.testJobTimeout }}
22 | steps:
23 | - template: /eng/common/templates/steps/test-images-linux-client.yml@self
24 | parameters:
25 | preBuildValidation: ${{ parameters.preBuildValidation }}
26 | internalProjectName: ${{ parameters.internalProjectName }}
27 | customInitSteps: ${{ parameters.customInitSteps }}
28 | sourceBuildPipelineRunId: ${{ parameters.sourceBuildPipelineRunId }}
29 |
--------------------------------------------------------------------------------
/eng/common/templates/jobs/test-images-windows-client.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | name: null
3 | pool: {}
4 | matrix: {}
5 | testJobTimeout: 60
6 | internalProjectName: null
7 | customInitSteps: []
8 | sourceBuildPipelineRunId: ""
9 |
10 | jobs:
11 | - job: ${{ parameters.name }}
12 | condition: and(succeeded(), ${{ parameters.matrix }})
13 | dependsOn: GenerateTestMatrix
14 | pool: ${{ parameters.pool }}
15 | strategy:
16 | matrix: $[ ${{ parameters.matrix }} ]
17 | timeoutInMinutes: ${{ parameters.testJobTimeout }}
18 | steps:
19 | - template: /eng/common/templates/steps/test-images-windows-client.yml@self
20 | parameters:
21 | internalProjectName: ${{ parameters.internalProjectName }}
22 | customInitSteps: ${{ parameters.customInitSteps }}
23 | sourceBuildPipelineRunId: ${{ parameters.sourceBuildPipelineRunId }}
24 |
--------------------------------------------------------------------------------
/eng/common/templates/stages/setup-service-connections.yml:
--------------------------------------------------------------------------------
1 | # This stage exists to tell Azure DevOps about all of the service connections
2 | # that will be used in the pipeline. A service connection will not work unless
3 | # it is declared in this stage's parameters, even if your pipeline has already
4 | # been granted access to the service connection. This stage also does not need
5 | # to complete before the service connection is used.
6 | parameters:
7 | - name: pool
8 | type: object
9 | # serviceConnections object shape:
10 | # - name: string
11 | - name: serviceConnections
12 | type: object
13 | default: []
14 |
15 | stages:
16 |
17 | - stage: SetupServiceConnectionsStage
18 | displayName: Setup service connections
19 | jobs:
20 |
21 | - job: SetupServiceConnectionsJob
22 | displayName: Setup service connections
23 | pool: ${{ parameters.pool }}
24 | steps:
25 |
26 | - ${{ each serviceConnection in parameters.serviceConnections }}:
27 | - task: AzureCLI@2
28 | displayName: Setup ${{ serviceConnection.name }}
29 | inputs:
30 | azureSubscription: ${{ serviceConnection.name }}
31 | scriptType: pscore
32 | scriptLocation: inlineScript
33 | inlineScript: |
34 | az account show
35 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/clean-acr-images.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | repo: null
3 | subscription: null
4 | resourceGroup: null
5 | acr: null
6 | action: null
7 | age: null
8 | customArgs: ""
9 | internalProjectName: null
10 | steps:
11 | - template: /eng/common/templates/steps/run-imagebuilder.yml@self
12 | parameters:
13 | displayName: Clean ACR Images - ${{ parameters.repo }}
14 | serviceConnections:
15 | - name: acr
16 | id: $(clean.serviceConnection.id)
17 | tenantId: $(clean.serviceConnection.tenantId)
18 | clientId: $(clean.serviceConnection.clientId)
19 | internalProjectName: ${{ parameters.internalProjectName }}
20 | args: >-
21 | cleanAcrImages
22 | ${{ parameters.repo }}
23 | ${{ parameters.subscription }}
24 | ${{ parameters.resourceGroup }}
25 | ${{ parameters.acr }}
26 | --action ${{ parameters.action }}
27 | --age ${{ parameters.age }}
28 | ${{ parameters.customArgs }}
29 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/cleanup-docker-linux.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | condition: true
3 |
4 | steps:
5 | ################################################################################
6 | # Cleanup local Docker server
7 | ################################################################################
8 | - script: docker stop $(docker ps -q) || true
9 | displayName: Stop Running Containers
10 | condition: and(always(), ${{ parameters.condition }})
11 | continueOnError: true
12 | - script: docker system prune -a -f --volumes
13 | displayName: Cleanup Docker
14 | condition: and(always(), ${{ parameters.condition }})
15 | continueOnError: true
16 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/cleanup-docker-windows.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | condition: true
3 |
4 | steps:
5 | ################################################################################
6 | # Cleanup Docker Resources
7 | ################################################################################
8 | - powershell: $(engCommonPath)/Invoke-CleanupDocker.ps1
9 | displayName: Cleanup Docker Images
10 | condition: and(always(), ${{ parameters.condition }})
11 | continueOnError: true
12 | - powershell: |
13 | if (Test-Path $(Build.BinariesDirectory)\.Microsoft.DotNet.ImageBuilder) {
14 | Remove-Item $(Build.BinariesDirectory)\.Microsoft.DotNet.ImageBuilder -Force -Recurse;
15 | }
16 | displayName: Cleanup Image Builder
17 | condition: and(always(), ${{ parameters.condition }})
18 | continueOnError: true
19 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/init-common.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | condition: true
3 |
4 | steps:
5 | - powershell: |
6 | $sourceBranch=$Env:BUILD_SOURCEBRANCH -replace "refs/heads/","" -replace "refs/tags/","" -replace "refs/pull/",""
7 | echo "##vso[task.setvariable variable=sourceBranch]$sourceBranch"
8 | displayName: Define Source Branch Variable
9 | condition: and(succeeded(), ${{ parameters.condition }})
10 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/parse-test-arg-arrays.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - powershell: |
3 | # Formats the OS versions in a compact human-readable form (e.g. "os1/os2")
4 | $osVersionsDisplayName = '$(osVersions)' -Replace '--os-version ', '' -Replace ' ', '/'
5 |
6 | # Defines a PowerShell snippet in string-form that can be used to initialize an array of the OS versions
7 | $osVersionsArrayInitStr = "@('" + $($osVersionsDisplayName -Replace "/", "', '") + "')"
8 |
9 | echo "##vso[task.setvariable variable=osVersionsDisplayName]$osVersionsDisplayName"
10 | echo "##vso[task.setvariable variable=osVersionsArrayInitStr]$osVersionsArrayInitStr"
11 |
12 | # Defines a PowerShell snippet in string-form that can be used to initialize an array of the image builder paths
13 | $pathInitStr = "@('" + $('$(imageBuilderPaths)' -Replace '--path', '' -Replace " ", "', '") + "')"
14 | echo "##vso[task.setvariable variable=imageBuilderPathsArrayInitStr]$pathInitStr"
15 | displayName: Parse Test Arg Arrays
16 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/publish-artifact.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: path
3 | type: string
4 | - name: artifactName
5 | type: string
6 | - name: displayName
7 | type: string
8 | - name: internalProjectName
9 | type: string
10 | - name: publicProjectName
11 | type: string
12 | - name: condition
13 | type: string
14 | default: 'true'
15 |
16 | steps:
17 | - ${{ if eq(variables['System.TeamProject'], parameters.internalProjectName) }}:
18 | - task: 1ES.PublishPipelineArtifact@1
19 | inputs:
20 | path: ${{ parameters.path }}
21 | artifact: ${{ parameters.artifactName }}
22 | displayName: ${{ parameters.displayName }}
23 | condition: and(succeeded(), ${{ parameters.condition }})
24 | - ${{ if eq(variables['System.TeamProject'], parameters.publicProjectName) }}:
25 | - publish: ${{ parameters.path }}
26 | artifact: ${{ parameters.artifactName }}
27 | displayName: ${{ parameters.displayName }}
28 | condition: and(succeeded(), ${{ parameters.condition }})
29 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/publish-readmes.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | dryRunArg: ""
3 | condition: true
4 |
5 | steps:
6 | - script: >
7 | $(runImageBuilderCmd) publishMcrDocs
8 | --manifest '$(manifest)'
9 | --registry-override '$(acr.server)'
10 | '$(mcrDocsRepoInfo.userName)'
11 | '$(mcrDocsRepoInfo.email)'
12 | $(mcrDocsRepoInfo.authArgs)
13 | '$(publicGitRepoUri)'
14 | ${{ parameters.dryRunArg }}
15 | $(manifestVariables)
16 | $(imageBuilder.queueArgs)
17 | --git-owner 'Microsoft'
18 | --git-repo 'mcrdocs'
19 | --git-branch 'main'
20 | --git-path 'teams'
21 | $(additionalPublishMcrDocsArgs)
22 | name: PublishReadmes
23 | displayName: Publish Readmes
24 | condition: ${{ parameters.condition }}
25 | - template: /eng/common/templates/steps/wait-for-mcr-doc-ingestion.yml@self
26 | parameters:
27 | commitDigest: $(PublishReadmes.readmeCommitDigest)
28 | condition: and(${{ parameters.condition }}, ne(variables['PublishReadmes.readmeCommitDigest'], ''))
29 | dryRunArg: ${{ parameters.dryRunArg }}
30 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/retain-build.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - powershell: >
3 | $(engCommonPath)/Retain-Build.ps1
4 | -BuildId $(Build.BuildId)
5 | -AzdoOrgUri '$(System.CollectionUri)'
6 | -AzdoProject '$(System.TeamProject)'
7 | -Token '$(System.AccessToken)'
8 | displayName: Enable permanent build retention
9 | condition: and(succeeded(), eq(variables.retainBuild, 'true'))
10 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/run-pwsh-with-auth.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: name
3 | type: string
4 | default: ""
5 | - name: displayName
6 | type: string
7 | default: "Run PowerShell"
8 | - name: serviceConnection
9 | type: string
10 | default: ""
11 | - name: command
12 | type: string
13 | default: null
14 | - name: continueOnError
15 | type: boolean
16 | default: false
17 | - name: dockerClientOS
18 | type: string
19 | default: "linux"
20 | - name: condition
21 | type: string
22 | default: true
23 |
24 | steps:
25 | - task: AzureCLI@2
26 | ${{ if ne(parameters.name, '') }}:
27 | name: ${{ parameters.name }}
28 | displayName: ${{ parameters.displayName }} (Authenticated)
29 | continueOnError: ${{ parameters.continueOnError }}
30 | condition: and(succeeded(), ${{ parameters.condition }})
31 | inputs:
32 | azureSubscription: ${{ parameters.serviceConnection }}
33 | addSpnToEnvironment: true
34 | ${{ if eq(parameters.dockerClientOS, 'windows') }}:
35 | scriptType: 'ps'
36 | ${{ else }}:
37 | scriptType: 'pscore'
38 | scriptLocation: 'inlineScript'
39 | inlineScript: ${{ parameters.command }};
40 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/set-dry-run.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - powershell: |
3 | # Use dry-run option for certain publish operations if this is not a production build
4 | $dryRunArg=""
5 | if (-not "$(officialRepoPrefixes)".Split(',').Contains("$(publishRepoPrefix)") `
6 | -or "$(System.TeamProject)" -eq "$(publicProjectName)")
7 | {
8 | $dryRunArg="--dry-run"
9 | }
10 | echo "##vso[task.setvariable variable=dryRunArg]$dryRunArg"
11 | displayName: Set dry-run arg for non-prod
12 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/set-image-info-path-var.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | publicSourceBranch: null
3 |
4 | steps:
5 | - powershell: |
6 | $basePath = "$(gitHubVersionsRepoInfo.path)"
7 |
8 | $publicSourceBranch = "${{ parameters.publicSourceBranch }}"
9 |
10 | if ($publicSourceBranch -eq "") {
11 | throw "publicSourceBranch variable is not set"
12 | }
13 |
14 | $buildRepoName = "$(Build.Repository.Name)".Replace("/", "-")
15 | $imageInfoName = "image-info.$buildRepoName-$publicSourceBranch$(imageInfoVariant).json"
16 |
17 | echo "##vso[task.setvariable variable=imageInfoVersionsPath]$basePath/$imageInfoName"
18 | echo "##vso[task.setvariable variable=gitHubImageInfoVersionsPath]$(gitHubVersionsRepoInfo.path)/$imageInfoName"
19 | displayName: Set Image Info Path Vars
20 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/validate-branch.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | internalProjectName: null
3 |
4 | steps:
5 | - ${{ if and(eq(variables['System.TeamProject'], parameters.internalProjectName), ne(variables['Build.Reason'], 'PullRequest')) }}:
6 | - powershell: |
7 | if ("$(officialBranches)".Split(',').Contains("$(sourceBranch)") `
8 | -and "$(officialRepoPrefixes)".Split(',').Contains("$(publishRepoPrefix)"))
9 | {
10 | echo "Conditions met for official build, continuing..."
11 | exit 0
12 | }
13 |
14 | if (-not "$(officialRepoPrefixes)".Split(',').Contains("$(publishRepoPrefix)"))
15 | {
16 | echo "This build is a test build, continuing..."
17 | exit 0
18 | }
19 |
20 | if ("$(overrideOfficialBranchValidation)" -eq "true")
21 | {
22 | echo "Variable overrideOfficialBranchValidation is set to true, continuing..."
23 | exit 0
24 | }
25 |
26 | echo "##vso[task.logissue type=error]Official builds must be done from an official branch ($(officialBranches)) and repo prefix ($(officialRepoPrefixes))."
27 | exit 1
28 | displayName: Validate Branch
29 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/wait-for-mcr-doc-ingestion.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | commitDigest: null
3 | condition: true
4 | dryRunArg: ""
5 |
6 | steps:
7 | - template: /eng/common/templates/steps/run-imagebuilder.yml@self
8 | parameters:
9 | displayName: Wait for MCR Doc Ingestion
10 | condition: and(${{ parameters.condition }}, eq(variables['waitForIngestionEnabled'], 'true'))
11 | serviceConnections:
12 | - name: mar
13 | id: $(marStatus.serviceConnection.id)
14 | tenantId: $(marStatus.serviceConnection.tenantId)
15 | clientId: $(marStatus.serviceConnection.clientId)
16 | internalProjectName: 'internal'
17 | args: >-
18 | waitForMcrDocIngestion
19 | '${{ parameters.commitDigest }}'
20 | --timeout '$(mcrDocIngestionTimeout)'
21 | ${{ parameters.dryRunArg }}
22 |
--------------------------------------------------------------------------------
/eng/common/templates/steps/wait-for-mcr-image-ingestion.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | imageInfoPath: null
3 | minQueueTime: null
4 | condition: true
5 | dryRunArg: ""
6 |
7 | steps:
8 | - template: /eng/common/templates/steps/run-imagebuilder.yml@self
9 | parameters:
10 | displayName: Wait for Image Ingestion
11 | condition: and(${{ parameters.condition }}, eq(variables['waitForIngestionEnabled'], 'true'))
12 | serviceConnections:
13 | - name: mar
14 | id: $(marStatus.serviceConnection.id)
15 | tenantId: $(marStatus.serviceConnection.tenantId)
16 | clientId: $(marStatus.serviceConnection.clientId)
17 | internalProjectName: 'internal'
18 | args: >-
19 | waitForMcrImageIngestion
20 | '${{ parameters.imageInfoPath }}'
21 | --manifest '$(manifest)'
22 | --repo-prefix '$(publishRepoPrefix)'
23 | --min-queue-time '${{ parameters.minQueueTime }}'
24 | --timeout '$(mcrImageIngestionTimeout)'
25 | $(manifestVariables)
26 | ${{ parameters.dryRunArg }}
27 |
--------------------------------------------------------------------------------
/eng/common/templates/variables/common-paths.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | engCommonRelativePath: eng/common
3 | engCommonPath: $(Build.Repository.LocalPath)/$(engCommonRelativePath)
4 | engPath: $(Build.Repository.LocalPath)/eng
5 | testScriptPath: ""
6 |
--------------------------------------------------------------------------------
/eng/common/templates/variables/docker-images.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | imageNames.imageBuilderName: mcr.microsoft.com/dotnet-buildtools/image-builder:2718660
3 | imageNames.imageBuilder: $(imageNames.imageBuilderName)
4 | imageNames.imageBuilder.withrepo: imagebuilder-withrepo:$(Build.BuildId)-$(System.JobId)
5 | imageNames.testRunner: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux3.0-docker-testrunner
6 | imageNames.testRunner.withrepo: testrunner-withrepo:$(Build.BuildId)-$(System.JobId)
7 |
--------------------------------------------------------------------------------
/eng/eng-common-file-pusher-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "commitMessage": "Update common Docker engineering infrastructure with latest",
3 | "pullRequestTitle": "Update common Docker engineering infrastructure with latest",
4 | "pullRequestDescription": "Updates the common Docker engineering infrastructure with latest changes from the dotnet/docker-tools repo.",
5 | "sourcePath": "eng/common",
6 | "workingBranchSuffix": "-update-eng-common",
7 | "repos": [
8 | {
9 | "owner": "dotnet",
10 | "name": "dotnet-docker",
11 | "branch": "nightly"
12 | },
13 | {
14 | "owner": "dotnet",
15 | "name": "dotnet-docker",
16 | "branch": "main"
17 | },
18 | {
19 | "owner": "dotnet",
20 | "name": "dotnet-buildtools-prereqs-docker",
21 | "branch": "main"
22 | },
23 | {
24 | "owner": "microsoft",
25 | "name": "dotnet-framework-docker",
26 | "branch": "main"
27 | }
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/eng/image-builder-tag-update-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "commitMessage": "Update Image Builder tag reference",
3 | "pullRequestTitle": "Update Image Builder tag reference",
4 | "pullRequestDescription": "Updates the common pipeline variables to reference an updated tag of Image Builder.",
5 | "sourcePath": "eng/common/templates/variables/docker-images.yml",
6 | "workingBranchSuffix": "-image-builder-tag",
7 | "repos": [
8 | {
9 | "owner": "dotnet",
10 | "name": "docker-tools",
11 | "branch": "main"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/eng/pipelines/annotate-eol-digests.yml:
--------------------------------------------------------------------------------
1 | trigger: none
2 | pr: none
3 |
4 | parameters:
5 | - name: dataFile
6 | displayName: Relative path to EOL annotations data file (e.g. eol-3.1.json for file in root of the branch)
7 | type: string
8 |
9 | variables:
10 | - template: templates/variables/image-builder.yml
11 | - name: publishEolAnnotations
12 | value: true
13 | - name: dryRunArg
14 | value: ""
15 |
16 | extends:
17 | template: /eng/common/templates/1es-official.yml@self
18 | parameters:
19 | serviceConnections:
20 | - name: $(publish.serviceConnectionName)
21 | - name: $(marStatus.serviceConnectionName)
22 | stages:
23 | - stage: eolAnnotate
24 | displayName: Annotate EOL images
25 | dependsOn: []
26 | jobs:
27 | - job: AnnotateImages
28 | displayName: Annotate EOL Images
29 | steps:
30 | - template: /eng/common/templates/steps/init-docker-linux.yml@self
31 | - template: /eng/common/templates/steps/annotate-eol-digests.yml@self
32 | parameters:
33 | dataFile: /repo/${{ parameters.dataFile }}
34 |
--------------------------------------------------------------------------------
/eng/pipelines/cg-detection.yml:
--------------------------------------------------------------------------------
1 | # This pipelines builds all projects in the repository outside of Dockerfiles so that the artifacts
2 | # can be scanned by SDL steps. SDL steps do not scan artifacts that are built within Dockerfiles.
3 | trigger:
4 | branches:
5 | include:
6 | - main
7 | pr: none
8 |
9 | parameters:
10 | # Setting cgDryRun will run CG but not submit the results
11 | - name: cgDryRun
12 | type: boolean
13 | default: false
14 | displayName: CG Dry Run
15 |
16 | variables:
17 | - template: /eng/pipelines/templates/variables/common.yml@self
18 | # Skip CG detection (for debugging project builds, etc.)
19 | - name: skipComponentGovernanceDetection
20 | value: false
21 |
22 | extends:
23 | template: /eng/common/templates/1es-official.yml@self
24 | parameters:
25 | cgDryRun: ${{ parameters.cgDryRun }}
26 | stages:
27 | - stage: CgDetection
28 | displayName: CG Detection
29 | jobs:
30 | - template: /eng/common/templates/jobs/cg-build-projects.yml@self
31 | parameters:
32 | cgDryRun: ${{ parameters.cgDryRun }}
33 |
--------------------------------------------------------------------------------
/eng/pipelines/check-base-image-updates.yml:
--------------------------------------------------------------------------------
1 | trigger: none
2 | pr: none
3 |
4 | schedules:
5 | - cron: "0 0,4,8,12,16,20 * * *"
6 | displayName: Daily build
7 | branches:
8 | include:
9 | - main
10 | always: true
11 |
12 | variables:
13 | - template: /eng/pipelines/templates/variables/common.yml@self
14 |
15 | extends:
16 | template: /eng/common/templates/1es-official.yml@self
17 | parameters:
18 | serviceConnections:
19 | - name: $(acr-staging.serviceConnectionName)
20 | stages:
21 | - stage: CheckBaseImages
22 | displayName: Check Base Images
23 | dependsOn: []
24 | jobs:
25 | - template: /eng/pipelines/templates/jobs/check-base-image-updates.yml@self
26 | parameters:
27 | jobName: CheckBaseImages
28 | subscriptionsPath: eng/check-base-image-subscriptions.json
29 | publicProjectName: ${{ variables.publicProjectName }}
30 | internalProjectName: ${{ variables.internalProjectName }}
31 | - template: /eng/pipelines/templates/jobs/check-base-image-updates.yml@self
32 | parameters:
33 | jobName: CheckBaseImages_BuildTools
34 | subscriptionsPath: eng/check-base-image-subscriptions-buildtools.json
35 | customGetStaleImagesArgs: --base-override-regex '^((centos|debian|ubuntu):.+)' --base-override-sub '$(overrideRegistry)/$1'
36 | publicProjectName: ${{ variables.publicProjectName }}
37 | internalProjectName: ${{ variables.internalProjectName }}
38 |
--------------------------------------------------------------------------------
/eng/pipelines/cleanup-acr-images-custom.yml:
--------------------------------------------------------------------------------
1 | trigger: none
2 | pr: none
3 |
4 | variables:
5 | - template: templates/variables/common.yml
6 |
7 | jobs:
8 | - job: Build
9 | pool:
10 | vmImage: $(defaultLinuxAmd64PoolImage)
11 | steps:
12 | - template: ../common/templates/steps/init-docker-linux.yml
13 | - template: ../common/templates/steps/clean-acr-images.yml
14 | parameters:
15 | internalProjectName: ${{ variables.internalProjectName }}
16 | repo: $(repo)
17 | subscription: $(acr.subscription)
18 | resourceGroup: $(acr.resourceGroup)
19 | acr: $(acr.server)
20 | action: $(action)
21 | age: $(age)
22 | customArgs: $(customArgs)
23 |
--------------------------------------------------------------------------------
/eng/pipelines/dotnet-buildtools-image-builder-official.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | batch: true
3 | branches:
4 | include:
5 | - main
6 | paths:
7 | include:
8 | - src/*
9 | pr: none
10 |
11 | parameters:
12 | - name: sourceBuildPipelineRunId
13 | displayName: >
14 | Source build pipeline run ID. This refers to runs of *this pipeline*.
15 | Override this parametre in combination with disabling the `Build` stage to
16 | test or publish images that were build in a different pipeline run.
17 | The default value should be left alone if you want to build new images.
18 | type: string
19 | default: $(Build.BuildId)
20 |
21 | variables:
22 | - template: /eng/pipelines/templates/variables/image-builder.yml@self
23 | parameters:
24 | sourceBuildPipelineRunId: ${{ parameters.sourceBuildPipelineRunId }}
25 | - name: publishEolAnnotations
26 | value: true
27 |
28 | extends:
29 | template: /eng/common/templates/1es-official.yml@self
30 | parameters:
31 | serviceConnections:
32 | - name: $(internal-mirror.serviceConnectionName)
33 | - name: $(build.serviceConnectionName)
34 | - name: $(publish.serviceConnectionName)
35 | - name: $(kusto.serviceConnectionName)
36 | - name: $(marStatus.serviceConnectionName)
37 | stages:
38 | - template: /eng/common/templates/stages/dotnet/build-test-publish-repo.yml@self
39 | parameters:
40 | noCache: true
41 | internalProjectName: ${{ variables.internalProjectName }}
42 | publicProjectName: ${{ variables.publicProjectName }}
43 | sourceBuildPipelineRunId: ${{ parameters.sourceBuildPipelineRunId }}
44 |
--------------------------------------------------------------------------------
/eng/pipelines/dotnet-buildtools-image-builder-pr.yml:
--------------------------------------------------------------------------------
1 | pr:
2 | branches:
3 | include:
4 | - main
5 | - feature/*
6 | paths:
7 | include:
8 | - src/*
9 |
10 | trigger: none
11 |
12 | variables:
13 | - template: templates/variables/image-builder.yml
14 |
15 | stages:
16 | - template: ../common/templates/stages/dotnet/build-test-publish-repo.yml
17 | parameters:
18 | buildMatrixType: platformVersionedOs
19 | noCache: true
20 | internalProjectName: ${{ variables.internalProjectName }}
21 | publicProjectName: ${{ variables.publicProjectName }}
22 |
--------------------------------------------------------------------------------
/eng/pipelines/dotnet-docker-tools-eng-validation-pr.yml:
--------------------------------------------------------------------------------
1 | pr:
2 | branches:
3 | include:
4 | - main
5 | paths:
6 | include:
7 | - eng/*
8 | - test/*
9 |
10 | trigger: none
11 |
12 | variables:
13 | - template: templates/variables/eng-validation.yml
14 |
15 | stages:
16 | - template: ../common/templates/stages/dotnet/build-test-publish-repo.yml
17 | parameters:
18 | buildMatrixType: platformVersionedOs
19 | noCache: true
20 | internalProjectName: ${{ variables.internalProjectName }}
21 | publicProjectName: ${{ variables.publicProjectName }}
22 |
--------------------------------------------------------------------------------
/eng/pipelines/dotnet-docker-tools-eng-validation.yml:
--------------------------------------------------------------------------------
1 | pr: none
2 |
3 | trigger:
4 | branches:
5 | include:
6 | - main
7 | paths:
8 | include:
9 | - eng/*
10 | - test/*
11 |
12 | variables:
13 | - template: /eng/pipelines/templates/variables/eng-validation.yml@self
14 |
15 | extends:
16 | template: /eng/common/templates/1es-official.yml@self
17 | parameters:
18 | serviceConnections:
19 | - name: $(internal-mirror.serviceConnectionName)
20 | - name: $(build.serviceConnectionName)
21 | - name: $(publish.serviceConnectionName)
22 | - name: $(kusto.serviceConnectionName)
23 | - name: $(marStatus.serviceConnectionName)
24 | stages:
25 | - template: /eng/common/templates/stages/dotnet/build-test-publish-repo.yml@self
26 | parameters:
27 | noCache: true
28 | internalProjectName: ${{ variables.internalProjectName }}
29 | publicProjectName: ${{ variables.publicProjectName }}
30 |
--------------------------------------------------------------------------------
/eng/pipelines/mirror-base-images.yml:
--------------------------------------------------------------------------------
1 | trigger: none
2 | pr: none
3 |
4 | schedules:
5 | - cron: "0 0,6,12,18 * * *"
6 | displayName: Daily build
7 | branches:
8 | include:
9 | - main
10 | always: true
11 |
12 | parameters:
13 | - name: dryRun
14 | displayName: Dry Run
15 | type: boolean
16 | default: false
17 |
18 | variables:
19 | - template: /eng/common/templates/variables/dotnet/common.yml@self
20 | - name: mirrorRepoPrefix
21 | value: ""
22 |
23 | extends:
24 | template: /eng/common/templates/1es-official.yml@self
25 | parameters:
26 | serviceConnections:
27 | - name: $(public-mirror.serviceConnectionName)
28 | stages:
29 | - stage: MirrorBaseImages
30 | displayName: Mirror Base Images
31 | dependsOn: []
32 | jobs:
33 | - template: /eng/pipelines/templates/jobs/copy-base-images-public-mirror.yml@self
34 | parameters:
35 | name: "Public"
36 | subscriptionsPath: eng/check-base-image-subscriptions.json
37 | dryRun: ${{ parameters.dryRun }}
38 | - template: /eng/pipelines/templates/jobs/copy-base-images-public-mirror.yml@self
39 | parameters:
40 | name: "Public_Buildtools"
41 | subscriptionsPath: eng/check-base-image-subscriptions-buildtools.json
42 | dryRun: ${{ parameters.dryRun }}
43 |
--------------------------------------------------------------------------------
/eng/pipelines/push-common-updates.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | batch: true
3 | branches:
4 | include:
5 | - main
6 | paths:
7 | include:
8 | - eng/common/*
9 | pr: none
10 |
11 | variables:
12 | - template: templates/variables/common.yml
13 |
14 | jobs:
15 | - job: Build
16 | pool:
17 | vmImage: $(defaultLinuxAmd64PoolImage)
18 | steps:
19 | - script: >
20 | docker build . -f ./eng/src/file-pusher/Dockerfile -t file-pusher
21 | displayName: Build File Pusher
22 | - script: >
23 | docker run --rm file-pusher
24 | $(filters)
25 | ./eng/eng-common-file-pusher-config.json
26 | $(dotnetDockerBot.userName)
27 | $(dotnetDockerBot.email)
28 | $(BotAccount-dotnet-docker-bot-PAT)
29 | displayName: Run File Pusher
30 |
--------------------------------------------------------------------------------
/eng/pipelines/secret-management-weekly.yml:
--------------------------------------------------------------------------------
1 | trigger: none
2 |
3 | schedules:
4 | - cron: 0 12 * * 0
5 | displayName: Weekly Sunday build
6 | branches:
7 | include:
8 | - main
9 | always: true
10 |
11 | variables:
12 | - template: templates/variables/common.yml
13 |
14 | extends:
15 | template: /eng/common/templates/1es-unofficial.yml@self
16 | parameters:
17 | stages:
18 | - stage: SynchronizeSecrets
19 | jobs:
20 | - job: Synchronize
21 | displayName: Synchronize secrets
22 | steps:
23 | - task: UseDotNet@2
24 | displayName: Install .NET 8.0 SDK
25 | inputs:
26 | packageType: sdk
27 | version: 8.0.x
28 | installationPath: '$(Build.Repository.LocalPath)/.dotnet'
29 |
30 | - task: UseDotNet@2
31 | displayName: Install .NET 6.0 runtime
32 | inputs:
33 | packageType: runtime
34 | version: 6.0.x
35 | installationPath: '$(Build.Repository.LocalPath)/.dotnet'
36 |
37 | - powershell: .dotnet/dotnet tool restore --tool-manifest .config/dotnet-tools.json
38 | workingDirectory: $(Build.Repository.LocalPath)
39 | displayName: Restore secret-manager
40 |
41 | - task: AzureCLI@2
42 | inputs:
43 | azureSubscription: DotNet Eng Services Secret Manager
44 | scriptType: pscore
45 | scriptLocation: inlineScript
46 | inlineScript: |
47 | Get-ChildItem .vault-config/*.yaml |% { .dotnet/dotnet secret-manager synchronize $_}
48 | workingDirectory: $(Build.Repository.LocalPath)
49 | displayName: Run secret-manager synchronize
50 |
--------------------------------------------------------------------------------
/eng/pipelines/templates/jobs/copy-base-images-public-mirror.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: name
3 | type: string
4 | default: null
5 | - name: subscriptionsPath
6 | type: string
7 | default: null
8 | - name: customInitSteps
9 | type: stepList
10 | default: []
11 | - name: dryRun
12 | type: boolean
13 | default: false
14 |
15 | jobs:
16 | - template: /eng/common/templates/jobs/copy-base-images.yml@self
17 | parameters:
18 | name: MirrorBaseImages_${{ parameters.name }}
19 | pool:
20 | name: $(default1ESInternalPoolName)
21 | image: $(default1ESInternalPoolImage)
22 | os: linux
23 | acr:
24 | server: $(public-mirror.server)
25 | serviceConnection:
26 | id: $(public-mirror.serviceConnection.id)
27 | tenantId: $(public-mirror.serviceConnection.tenantId)
28 | clientId: $(public-mirror.serviceConnection.clientId)
29 | subscription: $(public-mirror.subscription)
30 | resourceGroup: $(public-mirror.resourceGroup)
31 | repoPrefix: $(mirrorRepoPrefix)
32 | customInitSteps: ${{ parameters.customInitSteps }}
33 | additionalOptions: '--subscriptions-path ${{ parameters.subscriptionsPath }}'
34 | forceDryRun: ${{ parameters.dryRun }}
35 |
--------------------------------------------------------------------------------
/eng/pipelines/templates/variables/build-test-publish.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: sourceBuildPipelineRunId
3 | type: string
4 | default: ''
5 |
6 | variables:
7 | - template: /eng/pipelines/templates/variables/common.yml@self
8 | parameters:
9 | sourceBuildPipelineRunId: ${{ parameters.sourceBuildPipelineRunId }}
10 | - template: /eng/common/templates/variables/dotnet/build-test-publish.yml@self
11 | - name: publicSourceBranch
12 | value: main
13 |
--------------------------------------------------------------------------------
/eng/pipelines/templates/variables/common.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: sourceBuildPipelineRunId
3 | type: string
4 | default: ''
5 |
6 | variables:
7 | - template: /eng/common/templates/variables/dotnet/common.yml@self
8 | parameters:
9 | sourceBuildPipelineRunId: ${{ parameters.sourceBuildPipelineRunId }}
10 |
--------------------------------------------------------------------------------
/eng/pipelines/templates/variables/eng-validation.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | - template: build-test-publish.yml
3 | - name: manifest
4 | value: eng/tests/pipeline-validation/test-manifest.json
5 | - name: testScriptPath
6 | value: ./eng/tests/pipeline-validation/run-tests.ps1
7 | - name: testResultsDirectory
8 | value: eng/tests/pipeline-validation/TestResults/
9 | - name: publicGitRepoUri
10 | value: https://github.com/dotnet/dotnet-docker-test
11 | - name: publishRepoPrefix
12 | value: test/
13 | - name: imageInfoVariant
14 | value: "-test"
15 |
--------------------------------------------------------------------------------
/eng/pipelines/templates/variables/image-builder.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: sourceBuildPipelineRunId
3 | type: string
4 | default: '$(Build.BuildId)'
5 |
6 | variables:
7 | - template: /eng/pipelines/templates/variables/build-test-publish.yml@self
8 | parameters:
9 | sourceBuildPipelineRunId: ${{ parameters.sourceBuildPipelineRunId }}
10 | - name: manifest
11 | value: src/Microsoft.DotNet.ImageBuilder/manifest.json
12 | - name: publishReadme
13 | value: false
14 | - name: manifestVariables
15 | value: --var UniqueId=${{ parameters.sourceBuildPipelineRunId }}
16 | - name: imageInfoVariant
17 | value: "-imagebuilder"
18 | - name: testScriptPath
19 | value: ./src/Microsoft.DotNet.ImageBuilder/run-tests.ps1
20 | - name: testResultsDirectory
21 | value: src/Microsoft.DotNet.ImageBuilder/tests/TestResults/
22 | - name: publicGitRepoUri
23 | value: https://github.com/dotnet/docker-tools
24 |
--------------------------------------------------------------------------------
/eng/pipelines/update-image-builder-tag.yml:
--------------------------------------------------------------------------------
1 | trigger: none
2 | pr: none
3 |
4 | resources:
5 | pipelines:
6 | - pipeline: image-builder
7 | source: docker-tools-imagebuilder
8 | trigger:
9 | branches:
10 | include:
11 | - main
12 | stages:
13 | - Publish
14 |
15 | variables:
16 | - template: templates/variables/common.yml
17 |
18 | jobs:
19 | - job: Build
20 | pool:
21 | vmImage: $(defaultLinuxAmd64PoolImage)
22 | steps:
23 | - download: image-builder
24 | artifact: source-build-id
25 | displayName: Download Source Build ID artifact
26 | - script: >
27 | echo "##vso[task.setvariable variable=imageBuilderTag]$(cat $(Pipeline.Workspace)/image-builder/source-build-id/source-build-id.txt)"
28 | displayName: Get Image Builder Tag
29 | - script: >
30 | docker build . -f ./eng/src/yaml-updater/Dockerfile -t yaml-updater
31 | displayName: Build YAML Updater
32 | - script: >
33 | docker run --rm yaml-updater
34 | ./eng/image-builder-tag-update-config.json
35 | variables/imageNames.imageBuilderName
36 | mcr.microsoft.com/dotnet-buildtools/image-builder:$(imageBuilderTag)
37 | $(dotnetDockerBot.userName)
38 | $(dotnetDockerBot.email)
39 | $(BotAccount-dotnet-docker-bot-PAT)
40 | dotnet
41 | docker-tools
42 | main
43 | displayName: Run YAML Updater
44 |
--------------------------------------------------------------------------------
/eng/pipelines/upload-file.yml:
--------------------------------------------------------------------------------
1 | trigger: none
2 | pr: none
3 |
4 | parameters:
5 | - name: containerName
6 | displayName: Blob Container Name
7 | type: string
8 | - name: sourceFilePath
9 | displayName: Source File Path
10 | type: string
11 | - name: destName
12 | displayName: Destination Name
13 | type: string
14 |
15 | variables:
16 | - template: /eng/pipelines/templates/variables/common.yml@self
17 |
18 | extends:
19 | template: /eng/common/templates/1es-official.yml@self
20 | parameters:
21 | stages:
22 | - stage: UploadFile
23 | displayName: Upload File
24 | jobs:
25 | - job: Execute
26 | steps:
27 | - script: >
28 | az storage blob upload
29 | --account-name $(dotnetBinaries.accountName)
30 | --account-key $(dotnetbinaries-accountkey)
31 | --container-name ${{ parameters.containerName }}
32 | --file $(Build.SourcesDirectory)/${{ parameters.sourceFilePath }}
33 | --name ${{ parameters.destName }}
34 | displayName: Upload File
35 |
--------------------------------------------------------------------------------
/eng/src/file-pusher/AzDoSafeTraceListenerWrapper.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.Diagnostics;
6 |
7 | namespace FilePusher;
8 |
9 | public class AzDoSafeTraceListenerWrapper(TraceListener innerTraceListener) : TraceListener
10 | {
11 | private readonly TraceListener _innerTraceListener = innerTraceListener;
12 |
13 | public override void Write(string? message)
14 | {
15 | _innerTraceListener.Write(EscapeVsoDirectives(message));
16 | }
17 |
18 | public override void WriteLine(string? message)
19 | {
20 | _innerTraceListener.WriteLine(EscapeVsoDirectives(message));
21 | }
22 |
23 | ///
24 | /// This method "escapes" Azure DevOps Pipeline tasks/variable assignments in strings so that they are safe to
25 | /// output to the console in pipeline.
26 | /// This prevents issues like https://github.com/dotnet/docker-tools/issues/1388, where pushing files containing
27 | /// these AzDO variable assignments results in pipeline failure.
28 | /// Azure DevOps documentation: https://learn.microsoft.com/en-us/azure/devops/pipelines/process/set-variables-scripts
29 | ///
30 | private static string? EscapeVsoDirectives(string? message)
31 | {
32 | return message?.Replace("##vso", "#VSO_DIRECTIVE");
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/eng/src/file-pusher/Dockerfile:
--------------------------------------------------------------------------------
1 | # This Dockerfile is intended to be built at the root of the repo.
2 |
3 | # build image
4 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build-env
5 |
6 | WORKDIR /file-pusher
7 |
8 | # copy csproj and restore as distinct layers
9 | COPY eng/src/file-pusher/*.csproj ./
10 | COPY NuGet.config ./
11 | RUN dotnet restore
12 |
13 | # copy everything else and build
14 | COPY eng/src/file-pusher/. ./
15 | RUN dotnet publish -c Release -o out --no-restore
16 |
17 |
18 | # runtime image
19 | FROM mcr.microsoft.com/dotnet/runtime:9.0-alpine
20 |
21 | # copy file-pusher
22 | WORKDIR /file-pusher
23 | COPY --from=build-env /file-pusher/out ./
24 |
25 | # copy repo
26 | WORKDIR /repo
27 | COPY . ./
28 |
29 | ENTRYPOINT ["/file-pusher/file-pusher"]
30 |
--------------------------------------------------------------------------------
/eng/src/file-pusher/Models/Config.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using Newtonsoft.Json;
6 |
7 | namespace FilePusher.Models
8 | {
9 | public class Config
10 | {
11 | [JsonProperty(Required = Required.Always)]
12 | public string CommitMessage { get; set; } = string.Empty;
13 |
14 | public string? PullRequestDescription { get; set; }
15 |
16 | [JsonProperty(Required = Required.Always)]
17 | public string PullRequestTitle { get; set; } = string.Empty;
18 |
19 | [JsonProperty(Required = Required.Always)]
20 | public string SourcePath { get; set; } = string.Empty;
21 |
22 | [JsonProperty(Required = Required.Always)]
23 | public string WorkingBranchSuffix { get; set; } = string.Empty;
24 |
25 | public GitRepo[] Repos { get; set; } = System.Array.Empty();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/eng/src/file-pusher/Models/GitRepo.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using Newtonsoft.Json;
6 |
7 | namespace FilePusher.Models
8 | {
9 | public class GitRepo
10 | {
11 | [JsonProperty(Required = Required.Always)]
12 | public string Owner { get; set; } = string.Empty;
13 |
14 | [JsonProperty(Required = Required.Always)]
15 | public string Name { get; set; } = string.Empty;
16 |
17 | [JsonProperty(Required = Required.Always)]
18 | public string Branch { get; set; } = string.Empty;
19 |
20 | public override string ToString() => $"{Owner}/{Name}/{Branch}";
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/eng/src/file-pusher/Options.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.CommandLine;
7 | using System.Linq;
8 |
9 | namespace FilePusher
10 | {
11 | public class Options
12 | {
13 | public IEnumerable Filters { get; set; } = Enumerable.Empty();
14 | public string GitEmail { get; set; } = string.Empty;
15 | public string GitAuthToken { get; set; } = string.Empty;
16 | public string GitUser { get; set; } = string.Empty;
17 | public string ConfigPath { get; set; } = string.Empty;
18 |
19 | public static IEnumerable GetCliOptions() =>
20 | new Symbol[]
21 | {
22 | new Option("--filter", () => Array.Empty(),
23 | "Filter to apply to repositories of the config json - wildcard chars * and ? supported")
24 | {
25 | Name = nameof(Filters),
26 | AllowMultipleArgumentsPerToken = false
27 | },
28 | new Argument(nameof(ConfigPath), "Path to the config json file"),
29 | new Argument(nameof(GitUser), "GitHub user used to make PR"),
30 | new Argument(nameof(GitEmail), "GitHub email used to make PR"),
31 | new Argument(nameof(GitAuthToken), "GitHub authorization token used to make PR")
32 | };
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/eng/src/file-pusher/file-pusher.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0
6 | FilePusher
7 | latest
8 | enable
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/eng/src/yaml-updater/Dockerfile:
--------------------------------------------------------------------------------
1 | # This Dockerfile is intended to be built at the root of the repo.
2 |
3 | # build image
4 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build-env
5 |
6 | WORKDIR /src
7 |
8 | # copy csproj and restore as distinct layers
9 | COPY eng/src/file-pusher/*.csproj ./file-pusher/
10 | COPY eng/src/yaml-updater/*.csproj ./yaml-updater/
11 | COPY NuGet.config ./
12 |
13 | RUN dotnet restore ./yaml-updater/*.csproj
14 |
15 | # copy everything else and build
16 | COPY eng/src/file-pusher/. ./file-pusher/
17 | COPY eng/src/yaml-updater/. ./yaml-updater/
18 | RUN dotnet publish ./yaml-updater/*.csproj -c Release -o out --no-restore
19 |
20 |
21 | # runtime image
22 | FROM mcr.microsoft.com/dotnet/runtime:9.0-alpine
23 |
24 | # copy yaml-updater
25 | WORKDIR /yaml-updater
26 | COPY --from=build-env /src/out ./
27 |
28 | # copy repo
29 | WORKDIR /repo
30 | COPY . ./
31 |
32 | ENTRYPOINT ["/yaml-updater/yaml-updater"]
33 |
--------------------------------------------------------------------------------
/eng/src/yaml-updater/yaml-updater.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0
6 | YamlUpdater
7 | latest
8 | enable
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/eng/tests/pipeline-validation/1.0/nanoserver-1809/amd64/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/windows/nanoserver:1809
2 |
--------------------------------------------------------------------------------
/eng/tests/pipeline-validation/1.0/noble/amd64/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu.azurecr.io/ubuntu:noble
2 |
--------------------------------------------------------------------------------
/eng/tests/pipeline-validation/1.0/noble/arm64v8/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu.azurecr.io/ubuntu:noble
2 |
--------------------------------------------------------------------------------
/eng/tests/pipeline-validation/README.placeholder.md:
--------------------------------------------------------------------------------
1 | # Test Readme
2 |
3 | A placeholder file for testing purposes. The image tags and URLs referenced here are not meant to be accessible. This is just test data.
4 |
5 | # Full Tag Listing
6 |
7 | ## Linux amd64 Tags
8 | Tags | Dockerfile | OS Version
9 | -----------| -------------| -------------
10 | noble | [Dockerfile](https://github.com/dotnet/dotnet-docker-test/blob/main/test/pipeline-validation/1.0/noble/amd64/Dockerfile) | Ubuntu 24.04
11 |
12 | ## Linux arm64 Tags
13 | Tags | Dockerfile | OS Version
14 | -----------| -------------| -------------
15 | noble-arm64 | [Dockerfile](https://github.com/dotnet/dotnet-docker-test/blob/main/test/pipeline-validation/1.0/noble/arm64v8/Dockerfile) | Ubuntu 24.04
16 |
17 | ## Windows Server 2019 amd64 Tags
18 | Tag | Dockerfile
19 | ---------| ---------------
20 | nanoserver-1809 | [Dockerfile](https://github.com/dotnet/dotnet-docker-test/blob/main/test/pipeline-validation/1.0/nanoserver-1809/amd64/Dockerfile)
21 |
22 | # Next Header
23 |
--------------------------------------------------------------------------------
/eng/tests/pipeline-validation/run-tests.ps1:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env pwsh
2 | #
3 | # Copyright (c) .NET Foundation and contributors. All rights reserved.
4 | # Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 | #
6 |
7 | [cmdletbinding()]
8 | param(
9 | [string]$Version,
10 | [string]$Architecture,
11 | [string[]]$Paths,
12 | [string[]]$OSVersions,
13 | [string]$Registry,
14 | [string]$RepoPrefix,
15 | [switch]$DisableHttpVerification,
16 | [switch]$PullImages,
17 | [string]$ImageInfoPath,
18 | [ValidateSet("functional", "pre-build")]
19 | [string[]]$TestCategories = @("functional")
20 | )
21 |
22 | # This script intentionally doesn't run any tests. It is to be used for pipeline validation.
23 |
24 | # Ensure that a TestResults folder exists to allow test pipeline to target folder for copying.
25 | $scriptDir = Split-Path -parent $PSCommandPath
26 | New-Item -ItemType Directory $scriptDir/TestResults
27 |
--------------------------------------------------------------------------------
/eng/tests/pipeline-validation/templates/README.md:
--------------------------------------------------------------------------------
1 | # Test Readme
2 |
3 | A placeholder file for testing purposes. The image tags and URLs referenced here are not meant to be accessible. This is just test data.
4 |
5 | # Full Tag Listing
6 |
7 | ## Linux amd64 Tags
8 | Tags | Dockerfile | OS Version
9 | -----------| -------------| -------------
10 | noble | [Dockerfile](https://github.com/dotnet/dotnet-docker-test/blob/main/test/pipeline-validation/1.0/noble/amd64/Dockerfile) | Ubuntu 24.04
11 |
12 | ## Linux arm64 Tags
13 | Tags | Dockerfile | OS Version
14 | -----------| -------------| -------------
15 | noble-arm64 | [Dockerfile](https://github.com/dotnet/dotnet-docker-test/blob/main/test/pipeline-validation/1.0/noble/arm64v8/Dockerfile) | Ubuntu 24.04
16 |
17 | ## Windows Server 2019 amd64 Tags
18 | Tag | Dockerfile
19 | ---------| ---------------
20 | nanoserver-1809 | [Dockerfile](https://github.com/dotnet/dotnet-docker-test/blob/main/test/pipeline-validation/1.0/nanoserver-1809/amd64/Dockerfile)
21 |
22 | # Next Header
23 |
--------------------------------------------------------------------------------
/eng/tests/pipeline-validation/templates/test-tags.yml:
--------------------------------------------------------------------------------
1 | $(McrTagsYmlRepo:test)
2 | $(McrTagsYmlTagGroup:noble)
3 | $(McrTagsYmlTagGroup:noble-arm64)
4 | $(McrTagsYmlTagGroup:nanoserver-1809)
5 |
--------------------------------------------------------------------------------
/eng/tests/pipeline-validation/test-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "registry": "mcr.microsoft.com",
3 | "repos": [
4 | {
5 | "id": "test",
6 | "name": "dotnet/test",
7 | "readme": "README.placeholder.md",
8 | "readmeTemplate": "templates/README.md",
9 | "mcrTagsMetadataTemplate": "templates/test-tags.yml",
10 | "images": [
11 | {
12 | "platforms": [
13 | {
14 | "dockerfile": "1.0/noble/amd64",
15 | "os": "linux",
16 | "osVersion": "noble",
17 | "tags": {
18 | "noble": {}
19 | }
20 | },
21 | {
22 | "architecture": "arm64",
23 | "dockerfile": "1.0/noble/arm64v8",
24 | "os": "linux",
25 | "osVersion": "noble",
26 | "tags": {
27 | "noble-arm64": {}
28 | },
29 | "variant": "v8"
30 | },
31 | {
32 | "dockerfile": "1.0/nanoserver-1809/amd64",
33 | "os": "windows",
34 | "osVersion": "nanoserver-1809",
35 | "tags": {
36 | "nanoserver-1809": {}
37 | }
38 | }
39 | ]
40 | }
41 | ]
42 | }
43 | ]
44 | }
45 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/.dockerignore:
--------------------------------------------------------------------------------
1 | **/bin
2 | **/obj
3 | **/out
4 | **/.vscode
5 | **/.vs
6 | **/Dockerfile.windows
7 | **/Dockerfile.linux
8 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/Dockerfile.linux:
--------------------------------------------------------------------------------
1 | # Use this Dockerfile to create a runner image
2 | # docker build -t image-builder .
3 | # docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v :/repo -w /repo image-builder
4 |
5 | # build Microsoft.DotNet.ImageBuilder
6 | FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0-azurelinux3.0 AS build-env
7 | ARG TARGETARCH
8 |
9 | # download oras package tarball
10 | WORKDIR /
11 | RUN oras_version=1.2.2 \
12 | && curl -fSL --output oras_linux.tar.gz https://github.com/oras-project/oras/releases/download/v${oras_version}/oras_${oras_version}_linux_${TARGETARCH}.tar.gz \
13 | && mkdir -p oras-install/ \
14 | && tar -zxf oras_linux.tar.gz -C oras-install/ \
15 | && rm -rf oras_linux.tar.gz
16 |
17 | WORKDIR /image-builder
18 |
19 | # restore packages before copying entire source - provides optimizations when rebuilding
20 | COPY NuGet.config ./
21 | COPY src/Microsoft.DotNet.ImageBuilder.csproj ./src/
22 | RUN dotnet restore -r linux-$TARGETARCH ./src/Microsoft.DotNet.ImageBuilder.csproj
23 |
24 | # copy everything else and publish
25 | COPY . ./
26 | RUN dotnet publish -r linux-$TARGETARCH ./src/Microsoft.DotNet.ImageBuilder.csproj --self-contained=true --no-restore -o out
27 |
28 |
29 | # build runtime image
30 | FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-azurelinux3.0
31 |
32 | # install tooling
33 | RUN tdnf install -y \
34 | moby-engine \
35 | docker-cli \
36 | docker-buildx \
37 | git \
38 | && tdnf clean all
39 |
40 | # install oras tool
41 | COPY --from=build-env ["/oras-install/oras", "/usr/local/bin"]
42 |
43 | # install image-builder
44 | WORKDIR /image-builder
45 | COPY --from=build-env /image-builder/out ./
46 |
47 | ENTRYPOINT ["/image-builder/Microsoft.DotNet.ImageBuilder"]
48 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/NuGet.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/README.md:
--------------------------------------------------------------------------------
1 | # ImageBuilder
2 |
3 | ImageBuilder is a tool used to build and publish Docker images.
4 |
5 | ## Building the ImageBuilder container image
6 |
7 | All commands are relative to the root of the repo.
8 |
9 | ### Build a single-platform image
10 |
11 | Using Linux or Windows, simply run the build script:
12 |
13 | ```pwsh
14 | # From src/Microsoft.DotNet.ImageBuilder
15 | pwsh -f build.ps1
16 |
17 | # From the root of the repo
18 | pwsh -wd ./src/Microsoft.DotNet.ImageBuilder/ -f src/Microsoft.DotNet.ImageBuilder/build.ps1
19 | ```
20 |
21 | ### Build a multi-arch Linux image
22 |
23 | If you don't need to test on Windows, this is the easiest way to create a multi-arch manifest list.
24 |
25 | ```pwsh
26 | # Build the image. Choose one or both platforms, and optionally push to a registry or load the image locally.
27 | docker buildx build [--push,--load] --platform [linux/amd64,linux/arm64] -t "${REPO}:${TAG}" -f .\src\Microsoft.DotNet.ImageBuilder\Dockerfile.linux .\src\Microsoft.DotNet.ImageBuilder\
28 | ```
29 |
30 | ### Create a multi-platform manifest list
31 |
32 | First, build and push Linux and Windows images separately.
33 | Gather the specific digests for the images you want to put into one manifest list.
34 | Then, create the manifest list and push it:
35 |
36 | ```pwsh
37 | docker manifest create "${REPO}:${TAG}" "${REPO}@sha256:abcde12345" "${REPO}@sha256:fghij67890"
38 | docker manifest push "${REPO}:${TAG}"
39 | ```
40 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/build.ps1:
--------------------------------------------------------------------------------
1 | Set-StrictMode -Version Latest
2 | $ErrorActionPreference = 'Stop'
3 |
4 | & ./../../eng/common/build.ps1 `
5 | -Manifest src/Microsoft.DotNet.ImageBuilder/manifest.json `
6 | -OptionalImageBuilderArgs "--var UniqueId=$(Get-Date -Format yyyyMMddHHmmss)" `
7 | -Paths "*"
8 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/run-tests.ps1:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env pwsh
2 | #
3 | # Copyright (c) .NET Foundation and contributors. All rights reserved.
4 | # Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 | #
6 |
7 | [cmdletbinding()]
8 | param(
9 | [string]$Version,
10 | [string]$Architecture,
11 | [string[]]$Paths,
12 | [string[]]$OSVersions,
13 | [string]$Registry,
14 | [string]$RepoPrefix,
15 | [switch]$DisableHttpVerification,
16 | [switch]$PullImages,
17 | [string]$ImageInfoPath,
18 | [ValidateSet("functional", "pre-build")]
19 | [string[]]$TestCategories = @("functional")
20 | )
21 |
22 | Set-StrictMode -Version Latest
23 | $ErrorActionPreference = 'Stop'
24 |
25 | $dotnetInstallDir = "$PSScriptRoot/../../.dotnet"
26 |
27 | Push-Location $PSScriptRoot
28 |
29 | if ($TestCategories.Contains("pre-build")) {
30 | Write-Output "There are no pre-build tests"
31 | }
32 |
33 | if ($TestCategories.Contains("functional")) {
34 | try {
35 | & ../../eng/common/Install-DotNetSdk.ps1 $dotnetInstallDir
36 |
37 | $cmd = "$DotnetInstallDir/dotnet test $PSScriptRoot/tests/Microsoft.DotNet.ImageBuilder.Tests.csproj --logger:trx"
38 |
39 | Write-Output "Executing '$cmd'"
40 | Invoke-Expression $cmd
41 | if ($LASTEXITCODE -ne 0) {
42 | throw "Failed: '$cmd'"
43 | }
44 | }
45 | finally {
46 | Pop-Location
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/src/AuthHelper.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using Azure.Core;
9 | using Azure.ResourceManager;
10 |
11 | namespace Microsoft.DotNet.ImageBuilder
12 | {
13 | public static class AuthHelper
14 | {
15 | public static Guid GetTenantId(ILoggerService loggerService, TokenCredential credential)
16 | {
17 | ArmClient armClient = new(credential);
18 | IEnumerable tenants = armClient.GetTenants().ToList()
19 | .Select(tenantResource => tenantResource.Data.TenantId)
20 | .Where(guid => guid != null)
21 | .Select(guid => (Guid)guid);
22 |
23 | if (!tenants.Any())
24 | {
25 | throw new Exception("Found no tenants for given credential.");
26 | }
27 |
28 | if (tenants.Count() > 1)
29 | {
30 | string allTenantIds = string.Join(' ', tenants.Select(guid => guid.ToString()));
31 | loggerService.WriteMessage("Found more than one tenant. Selecting the first one.");
32 | loggerService.WriteMessage($"Tenants: {allTenantIds}");
33 | }
34 |
35 | return tenants.First();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/src/AzureScopes.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | namespace Microsoft.DotNet.ImageBuilder;
5 |
6 | #nullable enable
7 | internal static class AzureScopes
8 | {
9 | public const string ScopeSuffix = "/.default";
10 | public const string DefaultAzureManagementScope = "https://management.azure.com" + ScopeSuffix;
11 | public const string ContainerRegistryScope = "https://containerregistry.azure.net" + ScopeSuffix;
12 | public const string McrStatusScope = "api://c00053c3-a979-4ee6-b94e-941881e62d8e" + ScopeSuffix;
13 | }
14 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/src/AzureTokenCredentialProviderExtensions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using Azure.Core;
7 |
8 | namespace Microsoft.DotNet.ImageBuilder;
9 |
10 | #nullable enable
11 | internal static class AzureTokenCredentialProviderExtensions
12 | {
13 | public static ValueTask GetTokenAsync(
14 | this IAzureTokenCredentialProvider provider,
15 | IServiceConnection serviceConnection,
16 | string scope = AzureScopes.DefaultAzureManagementScope)
17 | {
18 | return provider
19 | .GetCredential(serviceConnection, scope)
20 | .GetTokenAsync(new TokenRequestContext([scope]), CancellationToken.None);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/src/BlobsClientExtensions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | using System;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Octokit;
8 |
9 | #nullable enable
10 | namespace Microsoft.DotNet.ImageBuilder
11 | {
12 | public static class BlobsClientExtensions
13 | {
14 | public static async Task GetFileContentAsync(
15 | this IBlobsClient blobsClient, string repoOwner, string repoName, string fileSha)
16 | {
17 | Blob fileBlob = await blobsClient.Get(repoOwner, repoName, fileSha);
18 |
19 | switch (fileBlob.Encoding.Value)
20 | {
21 | case EncodingType.Utf8:
22 | return fileBlob.Content;
23 | case EncodingType.Base64:
24 | byte[] bytes = Convert.FromBase64String(fileBlob.Content);
25 | return Encoding.UTF8.GetString(bytes);
26 | default:
27 | throw new NotSupportedException(
28 | $"The blob for file SHA '{fileSha}' in repo '{repoOwner}/{repoName}' uses an unsupported encoding: {fileBlob.Encoding}");
29 | }
30 | }
31 | }
32 | }
33 | #nullable disable
34 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/src/Commands/AzdoTags.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | namespace Microsoft.DotNet.ImageBuilder.Commands
5 | {
6 | public static class AzdoTags
7 | {
8 | public const string AutoBuilder = "autobuilder";
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/src/Commands/BuildLegInfo.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.Collections.Generic;
6 |
7 | namespace Microsoft.DotNet.ImageBuilder.Commands
8 | {
9 | public class BuildLegInfo
10 | {
11 | public string Name { get; set; }
12 | public List<(string Name, string Value)> Variables { get; } = new List<(string, string)>();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/src/Commands/BuildMatrixInfo.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.Collections.Generic;
6 | using System.Linq;
7 |
8 | namespace Microsoft.DotNet.ImageBuilder.Commands
9 | {
10 | public class BuildMatrixInfo
11 | {
12 | public string Name { get; set; }
13 | public List Legs { get; } = new List();
14 |
15 | public IEnumerable OrderedLegs { get => Legs.OrderBy(leg => leg.Name); }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/src/Commands/CommandExtensions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | namespace Microsoft.DotNet.ImageBuilder.Commands
5 | {
6 | public static class CommandExtensions
7 | {
8 | public static string GetCommandName(this ICommand command)
9 | {
10 | string commandName = command.GetType().Name.TrimEndString("Command");
11 | return char.ToLowerInvariant(commandName[0]) + commandName.Substring(1);
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Microsoft.DotNet.ImageBuilder/src/Commands/DockerfileFilterOptions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.Collections.Generic;
6 | using System.CommandLine;
7 | using static Microsoft.DotNet.ImageBuilder.Commands.CliHelper;
8 |
9 | #nullable enable
10 | namespace Microsoft.DotNet.ImageBuilder.Commands;
11 |
12 | public class DockerfileFilterOptions
13 | {
14 | public IEnumerable Paths { get; set; } = [];
15 | public IEnumerable ProductVersions { get; set; } = [];
16 | }
17 |
18 | public class DockerfileFilterOptionsBuilder
19 | {
20 | public const string PathOptionName = "path";
21 |
22 | public IEnumerable