Skip to content

Skip redundant container uploads for existing manifests - #55690

Merged
baronfel merged 2 commits into
dotnet:mainfrom
jetersen:feat/skip-unchanged-container-push
Aug 18, 2026
Merged

Skip redundant container uploads for existing manifests#55690
baronfel merged 2 commits into
dotnet:mainfrom
jetersen:feat/skip-unchanged-container-push

Conversation

@jetersen

@jetersen jetersen commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Add an opt-in ContainerSkipPushIfAlreadyPresent property for remote registry publishes.

When enabled, the SDK checks whether the locally computed manifest digest already exists in the destination repository. If it does, the publish skips layer and configuration blob uploads while still applying every requested image tag to the existing manifest. If it does not, publishing follows the existing upload path.

The property defaults to false, so existing behavior is unchanged.

Details

  • add manifest HEAD support through IManifestOperations.ExistsAsync
  • treat a successful response as present and ordinary client/auth/method failures as a safe fall-through to the normal push path
  • propagate registry server errors
  • thread the opt-in through CreateNewImage, ImagePublisher, and the container targets
  • retain tag updates when blob uploads are skipped
  • emit a localized log message when an existing manifest is reused
  • apply the optimization to the individual image manifests in multi-platform publishing, while leaving image-index publishing unchanged

This intentionally does not skip the local image build. The SDK must still build the image locally to compute BuiltImage.ManifestDigest. The optimization avoids redundant registry blob transfer.

Dependency

The common unchanged-build case depends on deterministic image output. #55689 implements the deterministic timestamps, layer ordering, and PAX normalization needed for independently built identical inputs to produce the same digest.

Verification

  • focused RegistryTests: 32 passed, 5 skipped
  • full Microsoft.NET.Build.Containers.UnitTests: 322 passed, 6 skipped, with one unrelated environment-specific failure in DockerDaemonTests.Can_detect_when_no_daemon_is_running; the isolated rerun reproduced because a runtime is available at the test's supposedly unused endpoint
  • package-based end-to-end publish against a local registry: second identical publish emitted the manifest-reuse message, performed zero layer/config uploads, preserved the blob count at 8, added the reused tag, and kept both tags on digest sha256:1754b379…
  • remote registry validation using the unified Make published container images reproducible #55689 plus this change payload: all four single/multi-RID × OCI/Docker cells preserved their first digest across stable and reused, emitted one skip per single manifest or two skips for multi-platform inner manifests, performed zero repeated layer/config uploads, and reported the expected manifest/index media type; all four temporary repositories were deleted afterward

Fixes #54038

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
2 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@jetersen
jetersen marked this pull request as ready for review August 9, 2026 07:08
@jetersen
jetersen requested a review from a team as a code owner August 9, 2026 07:08
Copilot AI lite review requested due to automatic review settings August 9, 2026 07:08
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
2 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an opt-in ContainerSkipPushIfAlreadyPresent property to optimize remote container publishes by checking (via manifest HEAD) whether a locally computed manifest digest already exists in the destination repository, and when present skipping layer/config uploads while still updating tags.

Changes:

  • Introduces manifest-existence probing via IManifestOperations.ExistsAsync and wires it into Registry.PushAsync to conditionally skip blob uploads.
  • Threads the new opt-in through the MSBuild targets and CreateNewImageImagePublisher publish path.
  • Adds unit test coverage for manifest existence behavior and the “skip uploads but still tag” push flow, plus a localized log message for manifest reuse.

Reviewed changes

Copilot reviewed 24 out of 25 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/Microsoft.NET.Build.Containers.UnitTests/RegistryTests.cs Adds unit tests for manifest HEAD existence checks and push skip behavior.
test/Microsoft.NET.Build.Containers.IntegrationTests/EndToEndTests.cs Updates call site for ImagePublisher.PublishImageAsync signature change.
src/Containers/packaging/build/Microsoft.NET.Build.Containers.targets Adds and flows ContainerSkipPushIfAlreadyPresent MSBuild property into tasks/logging.
src/Containers/Microsoft.NET.Build.Containers/Tasks/CreateNewImage.Interface.cs Adds new task parameter SkipPushIfAlreadyPresent.
src/Containers/Microsoft.NET.Build.Containers/Tasks/CreateNewImage.cs Passes the new opt-in to ImagePublisher.PublishImageAsync.
src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.*.xlf Adds localization entries for the new “manifest already exists” message.
src/Containers/Microsoft.NET.Build.Containers/Resources/Strings.resx Adds the Registry_ManifestExists resource string.
src/Containers/Microsoft.NET.Build.Containers/Resources/Strings.Designer.cs Regenerates designer to include Registry_ManifestExists.
src/Containers/Microsoft.NET.Build.Containers/Registry/Registry.cs Implements the skip behavior (manifest HEAD check + conditional blob uploads) and logs reuse.
src/Containers/Microsoft.NET.Build.Containers/Registry/IManifestOperations.cs Extends manifest operations abstraction with ExistsAsync.
src/Containers/Microsoft.NET.Build.Containers/Registry/DefaultManifestOperations.cs Implements ExistsAsync using HEAD with manifest accept headers and 5xx propagation.
src/Containers/Microsoft.NET.Build.Containers/PublicAPI/net11.0/PublicAPI.Unshipped.txt Adds the new CreateNewImage.SkipPushIfAlreadyPresent API surface.
src/Containers/Microsoft.NET.Build.Containers/ImagePublisher.cs Threads the new opt-in into the remote push delegate for single-arch images.
Files not reviewed (1)
  • src/Containers/Microsoft.NET.Build.Containers/Resources/Strings.Designer.cs: Generated file

Comment thread test/Microsoft.NET.Build.Containers.UnitTests/RegistryTests.cs Outdated
Comment thread src/Containers/Microsoft.NET.Build.Containers/Registry/Registry.cs Outdated
Comment thread src/Containers/Microsoft.NET.Build.Containers/Registry/Registry.cs Outdated
@baronfel baronfel self-assigned this Aug 10, 2026
@baronfel baronfel added the Area-Containers Related to dotnet SDK containers functionality label Aug 10, 2026
Comment thread src/Containers/Microsoft.NET.Build.Containers/Tasks/CreateNewImage.Interface.cs Outdated

@baronfel baronfel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this PR! It's a great change. The only feedback I have matches @lbussell - let's make this behavior the default.

@baronfel
baronfel merged commit 861789d into dotnet:main Aug 18, 2026
21 checks passed
@baronfel

Copy link
Copy Markdown
Member

/backport to release/11.0.1xx-rc1

@baronfel

Copy link
Copy Markdown
Member

/backport to release/11.0.1xx

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0.1xx-rc1 (link to workflow run)

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0.1xx (link to workflow run)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Containers Related to dotnet SDK containers functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cross-run publish skip via registry as oracle

4 participants