Repository navigation
fix(cli)!: build a Dockerfile configuration in one build as the reference does - #70
Merged
Merged
Conversation
…ence does build and up built a Dockerfile configuration in two steps: the user's Dockerfile with --target <stage> (written as <Dockerfile>.devcontainer.build next to it when its final stage had no name), then, with Features, a second build FROM that image. The file in the workspace failed a read-only workspace and was left behind on an interrupted build, the intermediate image changed layering and the cache, and --push/--output were dropped from the base build. As the reference CLI's buildAndExtendImage, the CLI now writes one combined Dockerfile-with-features (the user's Dockerfile, its final stage named, then the dev_containers_target_stage stage that installs the Features and writes the devcontainer.metadata LABEL, or only the label with no Features) into the Features folder under the cache folder, and runs one build with --target dev_containers_target_stage. The Dockerfile and the build arguments are byte-identical to what v0.90.0 writes and runs for the same configurations. Features and the lockfile are resolved before the build, as in TS. The Go-only behavior carries over to the single build: --secrets-file and --ca-bundle secrets, a sibling <Dockerfile>.dockerignore (#969), the final stage's own devcontainer.metadata entries (#1225), and build contexts. build's hidden --omit-syntax-directive now takes effect. BREAKING CHANGE: up tags a Dockerfile configuration's image with Features vsc-<folder>-<hash>, as the official CLI does, instead of vsc-<folder>-<hash>-features; the build no longer writes <Dockerfile>.devcontainer.build into the workspace. docs/migration.md lists both. Co-Authored-By: Claude Opus 5.5 <[email protected]>
aledbf
force-pushed
the
align-single-build
branch
from
November 13, 2026 02:08
6c4b1f9 to
ce4a03c
Compare
aledbf
added a commit
that referenced
this pull request
Nov 13, 2026
The one-build path for Dockerfile configurations (#70) built its Features stage without the config's containerEnv order, so those ENV lines came out sorted there while image configurations kept the declared order. A Dockerfile variant of the declaration-order parity case compares the built image with the reference. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Aligns how a Dockerfile-based dev container is built with the official CLI (TS
buildAndExtendImage,singleContainer.ts). Breaking: seedocs/migration.md.Before (Go)
build -f <workspace>/.devcontainer/Dockerfile.devcontainer.build --target <stage>. The file is written into the workspace when the final stage has no name, which fails on a read-only workspace.--push/--outputwere dropped when there were Features.FROMthat image (Dockerfile.extended), re-tagged; onup, tagged…-features.After (Go = TS v0.90.0)
Dockerfile-with-featuresis written to<cache>/container-features/<ver>-<ms>/, never the workspace. It holds the user's Dockerfile with its final stage named, then thedev_containers_target_stagestage that installs the Features and writes thedevcontainer.metadataLABEL. With no Features, that stage only writes the label, as TS does.--target dev_containers_target_stage. The Dockerfile and the argv are byte-identical to what TS wrote and ran for the same configs (golden-checked).--push/--outputreach the one build.docker historymatches TS (the label is aLABELinstruction).Go-only behavior kept, now in the single build:
--secrets-file/--ca-bundlesecrets, the sibling.dockerignore(#969), the final stage's owndevcontainer.metadata(#1225), build contexts, and the build-auth bridge.build --omit-syntax-directive, declared but ignored before, now takes effect for Dockerfile and compose builds.Breaking
uptags a Dockerfile config with Featuresvsc-<folder>-<hash>, as TS does, no longer…-features.<Dockerfile>.devcontainer.buildfile is written into the workspace.upFeature-fetch error on this path loses theinstall features:prefix.Tests
TestBuildDockerfileBuildsOnce/TestUpDockerfileBuildsOnceassert one build, the cache-folder-f, the target, the tags, and an unchanged read-only workspace. Onmainthey fail withpermission denied; with a writable workspace they show two builds.TestBuildDockerfileWritesTheReferenceDockerfile: byte-exact goldens of the Dockerfile and argv, compared with TS's output..dockerignore, metadata label order, build flags, the non-BuildKit path, failures and the syntax directive.build.read-only-workspace-dockerfile-success,up.read-only-workspace-dockerfile-success.docs/DIVERGENCES.mdnow citesTestBuildDockerfileMetadataLabel(#1225) andTestBuildDockerfileKeepsTheSiblingDockerignore(#969).Still different from TS (follow-ups):
build --labelapplies to Dockerfile configs (TS ignores it there); no SELinux--security-opt label=disablefor build contexts;build.argsorder comes from a Go map.Validation (local, after rebasing onto
mainwith #66)task lint: pass.task test:racewithTMPDIRoutside/tmp: pass.task parity:contract: only the 2 known/tmp/.gitcases fail.task spec:compliance: pass (before the rebase).test:e2e: all pass with a longer timeout; the 5m task budget ran out under parallel load. After the rebase,TestE2E_BuildUpExec_Dockerfile,TestE2E_SiblingDockerignoreandTestE2E_UpSecretsFilepass.PARITY_COMMAND=build task parity:runtime: 48 pass; 4 TS-timeout inconclusives pass alone.PARITY_COMMAND=up task parity:runtime: the only failures are the/tmp/.gitremoteWorkspaceFoldergroup, also present onmainon this machine.🤖 Generated with Claude Code