Skip to content

ci: default local compose runs to the pinned Quest build - #150

Merged
VibeSWE merged 3 commits into
mainfrom
ci/pin-quest-image
Nov 12, 2026
Merged

VibeSWE merged 3 commits into
mainfrom
ci/pin-quest-image

Conversation

@VibeSWE

@VibeSWE VibeSWE commented Nov 11, 2026 •

Copy link
Copy Markdown

Why

#152 already builds Quest in CI from f4a026eecde1badde8776ff366a743f9bbca2e67. It tags the result quest-ci:pinned with pull policy never and runs Compose with --no-build.

Local Compose still defaulted to the floating quay.io/parseablehq/quest:main image. That image expects HTTP 202 from stream DELETE, but this fork deletes synchronously and returns 200, so the smoke tests fail locally.

What changes

A new shared file, docker-compose-quest.yaml, holds the only Quest definition outside the workflow. It has two variants:

Variant Contents Default pull_policy
quest-source Build context only: https://github.com/parseablehq/quest.git#${QUEST_SOURCE_REF:-f4a026ee…}. No image:, so Compose tags the build <project>-quest. build
quest-source-image image: ${QUEST_IMAGE} only, with no build section. missing

The quest service in each of the five integration compose files selects a variant with:

extends:
  file: docker-compose-quest.yaml
  service: quest-source${QUEST_IMAGE:+-image}

The per-file platform, command, depends_on, networks and deploy are unchanged. The workflow is not touched.

So:

  • An explicit QUEST_IMAGE is never rebuilt. It reuses the local image or pulls it if missing. Before this change, QUEST_IMAGE=quay.io/parseablehq/quest:main docker compose up rebuilt the pinned source and overwrote the local upstream image with it.
  • QUEST_SOURCE_REF no longer produces a misleading quest-pinned:f4a026e tag. Builds are tagged <project>-quest. Refs aren't used as tags because they can contain /.
  • The pin now lives in 2 places instead of ~16: docker-compose-quest.yaml and QUEST_SOURCE_REF in .github/workflows/integration-test.yaml. To remove it (issue Port upstream asynchronous, resumable stream deletion (DELETE returns 202) #151), run grep -rnE 'issue #151|f4a026e' .

Behaviour by env

These rows were verified identically for all five files, on Compose 2.24.7 and 5.6.1.

Env Quest image pull_policy up up --no-build
none <project>-quest build builds pinned source, no pull neither (needs an existing <project>-quest)
only QUEST_IMAGE=quay.io/parseablehq/quest:main supplied missing reuses if local, pulls if absent, never builds same
only QUEST_PULL_POLICY=build <project>-quest build builds pinned source neither
only QUEST_PULL_POLICY=never <project>-quest never reuses local; Compose builds if absent neither
only QUEST_SOURCE_REF=<ref> <project>-quest build builds that ref neither (may reuse an older ref's build — rebuild first)
CI: QUEST_IMAGE=quest-ci:pinned QUEST_PULL_POLICY=never QUEST_SOURCE_REF=<pin> quest-ci:pinned never neither build nor pull neither build nor pull
upstream opt-out: QUEST_IMAGE=quay.io/parseablehq/quest:main QUEST_PULL_POLICY=always supplied always pulls, never builds pulls, never builds

An empty QUEST_IMAGE= counts as unset and selects the source build. Whitespace selects image mode and fails with invalid reference format.

Trade-off: rebuild on every up

Without env vars, pull_policy: build re-runs the Quest build on every up. It is deliberate: the tag doesn't encode the ref, so a changed QUEST_SOURCE_REF must never silently reuse a stale image.

  • BuildKit's layer cache makes repeat builds cheap: 4.8 s the first time and 0.9 s the second here, on a host whose BuildKit cache already held these Quest layers. A cold first build, especially under QEMU on Apple Silicon, will be slower.
  • The git build context still needs network access.
  • For offline or repeated runs, run docker compose build quest once and then docker compose up --no-build.

Verification

Each case was resolved with docker compose config --format json and run with docker compose --dry-run up --no-deps quest, with and without --no-build. That covered the 7 env rows above (plus CI's env passed via COMPOSE_FILE=), all 5 files, on Compose 5.6.1 and 2.24.7.

  • Before the fix (7a6b198): the image-only override bug reproduced in all five files on both versions.
  • After the fix (61f9a93): 40/40 rows matched the expected behaviour on each version. Running the matrix left the local image inventory unchanged.

Core commands:

# Default: source build, no image, pull_policy build
env -u QUEST_IMAGE -u QUEST_SOURCE_REF -u QUEST_PULL_POLICY \
  docker compose -f docker-compose-test.yaml config --format json | jq '.services.quest | {image, build, pull_policy}'

# Image override: image + missing, no build section; dry run never builds
QUEST_IMAGE=quay.io/parseablehq/quest:main docker compose -f docker-compose-test.yaml config --format json | jq '.services.quest | {image, build, pull_policy}'
QUEST_IMAGE=quay.io/parseablehq/quest:main docker compose -f docker-compose-test.yaml --dry-run up --no-deps quest

# CI's exact env: neither build nor pull
QUEST_IMAGE=quest-ci:pinned QUEST_PULL_POLICY=never QUEST_SOURCE_REF=f4a026eecde1badde8776ff366a743f9bbca2e67 \
  COMPOSE_FILE=docker-compose-test.yaml docker compose --dry-run up --no-build --no-deps quest

# All five files resolve
for f in docker-compose-test.yaml docker-compose-test-with-kafka.yaml docker-compose-distributed-test.yaml \
  docker-compose-distributed-test-with-kafka.yaml docker-compose-gcs-distributed-test.yaml; do
  docker compose -f "$f" config -q
done

Further checks:

  • With CI's env, the resolved services config is byte-identical to main for all five files, with and without the CI smoke overlay, on both Compose versions.
  • Real local standalone smoke on e784cd3, with no QUEST_* variables, so Compose built the pinned Quest itself: 73 passed and 0 failed (including subtests), Quest exited 0. A second up also passed 73/0, rebuilding Quest from cache in 0.9 s. The follow-up commit 61f9a93 only changes comments, and its resolved config is byte-identical.
  • Two independent reviewers re-reviewed the change and both approved. Their minor comment suggestions went into 61f9a93.

Temporary compatibility pin: remove with #151.

🤖 Generated with Claude Code

@VibeSWE VibeSWE changed the title ci: pin Quest to the pre-async-delete commit so smoke tests pass ci: default local compose runs to the pinned Quest build Nov 11, 2026
VibeSWE and others added 2 commits November 11, 2026 15:28
Share the pinned source definition and select an image-only service when QUEST_IMAGE is supplied. Preserve CI no-build/no-pull behavior and avoid ref-derived tags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@VibeSWE
VibeSWE merged commit 65ee74f into main Nov 12, 2026
9 checks 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.

1 participant