Skip to content

fix(compose): forward build.target/args and honor image+build (#14)#16

Merged
us merged 1 commit into
mainfrom
fix/compose-build-target-args
Jun 11, 2026
Merged

fix(compose): forward build.target/args and honor image+build (#14)#16
us merged 1 commit into
mainfrom
fix/compose-build-target-args

Conversation

@us

@us us commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Fixes #14.

Problem

mocker compose up --build ignored services.<svc>.build.target from the compose file and built the entire Dockerfile (all stages) instead of stopping at the named target. While investigating, two more related bugs surfaced.

Root causes

  1. build.target / build.args dropped at parse time. ComposeBuild had no target/args fields and ComposeService.parse() never read them, so the orchestrator had nothing to forward to container build (which already supports --target).
  2. image: + build: → registry pull (401). The orchestrator's if image { pull } else if build { build } was exclusive, so a service with both pulled image: from the registry instead of building and tagging — failing with 401 Unauthorized (reported in an issue comment).
  3. compose up --build flag never plumbed. The --build flag was parsed but never reached the orchestrator, so it couldn't force a rebuild.

Changes

  • ComposeFile.swift: add target + args to ComposeBuild; parse both (args supports map and list KEY=VALUE forms, preserving explicit empty values like REQUIRED_TOKEN=). Add a pure ComposeService.resolveImageSource(projectName:noBuild:) that decides build-vs-pull per the Compose spec, plus imageMatches for the rebuild-skip check.
  • ComposeOrchestrator.swift: startService now builds when build: is present (tagging with image: if set, never pulling), forwards target + args, and honors forceBuild/noBuild. up() accepts build/noBuild.
  • Compose.swift: compose up and compose create forward --build/--no-build; compose build forwards compose-file build.args (CLI --build-arg overrides) and build.target.

Tests

10 new unit tests (no container runtime needed) covering the exact bug points:

  • parse build.target, build.args (map + list + explicit empty value), image: + build: together
  • resolveImageSource: image-only → pull, build-only → build (synthesized tag), image:+build: → build tagged with image name, --no-build → pull, empty → none
  • imageMatches repository/tag comparison

Full suite green: 75 tests in 8 suites pass (swift build + swift test).

Note

An end-to-end compose up --build against the Apple container runtime was not run (needs a live daemon and image builds); the fix is verified by unit tests at the parse + decision layers where the bugs lived, plus the existing --target plumbing in ImageManager.build.

`compose up --build` ignored `build.target` and `build.args` because
the compose parser never read those fields, so the orchestrator could
not pass them to `container build` — the whole Dockerfile was built
instead of stopping at the target stage. Parse both (args supports map
and list forms, preserving explicit empty values) and forward them from
both `compose up` and `compose build`.

A service declaring both `image:` and `build:` previously pulled the
`image:` reference from a registry (401) instead of building. Per the
Compose spec it must build from context and tag the result with the
`image:` name; pull only when there is no build config. The decision is
extracted into a pure `ComposeService.resolveImageSource` for testing.

Also plumb `--build`/`--no-build` from the CLI into the orchestrator so
`--build` forces a rebuild instead of being silently ignored.
@us us merged commit 31a9a69 into main Jun 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mocker compose up --build ignores build.target from docker-compose.yaml

1 participant